~james/core

core/camo/src/index.test.js -rw-r--r-- 2.0 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 16 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { createHmac } from "node:crypto";
import { afterEach, describe, expect, it, vi } from "vitest";
import worker from "./index.js";

const SANDBOX_CSP = "default-src 'none'; style-src 'unsafe-inline'; sandbox";
const env = { CAMO_SHARED_SECRET: "s3cret" };
const signed = (url) =>
	`https://camo.test/${createHmac("sha256", "s3cret").update(Buffer.from(url, "utf8")).digest("hex")}/${Buffer.from(url, "utf8").toString("hex")}`;

const serve = (url, fetch, match = async () => undefined, put = async () => {}) => {
	vi.stubGlobal("fetch", fetch);
	vi.stubGlobal("caches", { default: { match, put } });
	return worker.fetch(new Request(signed(url)), env);
};

afterEach(() => vi.unstubAllGlobals());

describe("fetch", () => {
	it("sandboxes an SVG with scripts in it", async () => {
		const svg =
			'<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>';
		const fresh = await serve(
			"https://ebilupstream.test/logo.svg",
			vi.fn(async () =>
				new Response(svg, { headers: { "Content-Type": "image/svg+xml" } }),
			),
		);
		expect(fresh.status).toBe(200);
		expect(fresh.headers.get("Content-Type")).toBe("image/svg+xml");
		expect(fresh.headers.get("Content-Security-Policy")).toBe(SANDBOX_CSP);
		expect(fresh.headers.get("X-Content-Type-Options")).toBe("nosniff");

		const stored = new Response(svg, {
			headers: {
				"Content-Type": "image/svg+xml",
				"Cache-Control": "public, max-age=86400, immutable",
			},
		});
		const cached = await serve(
			"https://ebilupstream.test/logo.svg",
			vi.fn(),
			async () => stored,
		);
		expect(cached.status).toBe(200);
		expect(cached.headers.get("Content-Security-Policy")).toBe(SANDBOX_CSP);
		expect(cached.headers.get("X-Content-Type-Options")).toBe("nosniff");
	});

	it("returns 415 for a type off the allowlist", async () => {
		const res = await serve(
			"https://ebilupstream.test/page",
			vi.fn(async () =>
				new Response("<html></html>", {
					headers: { "Content-Type": "text/html" },
				}),
			),
		);
		expect(res.status).toBe(415);
	});
});