- 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.
57 lines
1.7 KiB
Go
57 lines
1.7 KiB
Go
package web
|
|
|
|
import (
|
|
"embed"
|
|
"io/fs"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// #139 regression guards: with CSP script-src/style-src 'self' (no
|
|
// 'unsafe-inline'), the templates must not carry inline <script> blocks or
|
|
// style="" attributes, and the external scripts referenced must exist.
|
|
func TestNoInlineScripts(t *testing.T) {
|
|
entries, err := fs.ReadDir(tmplFS, "templates")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
re := regexp.MustCompile(`(?s)<script[^>]*>.*?</script>`)
|
|
srcOnly := regexp.MustCompile(`<script[^>]+src=`)
|
|
for _, e := range entries {
|
|
b, err := fs.ReadFile(tmplFS, "templates/"+e.Name())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, m := range re.FindAll(b, -1) {
|
|
if srcOnly.Match(m) {
|
|
continue // external script tag with src: fine
|
|
}
|
|
t.Errorf("%s: inline <script> block found (CSP #139): %q", e.Name(), string(m[:60]))
|
|
}
|
|
if strings.Contains(string(b), " onclick=") || strings.Contains(string(b), "onload=") {
|
|
t.Errorf("%s: inline event handler attribute found (CSP #139)", e.Name())
|
|
}
|
|
if strings.Contains(string(b), "style=\"") {
|
|
t.Errorf("%s: inline style attribute found (CSP #139)", e.Name())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReferencedStaticScriptsExist(t *testing.T) {
|
|
entries, _ := fs.ReadDir(tmplFS, "templates")
|
|
var staticFiles embed.FS = staticFS
|
|
for _, e := range entries {
|
|
b, err := fs.ReadFile(tmplFS, "templates/"+e.Name())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, m := range regexp.MustCompile(`<script src="/static/([^"]+)"`).FindAllSubmatch(b, -1) {
|
|
name := string(m[1])
|
|
if _, err := fs.ReadFile(staticFiles, "static/"+name); err != nil {
|
|
t.Errorf("%s references /static/%s: %v", e.Name(), name, err)
|
|
}
|
|
}
|
|
}
|
|
}
|