diff options
Diffstat (limited to 'packages/meshbay-hub/tests/test_desktop_shell.py')
| -rw-r--r-- | packages/meshbay-hub/tests/test_desktop_shell.py | 49 |
1 files changed, 37 insertions, 12 deletions
diff --git a/packages/meshbay-hub/tests/test_desktop_shell.py b/packages/meshbay-hub/tests/test_desktop_shell.py index 13d194e..c4f5b08 100644 --- a/packages/meshbay-hub/tests/test_desktop_shell.py +++ b/packages/meshbay-hub/tests/test_desktop_shell.py @@ -85,11 +85,18 @@ def test_no_permission_is_granted_to_the_page(): ]) def test_the_scheme_is_privileged(privilege): """ - Without `secure` the scheme is not a secure context, the service worker - silently refuses to register, and streamed downloads break with no error — - the same failure mode as an uncontrolled page, which this codebase has - already learned once. `standard` gives a real origin, so IndexedDB survives - an update instead of being keyed to something that moves. + `secure` is what makes it a secure context, and without it **the whole of + `crypto.subtle` is undefined** — measured, not assumed: the first probe + loaded a `data:` URL and every algorithm failed with TypeError, AES-GCM + included. `standard` gives a real origin, so IndexedDB survives an update + instead of being keyed to something that moves. + + An earlier version of this docstring said `secure` was what let the service + worker register. That is wrong: Chromium refuses to register a worker on a + custom scheme whatever its privileges — "The URL protocol of the current + origin ('app://meshbay') is not supported". The application therefore has no + service worker and does not need one; it saves files through a native + dialog, which is better than the path the worker exists to provide. """ assert privilege in _main(), f"{privilege} missing from the scheme privileges" @@ -107,6 +114,18 @@ def test_the_protocol_handler_cannot_be_walked_out_of(): # ── Content Security Policy ───────────────────────────────────────────────── +def test_the_policy_is_sent_as_a_header(): + """ + A <meta> policy cannot carry `frame-ancestors`, and having it there means + one directive of the policy is decoration. The handler is also the only + thing that serves the interface, so this is one source rather than two. + """ + source = _main() + assert "'Content-Security-Policy': CSP" in source + assert "Content-Security-Policy" not in INDEX.read_text(encoding="utf-8") \ + .split("-->")[1], "the packaged page still carries a policy of its own" + + def test_the_policy_keeps_wasm_unsafe_eval(): """ The bundle key is Argon2id in WebAssembly. A policy that forbids it does not @@ -116,14 +135,20 @@ def test_the_policy_keeps_wasm_unsafe_eval(): def _policy() -> str: - """The meta tag's content, not the file — the comment above it names the - same directives and would satisfy a naive search.""" + """ + The policy the protocol handler sends, read out of the CSP constant. + + Not a <meta> tag: `frame-ancestors` is ignored there, and a directive that + silently does nothing is worse than one that is absent. Chromium said so in + the console the first time the application was launched. + """ import re - page = INDEX.read_text(encoding="utf-8") - match = re.search( - r'http-equiv="Content-Security-Policy"\s+content="([^"]*)"', page) - assert match, "no Content-Security-Policy meta tag" - return match.group(1) + source = _main() + match = re.search(r"const CSP = \[(.*?)\]\.join", source, re.S) + assert match, "no CSP constant in the main process" + return "; ".join( + line.strip().strip('",').strip('"') + for line in match.group(1).splitlines() if line.strip()) def _directive(name: str) -> str: |