97 lines
2.9 KiB
Go
97 lines
2.9 KiB
Go
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)
|
|
}
|
|
}
|