Files
app/frontend/src/csp.check.ts
T
stroblme 7d6cc5b0bf Serve index.html no-cache on every route; check the theme script's CSP hash
`try_files` served the SPA fallback inside `location /`, so `/` and every
client route went out without `Cache-Control: no-cache`. The fallback is now
the last argument, an internal redirect to the exact no-cache location.

`src/csp.check.ts` recomputes the inline theme script's sha256 and fails
`bun run check` with the new value when the CSP no longer names it.
2026-10-07 09:32:06 +02:00

34 lines
1.1 KiB
TypeScript

/**
* The CSP's hash for the theme script, checked against the script.
*
* ponytail: a script rather than a suite, as with the other `.check.ts` files:
*
* cd frontend && bun run src/csp.check.ts
*
* `index.html` runs one inline script, the theme class before first paint, and
* `nginx-security-headers.conf` admits it by its sha256. Edit one without the
* other and the browser blocks the script, so the app paints light-then-dark
* again, with nothing failing anywhere but the console.
*/
import assert from "node:assert/strict"
import { createHash } from "node:crypto"
import { readFileSync } from "node:fs"
const read = (path: string) =>
readFileSync(new URL(path, import.meta.url), "utf8")
const inline = [
...read("../index.html").matchAll(/<script>([\s\S]*?)<\/script>/g),
]
assert.equal(inline.length, 1, "index.html has one inline script")
const hash = createHash("sha256").update(inline[0][1]).digest("base64")
const csp = read("../nginx-security-headers.conf")
assert.ok(
csp.includes(`'sha256-${hash}'`),
`the theme script's hash is not in nginx-security-headers.conf; set it to 'sha256-${hash}'`,
)
console.log("csp: ok")