eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1package main
2
3import (
4 "io"
5 "net/http"
6 "regexp"
7 "strings"
8 "testing"
9)
10
11var cspNonceRE = regexp.MustCompile(`'nonce-([A-Za-z0-9+/=]+)'`)
12
13func TestSecurityHeaders(t *testing.T) {
14 ts, _ := newTestServer(t)
15
16 // Static headers apply to every response, including non-page routes.
17 resp, err := http.Get(ts.URL + "/api/version")
18 if err != nil {
19 t.Fatal(err)
20 }
21 resp.Body.Close()
22 for k, want := range map[string]string{
23 "X-Content-Type-Options": "nosniff",
24 "X-Frame-Options": "DENY",
25 "Referrer-Policy": "no-referrer",
26 } {
27 if got := resp.Header.Get(k); got != want {
28 t.Errorf("%s = %q, want %q", k, got, want)
29 }
30 }
31
32 // The chat page carries a nonce CSP.
33 resp, err = http.Get(ts.URL + "/")
34 if err != nil {
35 t.Fatal(err)
36 }
37 body, _ := io.ReadAll(resp.Body)
38 resp.Body.Close()
39
40 csp := resp.Header.Get("Content-Security-Policy")
41 for _, want := range []string{
42 "default-src 'self'", "script-src 'self' 'nonce-",
43 "object-src 'none'", "base-uri 'none'", "frame-ancestors 'none'",
44 } {
45 if !strings.Contains(csp, want) {
46 t.Errorf("CSP missing %q; got %q", want, csp)
47 }
48 }
49
50 // The CSP nonce must match the one substituted into the page's inline scripts,
51 // and no literal placeholder may remain.
52 m := cspNonceRE.FindStringSubmatch(csp)
53 if m == nil {
54 t.Fatalf("no nonce in CSP: %q", csp)
55 }
56 nonce := m[1]
57 if !strings.Contains(string(body), `<script nonce="`+nonce+`">`) {
58 t.Errorf("inline <script> nonce doesn't match CSP nonce %q", nonce)
59 }
60 if strings.Contains(string(body), "__CSP_NONCE__") {
61 t.Errorf("literal __CSP_NONCE__ placeholder left unsubstituted")
62 }
63
64 // Nonces are fresh per request.
65 resp2, _ := http.Get(ts.URL + "/")
66 csp2 := resp2.Header.Get("Content-Security-Policy")
67 resp2.Body.Close()
68 if m2 := cspNonceRE.FindStringSubmatch(csp2); m2 != nil && m2[1] == nonce {
69 t.Errorf("nonce reused across requests: %q", nonce)
70 }
71}
72