oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1package docs
2
3import (
4 "net/http"
5 "net/http/httptest"
6 "strings"
7 "testing"
8
9 "amadan.net/rastrillo/rastrillo"
10)
11
12func TestHomeFormPolicyPreservesFrameworkAndStandalone(t *testing.T) {
13 // Served the way cmd/docs serves it: rastrillo's handler with Docs'
14 // own policy (ContentSecurityPolicy) in place of the default.
15 mux := http.NewServeMux()
16 mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) })
17 baselineHandler, cleanup, err := rastrillo.Handler(rastrillo.Options{Mux: mux, CSP: ContentSecurityPolicy})
18 if err != nil {
19 t.Fatal(err)
20 }
21 if cleanup != nil {
22 defer cleanup()
23 }
24 rec := httptest.NewRecorder()
25 baselineHandler.ServeHTTP(rec, httptest.NewRequest("GET", bridgeOrigin+"/", nil))
26 baseline := rec.Header().Get("Content-Security-Policy")
27 if baseline != ContentSecurityPolicy {
28 t.Fatalf("rastrillo did not serve Options.CSP as given: %q", baseline)
29 }
30 // Docs' policy departs from the framework's only in style-src. Any
31 // other directive rastrillo tightens later must reach Docs too, so
32 // compare against the real default, not Docs' own constant.
33 plain, plainDone, err := rastrillo.Handler(rastrillo.Options{Mux: mux})
34 if err != nil {
35 t.Fatal(err)
36 }
37 if plainDone != nil {
38 defer plainDone()
39 }
40 rec = httptest.NewRecorder()
41 plain.ServeHTTP(rec, httptest.NewRequest("GET", bridgeOrigin+"/", nil))
42 if a, b := withoutStyleSrc(rec.Header().Get("Content-Security-Policy")), withoutStyleSrc(ContentSecurityPolicy); a != b {
43 t.Fatalf("ContentSecurityPolicy differs from rastrillo's default outside style-src:\n framework %q\n docs %q", a, b)
44 }
45 want := strings.Replace(baseline, "form-action 'self'", "form-action 'self' "+bridgeIssuer, 1)
46 if want == baseline {
47 t.Fatal("form-action changed; review policy")
48 }
49 f := newRouterHomeFixture(t)
50 wrapped, done, err := rastrillo.Handler(rastrillo.Options{Mux: f.app.Handler(), CSP: ContentSecurityPolicy})
51 if err != nil {
52 t.Fatal(err)
53 }
54 if done != nil {
55 defer done()
56 }
57 for _, path := range []string{"/signin/local", "/account/home", "/auth/start", "/signed-out"} {
58 w := httptest.NewRecorder()
59 wrapped.ServeHTTP(w, httptest.NewRequest("GET", bridgeOrigin+path, nil))
60 if got := w.Header().Get("Content-Security-Policy"); got != want {
61 t.Fatalf("policy drift at %s: %q", path, got)
62 }
63 }
64 app, err := NewForTestWith(t, Config{Origin: bridgeOrigin, SampleDocuments: "0"})
65 if err != nil {
66 t.Fatal(err)
67 }
68 standalone, closeStandalone, err := rastrillo.Handler(rastrillo.Options{Mux: app.Handler(), CSP: ContentSecurityPolicy})
69 if err != nil {
70 t.Fatal(err)
71 }
72 if closeStandalone != nil {
73 defer closeStandalone()
74 }
75 w := httptest.NewRecorder()
76 standalone.ServeHTTP(w, httptest.NewRequest("GET", bridgeOrigin+"/signin", nil))
77 if got := w.Header().Get("Content-Security-Policy"); got != baseline {
78 t.Fatal("standalone policy changed")
79 }
80}
81
82// withoutStyleSrc is policy with its style-src directive removed.
83func withoutStyleSrc(policy string) string {
84 var kept []string
85 for _, d := range strings.Split(policy, ";") {
86 if d = strings.TrimSpace(d); d != "" && !strings.HasPrefix(d, "style-src") {
87 kept = append(kept, d)
88 }
89 }
90 return strings.Join(kept, "; ")
91}
92