5 Commits
Author SHA1 Message Date
fen 0ceeabc810 Merge dev: burn fix, version label, theme persistence, admin/settings UI, theme grid, CSP fix, docs
CI / test (push) Successful in 21s
CI / docker (push) Successful in 47s
2026-09-09 21:32:30 -05:00
fen aca99bc6d4 Merge pull request 'Fix #116: allow inline styles in CSP (style-src)' (#117) from fix-116-csp-inline-styles into dev
CI / test (push) Successful in 22s
CI / docker (push) Successful in 36s
2026-09-10 02:20:53 +00:00
fen 073d39ccba Fix #116: allow inline styles in CSP (style-src 'self' 'unsafe-inline')
CI / test (pull_request) Successful in 24s
CI / docker (pull_request) Skipped
2026-09-09 21:18:53 -05:00
fen 9ec7d5152e Merge pull request 'Fix #114: theme grid empty (t.colors undefined)' (#115) from fix-114-theme-grid-empty into dev
CI / test (push) Successful in 21s
CI / docker (push) Successful in 42s
2026-09-10 02:01:38 +00:00
fen a677e627a8 Fix #114: use presetColors(t.id) for theme card swatches
CI / test (pull_request) Successful in 24s
CI / docker (pull_request) Skipped
t.colors was removed by #113; rendering threw on first iteration and
the theme grid rendered empty. Use the colors returned by
presetColors(t.id) instead. Verified in headless chromium: 5
theme-card elements render on /settings.
2026-09-09 20:55:13 -05:00
3 changed files with 3 additions and 3 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ func TestSecurityHeaders(t *testing.T) {
h := SecurityHeaders(pages) h := SecurityHeaders(pages)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil)) h.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
wantCSP := "default-src 'self'; script-src 'self' 'unsafe-inline'; frame-ancestors 'none'" wantCSP := "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'"
if got := rec.Header().Get("Content-Security-Policy"); got != wantCSP { if got := rec.Header().Get("Content-Security-Policy"); got != wantCSP {
t.Errorf("CSP = %q, want %q", got, wantCSP) t.Errorf("CSP = %q, want %q", got, wantCSP)
} }
+1 -1
View File
@@ -44,7 +44,7 @@
btn.className = 'theme-card'; btn.className = 'theme-card';
btn.setAttribute('aria-pressed', current === t.id ? 'true' : 'false'); btn.setAttribute('aria-pressed', current === t.id ? 'true' : 'false');
btn.innerHTML = '<strong>' + t.name + '</strong>' + btn.innerHTML = '<strong>' + t.name + '</strong>' +
'<span class="swatches">' + t.colors.map(function (c) { '<span class="swatches">' + colors.map(function (c) {
return '<span class="swatch" style="background:' + c + '"></span>'; return '<span class="swatch" style="background:' + c + '"></span>';
}).join('') + '</span>'; }).join('') + '</span>';
btn.addEventListener('click', function () { btn.addEventListener('click', function () {
+1 -1
View File
@@ -344,7 +344,7 @@ func SecurityHeaders(next http.Handler) http.Handler {
// is harmless and arguably desirable. // is harmless and arguably desirable.
h := w.Header() h := w.Header()
h.Set("Content-Security-Policy", h.Set("Content-Security-Policy",
"default-src 'self'; script-src 'self' 'unsafe-inline'; frame-ancestors 'none'") "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'")
h.Set("Referrer-Policy", "no-referrer") h.Set("Referrer-Policy", "no-referrer")
h.Set("X-Content-Type-Options", "nosniff") h.Set("X-Content-Type-Options", "nosniff")
next.ServeHTTP(w, r) next.ServeHTTP(w, r)