| 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; |
| 3 | |
| 4 | import { CONTENT_SECURITY_POLICY, makeNonce, pagePolicy, secure } from "./guard.ts"; |
| 5 | |
| 6 | function directives(policy: string): Map<string, string> { |
| 7 | return new Map(policy.split("; ").map((part) => [part.split(" ")[0]!, part])); |
| 8 | } |
| 9 | |
| 10 | test("a page runs only sudo's own scripts, by its nonce", () => { |
| 11 | const nonce = makeNonce(); |
| 12 | assert.match(nonce, /^[A-Za-z0-9+/]{22}==$/); |
| 13 | assert.notEqual(nonce, makeNonce()); |
| 14 | const page = directives(pagePolicy(nonce)); |
| 15 | assert.equal(page.get("script-src"), `script-src 'self' 'nonce-${nonce}'`); |
| 16 | assert.equal(page.get("connect-src"), "connect-src 'self'"); |
| 17 | assert.doesNotMatch(pagePolicy(nonce), /unsafe-|strict-dynamic|https?:|\*/); |
| 18 | // Everything else as strict as an answer that is not a page. |
| 19 | const rest = directives(CONTENT_SECURITY_POLICY); |
| 20 | for (const [name, value] of rest) if (name !== "script-src") assert.equal(page.get(name), value, name); |
| 21 | assert.deepEqual([...page.keys()].filter((name) => !rest.has(name)), ["connect-src"]); |
| 22 | }); |
| 23 | |
| 24 | test("an answer that is not a page runs nothing", () => { |
| 25 | assert.equal(directives(CONTENT_SECURITY_POLICY).get("script-src"), "script-src 'none'"); |
| 26 | assert.equal(directives(CONTENT_SECURITY_POLICY).get("default-src"), "default-src 'none'"); |
| 27 | }); |
| 28 | |
| 29 | test("a page keeps its own policy; anything else gets the strict one", () => { |
| 30 | const nonce = makeNonce(); |
| 31 | const page = secure(new Response("<html></html>", { headers: { "content-security-policy": pagePolicy(nonce) } })); |
| 32 | assert.equal(page.headers.get("content-security-policy"), pagePolicy(nonce)); |
| 33 | assert.equal(page.headers.get("cache-control"), "no-store"); |
| 34 | const data = secure(new Response("{}")); |
| 35 | assert.equal(data.headers.get("content-security-policy"), CONTENT_SECURITY_POLICY); |
| 36 | }); |