chore: initialize from frontend template 4dc033c
This commit is contained in:
@@ -0,0 +1,281 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import {
|
||||
BrowserFilePolicyRegistry,
|
||||
browserFilePolicyReference,
|
||||
} from "../../src/adapters/browser-files/browser-file-policy-registry.ts";
|
||||
import { BrowserFileVault } from "../../src/adapters/browser-files/browser-file-vault.ts";
|
||||
import {
|
||||
BrowserTransientPreview,
|
||||
ObjectUrlLeaseRegistry,
|
||||
} from "../../src/adapters/browser-files/object-url-lease.ts";
|
||||
|
||||
const hardLimits = Object.freeze({
|
||||
maxInspectionBytes: 64,
|
||||
maxRetainedFileBytes: 1_024,
|
||||
maxPreviewBytes: 1_024,
|
||||
maxObjectUrlBytes: 1_024,
|
||||
maxTransferBytes: 1_024,
|
||||
});
|
||||
|
||||
describe("browser file composition policy registry", () => {
|
||||
it("deep-snapshots every policy axis and permits only limit reductions", () => {
|
||||
const reference = browserFilePolicyReference(
|
||||
"documents",
|
||||
"select-preview-download-pdf",
|
||||
);
|
||||
const selection = {
|
||||
policyId: "documents-v1",
|
||||
purpose: "document",
|
||||
classification: "PERSONAL" as const,
|
||||
multiple: false,
|
||||
maxCount: 1,
|
||||
maxFileBytes: 100,
|
||||
maxTotalBytes: 100,
|
||||
allowEmpty: false,
|
||||
accept: [
|
||||
{ mediaType: "application/pdf", extensions: [".pdf"] },
|
||||
],
|
||||
};
|
||||
const inspection = {
|
||||
policyId: "documents-v1",
|
||||
maxInspectionBytes: 8,
|
||||
acceptedSignatures: [
|
||||
{
|
||||
mediaType: "application/pdf",
|
||||
extensions: [".pdf"],
|
||||
patterns: [{ offset: 0, bytes: [0x25, 0x50] }],
|
||||
},
|
||||
],
|
||||
};
|
||||
const preview = {
|
||||
allowedMediaTypes: ["application/pdf"],
|
||||
maxPreviewBytes: 100,
|
||||
};
|
||||
const download = {
|
||||
strategy: "PROMPT_AND_STREAM" as const,
|
||||
mediaType: "application/pdf",
|
||||
safeExtension: ".pdf",
|
||||
maxTransferBytes: 100,
|
||||
maxBufferedBytes: 50,
|
||||
integrity: "REQUIRED" as const,
|
||||
};
|
||||
const registry = new BrowserFilePolicyRegistry({
|
||||
profiles: [
|
||||
{
|
||||
reference,
|
||||
selection,
|
||||
inspection,
|
||||
preview,
|
||||
download,
|
||||
},
|
||||
],
|
||||
hardLimits,
|
||||
});
|
||||
|
||||
selection.maxFileBytes = 1;
|
||||
selection.accept[0]!.extensions[0] = ".exe";
|
||||
inspection.acceptedSignatures[0]!.patterns[0]!.bytes[0] = 0;
|
||||
preview.allowedMediaTypes[0] = "text/html";
|
||||
(
|
||||
download as { strategy: string }
|
||||
).strategy = "BROWSER_MANAGED";
|
||||
download.safeExtension = ".exe";
|
||||
|
||||
expect(
|
||||
registry.resolveSelection(reference, {
|
||||
maxFileBytes: 80,
|
||||
}),
|
||||
).toMatchObject({
|
||||
ok: true,
|
||||
value: {
|
||||
maxFileBytes: 80,
|
||||
accept: [{ extensions: [".pdf"] }],
|
||||
},
|
||||
});
|
||||
expect(
|
||||
registry.resolveSelection(reference, {
|
||||
maxFileBytes: 101,
|
||||
}),
|
||||
).toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "LIMIT_EXCEEDED" },
|
||||
});
|
||||
expect(registry.resolveInspection(reference)).toMatchObject({
|
||||
ok: true,
|
||||
value: {
|
||||
acceptedSignatures: [
|
||||
{ patterns: [{ bytes: [0x25, 0x50] }] },
|
||||
],
|
||||
},
|
||||
});
|
||||
const resolvedPreview = registry.resolvePreview(reference);
|
||||
expect(resolvedPreview.ok).toBe(true);
|
||||
if (resolvedPreview.ok) {
|
||||
expect(
|
||||
resolvedPreview.value.allowedMediaTypes.has(
|
||||
"application/pdf",
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
resolvedPreview.value.allowedMediaTypes.has("text/html"),
|
||||
).toBe(false);
|
||||
(
|
||||
resolvedPreview.value.allowedMediaTypes as Set<string>
|
||||
).clear();
|
||||
expect(
|
||||
registry.resolvePreview(reference),
|
||||
).toMatchObject({
|
||||
ok: true,
|
||||
value: {
|
||||
allowedMediaTypes: new Set(["application/pdf"]),
|
||||
},
|
||||
});
|
||||
}
|
||||
expect(
|
||||
registry.resolveDownload(reference, {}),
|
||||
).toMatchObject({
|
||||
ok: true,
|
||||
value: {
|
||||
strategy: "PROMPT_AND_STREAM",
|
||||
safeExtension: ".pdf",
|
||||
},
|
||||
});
|
||||
expect(
|
||||
registry.resolveDownload(
|
||||
browserFilePolicyReference("unknown", "unknown"),
|
||||
{},
|
||||
),
|
||||
).toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "POLICY_REJECTED" },
|
||||
});
|
||||
expect(
|
||||
registry.resolveSelection(
|
||||
browserFilePolicyReference(
|
||||
"documents",
|
||||
"select-preview-download-pdf",
|
||||
),
|
||||
),
|
||||
).toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "POLICY_REJECTED" },
|
||||
});
|
||||
expect(
|
||||
registry.resolveSelection(
|
||||
{
|
||||
policyKey: "documents",
|
||||
intention: "select-preview-download-pdf",
|
||||
} as typeof reference,
|
||||
),
|
||||
).toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "POLICY_REJECTED" },
|
||||
});
|
||||
});
|
||||
|
||||
it("binds verification receipts to the exact profile, not a reused policyId", async () => {
|
||||
const profileA = browserFilePolicyReference(
|
||||
"images-a",
|
||||
"preview-avatar",
|
||||
);
|
||||
const profileB = browserFilePolicyReference(
|
||||
"images-b",
|
||||
"preview-banner",
|
||||
);
|
||||
const inspection = {
|
||||
policyId: "shared-png-v1",
|
||||
maxInspectionBytes: 8,
|
||||
acceptedSignatures: [
|
||||
{
|
||||
mediaType: "image/png",
|
||||
extensions: [".png"],
|
||||
patterns: [{ offset: 0, bytes: [0x89, 0x50] }],
|
||||
},
|
||||
],
|
||||
};
|
||||
const policies = new BrowserFilePolicyRegistry({
|
||||
profiles: [profileA, profileB].map((reference) => ({
|
||||
reference,
|
||||
inspection,
|
||||
preview: {
|
||||
allowedMediaTypes: ["image/png"],
|
||||
maxPreviewBytes: 16,
|
||||
},
|
||||
})),
|
||||
hardLimits,
|
||||
});
|
||||
const vault = new BrowserFileVault({
|
||||
policies,
|
||||
createReference: () => "file:profile-bound",
|
||||
createVerificationReceipt: () =>
|
||||
"verification:profile-bound",
|
||||
});
|
||||
const captured = vault.captureFiles(
|
||||
[
|
||||
new File(
|
||||
[new Uint8Array([0x89, 0x50, 1])],
|
||||
"avatar.png",
|
||||
{ type: "image/png", lastModified: 1 },
|
||||
),
|
||||
],
|
||||
{
|
||||
policyId: "capture-v1",
|
||||
purpose: "capture",
|
||||
classification: "PERSONAL",
|
||||
multiple: false,
|
||||
maxCount: 1,
|
||||
maxFileBytes: 16,
|
||||
maxTotalBytes: 16,
|
||||
allowEmpty: false,
|
||||
accept: [
|
||||
{ mediaType: "image/png", extensions: [".png"] },
|
||||
],
|
||||
},
|
||||
);
|
||||
expect(captured.ok).toBe(true);
|
||||
if (!captured.ok || !captured.value[0]) return;
|
||||
const inspected = await vault.inspect({
|
||||
ref: captured.value[0].ref,
|
||||
policy: profileA,
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
expect(inspected.ok).toBe(true);
|
||||
if (!inspected.ok || !inspected.value.verificationReceipt) {
|
||||
return;
|
||||
}
|
||||
const createObjectURL = vi.fn(() => "blob:profile-bound");
|
||||
const previews = new BrowserTransientPreview({
|
||||
files: vault,
|
||||
policies,
|
||||
hardMaxPreviewBytes: 16,
|
||||
leases: new ObjectUrlLeaseRegistry({
|
||||
createObjectURL,
|
||||
revokeObjectURL() {},
|
||||
}),
|
||||
});
|
||||
|
||||
expect(
|
||||
await previews.create({
|
||||
ref: captured.value[0].ref,
|
||||
verificationReceipt:
|
||||
inspected.value.verificationReceipt,
|
||||
policy: profileB,
|
||||
signal: new AbortController().signal,
|
||||
}),
|
||||
).toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "POLICY_REJECTED" },
|
||||
});
|
||||
expect(createObjectURL).not.toHaveBeenCalled();
|
||||
expect(
|
||||
await previews.create({
|
||||
ref: captured.value[0].ref,
|
||||
verificationReceipt:
|
||||
inspected.value.verificationReceipt,
|
||||
policy: profileA,
|
||||
signal: new AbortController().signal,
|
||||
}),
|
||||
).toMatchObject({ ok: true });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user