import assert from "node:assert/strict"; import { createPublicKey, verify } from "node:crypto"; import { test } from "node:test"; import { createDidKey, didkeyCall, GET_SERVICE_AUTH, ingressHost, SIGN, serviceAud } from "./index.js"; const N = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551n; const key = await createDidKey(); const pub = createPublicKey({ key: { kty: "EC", crv: "P-256", x: key.jwk.x, y: key.jwk.y }, format: "jwk" }); const verifies = (data, sig) => verify("sha256", data, { key: pub, dsaEncoding: "ieee-p1363" }, sig); const unb64url = (text) => Buffer.from(text, "base64url"); test("the did is a P-256 did:key, stable for the same JWK", async () => { assert.match(key.did, /^did:key:zDn[1-9A-HJ-NP-Za-km-z]{44,46}$/); assert.equal((await createDidKey(key.jwk)).did, key.did); assert.notEqual((await createDidKey()).did, key.did); assert.equal(ingressHost(key.did), `${key.did.replaceAll(":", "-").toLowerCase()}.xrpc.fedproxy.com`); }); test("sign is sha256 ECDSA, compact and low-S", async () => { for (let i = 0; i < 20; i++) { const data = crypto.getRandomValues(new Uint8Array(64)); const sig = await key.sign(data); assert.equal(sig.length, 64); assert.ok(BigInt(`0x${Buffer.from(sig.subarray(32)).toString("hex")}`) <= N / 2n); assert.ok(verifies(data, sig)); } }); test("serviceAuth is an ES256 JWT the did:key signs for itself, exp capped at an hour", async () => { const now = Math.floor(Date.now() / 1000); const token = await key.serviceAuth({ aud: "did:web:xrpc.fedproxy.com", lxm: "com.fedproxy.temp.xrpc.subscribe", exp: now + 99999 }); const [header, payload, sig] = token.split("."); assert.deepEqual(JSON.parse(unb64url(header)), { typ: "JWT", alg: "ES256" }); const claims = JSON.parse(unb64url(payload)); assert.equal(claims.iss, key.did); assert.equal(claims.aud, "did:web:xrpc.fedproxy.com"); assert.equal(claims.lxm, "com.fedproxy.temp.xrpc.subscribe"); assert.ok(claims.exp <= now + 3601 && claims.exp >= now + 3599); assert.ok(verifies(Buffer.from(`${header}.${payload}`), unb64url(sig))); const short = JSON.parse(unb64url((await key.serviceAuth({ aud: "did:web:x", lxm: "a.b.c" })).split(".")[1])); assert.ok(short.exp - short.iat === 300); }); test("didkeyCall answers the pseudo-calls, signs service calls it is told to, passes the rest on", async () => { const fetched = []; const passed = []; const call = didkeyCall(key, async (nsid, request) => (passed.push([nsid, request]), { inner: true }), { services: ["https://xrpc.fedproxy.com"], fetch: async (url, init) => (fetched.push([url, init]), new Response(JSON.stringify({ nonce: "bm9uY2U=" }))), }); const auth = await call(GET_SERVICE_AUTH, { params: { aud: "did:web:xrpc.fedproxy.com", lxm: "com.fedproxy.temp.xrpc.getRegistrationNonce" } }); assert.equal(auth.did, key.did); assert.equal(JSON.parse(unb64url(auth.token.split(".")[1])).lxm, "com.fedproxy.temp.xrpc.getRegistrationNonce"); await assert.rejects(call(GET_SERVICE_AUTH, { params: { aud: "nope", lxm: "a.b.c" } }), /aud/); const nonce = crypto.getRandomValues(new Uint8Array(64)); const signed = await call(SIGN, { input: { data: Buffer.from(nonce).toString("base64") } }); assert.equal(signed.did, key.did); assert.ok(verifies(nonce, Buffer.from(signed.signature, "base64"))); await assert.rejects(call(SIGN, { input: {} }), /data/); // only the relay nonce shape: a module must not get a JWS signing input signed (its own JWT) const jws = (await key.serviceAuth({ aud: "did:web:x", lxm: "a.b.c" })).split(".").slice(0, 2).join("."); for (const bad of [Buffer.from("hello"), Buffer.from(jws), Buffer.from(jws.slice(0, 64)), Buffer.concat([nonce, nonce])]) await assert.rejects(call(SIGN, { input: { data: bad.toString("base64") } }), /only a relay nonce/); assert.deepEqual(await call("com.fedproxy.temp.xrpc.getRegistrationNonce", { service: "https://xrpc.fedproxy.com", input: { key: key.did, signatures: [] } }), { nonce: "bm9uY2U=" }); const [url, init] = fetched[0]; assert.equal(url, "https://xrpc.fedproxy.com/xrpc/com.fedproxy.temp.xrpc.getRegistrationNonce"); assert.equal(init.method, "POST"); assert.deepEqual(JSON.parse(init.body), { key: key.did, signatures: [] }); const claims = JSON.parse(unb64url(init.headers.authorization.slice("Bearer ".length).split(".")[1])); assert.deepEqual([claims.iss, claims.aud, claims.lxm], [key.did, "did:web:xrpc.fedproxy.com", "com.fedproxy.temp.xrpc.getRegistrationNonce"]); // Subscriptions, other services and plain calls are the inner call's. await call("com.fedproxy.temp.xrpc.subscribe", { service: "https://xrpc.fedproxy.com", subscribe: true, params: {} }); await call("a.b.c", { service: "https://elsewhere.example" }); await call("com.atproto.repo.describeRepo", { service: "did:plc:abc", params: { repo: "did:plc:abc" } }); assert.deepEqual(passed.map(([nsid]) => nsid), ["com.fedproxy.temp.xrpc.subscribe", "a.b.c", "com.atproto.repo.describeRepo"]); assert.equal(fetched.length, 1); }); test("serviceAud: did:web of the service host, a port as %3A (the Rust host's service_aud)", () => { assert.equal(serviceAud("https://svc.example/x"), "did:web:svc.example"); assert.equal(serviceAud("https://svc.example:443/"), "did:web:svc.example"); assert.equal(serviceAud("https://svc.example:8443/xrpc"), "did:web:svc.example%3A8443"); }); test("didkeyCall: a subscribe with serviceAuth to a listed service carries a token the did:key signs", async () => { const key = await createDidKey(); const seen = []; const inner = async (nsid, request) => (seen.push(request), { async *[Symbol.asyncIterator]() { yield "message"; }, close() {} }); const call = didkeyCall(key, inner, { services: ["https://xrpc.fedproxy.com"] }); const NSID = "com.fedproxy.temp.xrpc.subscribe"; const first = await call(NSID, { subscribe: true, service: "https://xrpc.fedproxy.com", params: { did: key.did }, serviceAuth: { param: "service_auth" } }); // one serving instance per did:key: another relay subscribe is refused while this one is open await assert.rejects(call(NSID, { subscribe: true, service: "https://xrpc.fedproxy.com", serviceAuth: {} }), /already serving in another run/); first.close(); const second = await call(NSID, { subscribe: true, service: "https://xrpc.fedproxy.com", serviceAuth: {} }); for await (const message of second) assert.equal(message, "message"); // the stream ending gives the lease back too (await call(NSID, { subscribe: true, service: "https://xrpc.fedproxy.com", serviceAuth: {} })).close(); await call(NSID, { subscribe: true, service: "https://other.example", serviceAuth: {} }); const claims = (jwt) => JSON.parse(Buffer.from(jwt.split(".")[1], "base64url")); assert.equal(seen[0].serviceAuth, undefined); assert.deepEqual({ ...claims(seen[0].params.service_auth), exp: 0, iat: 0, jti: 0 }, { ...claims(seen[0].params.service_auth), iss: key.did, aud: "did:web:xrpc.fedproxy.com", lxm: NSID, exp: 0, iat: 0, jti: 0 }); assert.match(seen[1].headers.authorization, /^Bearer ey/); assert.deepEqual(seen[3].serviceAuth, {}, "not a listed service: left for the host (the session's token)"); const browser = didkeyCall(key, inner, { services: ["https://xrpc.fedproxy.com"], canHeader: false }); await assert.rejects(browser(NSID, { subscribe: true, service: "https://xrpc.fedproxy.com", serviceAuth: {} }), /browsers cannot set WebSocket headers/); });