summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_security_headers.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/tests/test_security_headers.py')
-rw-r--r--packages/meshbay-hub/tests/test_security_headers.py40
1 files changed, 36 insertions, 4 deletions
diff --git a/packages/meshbay-hub/tests/test_security_headers.py b/packages/meshbay-hub/tests/test_security_headers.py
index 44dd7e8..b068656 100644
--- a/packages/meshbay-hub/tests/test_security_headers.py
+++ b/packages/meshbay-hub/tests/test_security_headers.py
@@ -46,7 +46,9 @@ async def test_even_a_404_carries_the_headers(client):
def test_the_policy_is_locked_down_where_it_matters():
- assert "default-src 'none'" in CSP # covers object-src, etc.
+ # The catch-all. It no longer "covers object-src" — that directive is set
+ # explicitly below, and this comment used to say otherwise.
+ assert "default-src 'none'" in CSP
# `'self'`, not `'none'`: every foreign origin is still refused, which is
# the whole of the clickjacking protection. What `'self'` adds is this
# origin framing itself, which the streamed download needs — see
@@ -95,6 +97,38 @@ def test_the_streamed_download_frame_is_allowed():
assert "*" not in frame_src
+def test_the_pdf_preview_has_both_permissions_it_needs():
+ """
+ Two directives govern one feature, and fixing either alone changes nothing
+ visible.
+
+ `files-app.js` decrypts a PDF in the page and shows it from a Blob through
+ `<object type="application/pdf">`. Chromium's viewer loads that as plugin
+ data (`object-src`) and renders it in an internal frame (`frame-src`).
+ `object-src` was absent, so it fell back to `default-src 'none'` and every
+ preview showed the "will not display the PDF inline" fallback instead —
+ measured in Chrome 152 against the deployed page, where the violation was
+ `object-src` and the fallback was on screen. It had been broken here since
+ this file started sending a policy (2026-09-01); before that the hub sent
+ none, which is why the browser was believed to be the working one.
+
+ `'self'` is not what either directive needs: a same-origin `blob:` URL is
+ not matched by `'self'`, so with `object-src` opened the preview still
+ failed at `frame-src`. Both carry `blob:`, and neither carries a wildcard.
+ """
+ for name in ("object-src", "frame-src"):
+ directive = _directive(CSP, name)
+ assert directive, f"no {name} directive"
+ sources = directive.split()[1:]
+ assert "blob:" in sources, (
+ f"{name} refuses the decrypted PDF; the preview shows its fallback "
+ f"message on every browser")
+ assert "*" not in sources
+ # A blob URL is minted by this page's own script. Nothing else needs
+ # these directives, so nothing else belongs in them.
+ assert "data:" not in sources
+
+
def test_no_foreign_origin_may_frame_this_page():
"""The clickjacking property, stated separately from how it is spelled.
@@ -122,9 +156,7 @@ def test_the_two_framing_headers_agree():
Checked as a pair rather than one value apiece, because the defect was the
disagreement and either one alone reads as correct.
"""
- import asyncio
-
- from meshbay_hub.app import create_app # noqa: F401 (import check)
+ from meshbay_hub.app import create_app # noqa: F401 (import check)
ancestors = _directive(CSP, "frame-ancestors").split(" ", 1)[1].strip()
expected = {"'none'": "DENY", "'self'": "SAMEORIGIN"}[ancestors]