from __future__ import annotations import secrets from django.contrib.messages import get_messages from .consent import ConsentService class ConsentMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): request.consent = ConsentService.get_consent(request) return self.get_response(request) class SecurityHeadersMiddleware: def __init__(self, get_response): self.get_response = get_response ADMIN_PREFIXES = ("/cms/", "/django-admin/") def __call__(self, request): nonce = secrets.token_urlsafe(16) request.csp_nonce = nonce response = self.get_response(request) if request.path.startswith(self.ADMIN_PREFIXES): return response response["Content-Security-Policy"] = ( f"default-src 'self'; " f"script-src 'self' 'nonce-{nonce}' https://challenges.cloudflare.com; " "style-src 'self' https://fonts.googleapis.com; " "img-src 'self' data: blob:; " "font-src 'self' https://fonts.gstatic.com; " "connect-src 'self' https://challenges.cloudflare.com; " "frame-src https://challenges.cloudflare.com; " "object-src 'none'; " "base-uri 'self'; " "frame-ancestors 'self'" ) response["Permissions-Policy"] = "camera=(), microphone=(), geolocation=()" return response class AdminMessageGuardMiddleware: ADMIN_PREFIXES = ("/cms/", "/django-admin/") def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # The public site has no legitimate use of Django's shared flash queue. # Drain any stale admin messages before frontend rendering can see them. if not request.path.startswith(self.ADMIN_PREFIXES): storage = get_messages(request) list(storage) storage._queued_messages = [] storage._loaded_data = [] for sub_storage in getattr(storage, "storages", []): sub_storage._queued_messages = [] sub_storage._loaded_data = [] sub_storage.used = True storage.used = True return self.get_response(request)