package middleware //nolint:testpackage // tests internal CSRF behavior import ( "log/slog" "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" "sneak.berlin/go/upaas/internal/config" ) //nolint:gosec // test credentials func newCSRFTestMiddleware(plaintextHTTP bool) *Middleware { return &Middleware{ log: slog.Default(), params: &Params{ Config: &config.Config{ SessionSecret: "test-secret-32-bytes-long-enough", PlaintextHTTP: plaintextHTTP, }, }, } } // postWithPlainHTTPOrigin drives a tokenless POST carrying a plain-HTTP Origin // through the CSRF middleware and returns the "Forbidden - " body. // gorilla/csrf checks the Origin before the token, so the reason reveals which // check rejected the request. func postWithPlainHTTPOrigin(t *testing.T, plaintextHTTP bool) string { t.Helper() m := newCSRFTestMiddleware(plaintextHTTP) handler := m.CSRF()(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) })) req := httptest.NewRequestWithContext( t.Context(), http.MethodPost, "http://example.com/setup", nil) req.Header.Set("Origin", "http://example.com") rec := httptest.NewRecorder() handler.ServeHTTP(rec, req) assert.Equal(t, http.StatusForbidden, rec.Code) return rec.Body.String() } // Without PlaintextHTTP the origin check assumes https and rejects a browser's // http:// Origin, which is what broke setup over plain HTTP. func TestCSRF_PlaintextDisabled_RejectsPlainHTTPOrigin(t *testing.T) { t.Parallel() assert.Contains(t, postWithPlainHTTPOrigin(t, false), "origin invalid") } // With PlaintextHTTP the origin check uses http, so a matching http:// Origin // passes it and the request only fails later for the missing token. func TestCSRF_PlaintextEnabled_AllowsPlainHTTPOrigin(t *testing.T) { t.Parallel() body := postWithPlainHTTPOrigin(t, true) assert.NotContains(t, body, "origin invalid") assert.Contains(t, body, "CSRF token not found") }