headers->has('Content-Security-Policy')) { $reponse->headers->set('Content-Security-Policy', $this->politique($request)); } return $reponse; } private function politique(Request $request): string { $communes = [ 'default-src' => "'self'", 'img-src' => "'self' data:", // Polices servies par le portail (Vite), depuis l'étape 14. 'font-src' => "'self'", 'object-src' => "'none'", 'base-uri' => "'self'", 'form-action' => "'self'", 'frame-ancestors' => "'none'", 'report-uri' => '/csp-rapport', ]; // Visio (étape 15) : script d'intégration et cadre servis par Jitsi. $visio = config('visio.domaine') ? ' https://'.config('visio.domaine') : ''; $directives = $this->estApplication($request) ? [ 'script-src' => "'self' 'nonce-".Vite::cspNonce()."'".$visio, 'frame-src' => "'self'".$visio, // Attributs style= présents dans le gabarit commun : sans // risque d'exécution de code, tolérés. 'style-src' => "'self' 'unsafe-inline'", 'connect-src' => "'self' wss://{$request->getHost()}", ] : [ // jsDelivr : Pyodide et sql.js, téléchargés par /ide à la // demande (WebAssembly, d'où 'wasm-unsafe-eval', qui n'autorise // pas eval() en JavaScript). Tailwind : CDN d'exécution des // pages du design. Voir docs/dette.md. 'script-src' => "'self' 'unsafe-inline' 'wasm-unsafe-eval' https://cdn.jsdelivr.net https://cdn.tailwindcss.com", 'style-src' => "'self' 'unsafe-inline'", 'connect-src' => "'self' https://cdn.jsdelivr.net", 'frame-src' => 'https://www.youtube-nocookie.com', ]; return collect($communes + $directives) ->map(fn (string $valeur, string $directive) => "{$directive} {$valeur}") ->implode('; '); } private function estApplication(Request $request): bool { $route = $request->route(); if ($route === null) { return false; } if (in_array($route->getName(), ['login', 'register'], true) || str_starts_with((string) $route->getName(), 'rejoindre')) { return true; } return collect($route->gatherMiddleware()) ->contains(fn ($middleware) => is_string($middleware) && str_starts_with($middleware, 'auth:')); } }