diff --git a/app/main.py b/app/main.py index 414c351..95da1c7 100644 --- a/app/main.py +++ b/app/main.py @@ -418,6 +418,50 @@ class AuthMiddleware(BaseHTTPMiddleware): return RedirectResponse(f"/login?next={quote(target, safe='')}", status_code=303) +class DracoAlertesCorsMiddleware(BaseHTTPMiddleware): + """CORS Fusion #69, limité à GET /api/events. + + Le panneau Alertes unifiées lit ce journal depuis les autres + hôtes dracodev, avec credentials. Seules les origines des + applications soeurs (résolues comme les liens de la barre : + explicite > hôte de la requête > dérivation > défaut officiel, + via resoudre_urls_draco()) reçoivent Access-Control-Allow-Origin. + Le preflight OPTIONS ne porte aucune donnée et ne contourne + aucune authentification : le GET reste soumis à AuthMiddleware + (session ou jeton). Toute autre origine ou route traverse sans + en-tête CORS — le navigateur bloque alors la lecture, comme + avant. Aucune CSP connect-src n'est à ouvrir ici : Kanbante + n'énonce que frame-src (console Spark). + """ + + async def dispatch(self, request, call_next): + if request.url.path != "/api/events": + return await call_next(request) + from app.config import resoudre_urls_draco + + urls = resoudre_urls_draco(request.headers.get("host")) + soeurs = {urls.sso_url, urls.flowdeck_url, urls.tiktak_url, + urls.public_url} + origine = request.headers.get("origin", "") + if origine not in soeurs: + return await call_next(request) + headers = { + "Access-Control-Allow-Origin": origine, + "Access-Control-Allow-Credentials": "true", + "Vary": "Origin", + } + if request.method == "OPTIONS": + headers.update({ + "Access-Control-Allow-Methods": "GET", + "Access-Control-Allow-Headers": "Content-Type", + "Access-Control-Max-Age": "600", + }) + return JSONResponse({}, status_code=200, headers=headers) + response = await call_next(request) + response.headers.update(headers) + return response + + app.add_middleware(AuthMiddleware) @@ -428,6 +472,7 @@ app.add_middleware(AuthMiddleware) from app.recherche import RechercheCorsMiddleware app.add_middleware(RechercheCorsMiddleware) +app.add_middleware(DracoAlertesCorsMiddleware) def _safe_next(raw: str) -> str: