feat: harden bridge origin/CSP, cache decryption, and overhaul the web client UI
This commit is contained in:
parent
f637d5be57
commit
80133da100
10 changed files with 975 additions and 352 deletions
|
|
@ -184,4 +184,46 @@ for (const v of vectors.ed_to_x25519) {
|
|||
eq("cert-len", String(chain[0].length), "136");
|
||||
}
|
||||
|
||||
// --- response framing guards (§6.1) -------------------------------------------
|
||||
|
||||
// A Session over a scripted server. The cipher states are the identity, so the
|
||||
// bytes handed in are exactly what call() parses; readNoise wants at least 16,
|
||||
// and trailing bytes past the frame length are ignored by design.
|
||||
function scriptedSession(frame) {
|
||||
const message = crypto.concat(frame, new Uint8Array(Math.max(0, 16 - frame.length)));
|
||||
const wire = {
|
||||
queue: crypto.concat(proto.u16BE(message.length), message),
|
||||
pos: 0,
|
||||
async readExact(n) {
|
||||
if (this.pos + n > this.queue.length) throw new Error("script exhausted");
|
||||
this.pos += n;
|
||||
return this.queue.slice(this.pos - n, this.pos);
|
||||
},
|
||||
};
|
||||
const passthrough = { encrypt: bytes => bytes, decrypt: bytes => bytes };
|
||||
return new proto.Session(wire, { send() {}, close() {} }, passthrough, passthrough);
|
||||
}
|
||||
|
||||
async function refuses(name, frame, op) {
|
||||
let threw = false;
|
||||
try { await scriptedSession(frame).call(op); } catch { threw = true; }
|
||||
ok(name, threw, "call resolved instead of throwing");
|
||||
}
|
||||
|
||||
// The shortest legal response is a type byte and a status byte.
|
||||
await refuses("frame-too-short",
|
||||
crypto.concat(proto.u32BE(1), Uint8Array.of(proto.OP.FETCH)), proto.OP.FETCH);
|
||||
|
||||
// A response reuses the request's type byte; a mismatch means the session
|
||||
// desynchronised, which must not be read as a status.
|
||||
await refuses("frame-op-mismatch",
|
||||
crypto.concat(proto.u32BE(2), Uint8Array.of(proto.OP.RESOLVE, 0)), proto.OP.FETCH);
|
||||
|
||||
// The same frame with the right echo still passes, so the guard is not
|
||||
// simply rejecting everything.
|
||||
{
|
||||
const session = scriptedSession(crypto.concat(proto.u32BE(2), Uint8Array.of(proto.OP.FETCH, 0)));
|
||||
eq("frame-op-echo-ok", (await session.call(proto.OP.FETCH)).status, 0);
|
||||
}
|
||||
|
||||
console.log(`${passed} checks passed`);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue