diff options
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/app.py')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/app.py | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/app.py b/packages/meshbay-hub/src/meshbay_hub/app.py index 76d7ec0..2daa55b 100644 --- a/packages/meshbay-hub/src/meshbay_hub/app.py +++ b/packages/meshbay-hub/src/meshbay_hub/app.py @@ -35,7 +35,7 @@ from meshbay_hub.api.relay import router as relay_router from meshbay_hub.api.signaling import router as signaling_router from meshbay_hub.api.admin import router as admin_router from meshbay_hub.api.notifications import router as notifications_router -from meshbay_hub.api.webapp import router as webapp_router, STATIC_DIR, ASSET_V +from meshbay_hub.api.webapp import router as webapp_router, STATIC_DIR, ASSET_V, CSP from meshbay_hub.api.middleware import limiter @@ -142,6 +142,21 @@ def create_app(cfg: HubConfig | None = None) -> FastAPI: app.state.limiter = limiter app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) + @app.middleware("http") + async def _security_headers(request, call_next): + """ + Second-review L5, third-review M5: the SPA shell and its assets went out + with no CSP and no other protective headers. This adds them everywhere — + `webapp.CSP` is the same policy the desktop client already enforces on + these exact files. `setdefault` so a route that sets its own wins. + """ + response = await call_next(request) + response.headers.setdefault("Content-Security-Policy", CSP) + response.headers.setdefault("X-Content-Type-Options", "nosniff") + response.headers.setdefault("Referrer-Policy", "strict-origin-when-cross-origin") + response.headers.setdefault("X-Frame-Options", "DENY") + return response + # Routers (webapp last — catches / before API routes) app.include_router(hub_router) app.include_router(users_router) |