github.com/google/go-safeweb@v0.0.0-20231219055052-64d8cfc90fbb/tests/integration/csp/csp_test.go (about) 1 // Copyright 2020 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package csp_test 16 17 import ( 18 "net/http/httptest" 19 "testing" 20 21 "github.com/google/go-cmp/cmp" 22 "github.com/google/go-safeweb/safehttp" 23 "github.com/google/go-safeweb/safehttp/plugins/csp" 24 "github.com/google/safehtml/template" 25 ) 26 27 func TestServeMuxInstallCSP(t *testing.T) { 28 mb := safehttp.NewServeMuxConfig(nil) 29 for _, i := range csp.Default("") { 30 mb.Intercept(i) 31 } 32 33 var nonce string 34 var err error 35 handler := safehttp.HandlerFunc(func(w safehttp.ResponseWriter, r *safehttp.IncomingRequest) safehttp.Result { 36 fns := map[string]interface{}{ 37 "CSPNonce": func() string { return "WrongNonce" }, 38 } 39 // These are not used in the handler, just recorded to test whether the 40 // handler can retrieve the CSP nonce (e.g. for when the CSP plugin is 41 // installed, but auto-injection isn't yet supported and has to be done 42 // manually by the handler). 43 nonce, err = csp.Nonce(r.Context()) 44 t := template.Must(template.New("name").Funcs(fns).Parse(`<script nonce="{{CSPNonce}}" type="application/javascript">alert("script")</script><h1>{{.}}</h1>`)) 45 46 return safehttp.ExecuteTemplateWithFuncs(w, t, "Content", fns) 47 }) 48 mux := mb.Mux() 49 mux.Handle("/bar", safehttp.MethodGet, handler) 50 51 rr := httptest.NewRecorder() 52 53 req := httptest.NewRequest(safehttp.MethodGet, "https://foo.com/bar", nil) 54 55 mux.ServeHTTP(rr, req) 56 57 if err != nil { 58 t.Fatalf("csp.Nonce: got error %v", err) 59 } 60 61 if nonce == "" { 62 t.Fatalf("csp.Nonce: got %q, want non-empty", nonce) 63 } 64 65 if got, want := rr.Code, safehttp.StatusOK; got != int(want) { 66 t.Errorf("rr.Code got: %v want: %v", got, want) 67 } 68 69 wantHeaders := map[string][]string{ 70 "Content-Type": {"text/html; charset=utf-8"}, 71 "Content-Security-Policy": { 72 "object-src 'none'; script-src 'unsafe-inline' 'nonce-" + nonce + "' 'strict-dynamic' https: http:; base-uri 'none'", 73 "require-trusted-types-for 'script'"}, 74 } 75 if diff := cmp.Diff(wantHeaders, map[string][]string(rr.Header())); diff != "" { 76 t.Errorf("rr.Header(): mismatch (-want +got):\n%s", diff) 77 } 78 79 wantBody := `<script nonce="` + nonce + 80 `" type="application/javascript">alert("script")</script><h1>Content</h1>` 81 if gotBody := rr.Body.String(); gotBody != wantBody { 82 t.Errorf("response body: got %q, want nonce %q", gotBody, wantBody) 83 } 84 85 }