// What the two runs here share (verify_peer.mjs under node, run.mjs with a browser): the bundle // loaded in node, the corpus's world, and a holder reached over HTTP (§4.5) on node's own // http module. Nothing here is fetched or installed. import { createServer } from "node:http"; import { readFileSync } from "node:fs"; import { join } from "node:path"; import { hex, unhex } from "./peer.js"; /** The `peer` bundle (pkg/, built for the web) instantiated in node. */ export async function loadBundle(pkg) { const glue = readFileSync(join(pkg, "wai_peer.js")); const w = await import(`data:text/javascript;base64,${glue.toString("base64")}`); await w.default({ module_or_path: readFileSync(join(pkg, "wai_peer_bg.wasm")) }); return w; } /** The corpus's world: groups with their receipts, and each object's receipt and envelope. */ export function loadWorld(waiRoot) { const text = readFileSync(join(waiRoot, "live-conformance/peer-delivery/vectors.json"), "utf8"); const groups = JSON.parse(text).world.groups.map((g) => ({ link: g.link, receipt: g.receipt, objects: g.objects.map((o) => ({ receipt: o.receipt, envelope: unhex(o.envelope) })), })); return { text, groups }; } /** Listen on a port the system picks, and say which. */ export function listen(handler, name) { return new Promise((ok) => { const server = createServer(handler); server.listen(0, "127.0.0.1", () => { console.log(` ${name}: listening on 127.0.0.1:${server.address().port}`); ok(server); }); }); } const CORS = { "access-control-allow-origin": "*", "access-control-allow-methods": "GET, POST", "access-control-allow-headers": "content-type", "cache-control": "no-store" }; /** * A holder reached over HTTP: `server` is a PeerServer; `log` takes one line a request. The * handler answers the three requests of §4.5 under `/`, and nothing else. */ export function httpHolder(server, log = () => {}) { return async (req, res) => { const path = new URL(req.url, "http://x").pathname; // What the request carried that §7 says it must not: checked by the runs. log({ method: req.method, path, cookie: req.headers.cookie || null, authorization: req.headers.authorization || null, referer: req.headers.referer || null }); const end = (status, body = new Uint8Array(0)) => res.writeHead(status, { ...CORS, "content-type": "application/octet-stream", "content-length": body.length }).end(body); if (req.method === "OPTIONS") return end(204); if (!server.mayServe) return end(503); const object = /^\/object\/([0-9a-f]{64})\/(0|[1-9][0-9]*)$/.exec(path); if (req.method === "GET" && path === "/holdings") { const r = server.record(); return r ? end(200, r) : end(503); } if (req.method === "GET" && object) { const a = await server.object("http", unhex(object[1]), Number(object[2])); if (a.miss) return end(a.miss === 3 ? 503 : 404); return end(200, a.bytes); } if (req.method === "POST" && path === "/ack") { const parts = []; let n = 0; for await (const c of req) { n += c.length; if (n > 1 << 16) return end(422); parts.push(c); } const r = server.takeAck("http", new Uint8Array(Buffer.concat(parts))); return r.outcome === "taken" ? end(200, unhex(r.digest)) : end(422); } return end(404); }; } /** A counter of checks, printed one a line; fewer checks than `expected` is a failure too. */ export function checks() { let passed = 0; let failed = 0; return { expect(cond, what) { if (cond) passed++; else failed++; console.log(` ${cond ? "ok " : "FAIL"} ${what}`); return cond; }, done(expected) { const short = passed + failed !== expected; if (short) console.log(` FAIL ${passed + failed} checks ran and ${expected} were expected`); console.log(`${failed || short ? "FAIL" : "PASS"}: ${passed} of ${expected} checks hold`); return failed || short ? 1 : 0; }, }; } export const sha256 = async (bytes) => hex(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes)));