package main
import (
"bytes"
"crypto/sha256"
"encoding/base64"
"html/template"
"net/http/httptest"
"strings"
"testing"
)
// TestCSPScriptHashMatchesRenderedScript renders the shell and checks that the
// CSP hash we advertise equals the hash of the script actually served — if a
// future edit to the shell changes either the script or how it's emitted, this
// fails instead of silently breaking every page under the strict policy.
func TestCSPScriptHashMatchesRenderedScript(t *testing.T) {
var buf bytes.Buffer
err := shellTpl.Execute(&buf, struct {
Title, Domain, Active, Username, Version, Initials, SearchQuery, Lang, Theme, ThemeIcon, ThemeNext, NextPath string
LoggedIn, IsAdmin bool
Body, BrandMark, IconSprite template.HTML
}{Title: "t", Lang: "en"})
if err != nil {
t.Fatalf("execute shell: %v", err)
}
html := buf.String()
open := strings.Index(html, "<script>")
close := strings.Index(html, "</script>")
if open < 0 || close < 0 || close < open {
t.Fatalf("no <script>…</script> in rendered shell")
}
served := html[open+len("<script>") : close]
sum := sha256.Sum256([]byte(served))
want := "sha256-" + base64.StdEncoding.EncodeToString(sum[:])
if want != scriptHash {
t.Fatalf("CSP script hash mismatch:\n advertised %s\n served %s", scriptHash, want)
}
}
func TestSameOriginPOST(t *testing.T) {
s := &server{}
handler := s.sameOriginPOST(nil)
_ = handler // constructed to ensure it wraps without panicking
cases := []struct {
name string
method string
origin string
referer string
host string
wantOrigin bool
}{
{"get always passes", "GET", "", "", "example.com", true},
{"matching origin", "POST", "https://example.com", "", "example.com", true},
{"mismatched origin", "POST", "https://evil.com", "", "example.com", false},
{"referer fallback match", "POST", "", "https://example.com/login", "example.com", true},
{"no headers refused", "POST", "", "", "example.com", false},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
r := httptest.NewRequest(c.method, "http://example.com/x", nil)
r.Host = c.host
if c.origin != "" {
r.Header.Set("Origin", c.origin)
}
if c.referer != "" {
r.Header.Set("Referer", c.referer)
}
got := c.method == "GET" || sameOrigin(r)
if got != c.wantOrigin {
t.Fatalf("got allowed=%v, want %v", got, c.wantOrigin)
}
})
}
}