summaryrefslogtreecommitdiff
path: root/crates/chat-crypto/browser
diff options
context:
space:
mode:
Diffstat (limited to 'crates/chat-crypto/browser')
-rw-r--r--crates/chat-crypto/browser/wasi.mjs50
1 files changed, 43 insertions, 7 deletions
diff --git a/crates/chat-crypto/browser/wasi.mjs b/crates/chat-crypto/browser/wasi.mjs
index d27fe4b..80d1299 100644
--- a/crates/chat-crypto/browser/wasi.mjs
+++ b/crates/chat-crypto/browser/wasi.mjs
@@ -15,10 +15,14 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-export async function runProbe(bytes) {
+async function execute(bytes, input) {
let memory;
let output = '';
let errors = '';
+ const stdoutDecoder = new TextDecoder('utf-8', { fatal: true });
+ const stderrDecoder = new TextDecoder('utf-8', { fatal: true });
+ const stdin = new TextEncoder().encode(input);
+ let position = 0;
let randomCalls = 0;
let randomBytes = 0;
const data = () => new DataView(memory.buffer);
@@ -54,15 +58,28 @@ export async function runProbe(bytes) {
for (let index = 0; index < count; index += 1) {
const address = data().getUint32(vectors + index * 8, true);
const length = data().getUint32(vectors + index * 8 + 4, true);
- const text = new TextDecoder().decode(new Uint8Array(memory.buffer, address, length));
+ const text = (fd === 1 ? stdoutDecoder : stderrDecoder).decode(new Uint8Array(memory.buffer, address, length), { stream: true });
if (fd === 1) output += text; else errors += text;
total += length;
- if (output.length + errors.length > 65536) throw new Error('Probe output exceeded its limit');
+ if (output.length + errors.length > 1048576) throw new Error('Probe output exceeded its limit');
}
put32(written, total);
return 0;
},
- fd_read(fd, vectors, count, read) { if (fd !== 0) return 8; put32(read, 0); return 0; },
+ fd_read(fd, vectors, count, read) {
+ if (fd !== 0) return 8;
+ let total = 0;
+ for (let index = 0; index < count && position < stdin.length; index += 1) {
+ const address = data().getUint32(vectors + index * 8, true);
+ const capacity = data().getUint32(vectors + index * 8 + 4, true);
+ const length = Math.min(capacity, stdin.length - position);
+ new Uint8Array(memory.buffer, address, length).set(stdin.subarray(position, position + length));
+ position += length;
+ total += length;
+ }
+ put32(read, total);
+ return 0;
+ },
fd_fdstat_get(fd, address) {
if (fd > 2) return 8;
new Uint8Array(memory.buffer, address, 24).fill(0);
@@ -97,10 +114,29 @@ export async function runProbe(bytes) {
memory = instance.exports.memory;
try { instance.exports._start(); }
catch (error) { if (!(error instanceof Exit) || error.code !== 0) throw new Error(`${error.message}: ${errors}`); }
- if (!output.startsWith('PASS: backend=OpenSSL ') || randomCalls === 0) {
- throw new Error(`OpenSSL probe did not pass: ${errors || output}`);
- }
+ output += stdoutDecoder.decode();
+ errors += stderrDecoder.decode();
+ stdin.fill(0);
return { output, randomCalls, randomBytes };
}
+async function runProbe(bytes) {
+ const result = await execute(bytes, '');
+ if (!result.output.startsWith('PASS: backend=OpenSSL ') || result.randomCalls === 0) {
+ throw new Error('OpenSSL probe did not pass');
+ }
+ return result;
+}
+
+async function runCommand(bytes, request) {
+ const input = JSON.stringify(request);
+ if (input.length > 8388608) throw new Error('Crypto request exceeds its limit');
+ const result = await execute(bytes, input);
+ const response = JSON.parse(result.output);
+ if (response.error) throw new Error(response.error);
+ return response;
+}
+
+globalThis.stackChatWasi = Object.freeze({ runCommand, runProbe });
+
// @license-end