87 lines
2.8 KiB
Go
87 lines
2.8 KiB
Go
package test
|
|
|
|
import (
|
|
"RenewCMS/api/handlers/frontend"
|
|
"RenewCMS/api/middleware"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func serveWithSecurityHeaders(hsts bool) http.Header {
|
|
handler := middleware.SecurityHeaders(hsts)(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
rec := httptest.NewRecorder()
|
|
handler.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/", nil))
|
|
return rec.Result().Header
|
|
}
|
|
|
|
func TestSecurityHeadersAlwaysSetBaseline(t *testing.T) {
|
|
headers := serveWithSecurityHeaders(false)
|
|
|
|
expected := map[string]string{
|
|
"X-Content-Type-Options": "nosniff",
|
|
"X-Frame-Options": "DENY",
|
|
"Referrer-Policy": "strict-origin-when-cross-origin",
|
|
"Cross-Origin-Opener-Policy": "same-origin",
|
|
}
|
|
for name, want := range expected {
|
|
if got := headers.Get(name); got != want {
|
|
t.Errorf("expected %s %q, got %q", name, want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSecurityHeadersContentSecurityPolicy(t *testing.T) {
|
|
csp := serveWithSecurityHeaders(false).Get("Content-Security-Policy")
|
|
|
|
for _, directive := range []string{
|
|
"default-src 'self'",
|
|
"script-src 'self' 'wasm-unsafe-eval';",
|
|
"object-src 'none'",
|
|
"base-uri 'self'",
|
|
"frame-ancestors 'none'",
|
|
} {
|
|
if !strings.Contains(csp, directive) {
|
|
t.Errorf("expected CSP to contain %q, got %q", directive, csp)
|
|
}
|
|
}
|
|
if strings.Contains(csp, "'unsafe-eval'") || strings.Contains(csp, "script-src 'self' 'unsafe-inline'") {
|
|
t.Errorf("script-src must not allow unsafe sources, got %q", csp)
|
|
}
|
|
}
|
|
|
|
func TestAllowInlineScriptsHashesOnlyInlineScripts(t *testing.T) {
|
|
policy := "default-src 'self'; script-src 'self'; object-src 'none'"
|
|
html := []byte(`<html><head><script>var a=1</script><script type="module" src="/a.js"></script><script> </script></head></html>`)
|
|
|
|
got := frontend.AllowInlineScripts(policy, html)
|
|
|
|
if !strings.Contains(got, "script-src 'self' 'sha256-") || strings.Count(got, "sha256-") != 1 {
|
|
t.Errorf("expected exactly one inline hash in script-src, got %q", got)
|
|
}
|
|
if !strings.Contains(got, "; object-src 'none'") {
|
|
t.Errorf("expected other directives untouched, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestAllowInlineScriptsLeavesPolicyWithoutInlineScripts(t *testing.T) {
|
|
policy := "script-src 'self'"
|
|
html := []byte(`<script type="module" src="/a.js"></script>`)
|
|
|
|
if got := frontend.AllowInlineScripts(policy, html); got != policy {
|
|
t.Errorf("expected policy unchanged, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSecurityHeadersHSTSOnlyWhenEnabled(t *testing.T) {
|
|
if got := serveWithSecurityHeaders(false).Get("Strict-Transport-Security"); got != "" {
|
|
t.Errorf("expected no HSTS header, got %q", got)
|
|
}
|
|
if got := serveWithSecurityHeaders(true).Get("Strict-Transport-Security"); got != "max-age=31536000" {
|
|
t.Errorf("expected HSTS max-age=31536000, got %q", got)
|
|
}
|
|
}
|