mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-17 19:36:28 +02:00
fix(auth): let the connected-app consent page load inside Bambuddy's own frames
An app opened from the sidebar signs in inside Bambuddy's iframe, but every page sent frame-ancestors 'none', so the browser refused to show /connect/authorize there. That path now gets 'self', like the streaming overlay: every ancestor must be Bambuddy itself, so foreign pages still cannot frame it.
This commit is contained in:
+9
-1
@@ -9695,7 +9695,15 @@ async def security_headers_middleware(request, call_next):
|
||||
# overlay — Home Assistant on another port — remains what
|
||||
# TRUSTED_FRAME_ORIGINS is for, and _frame_ancestors already folds that
|
||||
# allowlist in.
|
||||
embeddable_same_origin = request.url.path.startswith("/overlay/")
|
||||
#
|
||||
# The connected-app consent page (/connect/authorize) gets the same
|
||||
# 'self': an app opened from Bambuddy's sidebar runs in an iframe, and
|
||||
# its "Sign in with Bambuddy" navigates that iframe to this page. With
|
||||
# 'none' the browser refuses to show it even inside Bambuddy. 'self'
|
||||
# requires every ancestor to be this origin, so a foreign page -- a
|
||||
# sidebar link's site included -- still cannot frame the consent
|
||||
# screen to bait a click.
|
||||
embeddable_same_origin = request.url.path.startswith("/overlay/") or request.url.path == "/connect/authorize"
|
||||
# 'wasm-unsafe-eval' permits WebAssembly compilation ONLY — it does
|
||||
# not allow eval()/Function() for JS, unlike 'unsafe-eval'. Needed by
|
||||
# the STEP preview, which triangulates in the browser via OpenCascade
|
||||
|
||||
@@ -135,6 +135,24 @@ async def test_overlay_route_allows_same_origin_framing(async_client: AsyncClien
|
||||
assert resp.headers.get("X-Frame-Options") == "SAMEORIGIN"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.integration
|
||||
async def test_connect_authorize_allows_same_origin_framing(async_client: AsyncClient, monkeypatch):
|
||||
"""A connected app opened from the sidebar signs in inside Bambuddy's iframe.
|
||||
|
||||
Its "Sign in with Bambuddy" navigates that iframe to /connect/authorize;
|
||||
with 'none' the browser refused to render the consent page there. 'self'
|
||||
still refuses any foreign framer.
|
||||
"""
|
||||
from backend.app import main as main_module
|
||||
|
||||
monkeypatch.setattr(main_module, "_TRUSTED_FRAME_ORIGINS", ())
|
||||
|
||||
resp = await async_client.get("/connect/authorize?client_id=x")
|
||||
assert "frame-ancestors 'self';" in resp.headers.get("Content-Security-Policy", "")
|
||||
assert resp.headers.get("X-Frame-Options") == "SAMEORIGIN"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.integration
|
||||
async def test_other_spa_routes_still_refuse_all_framing(async_client: AsyncClient, monkeypatch):
|
||||
@@ -144,7 +162,16 @@ async def test_other_spa_routes_still_refuse_all_framing(async_client: AsyncClie
|
||||
|
||||
monkeypatch.setattr(main_module, "_TRUSTED_FRAME_ORIGINS", ())
|
||||
|
||||
for path in ("/", "/settings", "/printers", "/overlays", "/camwall"):
|
||||
for path in (
|
||||
"/",
|
||||
"/settings",
|
||||
"/printers",
|
||||
"/overlays",
|
||||
"/camwall",
|
||||
"/connect",
|
||||
"/connect/authorize/x",
|
||||
"/connect/other",
|
||||
):
|
||||
resp = await async_client.get(path)
|
||||
csp = resp.headers.get("Content-Security-Policy", "")
|
||||
assert "frame-ancestors 'none'" in csp, f"{path} must not be framable"
|
||||
|
||||
Reference in New Issue
Block a user