diff --git a/internal/auth/templates/account.html b/internal/auth/templates/account.html index 59bd07d..3ba56d2 100644 --- a/internal/auth/templates/account.html +++ b/internal/auth/templates/account.html @@ -169,7 +169,7 @@ - + @@ -290,6 +290,6 @@ document.getElementById("rename-name").value = btn.getAttribute("data-name") || ""; }); - - + + {{end}} diff --git a/internal/auth/templates/login.html b/internal/auth/templates/login.html index 22b2fd9..7e4525a 100644 --- a/internal/auth/templates/login.html +++ b/internal/auth/templates/login.html @@ -35,6 +35,6 @@
Don't have an account yet? Create one
- + {{end}} diff --git a/internal/auth/templates/signup.html b/internal/auth/templates/signup.html index ee4b45f..7a8df6d 100644 --- a/internal/auth/templates/signup.html +++ b/internal/auth/templates/signup.html @@ -40,5 +40,5 @@
Already have an account? Sign in
- + {{end}} diff --git a/internal/core/templates/add_repeater.html b/internal/core/templates/add_repeater.html index a0ad1dc..59719c3 100644 --- a/internal/core/templates/add_repeater.html +++ b/internal/core/templates/add_repeater.html @@ -277,10 +277,10 @@ } document.getElementById("region").addEventListener("change", applyRegion); - - - - + + + + {{else}} {{/* ---- Step 3 (KISS): details for a repeater that's already on the network ---- */}} diff --git a/internal/core/templates/config_regions_edit.html b/internal/core/templates/config_regions_edit.html index eaa034f..d639198 100644 --- a/internal/core/templates/config_regions_edit.html +++ b/internal/core/templates/config_regions_edit.html @@ -20,8 +20,8 @@ {{end}} - - + + @@ -114,9 +114,9 @@ function addBlock(kind) { } })(); - - - + + + {{end}} diff --git a/internal/core/templates/console.html b/internal/core/templates/console.html index 24697f9..7a4abb9 100644 --- a/internal/core/templates/console.html +++ b/internal/core/templates/console.html @@ -135,14 +135,14 @@ swap needs no new markup. The flex row is nested so the [hidden] attribute wins {{if .ShowConfig}} - - - - + + + + {{end}} - + {{end}} diff --git a/internal/core/templates/dashboard.html b/internal/core/templates/dashboard.html index ae09001..9973999 100644 --- a/internal/core/templates/dashboard.html +++ b/internal/core/templates/dashboard.html @@ -126,10 +126,10 @@

Repeater map

{{if .Mapped}}
- +
- - + + - + + - + {{end}} {{template "icon-arrow-left" "me-1"}}All organizations diff --git a/internal/core/templates/repeater.html b/internal/core/templates/repeater.html index d310b84..f44d4fc 100644 --- a/internal/core/templates/repeater.html +++ b/internal/core/templates/repeater.html @@ -135,10 +135,10 @@

Location

- +
- - + + diff --git a/internal/marketing/templates/repeater_public.html b/internal/marketing/templates/repeater_public.html index 04c07e2..467949f 100644 --- a/internal/marketing/templates/repeater_public.html +++ b/internal/marketing/templates/repeater_public.html @@ -64,10 +64,10 @@

Location

- +
- - + + diff --git a/internal/web/security_test.go b/internal/web/security_test.go index 4db91b5..d77ad12 100644 --- a/internal/web/security_test.go +++ b/internal/web/security_test.go @@ -104,6 +104,37 @@ func TestTemplatesHaveNoInlineJS(t *testing.T) { } } +// TestTemplatesUseAssetHelper enforces that every static reference goes through +// the {{ asset }} helper (href="{{ asset "/static/x" }}"), never a bare +// href="/static/x". The helper rewrites the URL to a content-hashed, +// immutably-cached path; a bare reference silently loses that caching. +func TestTemplatesUseAssetHelper(t *testing.T) { + t.Parallel() + root := moduleRoot(t) + bare := regexp.MustCompile(`(?i)(href|src)="/static/`) + + err := filepath.WalkDir(filepath.Join(root, "internal"), func(path string, d os.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() || !strings.HasSuffix(path, ".html") { + return nil + } + b, err := os.ReadFile(path) + if err != nil { + return err + } + rel, _ := filepath.Rel(root, path) + if loc := bare.FindIndex(b); loc != nil { + t.Errorf("%s: bare static reference — use {{ asset \"/static/...\" }}: %q", rel, snippet(b, loc[0])) + } + return nil + }) + if err != nil { + t.Fatalf("walk templates: %v", err) + } +} + func snippet(b []byte, at int) string { end := at + 40 if end > len(b) { diff --git a/internal/web/templates/base.html b/internal/web/templates/base.html index f5e0cbb..3515719 100644 --- a/internal/web/templates/base.html +++ b/internal/web/templates/base.html @@ -3,14 +3,14 @@ - + {{block "title" .}}MeshTender{{end}} - - - - - - + + + + + + Skip to main content @@ -164,14 +164,14 @@ - + {{template "title" .}} - - - - - - + + + + + + Skip to main content @@ -210,12 +210,12 @@ - + {{template "title" .}} - - - - + + + +
@@ -239,12 +239,12 @@ - + {{template "title" .}} - - - - + + + + {{template "rootnav" .}} diff --git a/internal/web/templates/org_config.html b/internal/web/templates/org_config.html index e3fae0f..26c1901 100644 --- a/internal/web/templates/org_config.html +++ b/internal/web/templates/org_config.html @@ -55,10 +55,10 @@

Preview a location

- +
- - + + - - + + + - - + + +