Files
clean-architecture-frontend…/tests/unit/presigned-transfer-upload.test.ts
T

550 lines
17 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import type { BrowserDataObservation } from "../../src/application/ports/browser-file-storage/shared.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,
jsonResponse,
responseWithUrl,
uploadCapabilityPayload,
} from "./presigned-transfer-fixture.ts";
describe("presigned upload part execution", () => {
it("snapshots, verifies and uploads a PUT part with a separate response receipt", async () => {
const original = new Uint8Array([9, 8, 7]);
const checksum = sha256Hex(original);
const payload = uploadCapabilityPayload({
bytes: original,
checksum,
});
let releaseDigest: (() => void) | undefined;
const digestGate = new Promise<void>((resolve) => {
releaseDigest = resolve;
});
const sentBodies: number[][] = [];
const dataCalls: RequestInit[] = [];
const fetcher = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
if (String(input) === CONTROL_ENDPOINT) return jsonResponse(payload);
dataCalls.push(init ?? {});
sentBodies.push([
...new Uint8Array(init?.body as ArrayBuffer),
]);
return responseWithUrl(
new Response(null, {
status: 200,
headers: {
[POLICY_HEADER]: "v1",
"Content-Length": "0",
ETag: "\"part-etag-1\"",
},
}),
String(payload.href),
);
}) as unknown as typeof fetch;
const { provider, executor } = createHarness({
fetcher,
digestBytes: async (bytes) => {
await digestGate;
return sha256Hex(bytes);
},
});
const issued = await provider.issueUploadPart({
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: original.byteLength,
checksumSha256: checksum,
mediaType: "application/octet-stream",
idempotencyKey: "part-attempt-1",
signal: new AbortController().signal,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
const request = {
capability: issued.value,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: original.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes: original,
signal: new AbortController().signal,
};
const pending = executor.uploadParts.put(request);
original.fill(0);
request.sessionId = "mutated-session";
request.requestBindingSha256 = "d".repeat(64);
request.checksumSha256 = "f".repeat(64);
releaseDigest?.();
expect(await pending).toEqual({
ok: true,
value: {
bytesWritten: 3,
checksumSha256: checksum,
receiptToken: "part-etag-1",
},
});
expect(sentBodies).toEqual([[9, 8, 7]]);
expect(dataCalls[0]).toMatchObject({
method: "PUT",
credentials: "omit",
redirect: "error",
referrerPolicy: "no-referrer",
});
expect(
(dataCalls[0]?.headers as Headers).get(CHECKSUM_HEADER),
).toBe(checksum);
});
it.each(["sessionId", "requestBindingSha256"] as const)(
"rejects an actual PUT whose %s differs from the capability",
async (field) => {
const bytes = new Uint8Array([3, 2, 1]);
const checksum = sha256Hex(bytes);
const payload = uploadCapabilityPayload({ bytes, checksum });
const fetcher = vi.fn(async () =>
jsonResponse(payload),
) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const issued = 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,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
expect(
await executor.uploadParts.put({
capability: issued.value,
sessionId:
field === "sessionId"
? "different-session"
: UPLOAD_SESSION_ID,
requestBindingSha256:
field === "requestBindingSha256"
? "d".repeat(64)
: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes,
signal: new AbortController().signal,
}),
).toMatchObject({
ok: false,
error: { code: "POLICY_REJECTED" },
});
expect(fetcher).toHaveBeenCalledTimes(1);
},
);
it("rejects URL-shaped upload receipts", async () => {
const bytes = new Uint8Array([4, 5, 6]);
const checksum = sha256Hex(bytes);
const payload = uploadCapabilityPayload({ bytes, checksum });
const fetcher = vi.fn(async (input: RequestInfo | URL) => {
if (String(input) === CONTROL_ENDPOINT) {
return jsonResponse(payload);
}
return responseWithUrl(
new Response(null, {
status: 200,
headers: {
[POLICY_HEADER]: "v1",
"Content-Length": "0",
ETag: "\"https://objects.example/authorizing-token\"",
},
}),
String(payload.href),
);
}) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const issued = 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,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
expect(
await executor.uploadParts.put({
capability: issued.value,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes,
signal: new AbortController().signal,
}),
).toMatchObject({
ok: false,
error: { code: "INTEGRITY_FAILED" },
});
});
it("drains a bounded successful PUT acknowledgement without cancelling it", async () => {
const bytes = new Uint8Array([4, 5, 6]);
const checksum = sha256Hex(bytes);
const payload = uploadCapabilityPayload(
{ bytes, checksum },
{ expectedResponseByteLength: 2 },
);
let cancelled = false;
const fetcher = vi.fn(async (input: RequestInfo | URL) => {
if (String(input) === CONTROL_ENDPOINT) {
return jsonResponse(payload);
}
const body = new ReadableStream<Uint8Array>({
start(controller) {
controller.enqueue(new Uint8Array([8, 9]));
controller.close();
},
cancel() {
cancelled = true;
},
});
return responseWithUrl(
new Response(body, {
status: 200,
headers: {
[POLICY_HEADER]: "v1",
"Content-Length": "2",
ETag: "\"part-etag-1\"",
},
}),
String(payload.href),
);
}) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const issued = 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,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
expect(
await executor.uploadParts.put({
capability: issued.value,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes,
signal: new AbortController().signal,
}),
).toMatchObject({
ok: true,
value: { receiptToken: "part-etag-1" },
});
expect(cancelled).toBe(false);
});
it("accepts an empty 204 PUT acknowledgement", async () => {
const bytes = new Uint8Array([4, 5, 6]);
const checksum = sha256Hex(bytes);
const payload = uploadCapabilityPayload(
{ bytes, checksum },
{
expectedStatus: 204,
expectedResponseByteLength: 0,
},
);
const fetcher = vi.fn(async (input: RequestInfo | URL) =>
String(input) === CONTROL_ENDPOINT
? jsonResponse(payload)
: responseWithUrl(
new Response(null, {
status: 204,
headers: {
[POLICY_HEADER]: "v1",
ETag: "\"part-etag-204\"",
},
}),
String(payload.href),
),
) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const issued = 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,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
expect(
await executor.uploadParts.put({
capability: issued.value,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes,
signal: new AbortController().signal,
}),
).toMatchObject({
ok: true,
value: { receiptToken: "part-etag-204" },
});
});
it("cancels a PUT acknowledgement whose declared length violates its binding", async () => {
const bytes = new Uint8Array([4, 5, 6]);
const checksum = sha256Hex(bytes);
const payload = uploadCapabilityPayload({ bytes, checksum });
let cancelled = false;
const fetcher = vi.fn(async (input: RequestInfo | URL) => {
if (String(input) === CONTROL_ENDPOINT) {
return jsonResponse(payload);
}
const body = new ReadableStream<Uint8Array>({
pull() {},
cancel() {
cancelled = true;
},
});
return responseWithUrl(
new Response(body, {
status: 200,
headers: {
[POLICY_HEADER]: "v1",
"Content-Length": "1",
ETag: "\"part-etag-1\"",
},
}),
String(payload.href),
);
}) as unknown as typeof fetch;
const { provider, executor } = createHarness({ fetcher });
const issued = 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,
});
expect(issued.ok).toBe(true);
if (!issued.ok) return;
expect(
await executor.uploadParts.put({
capability: issued.value,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes,
signal: new AbortController().signal,
}),
).toMatchObject({
ok: false,
error: { code: "POLICY_REJECTED" },
});
expect(cancelled).toBe(true);
});
it("observes only safe operation, outcome, failure and byte buckets", async () => {
const bytes = new Uint8Array([7, 8, 9]);
const downloadPayload = downloadCapabilityPayload(bytes);
const checksum = sha256Hex(bytes);
const uploadPayload = uploadCapabilityPayload({ bytes, checksum });
const observations: BrowserDataObservation[] = [];
const fetcher = vi.fn(
async (input: RequestInfo | URL, init?: RequestInit) => {
if (String(input) === CONTROL_ENDPOINT) {
const request = JSON.parse(String(init?.body)) as {
method: string;
};
return jsonResponse(
request.method === "GET"
? downloadPayload
: uploadPayload,
);
}
if (String(input) === DOWNLOAD_HREF) {
return downloadResponse(
bytes.slice().buffer,
downloadPayload,
);
}
return responseWithUrl(
new Response(null, {
status: 200,
headers: {
[POLICY_HEADER]: "v1",
"Content-Length": "0",
ETag: "\"part-etag-secret\"",
},
}),
String(uploadPayload.href),
);
},
) as unknown as typeof fetch;
const { provider, executor } = createHarness({
fetcher,
observer: {
record(observation) {
observations.push(observation);
},
},
});
const issuedDownload = await provider.issueDownload({
resourceId: "resource-1",
signal: new AbortController().signal,
});
expect(issuedDownload.ok).toBe(true);
if (!issuedDownload.ok) return;
const opened = await executor.downloadSources.open({
resourceId: "resource-1",
capability: issuedDownload.value,
signal: new AbortController().signal,
});
expect(opened.ok).toBe(true);
if (!opened.ok) return;
expect((await collect(opened.value)).every((result) => result.ok)).toBe(
true,
);
const issuedUpload = 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,
});
expect(issuedUpload.ok).toBe(true);
if (!issuedUpload.ok) return;
expect(
await executor.uploadParts.put({
capability: issuedUpload.value,
sessionId: UPLOAD_SESSION_ID,
requestBindingSha256: REQUEST_BINDING_SHA256,
uploadBindingSha256: "b".repeat(64),
partNumber: 1,
offset: 0,
byteLength: bytes.byteLength,
checksumSha256: checksum,
idempotencyKey: "part-attempt-1",
bytes,
signal: new AbortController().signal,
}),
).toMatchObject({ ok: true });
expect(observations).toEqual([
{
operation: "PRESIGNED_TRANSFER",
outcome: "SUCCEEDED",
byteBucket: "LT1MIB",
},
{
operation: "PRESIGNED_TRANSFER",
outcome: "SUCCEEDED",
byteBucket: "LT1MIB",
},
{
operation: "DOWNLOAD",
outcome: "SUCCEEDED",
byteBucket: "LT1MIB",
},
{
operation: "PRESIGNED_TRANSFER",
outcome: "SUCCEEDED",
byteBucket: "LT1MIB",
},
{
operation: "UPLOAD_PART",
outcome: "SUCCEEDED",
byteBucket: "LT1MIB",
},
]);
const serialized = JSON.stringify(observations);
for (const secret of [
DOWNLOAD_HREF,
"do-not-log-this",
checksum,
"capability-download-1",
"capability-upload-1",
"part-etag-secret",
"resource-1",
]) {
expect(serialized).not.toContain(secret);
}
});
});