Skip to content

Commit 0cf71cd

Browse files
committed
Let the graph draw under the policy it has to live with
The policy went out forbidding unsafe-eval on the theory that only the development bundles wanted it, and that was measured on a page that does not have a graph on it. pixi.js builds its shader batches by evaluating strings, so the graph rendered nothing and postscript.js threw on its way past — on every page, since the graph is in the sidebar. Checking the built HTML for the absence of the word eval is not the same as loading the page, and only the second one finds this. So script-src takes unsafe-eval, and the comment above it says which page needs which of the two unsafe words rather than leaving them to look like carelessness. pixi ships a pixi.js/unsafe-eval module that would avoid it, but reaching that means editing the graph plugin, which is somebody else's and pinned to a commit. What is left is a script-src that constrains where a script may be fetched from and nothing about what runs once it is there. The directives that were doing the work — connect-src above all, and base-uri, object-src, form-action, frame-src — are untouched. The development branch is now just the reload websocket.
1 parent 62715dc commit 0cf71cd

1 file changed

Lines changed: 22 additions & 19 deletions

File tree

‎quartz/components/contentSecurityPolicy.ts‎

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
* meta element may not carry — `frame-ancestors`, `report-uri` and `sandbox`,
77
* all of which are ignored there — and leaves the rest, which is most of it.
88
*
9-
* `script-src` keeps `'unsafe-inline'`, because Quartz bootstraps each page
10-
* from half a dozen inline scripts it writes itself. So this is not a policy
11-
* that stops an injected `<script>alert(1)</script>`, and it is not pretending
12-
* to be one. What it stops is everything around that: a script pulled in from
9+
* `script-src` has to keep both `'unsafe-inline'` and `'unsafe-eval'`; the
10+
* constant below says which page needs which. So this is not a policy that
11+
* stops an injected `<script>alert(1)</script>`, and it is not pretending to be
12+
* one. What it stops is everything around that: a script pulled in from
1313
* somewhere else, a page reparented under a new `<base>`, a form posted off to
1414
* a host of somebody's choosing, an `<object>`, and — the one that matters most
1515
* here — a connection opened to anywhere but the two CDNs that are supposed to
@@ -27,8 +27,22 @@
2727
* reason why.
2828
*/
2929

30-
/** Where the page's own code comes from, plus what the demo frames need. */
31-
const SCRIPTS = ["'self'", "'unsafe-inline'", "'wasm-unsafe-eval'"]
30+
/**
31+
* Where the page's own code comes from, plus what the demo frames need.
32+
*
33+
* Both of the unsafe words are here because something on the page will not run
34+
* without them, not because they were cheap to leave in. `unsafe-inline` is
35+
* Quartz bootstrapping every page from half a dozen inline scripts it writes
36+
* itself. `unsafe-eval` is pixi.js, which the graph draws with and which builds
37+
* its shader batches by evaluating strings; without it the graph does not
38+
* render, and `postscript.js` throws on the way past. pixi ships a
39+
* `pixi.js/unsafe-eval` module that avoids this, but reaching it means editing
40+
* the graph plugin, which is somebody else's and pinned to a commit.
41+
*
42+
* So this does not stop an injected `<script>alert(1)</script>`, and it is not
43+
* pretending to. What it stops is the rest.
44+
*/
45+
const SCRIPTS = ["'self'", "'unsafe-inline'", "'unsafe-eval'", "'wasm-unsafe-eval'"]
3246

3347
/** The two CDNs: katex and d3 and pixi from one, mermaid from the other. */
3448
const CDN = ["https://cdn.jsdelivr.net", "https://cdnjs.cloudflare.com"]
@@ -49,21 +63,10 @@ const EMBEDS = ["https://www.shadertoy.com", "https://graphtoy.com", "https://ww
4963
*/
5064
const ANY_MEDIA = ["'self'", "data:", "blob:", "https:"]
5165

52-
/**
53-
* The two things a development build needs and a published one must not have.
54-
*
55-
* webpack's default devtool in development mode is `eval`, so every module in
56-
* `content/js` arrives wrapped in one and the page cannot run at all under a
57-
* policy without `'unsafe-eval'`. In production the devtool is off and the
58-
* bundles contain no eval, which is the only reason it is safe to forbid: the
59-
* strict policy is the one that ships, and it is enforced by the same builds
60-
* that serve the site rather than trusted to hold.
61-
*
62-
* The other is the websocket `--serve` reloads the page over.
63-
*/
66+
/** The websocket `--serve` reloads the page over, and nothing else. */
6467
function development(wsPort: number): { script: string[]; connect: string[] } {
6568
return {
66-
script: ["'unsafe-eval'"],
69+
script: [],
6770
connect: [`ws://localhost:${wsPort}`, `ws://127.0.0.1:${wsPort}`],
6871
}
6972
}

0 commit comments

Comments
 (0)