- 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.
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user