Files
bookhoard/internal/middleware/security_headers.go
T
John O'Keefe b6eba66801 fix(web): restore Alpine theme members and allow eval for Alpine expressions
Two regressions from the cleanup cycle, caught in E2E:

1. The unexport pass stripped loadTheme, loadUserTheme, and
   updateThemeIndicators from the Alpine.data("theme") registration —
   the member-removal pass could not tell export-block lines from
   Alpine component object lines. Theme dropdowns on docs and
   non-app pages stopped reflecting the active theme. Members
   restored (functions were kept, only their scope registration was
   lost).

2. The new Content-Security-Policy shipped script-src without
   'unsafe-eval'. Alpine evaluates every @click / x-init / x-show
   expression through new Function(), so the CSP silently disabled
   ALL Alpine interactivity app-wide: sidebar categories stuck open,
   modals rendering unhidden and unresponsive, dropdowns inert.
   script-src now includes 'unsafe-eval' with a comment explaining
   the Alpine requirement.
2026-10-25 11:24:25 -04:00

24 lines
1020 B
Go

package middleware
import (
"github.com/labstack/echo/v5"
)
// SecurityHeadersMiddleware adds security headers to all responses
func SecurityHeadersMiddleware() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c *echo.Context) error {
// Add security headers
c.Response().Header().Set("X-Content-Type-Options", "nosniff")
c.Response().Header().Set("X-Frame-Options", "DENY")
c.Response().Header().Set("X-XSS-Protection", "1; mode=block")
c.Response().Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
c.Response().Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:")
c.Response().Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
c.Response().Header().Set("Permissions-Policy", "geolocation=(), microphone=(), camera=()")
return next(c)
}
}
}