package web import ( "bytes" "io" "net/http" "net/http/httptest" "net/url" "testing" "github.com/justinas/nosurf" ) func TestSecureHeaders(t *testing.T) { rr := httptest.NewRecorder() r, err := http.NewRequest(http.MethodGet, "/", nil) if err != nil { t.Fatal(err) } next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("OK")) }) secureHeaders(next).ServeHTTP(rr, r) rs := rr.Result() expectedValue := "default-src 'self'; style-src 'self'; style-src-attr 'unsafe-inline'; script-src 'self'; img-src 'self' data: blob:; media-src 'self' blob:; manifest-src 'self'; connect-src 'self'" if got := rs.Header.Get("Content-Security-Policy"); got != expectedValue { t.Errorf("Content-Security-Policy: got %q, want %q", got, expectedValue) } expectedValue = "strict-origin-when-cross-origin" if got := rs.Header.Get("Referrer-Policy"); got != expectedValue { t.Errorf("Referrer-Policy: got %q, want %q", got, expectedValue) } expectedValue = "nosniff" if got := rs.Header.Get("X-Content-Type-Options"); got != expectedValue { t.Errorf("X-Content-Type-Options: got %q, want %q", got, expectedValue) } expectedValue = "deny" if got := rs.Header.Get("X-Frame-Options"); got != expectedValue { t.Errorf("X-Frame-Options: got %q, want %q", got, expectedValue) } if got := rs.Header.Get("Permissions-Policy"); got != "camera=(self), microphone=(self)" { t.Errorf("Permissions-Policy: got %q, want %q", got, "camera=(self), microphone=(self)") } if rs.StatusCode != http.StatusOK { t.Errorf("status: got %d, want %d", rs.StatusCode, http.StatusOK) } defer rs.Body.Close() body, err := io.ReadAll(rs.Body) if err != nil { t.Fatal(err) } body = bytes.TrimSpace(body) if got := string(body); got != "OK" { t.Errorf("body: got %q, want %q", got, "OK") } } func TestNoSurfAcceptsSameOriginHTTPFromLAN(t *testing.T) { app := &application{config: Config{CookieSecure: false}} handler := app.noSurf(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet { _, _ = w.Write([]byte(nosurf.Token(r))) return } w.WriteHeader(http.StatusNoContent) })) getRequest := httptest.NewRequest(http.MethodGet, "http://192.168.1.50:4040/login", nil) getResponse := httptest.NewRecorder() handler.ServeHTTP(getResponse, getRequest) csrfCookie := getResponse.Result().Cookies()[0] form := url.Values{"csrf_token": {getResponse.Body.String()}} postRequest := httptest.NewRequest(http.MethodPost, "http://192.168.1.50:4040/login", bytes.NewBufferString(form.Encode())) postRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded") postRequest.Header.Set("Origin", "http://192.168.1.50:4040") postRequest.AddCookie(csrfCookie) postResponse := httptest.NewRecorder() handler.ServeHTTP(postResponse, postRequest) if postResponse.Code != http.StatusNoContent { t.Fatalf("status: got %d, want %d", postResponse.Code, http.StatusNoContent) } }