import { describe, expect, it, vi } from "vitest"; import { PRESIGNED_TRANSFER_PROTOCOL, type PresignedDownloadCapability, } from "../../src/application/ports/browser-transfer/presigned-transfer.ts"; import { createPresignedCapabilityVault } from "../../src/adapters/browser-transfer/presigned/presigned-capability-vault.ts"; import { sha256Hex } from "../../src/adapters/browser-transfer/presigned/incremental-sha256.ts"; import { CHECKSUM_HEADER, CONTROL_ENDPOINT, DATA_ORIGIN, DIGEST_HEADER, DOWNLOAD_HREF, DOWNLOAD_PATH, NOW, POLICY_HEADER, REQUEST_BINDING_SHA256, UPLOAD_SESSION_ID, collect, createHarness, downloadCapabilityPayload, downloadResponse, firstStreamResult, jsonResponse, responseWithUrl, uploadCapabilityPayload, } from "./presigned-transfer-fixture.ts"; describe("presigned transfer capability issuance and admission", () => { it("matches the standard SHA-256 vector", () => { expect(sha256Hex(new TextEncoder().encode("abc"))).toBe( "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", ); }); it("answers a refused capability envelope with a re-issuable recovery", async () => { // BT-PRE-04. A capability document the adapter will not accept is closed as // `POLICY_REJECTED`, and the caller's only way forward is a new capability. // `NONE` said there was nothing to be done, which contradicted both the // design record for an unsupported protocol and the vault, which already // answers `REISSUE_CAPABILITY` for the same class of refusal. for (const [label, overrides] of [ ["unknown protocol", { protocol: "PRESIGNED_TRANSFER_V2" }], ["missing protocol", { protocol: undefined }], ] as const) { const bytes = new Uint8Array([1, 2, 3]); const payload: Record = { ...downloadCapabilityPayload(bytes), ...overrides, }; if (overrides.protocol === undefined) delete payload["protocol"]; const fetcher = vi.fn(async () => jsonResponse(payload)) as unknown as typeof fetch; const { provider } = createHarness({ fetcher }); expect( await provider.issueDownload({ resourceId: "resource-1", signal: new AbortController().signal, }), label, ).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED", retryable: false, recovery: "REISSUE_CAPABILITY", }, }); } }); it("keeps URL and headers adapter-private and streams bounded verified chunks", async () => { const bytes = new Uint8Array([1, 2, 3, 4, 5]); const payload = downloadCapabilityPayload(bytes); const dataCalls: RequestInit[] = []; const fetcher = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => { if (String(input) === CONTROL_ENDPOINT) return jsonResponse(payload); dataCalls.push(init ?? {}); return downloadResponse(bytes.slice().buffer, payload); }) as unknown as typeof fetch; const { provider, executor } = createHarness({ fetcher }); const issued = await provider.issueDownload({ resourceId: "resource-1", signal: new AbortController().signal, }); expect(issued.ok).toBe(true); if (!issued.ok) return; expect(Object.isFrozen(issued.value)).toBe(true); expect("href" in issued.value).toBe(false); expect("requestHeaders" in issued.value).toBe(false); const opened = await executor.downloadSources.open({ resourceId: "resource-1", capability: issued.value, signal: new AbortController().signal, }); expect(opened.ok).toBe(true); if (!opened.ok) return; const results = await collect(opened.value); expect(results.every((result) => result.ok)).toBe(true); expect( results.flatMap((result) => result.ok ? [...result.value] : [], ), ).toEqual([...bytes]); expect( results.map((result) => result.ok ? result.value.byteLength : 0, ), ).toEqual([2, 2, 1]); expect(dataCalls[0]).toMatchObject({ method: "GET", credentials: "omit", redirect: "error", referrerPolicy: "no-referrer", cache: "no-store", }); expect( await executor.downloadSources.open({ resourceId: "resource-1", capability: issued.value, signal: new AbortController().signal, }), ).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED", }, }); }); it("retires consumed identities immediately and reuses the active slot before TTL", async () => { const bytes = new Uint8Array([1, 2, 3]); const responsePayload = downloadCapabilityPayload(bytes); let issueSequence = 0; const fetcher = vi.fn( async (input: RequestInfo | URL) => { if (String(input) === CONTROL_ENDPOINT) { issueSequence += 1; return jsonResponse( downloadCapabilityPayload(bytes, { capabilityReceipt: `capability-download-${issueSequence}`, }), ); } return downloadResponse( bytes.slice().buffer, responsePayload, ); }, ) as unknown as typeof fetch; const { provider, executor, vault } = createHarness({ fetcher, maxActiveCapabilities: 1, }); const signal = new AbortController().signal; const first = await provider.issueDownload({ resourceId: "resource-1", signal, }); expect(first.ok).toBe(true); if (!first.ok) return; expect( await provider.issueDownload({ resourceId: "resource-1", signal, }), ).toMatchObject({ ok: false, error: { code: "LIMIT_EXCEEDED" }, }); const opened = await executor.downloadSources.open({ resourceId: "resource-1", capability: first.value, signal, }); expect(opened.ok).toBe(true); if (!opened.ok) return; expect(vault.resolve(first.value)).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); expect((await collect(opened.value)).every((result) => result.ok)).toBe( true, ); const afterConsume = await provider.issueDownload({ resourceId: "resource-1", signal, }); expect(afterConsume.ok).toBe(true); if (!afterConsume.ok) return; vault.revoke(afterConsume.value); expect(vault.resolve(afterConsume.value)).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); const afterRevoke = await provider.issueDownload({ resourceId: "resource-1", signal, }); expect(afterRevoke.ok).toBe(true); if (!afterRevoke.ok) return; vault.dispose(); expect(vault.resolve(afterRevoke.value)).toMatchObject({ ok: false, error: { code: "UNAVAILABLE" }, }); }); it("snapshots the issuance request before asynchronous mutation", async () => { const bytes = new Uint8Array([1]); const payload = downloadCapabilityPayload(bytes); let release: (() => void) | undefined; const gate = new Promise((resolve) => { release = resolve; }); let posted: unknown; const fetcher = vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => { posted = JSON.parse(String(init?.body)) as unknown; await gate; return jsonResponse(payload); }) as unknown as typeof fetch; const { provider } = createHarness({ fetcher }); const request = { resourceId: "resource-1", signal: new AbortController().signal, }; const pending = provider.issueDownload(request); request.resourceId = "mutated-resource"; release?.(); expect(await pending).toMatchObject({ ok: true }); expect(posted).toMatchObject({ binding: { resourceId: "resource-1" }, }); }); it("rejects a capability BFF response from a different final URL", async () => { const bytes = new Uint8Array([1]); const payload = downloadCapabilityPayload(bytes); const fetcher = vi.fn(async () => jsonResponse( payload, "https://api.example/retargeted-capabilities", ), ) as unknown as typeof fetch; const { provider } = createHarness({ fetcher }); expect( await provider.issueDownload({ resourceId: "resource-1", signal: new AbortController().signal, }), ).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); }); it("snapshots multipart session bindings before capability issuance awaits", async () => { const bytes = new Uint8Array([1, 2]); const checksum = sha256Hex(bytes); const payload = uploadCapabilityPayload({ bytes, checksum }); let release: (() => void) | undefined; const gate = new Promise((resolve) => { release = resolve; }); let posted: unknown; const fetcher = vi.fn( async (_input: RequestInfo | URL, init?: RequestInit) => { posted = JSON.parse(String(init?.body)) as unknown; await gate; return jsonResponse(payload); }, ) as unknown as typeof fetch; const { provider } = createHarness({ fetcher }); const request = { sessionId: UPLOAD_SESSION_ID, requestBindingSha256: REQUEST_BINDING_SHA256, uploadBindingSha256: "b".repeat(64), partNumber: 1, offset: 0, byteLength: bytes.byteLength, checksumSha256: checksum, mediaType: "application/octet-stream", idempotencyKey: "part-attempt-1", signal: new AbortController().signal, }; const pending = provider.issueUploadPart(request); request.sessionId = "mutated-session"; request.requestBindingSha256 = "d".repeat(64); release?.(); expect(await pending).toMatchObject({ ok: true, value: { binding: { sessionId: UPLOAD_SESSION_ID, requestBindingSha256: REQUEST_BINDING_SHA256, }, }, }); expect(posted).toMatchObject({ binding: { sessionId: UPLOAD_SESSION_ID, requestBindingSha256: REQUEST_BINDING_SHA256, }, }); }); it.each([ "protocol", "sessionId", "requestBindingSha256", ] as const)( "rejects a capability response with a mismatched %s", async (field) => { const bytes = new Uint8Array([1, 2]); const checksum = sha256Hex(bytes); const valid = uploadCapabilityPayload({ bytes, checksum }); const payload = uploadCapabilityPayload( { bytes, checksum }, { binding: { ...valid.binding, [field]: field === "protocol" ? "PRESIGNED_MULTIPART_V2" : field === "sessionId" ? "different-session" : "d".repeat(64), }, }, ); const fetcher = vi.fn(async () => jsonResponse(payload), ) as unknown as typeof fetch; const { provider } = createHarness({ fetcher }); expect( await provider.issueUploadPart({ sessionId: UPLOAD_SESSION_ID, requestBindingSha256: REQUEST_BINDING_SHA256, uploadBindingSha256: "b".repeat(64), partNumber: 1, offset: 0, byteLength: bytes.byteLength, checksumSha256: checksum, mediaType: "application/octet-stream", idempotencyKey: "part-attempt-1", signal: new AbortController().signal, }), ).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); }, ); it("rejects capability query, origin, path and fabricated-handle mismatches", async () => { const bytes = new Uint8Array([1]); const malformed = downloadCapabilityPayload(bytes, { href: `${DOWNLOAD_HREF}&extra=1`, }); const fetcher = vi.fn(async () => jsonResponse(malformed)) as unknown as typeof fetch; const { provider, executor } = createHarness({ fetcher }); expect( await provider.issueDownload({ resourceId: "resource-1", signal: new AbortController().signal, }), ).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); const forged = Object.freeze({ capabilityReceipt: "forged", method: "GET", binding: Object.freeze({ kind: "DOWNLOAD", resourceId: "resource-1", }), mediaType: "application/octet-stream", byteLength: 1, maxBytes: 1, expectedSha256: "a".repeat(64), expiresAtEpochMs: NOW + 1_000, }) as unknown as PresignedDownloadCapability; expect( await executor.downloadSources.open({ resourceId: "resource-1", capability: forged, signal: new AbortController().signal, }), ).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); }); it("rejects redirected, retargeted and response-header-mismatched downloads", async () => { const bytes = new Uint8Array([1, 2]); const payload = downloadCapabilityPayload(bytes); let mode: "redirect" | "retarget" | "header" = "redirect"; const fetcher = vi.fn(async (input: RequestInfo | URL) => { if (String(input) === CONTROL_ENDPOINT) return jsonResponse(payload); const response = mode === "header" ? downloadResponse(bytes.slice().buffer, payload, { [DIGEST_HEADER]: "f".repeat(64), }) : downloadResponse(bytes.slice().buffer, payload); if (mode === "redirect") { Object.defineProperty(response, "redirected", { value: true }); } else if (mode === "retarget") { Object.defineProperty(response, "url", { value: `${DATA_ORIGIN}/files/different?sig=do-not-log-this`, }); } return response; }) as unknown as typeof fetch; let harness = createHarness({ fetcher }); let issued = await harness.provider.issueDownload({ resourceId: "resource-1", signal: new AbortController().signal, }); expect(issued.ok).toBe(true); if (!issued.ok) return; await expect( firstStreamResult( await harness.executor.downloadSources.open({ resourceId: "resource-1", capability: issued.value, signal: new AbortController().signal, }), ), ).resolves.toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); mode = "retarget"; harness = createHarness({ fetcher }); issued = await harness.provider.issueDownload({ resourceId: "resource-1", signal: new AbortController().signal, }); expect(issued.ok).toBe(true); if (!issued.ok) return; await expect( firstStreamResult( await harness.executor.downloadSources.open({ resourceId: "resource-1", capability: issued.value, signal: new AbortController().signal, }), ), ).resolves.toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); mode = "header"; harness = createHarness({ fetcher }); issued = await harness.provider.issueDownload({ resourceId: "resource-1", signal: new AbortController().signal, }); expect(issued.ok).toBe(true); if (!issued.ok) return; await expect( firstStreamResult( await harness.executor.downloadSources.open({ resourceId: "resource-1", capability: issued.value, signal: new AbortController().signal, }), ), ).resolves.toMatchObject({ ok: false, error: { code: "INTEGRITY_FAILED" }, }); }); it.each([ { label: "missing", protocol: undefined }, { label: "V0", protocol: "PRESIGNED_TRANSFER_V0" }, { label: "V2", protocol: "PRESIGNED_TRANSFER_V2" }, ])( "requires PRESIGNED_TRANSFER_V1 in request and response ($label)", async ({ protocol }) => { const bytes = new Uint8Array([1, 2, 3]); const payload = downloadCapabilityPayload(bytes); const body = protocol === undefined ? (({ protocol: _dropped, ...rest }) => rest)( payload as Record, ) : { ...payload, protocol }; const requests: unknown[] = []; const fetcher = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => { if (String(input) === CONTROL_ENDPOINT) { requests.push(JSON.parse(String(init?.body))); return jsonResponse(body as never); } return downloadResponse(bytes.slice().buffer, payload); }) as unknown as typeof fetch; const { provider, vault } = createHarness({ fetcher }); const issued = await provider.issueDownload({ resourceId: "resource-1", signal: new AbortController().signal, }); // BT-PRE-02. The request always declares V1, and a response that does not // is closed before the vault ever registers it. expect(requests[0]).toMatchObject({ protocol: PRESIGNED_TRANSFER_PROTOCOL, }); expect(issued).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); // The rejected envelope never reached vault registration. expect(vault.resolve).toBeTypeOf("function"); }, ); it.each([ { label: "encoded slash", path: "/files/a%2Fb" }, { label: "encoded backslash", path: "/files/a%5Cb" }, { label: "double-encoded dot segment", path: "/files/%252e%252e" }, { label: "lowercase percent-hex", path: "/files/a%c3%a9" }, { label: "encoded NUL", path: "/files/a%00b" }, ])("rejects a provider path that can decode again ($label)", async ({ path }) => { const bytes = new Uint8Array([1, 2, 3]); const payload = downloadCapabilityPayload(bytes, { path, href: `${DATA_ORIGIN}${path}`, }); const fetcher = vi.fn(async (input: RequestInfo | URL) => String(input) === CONTROL_ENDPOINT ? jsonResponse(payload) : downloadResponse(bytes.slice().buffer, payload), ) as unknown as typeof fetch; const { provider } = createHarness({ fetcher }); await expect( provider.issueDownload({ resourceId: "resource-1", signal: new AbortController().signal, }), ).resolves.toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); }); it("accepts a valid opaque UTF-8 path segment", async () => { const bytes = new Uint8Array([1, 2, 3]); // BT-PRE-05. Canonical uppercase percent-hex for a real UTF-8 segment. const path = `/files/${encodeURIComponent("caf\u00e9")}`; const payload = downloadCapabilityPayload(bytes, { path, href: `${DATA_ORIGIN}${path}?sig=do-not-log-this`, }); const fetcher = vi.fn(async (input: RequestInfo | URL) => String(input) === CONTROL_ENDPOINT ? jsonResponse(payload) : downloadResponse(bytes.slice().buffer, payload), ) as unknown as typeof fetch; const { provider } = createHarness({ fetcher }); await expect( provider.issueDownload({ resourceId: "resource-1", signal: new AbortController().signal, }), ).resolves.toMatchObject({ ok: true }); }); it("bounds a fetch that ignores its abort signal and cancels the late body", async () => { const bytes = new Uint8Array([1, 2, 3]); const payload = downloadCapabilityPayload(bytes); const cancel = vi.fn(async () => {}); let releaseControl: ((response: Response) => void) | undefined; const timers: Array<() => void> = []; const fetcher = vi.fn( async () => await new Promise((resolve) => { releaseControl = resolve; }), ) as unknown as typeof fetch; const { provider } = createHarness({ fetcher, scheduler: { setTimeout: (callback: () => void) => { timers.push(callback); return timers.length; }, clearTimeout: () => {}, }, }); const issuing = provider.issueDownload({ resourceId: "resource-1", signal: new AbortController().signal, }); await Promise.resolve(); // BT-PRE-03. The timeout fires while the fetch is still pending and never // settles on its own. timers.forEach((fire) => fire()); await expect(issuing).resolves.toMatchObject({ ok: false }); releaseControl?.({ body: { cancel } } as unknown as Response); await Promise.resolve(); await Promise.resolve(); expect(cancel).toHaveBeenCalledOnce(); void payload; }); /** * TR-RR-05. A scheduler that cannot install the deadline leaves the operation * unbounded. Releasing the caller listener and continuing anyway meant a * later abort was invisible, so an install failure is itself terminal: the * request fails closed with a typed Result and its resources are released. */ it("fails closed when the scheduler cannot install the deadline", async () => { const bytes = new Uint8Array([1, 2, 3]); const payload = downloadCapabilityPayload(bytes); const caller = new AbortController(); const remove = vi.spyOn(caller.signal, "removeEventListener"); const fetcher = vi.fn(async (input: RequestInfo | URL) => String(input) === CONTROL_ENDPOINT ? jsonResponse(payload) : downloadResponse(bytes.slice().buffer, payload), ) as unknown as typeof fetch; const { provider } = createHarness({ fetcher, scheduler: { setTimeout: () => { throw new TypeError("scheduler exploded"); }, clearTimeout: () => {}, }, }); // The public result stays a typed Result, not a rejection. await expect( provider.issueDownload({ resourceId: "resource-1", signal: caller.signal, }), ).resolves.toMatchObject({ ok: false }); expect(remove).toHaveBeenCalled(); }); it.each([ { label: "href/origin mismatch", patch: { origin: "https://evil.example" } }, { label: "href/path mismatch", patch: { path: "/files/other" } }, { label: "credentials in href", patch: { href: `https://u:p@objects.example${DOWNLOAD_PATH}` } }, { label: "maxBytes below byteLength", patch: { maxBytes: 0 } }, { label: "malformed digest", patch: { expectedSha256: "not-a-digest" } }, { label: "non-positive expiry", patch: { expiresAtEpochMs: 0 } }, // TR-RR-03. The registration is a versioned exact union: plaintext, an // ambient credential header, an unknown protocol version and any extra // own field are all refused at the issuer seam. { label: "unknown protocol version", patch: { protocol: "PRESIGNED_TRANSFER_V0" } }, { label: "missing protocol version", patch: { protocol: undefined } }, { label: "plaintext target", patch: { href: `http://objects.example${DOWNLOAD_PATH}`, origin: "http://objects.example", }, }, { label: "ambient credential header", patch: { requestHeaders: [{ name: "authorization", value: "Bearer leak" }], }, }, { label: "cookie response header", patch: { requiredResponseHeaders: [{ name: "set-cookie", value: "a=b" }], }, }, { label: "status outside 2xx", patch: { expectedStatus: 302 } }, { label: "extra own field", patch: { injected: true } }, ])( "rejects a malformed registration at the vault issuer seam ($label)", ({ patch }) => { // BT-PRE-04. The vault owns these invariants itself, so a second issuer // cannot register a weaker capability of the same type. const vault = createPresignedCapabilityVault({ now: () => NOW, maxActiveCapabilities: 4, }); const base = { protocol: PRESIGNED_TRANSFER_PROTOCOL, capabilityReceipt: "capability-direct-1", method: "GET" as const, binding: { kind: "DOWNLOAD" as const, resourceId: "resource-1" }, href: `${DATA_ORIGIN}${DOWNLOAD_PATH}`, origin: DATA_ORIGIN, path: DOWNLOAD_PATH, allowedQueryParameters: [], requestHeaders: [], requiredResponseHeaders: [], digestRequestHeader: null, digestResponseHeader: null, receiptResponseHeader: null, expectedStatus: 200, expectedResponseByteLength: 3, mediaType: "application/octet-stream", byteLength: 3, maxBytes: 3, expectedSha256: "a".repeat(64), expiresAtEpochMs: NOW + 60_000, }; expect( vault.register({ ...base, ...patch } as never), ).toMatchObject({ ok: false, error: { code: "POLICY_REJECTED" }, }); // The same registration without the defect is accepted. expect(vault.register(base as never)).toMatchObject({ ok: true }); vault.dispose(); }, ); /** * TR-01. The vault validated the issuer's own object and then read it again * to copy it. Between those reads a stateful issuer could show an allowed * header set to the forbidden-header check and hand `Authorization` to the * stored binding, so the executor sent a credential no rule had approved. */ });