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.
This commit is contained in:
John O'Keefe committed 2026-10-25 11:24:25 -04:00
1 parent 4ab6a64bd8
commit b6eba66801
2 files changed
+4 -1

No files matched your search

+1 -1
View File
@@ -13,7 +13,7 @@ func SecurityHeadersMiddleware() echo.MiddlewareFunc {
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'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:")
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=()")
+3
View File
@@ -288,8 +288,11 @@ Alpine.data("theme", () => ({
changeTheme,
changeWoodPaneling,
initializeTheme,
loadTheme,
loadUserTheme,
loadWoodPaneling,
revealCurrentTheme,
updateThemeIndicators,
updateWoodPanelingIndicators,
}));