""" Middleware to allow iframe embedding for the KeepItGoing mobile app. The mobile app uses Capacitor WebView which embeds the website in an iframe. This middleware detects requests from the mobile app and removes both X-Frame-Options and Content-Security-Policy frame-ancestors headers to allow iframe embedding, while keeping clickjacking protection for regular web browsers. """ class AllowMobileAppFramingMiddleware: """ Remove frame-blocking headers for requests from KeepItGoing mobile app. The mobile app uses a Capacitor WebView. We detect these requests via User-Agent and remove X-Frame-Options and CSP frame-ancestors headers. """ def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) # Check if request is from KeepItGoing mobile app user_agent = request.META.get('HTTP_USER_AGENT', '') # Detect Capacitor/Android WebView patterns is_mobile_app = ( 'wv' in user_agent.lower() or # Android WebView 'CapacitorHttp' in user_agent or 'com.firebugit.keepitgoing' in user_agent or ('KeepItGoing' in user_agent and 'Mobile' in user_agent) ) if is_mobile_app: # Mobile app: Allow iframe embedding - don't add frame-blocking headers # Remove any existing frame headers if 'X-Frame-Options' in response: del response['X-Frame-Options'] if 'Content-Security-Policy' in response: del response['Content-Security-Policy'] else: # Regular browsers: Add security headers for clickjacking protection if 'X-Frame-Options' not in response: response['X-Frame-Options'] = 'DENY' if 'Content-Security-Policy' not in response: response['Content-Security-Policy'] = ( "default-src 'self'; " "script-src 'self' 'unsafe-inline'; " "style-src 'self' 'unsafe-inline'; " "img-src 'self' data: https:; " "font-src 'self' data:; " "connect-src 'self'; " "frame-ancestors 'none'; " "base-uri 'self'; " "form-action 'self';" ) return response