import { defineMiddleware } from 'astro/middleware'; export const onRequest = defineMiddleware(async (context, next) => { // Security headers const securityHeaders = { // HTTPS enforcement 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', // XSS protection 'X-XSS-Protection': '1; mode=block', // Content type sniffing protection 'X-Content-Type-Options': 'nosniff', // Frame options disabled - Using CSP frame-ancestors instead for Stripe compatibility // 'X-Frame-Options': 'SAMEORIGIN', // Referrer policy 'Referrer-Policy': 'strict-origin-when-cross-origin', // Content Security Policy - Temporarily relaxed for Stripe Connect debugging 'Content-Security-Policy': [ "default-src 'self' https:", "script-src 'self' 'unsafe-inline' 'unsafe-eval' https:", "style-src 'self' 'unsafe-inline' https:", "font-src 'self' https:", "img-src 'self' data: https: blob:", "connect-src 'self' https: wss:", "frame-src 'self' https:", "frame-ancestors 'self' https:", "form-action 'self'", "base-uri 'self'", "object-src 'none'", "worker-src 'self' blob: https:" ].join('; '), // Permissions policy - Fixed syntax 'Permissions-Policy': [ 'camera=()', 'microphone=()', 'geolocation=()', 'payment=(self "https://js.stripe.com" "https://connect-js.stripe.com" "https://*.stripe.com")', 'usb=()', 'bluetooth=()', 'magnetometer=()', 'gyroscope=()', 'accelerometer=()' ].join(', ') }; // HTTPS redirect in production if (process.env.NODE_ENV === 'production') { const proto = context.request.headers.get('x-forwarded-proto'); const host = context.request.headers.get('host'); if (proto === 'http' && host) { return Response.redirect(`https://${host}${context.url.pathname}${context.url.search}`, 301); } } // Continue with the request const response = await next(); // Add security headers to response Object.entries(securityHeaders).forEach(([key, value]) => { response.headers.set(key, value); }); return response; });