package httpx import "net/http" // ContentSecurityPolicy is the strict default CSP (SPEC-003 §4). It allows only // same-origin assets; the PWA manifest and service worker are same-origin too. const ContentSecurityPolicy = "default-src 'self'; " + "img-src 'self' data:; " + "style-src 'self'; " + "script-src 'self'; " + "connect-src 'self'; " + "object-src 'none'; " + "base-uri 'none'; " + "form-action 'self'; " + "frame-ancestors 'none'" // SetSecurityHeaders writes the baseline security headers on every response // (SPEC-003 §4). HSTS is set only when the app is served over https (secure). func SetSecurityHeaders(w http.ResponseWriter, secure bool) { h := w.Header() h.Set("X-Content-Type-Options", "nosniff") h.Set("Referrer-Policy", "no-referrer") h.Set("X-Frame-Options", "DENY") h.Set("Content-Security-Policy", ContentSecurityPolicy) // L4s — the isolation trio: deny the powerful features the app never uses, // and keep the document and its subresources same-origin (so a compromised // or mis-hosted sibling cannot open, embed, or read MyDay). h.Set("Permissions-Policy", PermissionsPolicy) h.Set("Cross-Origin-Opener-Policy", "same-origin") h.Set("Cross-Origin-Resource-Policy", "same-origin") if secure { h.Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains") } } // PermissionsPolicy disables the browser features MyDay does not use (L4s). // An empty allowlist means "no origin, including self, may use it". const PermissionsPolicy = "accelerometer=(), camera=(), geolocation=(), " + "gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()"