import { expect, test } from "bun:test"; import { mkdtempSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { configureStorage, createSignedFileToken, getStore, safeObjectKey, serveStoredFile, upload, verifySignedFileToken, } from "../src/index.ts"; import { UPLOAD_RUNTIME } from "../src/runtime.ts"; test("browser upload response parse failures emit a diagnostic", () => { expect(UPLOAD_RUNTIME).toContain("upload response was not valid JSON"); expect(UPLOAD_RUNTIME).not.toContain("catch (e2) {}"); }); function configure() { configureStorage( { stores: { public: { driver: "local", access: "public", dir: "files" } } }, mkdtempSync(join(tmpdir(), "wrnexus-upload-")), ); } test("rejects unsafe upload prefixes before writing", async () => { configure(); const form = new FormData(); form.set("file", new File(["hello"], "hello.txt", { type: "text/plain" })); const request = new Request("http://local/upload", { method: "POST", body: form }); await expect(upload("public", request, { prefix: "../escape" })).rejects.toThrow( "unsafe upload prefix", ); }); test("public active content is attachment-only and cannot be MIME-sniffed", async () => { configure(); await getStore("public").driver.put( "safe/page.html", new TextEncoder().encode(""), { contentType: "text/html", }, ); const response = await serveStoredFile("/__wrnexus/uploads/public/safe/page.html"); expect(response?.headers.get("x-content-type-options")).toBe("nosniff"); expect(response?.headers.get("content-disposition")).toStartWith("attachment"); }); test("safe object keys discard traversal-like prefixes", () => { expect(safeObjectKey("report.pdf", "../../private/reports")).toMatch(/^private\/reports\//); expect(safeObjectKey("report.pdf", "../..")).toMatch(/^uploads\//); }); test("signed file tokens reject tampering and expired payloads", async () => { const secret = "a-long-test-secret-for-files"; const token = await createSignedFileToken( { store: "private", key: "reports/a.pdf", expiresAt: 2_000 }, secret, ); expect(await verifySignedFileToken(token, secret, 1_000)).toMatchObject({ store: "private", key: "reports/a.pdf", }); expect(await verifySignedFileToken(`${token}x`, secret, 1_000)).toBeNull(); expect(await verifySignedFileToken(token, secret, 2_000)).toBeNull(); }); test("upload scanning rejects unsafe bytes before storage", async () => { const form = new FormData(); form.set("file", new File(["virus"], "bad.txt", { type: "text/plain" })); await expect( upload("public", new Request("http://test/upload", { method: "POST", body: form }), { scan: async () => ({ safe: false, scanner: "test-av", reason: "signature" }), }), ).rejects.toMatchObject({ status: 422 }); expect(await getStore("public").driver.get("bad.txt")).toBeNull(); }); test("post-storage processor failure rolls back the object", async () => { const form = new FormData(); form.set("file", new File(["image"], "photo.png", { type: "image/png" })); let key = ""; await expect( upload("public", new Request("http://test/upload", { method: "POST", body: form }), { afterStore(file) { key = file.key; throw new Error("transform failed"); }, }), ).rejects.toMatchObject({ status: 422 }); expect(key).not.toBe(""); expect(await getStore("public").driver.get(key)).toBeNull(); });