import assert from "node:assert/strict"; import test from "node:test"; import { randomUUID } from "node:crypto"; import { AgentPushClient, agentPushAuthorityScope, agentPushCursor, createAgentPresenceReporter, createAgentPushController, MAX_AGENT_PUSH_REVOCATIONS, parseAgentPushConfig, parseAgentPushConsent, } from "../src/lib/agent-push.ts"; import { agentAuthFrame, applyAgentEvent, createAgentRoomState, parseAgentRoomEvent } from "../src/lib/agent-room.ts"; const sourceId = "4599d348-e053-4937-987d-1392746fb2ce"; const replacementSourceId = "22222222-2222-4222-8222-222222222222"; const configuration = () => ({ version: 1, enabled: true, webPushAvailable: true, apnsAvailable: false, sourceId, quarantined: false, vapidPublicKey: "B".repeat(87), policy: { presenceHeartbeatMs: 15000, presenceLeaseMs: 60000 } }); const deferred = () => { let resolve, reject; const promise = new Promise((yes, no) => { resolve = yes; reject = no; }); return { promise, resolve, reject }; }; const settle = () => new Promise(resolve => setImmediate(resolve)); function fixture(overrides = {}, shared = {}) { let record = shared.record || null, subscription = null, permission = "default", support = "supported", config = configuration(); const calls = [], states = []; const api = { config: async () => config, register: async (id, value) => { calls.push(["register", id, value]); }, revoke: async id => { calls.push(["revoke", id]); }, ...overrides.api, }; const makeSubscription = (endpoint = "https://push.example.test/opaque") => ({ toJSON: () => ({ endpoint, keys: { p256dh: "fixture-public", auth: "fixture-auth" } }), unsubscribe: async () => { calls.push(["unsubscribe"]); subscription = null; return true; }, }); const platform = { support: () => support, permission: () => permission, requestPermission: () => { calls.push(["permission"]); permission = "granted"; return Promise.resolve(permission); }, subscription: async () => subscription, subscribe: async key => { calls.push(["subscribe", key]); return subscription = makeSubscription(); }, clearNotifications: async () => { calls.push(["clear"]); }, ...overrides.platform, }; const options = { api, platform, read: () => record, write: value => { record = structuredClone(value); }, uuid: randomUUID, scope: async () => "a".repeat(64), lock: async operation => operation(), changed: state => states.push(state), ...shared.options, }; const controller = createAgentPushController(options); return { controller, options, calls, states, api, platform, makeSubscription, record: () => record, setConfig(value) { config = value; }, setPermission(value) { permission = value; }, setSupport(value) { support = value; }, setSubscription(value) { subscription = value; } }; } test("explicit gesture requests permission before yielding; permission alone never opts in", async () => { const f = fixture(); f.setPermission("granted"); await f.controller.refresh(); assert.equal(f.record(), null); assert.deepEqual(f.calls, []); const enabling = f.controller.enable(); assert.deepEqual(f.calls, [["permission"]], "request runs directly inside the click stack"); await enabling; assert.equal(f.record().enabled, true); assert.equal(f.record().sourceId, sourceId); assert.equal(f.record().revocationPending, false); assert.equal(f.calls.filter(([name]) => name === "register").length, 1); await f.controller.refresh(); await f.controller.refresh(); assert.equal(f.calls.filter(([name]) => name === "register").length, 1, "heartbeat does not repeatedly register an unchanged subscription"); }); test("denial, disabled config, unsupported browser and iOS installation guidance do not subscribe", async () => { for (const support of ["unsupported", "install"]) { const f = fixture(); f.setSupport(support); await f.controller.refresh(); await f.controller.enable(); assert.equal(f.controller.state().canEnable, false); assert.deepEqual(f.calls, []); assert.match(f.controller.state().message, support === "install" ? /Home Screen/ : /HTTPS/); } const disabled = fixture(); disabled.setConfig({ ...configuration(), enabled: false }); await disabled.controller.refresh(); await disabled.controller.enable(); assert.deepEqual(disabled.calls, []); const denied = fixture({ platform: { requestPermission: async () => "denied" } }); await denied.controller.refresh(); await denied.controller.enable(); assert.equal(denied.record().enabled, false); assert.equal(denied.calls.length, 0); assert.match(denied.controller.state().error, /not allowed/); }); test("registration failure rolls back subscription, persists revoke intent and never echoes provider errors", async () => { const f = fixture({ api: { register: async () => { throw new Error("https://private-provider/token-secret"); }, revoke: async () => { throw new Error("offline"); } } }); await f.controller.refresh(); await f.controller.enable(); assert.equal(f.record().enabled, false); assert.equal(f.record().revocationPending, true); assert.ok(f.calls.some(([name]) => name === "unsubscribe")); assert.doesNotMatch(JSON.stringify(f.states), /private-provider|token-secret/); assert.equal(f.controller.state().canEnable, false); }); test("offline logout writes tombstone synchronously, unsubscribes locally and retries before any enable", async () => { const f = fixture(); await f.controller.refresh(); await f.controller.enable(); const id = f.record().installationId; f.api.revoke = async () => { throw new Error("offline"); }; const disabling = f.controller.disable(); assert.equal(f.record().enabled, false); assert.equal(f.record().revocationPending, true); await disabling; assert.ok(f.calls.some(([name]) => name === "unsubscribe")); const count = f.calls.filter(([name]) => name === "register").length; await f.controller.refresh(); await f.controller.enable(); assert.equal(f.calls.filter(([name]) => name === "register").length, count); f.api.revoke = async revoked => { assert.equal(revoked, id); }; await f.controller.refresh(); assert.equal(f.record().revocationPending, false); assert.equal(f.record().enabled, false); }); test("storage failures during logout still revoke, unsubscribe and close notifications", async () => { const f = fixture(); await f.controller.refresh(); await f.controller.enable(); f.options.write = () => { throw new Error("quota"); }; let removed = false; f.options.remove = () => { removed = true; }; await f.controller.disable(); assert.ok(removed); assert.equal(f.controller.state().enabled, false); for (const name of ["revoke", "unsubscribe", "clear"]) assert.ok(f.calls.some(([action]) => action === name)); await f.controller.refresh(); assert.equal(f.controller.state().enabled, false); }); test("a stuck cross-tab lock cannot prevent server retirement or local logout cleanup", async () => { const f = fixture(); await f.controller.refresh(); await f.controller.enable(); f.options.lock = async () => { throw new Error("lock acquisition expired"); }; await f.controller.disable(); assert.equal(f.record().enabled, false); assert.equal(f.record().revocationPending, false); for (const name of ["revoke", "unsubscribe", "clear"]) assert.ok(f.calls.some(([action]) => action === name)); }); test("synchronous permission API failures remain a recoverable opt-in error", async () => { const f = fixture({ platform: { requestPermission: () => { throw new Error("user gesture rejected"); } } }); await f.controller.refresh(); await f.controller.enable(); assert.equal(f.record().enabled, false); assert.match(f.controller.state().error, /could not be requested/); }); test("subscription rotation upserts the same installation; permission revocation removes it", async () => { const f = fixture(); await f.controller.refresh(); await f.controller.enable(); const id = f.record().installationId; f.setSubscription(f.makeSubscription("https://push.example.test/rotated")); await f.controller.refresh(); const registrations = f.calls.filter(([name]) => name === "register"); assert.equal(registrations.length, 2); assert.ok(registrations.every(([, installation]) => installation === id)); f.setPermission("denied"); await f.controller.refresh(); assert.equal(f.record().enabled, false); assert.equal(f.record().revocationPending, false); }); test("logout while permission prompt is open cancels the older opt-in", async () => { const prompt = deferred(), f = fixture({ platform: { requestPermission: () => prompt.promise } }); await f.controller.refresh(); const enabling = f.controller.enable(); await f.controller.disable(); prompt.resolve("granted"); await enabling; assert.equal(f.record().enabled, false); assert.ok(!f.calls.some(([name]) => name === "subscribe" || name === "register")); }); test("two-tab enable → disable → enable uses permanent server tombstones and a new installation UUID", async () => { let sharedRecord = null, queue = Promise.resolve(), currentRegistration = false; const calls = [], pendingRegister = deferred(), retired = new Set(); let first = true; const common = { options: { read: () => sharedRecord, write: value => { sharedRecord = structuredClone(value); }, lock: operation => { const running = queue.then(operation); queue = running.catch(() => undefined); return running; }, } }; const api = { register: async id => { calls.push("register"); if (first) { first = false; await pendingRegister.promise; } assert.ok(!retired.has(id), "retired UUID must never be reused"); currentRegistration = true; }, revoke: async id => { calls.push("revoke"); retired.add(id); currentRegistration = false; }, }; const a = fixture({ api }, common), b = fixture({ api }, common); await a.controller.refresh(); await b.controller.refresh(); const enabling = a.controller.enable(); await settle(); assert.deepEqual(calls, ["register"]); const disabling = b.controller.disable(); assert.equal(sharedRecord.enabled, false); assert.equal(sharedRecord.revocationPending, true); pendingRegister.resolve(); await Promise.all([enabling, disabling]); assert.equal(currentRegistration, false); const id = sharedRecord.installationId; await b.controller.enable(); assert.equal(currentRegistration, true); assert.equal(sharedRecord.enabled, true); assert.notEqual(sharedRecord.installationId, id); assert.ok(retired.has(id)); assert.equal(calls.at(-1), "register"); }); test("a timed-out old PUT completing after DELETE cannot revive the retired installation or affect a new opt-in", async () => { const retired = new Set(), active = new Set(), late = deferred(); let firstId, lateStatus, first = true; const f = fixture({ api: { register: async id => { if (first) { first = false; firstId = id; late.promise.then(() => { lateStatus = retired.has(id) ? 409 : 200; if (lateStatus === 200) active.add(id); }); throw new Error("request timed out while server is still processing"); } assert.ok(!retired.has(id)); active.add(id); }, revoke: async id => { retired.add(id); active.delete(id); }, } }); await f.controller.refresh(); await f.controller.enable(); assert.equal(f.record().enabled, false); assert.equal(f.record().revocationPending, false); assert.ok(retired.has(firstId)); await f.controller.enable(); const currentId = f.record().installationId; assert.notEqual(currentId, firstId); assert.ok(active.has(currentId)); late.resolve(); await settle(); assert.equal(lateStatus, 409); assert.deepEqual([...active], [currentId]); }); test("authority changes retain original-server cleanup without issuing a misleading DELETE to the new server", async () => { const f = fixture(); await f.controller.refresh(); await f.controller.enable(); const oldId = f.record().installationId, registrations = f.calls.filter(([name]) => name === "register").length; f.options.scope = async () => "b".repeat(64); await f.controller.refresh(); await f.controller.refresh(); assert.equal(f.record().enabled, false); assert.equal(f.record().revocationPending, false, "local unsubscribe succeeded, but old server cleanup stays queued"); assert.deepEqual(f.record().pendingRevocations, [{ installationId: oldId, scope: "a".repeat(64) }]); assert.ok(!f.calls.some(([name]) => name === "revoke"), "new server's unknown-ID DELETE/204 cannot retire the original server registration"); assert.equal(f.calls.filter(([name]) => name === "register").length, registrations); await f.controller.enable(); const newId = f.record().installationId; assert.notEqual(newId, oldId); assert.equal(f.record().scope, "b".repeat(64)); assert.equal(f.record().enabled, true); assert.deepEqual(f.record().pendingRevocations, [{ installationId: oldId, scope: "a".repeat(64) }]); const reloaded = createAgentPushController(f.options); await reloaded.refresh(); assert.deepEqual(f.record().pendingRevocations, [{ installationId: oldId, scope: "a".repeat(64) }], "queue survives a reload on B"); assert.ok(!f.calls.some(([name]) => name === "revoke")); f.options.scope = async () => "a".repeat(64); await reloaded.refresh(); assert.deepEqual(f.calls.filter(([name]) => name === "revoke"), [["revoke", oldId]], "returning with A credentials retries only A's intent"); assert.deepEqual(f.record().pendingRevocations, [{ installationId: newId, scope: "b".repeat(64) }]); assert.equal(f.record().enabled, false); await reloaded.enable(); assert.equal(f.record().enabled, true); assert.equal(f.record().scope, "a".repeat(64)); assert.notEqual(f.record().installationId, oldId); }); test("revoked old credentials do not prevent fresh opt-in after same-server credential rotation", async () => { const f = fixture(); await f.controller.refresh(); await f.controller.enable(); const oldId = f.record().installationId; f.api.revoke = async () => { throw new Error("old credentials revoked"); }; await f.controller.disable(); assert.equal(f.record().revocationPending, true); f.options.scope = async () => "c".repeat(64); await f.controller.refresh(); await f.controller.enable(); assert.equal(f.record().enabled, true); assert.equal(f.record().scope, "c".repeat(64)); assert.notEqual(f.record().installationId, oldId); assert.deepEqual(f.record().pendingRevocations, [{ installationId: oldId, scope: "a".repeat(64) }]); assert.doesNotMatch(JSON.stringify(f.record()), /credentials|provider|opaque|fixture-auth/); }); test("failed old-authority retries retain intent while other queued authorities are never contacted", async () => { const f = fixture(); await f.controller.refresh(); await f.controller.enable(); await f.controller.disable(); const queue = [{ installationId: randomUUID(), scope: "a".repeat(64) }, { installationId: randomUUID(), scope: "b".repeat(64) }]; f.options.write({ ...f.record(), pendingRevocations: queue }); const attempted = []; f.api.revoke = async id => { attempted.push(id); throw new Error("offline"); }; await f.controller.refresh(); assert.deepEqual(attempted, [queue[0].installationId]); assert.deepEqual(f.record().pendingRevocations, queue); await f.controller.enable(); assert.equal(f.record().enabled, true); assert.deepEqual(f.record().pendingRevocations, queue); }); test("bounded revocation queue never silently evicts cleanup and gives actionable opt-in recovery", async () => { const f = fixture(); await f.controller.refresh(); await f.controller.enable(); await f.controller.disable(); const queue = Array.from({ length: MAX_AGENT_PUSH_REVOCATIONS }, () => ({ installationId: randomUUID(), scope: "b".repeat(64) })); f.options.write({ ...f.record(), pendingRevocations: queue }); await f.controller.refresh(); assert.equal(f.controller.state().canEnable, false); assert.match(f.controller.state().message, /Sign in to a previous server/); const count = f.calls.filter(([name]) => name === "register").length; await f.controller.enable(); assert.deepEqual(f.record().pendingRevocations, queue); assert.equal(f.calls.filter(([name]) => name === "register").length, count); assert.ok(parseAgentPushConsent(JSON.stringify(f.record()))); assert.equal(parseAgentPushConsent(JSON.stringify({ ...f.record(), pendingRevocations: [...queue, queue[0]] })), null); assert.equal(parseAgentPushConsent(JSON.stringify({ ...f.record(), pendingRevocations: [{ installationId: queue[0].installationId, scope: "raw-token" }] })), null); f.options.scope = async () => "b".repeat(64); await f.controller.refresh(); assert.deepEqual(f.record().pendingRevocations, []); assert.equal(f.controller.state().canEnable, true); }); test("in-flight cleanup cannot overwrite a newer tab's consent revision", async () => { const f = fixture(); await f.controller.refresh(); await f.controller.enable(); const entered = deferred(), release = deferred(); let reads = 0; f.options.scope = async () => { if (++reads === 2) { entered.resolve(); await release.promise; } return "a".repeat(64); }; const disabling = f.controller.disable(); await entered.promise; const newer = { ...f.record(), installationId: randomUUID(), revision: randomUUID(), enabled: true, revocationPending: false }; f.options.write(newer); release.resolve(); await disabling; assert.deepEqual(f.record(), newer); }); test("principal scope changing while permission is pending prevents registration", async () => { const prompt = deferred(), f = fixture({ platform: { requestPermission: () => prompt.promise } }); await f.controller.refresh(); const enabling = f.controller.enable(); f.options.scope = async () => "b".repeat(64); prompt.resolve("granted"); await enabling; assert.equal(f.record().enabled, false); assert.ok(!f.calls.some(([name]) => name === "subscribe" || name === "register")); }); test("authority changing during config fetch cannot enable against a mixed identity snapshot", async () => { const f = fixture({ api: { config: async () => { f.options.scope = async () => "b".repeat(64); return configuration(); } } }); await f.controller.refresh(); await f.controller.enable(); assert.equal(f.controller.state().canEnable, false); assert.equal(f.record(), null); assert.deepEqual(f.calls, []); }); test("same backend/token with a replaced source invalidates persisted consent on reload and requires a new opt-in", async () => { const f = fixture(); await f.controller.refresh(); await f.controller.enable(); const old = structuredClone(f.record()); f.setConfig({ ...configuration(), sourceId: replacementSourceId }); const reloaded = createAgentPushController(f.options); await reloaded.refresh(); await reloaded.refresh(); assert.equal(f.record().enabled, false); assert.equal(f.record().sourceId, sourceId); assert.equal(f.calls.filter(([name]) => name === "register").length, 1, "source replacement cannot reuse old consent"); assert.ok(f.calls.some(([name, id]) => name === "revoke" && id === old.installationId)); assert.ok(f.calls.some(([name]) => name === "unsubscribe")); await reloaded.enable(); assert.equal(f.record().enabled, true); assert.equal(f.record().sourceId, replacementSourceId); assert.equal(f.record().scope, old.scope); assert.notEqual(f.record().installationId, old.installationId); assert.equal(f.calls.filter(([name]) => name === "permission").length, 2, "replacement requires another explicit permission gesture"); }); test("null or invalid source prevents new opt-in even when transport is configured", async () => { for (const unknown of [null, undefined, "not-a-source-uuid"]) { const f = fixture(); f.setConfig({ ...configuration(), sourceId: unknown }); await f.controller.refresh(); await f.controller.enable(); assert.equal(f.controller.state().canEnable, false); assert.equal(f.record(), null); assert.deepEqual(f.calls, [], "unknown source must not request permission, subscribe or register"); } }); test("losing a known source retires old consent and never resumes it automatically", async () => { const f = fixture(); await f.controller.refresh(); await f.controller.enable(); const oldId = f.record().installationId; f.setConfig({ ...configuration(), sourceId: null }); await f.controller.refresh(); assert.equal(f.record().enabled, false); assert.equal(f.controller.state().canEnable, false); assert.ok(f.calls.some(([name, id]) => name === "revoke" && id === oldId)); f.setConfig(configuration()); await f.controller.refresh(); assert.equal(f.record().enabled, false); assert.equal(f.calls.filter(([name]) => name === "register").length, 1); }); test("legacy or malformed source bindings retain installation identity for retirement, not re-enrollment", async () => { for (const invalid of [undefined, null, "invalid-source"]) { const f = fixture(); await f.controller.refresh(); await f.controller.enable(); const oldId = f.record().installationId; const stored = parseAgentPushConsent(JSON.stringify({ ...f.record(), sourceId: invalid })); assert.equal(stored.installationId, oldId); assert.equal(stored.sourceId, undefined); f.options.write(stored); await createAgentPushController(f.options).refresh(); assert.equal(f.record().enabled, false); assert.equal(f.calls.filter(([name]) => name === "register").length, 1); assert.ok(f.calls.some(([name, id]) => name === "revoke" && id === oldId)); } }); test("source change while permission is pending prevents subscription and retires the incomplete intent", async () => { const prompt = deferred(), f = fixture({ platform: { requestPermission: () => prompt.promise } }); await f.controller.refresh(); const enabling = f.controller.enable(); const oldId = f.record().installationId; f.setConfig({ ...configuration(), sourceId: replacementSourceId }); f.setPermission("granted"); prompt.resolve("granted"); await enabling; assert.equal(f.record().enabled, false); assert.equal(f.record().sourceId, sourceId); assert.ok(!f.calls.some(([name]) => name === "subscribe" || name === "register")); assert.ok(f.calls.some(([name, id]) => name === "revoke" && id === oldId)); }); test("source change while subscribe is pending unsubscribes without registering", async () => { const entered = deferred(), release = deferred(); const f = fixture({ platform: { subscribe: async () => { entered.resolve(); await release.promise; const subscription = f.makeSubscription(); f.setSubscription(subscription); return subscription; } } }); await f.controller.refresh(); const enabling = f.controller.enable(); await entered.promise; f.setConfig({ ...configuration(), sourceId: replacementSourceId }); release.resolve(); await enabling; assert.equal(f.record().enabled, false); assert.equal(f.calls.filter(([name]) => name === "register").length, 0); assert.ok(f.calls.some(([name]) => name === "unsubscribe")); }); test("source change during initial registration rolls back instead of persisting enabled consent", async () => { const entered = deferred(), release = deferred(), registered = [], retired = []; const f = fixture({ api: { register: async id => { registered.push(id); entered.resolve(); await release.promise; }, revoke: async id => { retired.push(id); }, } }); await f.controller.refresh(); const enabling = f.controller.enable(); await entered.promise; f.setConfig({ ...configuration(), sourceId: replacementSourceId }); release.resolve(); await enabling; assert.equal(f.record().enabled, false); assert.equal(f.record().sourceId, sourceId); assert.deepEqual(retired, registered); assert.ok(f.calls.some(([name]) => name === "unsubscribe")); }); test("source change during automatic rotation registration retires the source-bound installation", async () => { const f = fixture(); await f.controller.refresh(); await f.controller.enable(); const oldId = f.record().installationId, entered = deferred(), release = deferred(); f.setSubscription(f.makeSubscription("https://push.example.test/rotated")); f.api.register = async id => { assert.equal(id, oldId); entered.resolve(); await release.promise; }; const refreshing = f.controller.refresh(); await entered.promise; f.setConfig({ ...configuration(), sourceId: replacementSourceId }); release.resolve(); await refreshing; assert.equal(f.record().enabled, false); assert.ok(f.calls.some(([name, id]) => name === "revoke" && id === oldId)); }); test("source verification failure after registration fails closed and rolls back", async () => { const f = fixture({ api: { register: async () => { f.api.config = async () => { throw new Error("source unavailable"); }; } } }); await f.controller.refresh(); await f.controller.enable(); assert.equal(f.record().enabled, false); assert.ok(f.calls.some(([name]) => name === "revoke")); assert.ok(f.calls.some(([name]) => name === "unsubscribe")); }); test("attention is per-tab, ordered, focused while idle, and recent input persists until acknowledged", async () => { const rows = [], failure = deferred(); let focus = true; const a = createAgentPresenceReporter({ snapshot: () => ({ visibility: "visible", focused: focus }), send: async value => { rows.push(["a", value]); } }); const b = createAgentPresenceReporter({ snapshot: () => ({ visibility: "hidden", focused: true }), send: async value => { rows.push(["b", value]); } }); await a.report(); await b.report(); assert.equal(rows[0][1].focused, true); assert.equal(rows[0][1].interacted, false); assert.equal(rows[1][1].focused, false); assert.equal(rows[1][1].sequence, 1); a.interact(); focus = false; await a.report(); await a.report(); assert.equal(rows[2][1].interacted, true); assert.equal(rows[2][1].focused, false); assert.equal(rows[3][1].interacted, false); assert.equal(rows[3][1].sequence, 3); let attempts = 0; const c = createAgentPresenceReporter({ snapshot: () => ({ visibility: "visible", focused: false }), send: async value => { assert.equal(value.interacted, true); if (++attempts === 1) return failure.promise; } }); c.interact(); const report = c.report(); failure.reject(new Error("offline")); await assert.rejects(report); await c.report(); const id = randomUUID(), frame = JSON.parse(agentAuthFrame("fixture-token", "2", id)); assert.equal(frame.clientKind, "web"); assert.equal(frame.presenceSessionId, id); assert.deepEqual(JSON.parse(agentAuthFrame(null, "0", "not-an-id")), { type: "auth", token: null, after: "0", clientKind: "web" }); }); test("read frames validate source/cursor and preserve existing read semantics", () => { const event = parseAgentRoomEvent(JSON.stringify({ type: "read_state", cursor: "9", updatedAt: null, sourceId })); assert.equal(applyAgentEvent(createAgentRoomState(), event).readCursor, "9"); for (const cursor of ["-1", "1e5", "9007199254740992", "1".repeat(200)]) { assert.equal(agentPushCursor(cursor), false); assert.throws(() => parseAgentRoomEvent(JSON.stringify({ type: "read_state", cursor, updatedAt: null, sourceId }))); } assert.throws(() => parseAgentRoomEvent(JSON.stringify({ type: "read_state", cursor: "1", updatedAt: null, sourceId: "https://evil.test" }))); assert.equal(parseAgentPushConsent('{"enabled":true}'), null); assert.throws(() => parseAgentPushConfig({ ...configuration(), policy: { presenceHeartbeatMs: 1, presenceLeaseMs: 60000 } })); }); test("API keeps credentials in headers, validates receipts, handles 204 and redacts provider bodies", async () => { const id = randomUUID(), requests = []; let mode = "config"; const api = new AgentPushClient({ baseUrl: "/api", token: () => "fixture-bearer", fetch: async (url, init) => { requests.push({ url, init }); if (mode === "revoke") return new Response(null, { status: 204 }); if (mode === "fail") return new Response(JSON.stringify({ error: "private-token-and-endpoint" }), { status: 500 }); if (mode === "register") return Response.json({ installationId: id, transport: "web", enabled: true, version: 1 }); if (mode === "read") return Response.json({ cursor: "0008", sourceId }); return Response.json(configuration()); } }); await api.config(); mode = "register"; await api.register(id, { endpoint: "https://provider.test/endpoint-secret" }); mode = "read"; assert.deepEqual(await api.readState(), { sourceId, cursor: "8" }); mode = "revoke"; await api.revoke(id); mode = "fail"; await assert.rejects(api.revoke(id), error => !/private-token/.test(error.message)); for (const request of requests) { assert.equal(request.init.headers.Authorization, "Bearer fixture-bearer"); assert.equal(request.init.cache, "no-store"); assert.equal(request.init.redirect, "error"); assert.doesNotMatch(request.url, /fixture-bearer|endpoint-secret/); } await assert.rejects(api.revoke("../../bad")); const unauthenticated = new AgentPushClient({ baseUrl: "/api", token: () => null, fetch: () => { throw new Error("must not send"); } }); await assert.rejects(unauthenticated.config(), /Sign in/); }); test("authority-guarded API refuses mismatched credentials and pins the captured bearer across async hashing", async () => { const id = randomUUID(), requests = [], baseUrl = "https://sybil.example.test/api/"; const scope = await agentPushAuthorityScope(baseUrl, "original-fixture-token"); assert.equal(scope, await agentPushAuthorityScope("/api", "original-fixture-token", "https://sybil.example.test/")); assert.match(scope, /^[a-f0-9]{64}$/); assert.equal(await agentPushAuthorityScope(baseUrl, null), null); let token = "rotated-fixture-token"; const api = new AgentPushClient({ baseUrl, token: () => token, fetch: async (url, init) => { requests.push({ url, init }); return init.method === "DELETE" ? new Response(null, { status: 204 }) : Response.json({ installationId: id, transport: "web", enabled: true, version: 1 }); } }); await assert.rejects(api.revoke(id, scope)); await assert.rejects(api.register(id, { endpoint: "https://provider.test/fixture" }, scope)); assert.deepEqual(requests, [], "wrong authority cannot send a mutation or falsely acknowledge cleanup"); token = "original-fixture-token"; const deleting = api.revoke(id, scope); token = "rotated-fixture-token"; await deleting; token = "original-fixture-token"; const registering = api.register(id, { endpoint: "https://provider.test/fixture" }, scope); token = "rotated-fixture-token"; await registering; assert.equal(requests.length, 2); assert.ok(requests.every(({ init }) => init.headers.Authorization === "Bearer original-fixture-token")); assert.ok(requests.every(({ url }) => !url.includes("fixture-token"))); });