aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-client/src
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-09 15:48:53 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-09 15:48:53 +0200
commit56776934c2ddfbad4884b252da6f5fb25864b8db (patch)
treeb34aa2a9b71a3129c937d9d0cecaa39505afbd6b /packages/meshbay-client/src
parent78b309d18efdd227c0efa42464988eaaf1483c16 (diff)
downloadmeshbay-56776934c2ddfbad4884b252da6f5fb25864b8db.tar.gz
fix: the PDF preview needs object-src and frame-src, in both policies
A PDF preview showed the "this browser will not display the PDF inline" fallback everywhere — in the desktop client since its first launch, and in the browser since the hub started sending a CSP on 2026-09-01. It read as a missing native feature because before that commit the hub sent no policy at all, so Chrome had once worked and the application never had. Two directives govern one feature. `files-app.js` decrypts the file in the page and hands it to `<object type="application/pdf">` from a Blob; Chromium loads that as plugin data (`object-src`, absent and therefore falling back to `default-src 'none'`) and then renders it in an internal frame (`frame-src`). Opening either alone changes nothing visible — the second refusal produces the same fallback. `'self'` covers neither: a same-origin `blob:` URL is not matched by it in either directive, measured in Chrome 152 against the deployed page and in Electron 44 against the client's own policy. `plugins` stays at its default `false`: the built-in viewer is not behind that flag on Electron 44, verified by rendering one. Widening `object-src` from `'none'` to `blob:` admits only what page script minted itself, at a type this code sets — PDFium parsing bytes that came from a node, which is what any browser does with the same file once downloaded. Tests: each policy is pinned to carry `blob:` in both directives (each fails if either token is removed), and the two policies are now held identical directive by directive apart from the two deliberate differences — the comment claiming they were the same had already drifted and nothing checked it. The CSP source parser in test_desktop_shell.py read `//` comment lines as directives, which is the "parse directives, not text" mistake this file already records; it skips them now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XauykfBvRrpy6RYbF6F7Wu
Diffstat (limited to 'packages/meshbay-client/src')
-rw-r--r--packages/meshbay-client/src/main.js20
1 files changed, 19 insertions, 1 deletions
diff --git a/packages/meshbay-client/src/main.js b/packages/meshbay-client/src/main.js
index ab579a1..83cf772 100644
--- a/packages/meshbay-client/src/main.js
+++ b/packages/meshbay-client/src/main.js
@@ -112,7 +112,25 @@ const CSP = [
"font-src 'self'",
"connect-src 'self' https: wss:",
"worker-src 'self'",
- `frame-src ${RECAPTCHA_SRC}`,
+ // `blob:` here and in `frame-src` are one thing, not two: the PDF preview.
+ //
+ // `files-app.js` decrypts a PDF in the page, wraps it in a Blob and hands it
+ // to `<object type="application/pdf">`, so the bytes never leave the
+ // renderer. Chromium serves that with its own viewer, and the viewer takes
+ // TWO permissions — it loads the resource as plugin data (`object-src`,
+ // which was falling back to `default-src 'none'`) and then renders it in an
+ // internal frame (`frame-src`). Fixing either alone still shows the "this
+ // browser will not display the PDF inline" fallback, which is how this
+ // looked like a missing feature rather than a policy.
+ //
+ // `'self'` does not cover it: a same-origin `blob:` URL is NOT matched by
+ // `'self'` in either directive — measured on Chromium 152, this build's and
+ // Chrome's alike — so the token has to be `blob:` in both. Only page script
+ // can mint a blob URL and the type is set by our code, so what this admits
+ // is PDFium parsing bytes that came from a node — exactly what a browser
+ // does with the same file.
+ "object-src blob:",
+ `frame-src blob: ${RECAPTCHA_SRC}`,
"frame-ancestors 'none'",
"base-uri 'none'",
"form-action 'none'",