`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.
34 lines
1.1 KiB
TypeScript
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")
|