- Move all inline <script> blocks (layout head/theme, topbar dark toggle, foot, paste, new, history, mine, settings, admin, unlock) to external files under internal/web/static/. Page data reaches scripts via data-* attributes (data-paste-id, data-default-dark) instead of template vars. - Replace inline onclick handlers (copy, delete, stats toggle) with addEventListener wiring. - Convert inline style="" attributes to CSS utility classes; swatch colors are now set via CSSOM/DOM APIs instead of innerHTML strings. - script-src/style-src are now plain 'self'; img-src data: stays for the SVG data-URI backgrounds. Verified with headless chromium: zero CSP violations on all pages in dark and light presets, theme swatches, admin lock, tables and paste view render correctly.
47 lines
1.9 KiB
Go
47 lines
1.9 KiB
Go
package web
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
// #59: SecurityHeaders must add the CSP and hardening headers to rendered
|
|
// HTML responses only; JSON and /raw responses pass through untouched.
|
|
func TestSecurityHeaders(t *testing.T) {
|
|
pages := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
w.Write([]byte("<html><body>ok</body></html>"))
|
|
})
|
|
h := SecurityHeaders(pages)
|
|
rec := httptest.NewRecorder()
|
|
h.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
|
|
wantCSP := "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; frame-ancestors 'none'"
|
|
if got := rec.Header().Get("Content-Security-Policy"); got != wantCSP {
|
|
t.Errorf("CSP = %q, want %q", got, wantCSP)
|
|
}
|
|
if got := rec.Header().Get("Referrer-Policy"); got != "no-referrer" {
|
|
t.Errorf("Referrer-Policy = %q, want no-referrer", got)
|
|
}
|
|
if got := rec.Header().Get("X-Content-Type-Options"); got != "nosniff" {
|
|
t.Errorf("X-Content-Type-Options = %q, want nosniff", got)
|
|
}
|
|
|
|
// JSON/raw responses: headers are now set unconditionally BEFORE the handler
|
|
// runs. The previous post-handler approach was silently dropped once a page
|
|
// handler flushed its template output (headers must be set before WriteHeader).
|
|
// CSP/nosniff/referrer on non-HTML bodies is harmless and desirable.
|
|
jsonh := SecurityHeaders(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.Write([]byte(`{"ok":true}`))
|
|
}))
|
|
rec = httptest.NewRecorder()
|
|
jsonh.ServeHTTP(rec, httptest.NewRequest("GET", "/api/x", nil))
|
|
if got := rec.Header().Get("Content-Security-Policy"); got != wantCSP {
|
|
t.Errorf("CSP missing on JSON response: got %q", got)
|
|
}
|
|
if got := rec.Header().Get("Referrer-Policy"); got != "no-referrer" {
|
|
t.Errorf("Referrer-Policy missing on JSON response: got %q", got)
|
|
}
|
|
}
|