diff options
| author | Adam Mathes <adam@adammathes.com> | 2026-02-16 15:36:49 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-16 15:36:49 -0800 |
| commit | c538ccd5cd1d6960c894a2969ee49317009dc9ed (patch) | |
| tree | 1d1b1295f3d63df85fffadaa1159414c74399c6c /web/login_test.go | |
| parent | feea1a814a212efd9b14b8f05e84104ace3c473a (diff) | |
| parent | 80d132b1714aaa281a6532ff66892bfdb7d2c5c2 (diff) | |
| download | neko-c538ccd5cd1d6960c894a2969ee49317009dc9ed.tar.gz neko-c538ccd5cd1d6960c894a2969ee49317009dc9ed.tar.bz2 neko-c538ccd5cd1d6960c894a2969ee49317009dc9ed.zip | |
Merge pull request #7 from adammathes/claude/thicket-ready-crank-RmQuI
More crank pulls from claude
Diffstat (limited to 'web/login_test.go')
| -rw-r--r-- | web/login_test.go | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/web/login_test.go b/web/login_test.go index f4931b2..9d78396 100644 --- a/web/login_test.go +++ b/web/login_test.go @@ -85,3 +85,89 @@ func TestCSRFLoginWithFormToken(t *testing.T) { t.Errorf("Expected POST /other with valid CSRF header to succeed, got 403") } } + +func TestCSRFExcludedPaths(t *testing.T) { + originalPw := config.Config.DigestPassword + defer func() { config.Config.DigestPassword = originalPw }() + config.Config.DigestPassword = "secret" + + mux := http.NewServeMux() + mux.HandleFunc("/api/login", apiLoginHandler) + mux.HandleFunc("/api/logout", apiLogoutHandler) + handler := CSRFMiddleware(&config.Config, mux) + + // POST /api/login without CSRF token should succeed (excluded path) + req := httptest.NewRequest("POST", "/api/login", strings.NewReader("password=secret")) + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + if rr.Code == http.StatusForbidden { + t.Error("POST /api/login should be excluded from CSRF protection") + } + + // POST /api/logout without CSRF token should succeed (excluded path) + req = httptest.NewRequest("POST", "/api/logout", nil) + rr = httptest.NewRecorder() + handler.ServeHTTP(rr, req) + if rr.Code == http.StatusForbidden { + t.Error("POST /api/logout should be excluded from CSRF protection") + } +} + +func TestCSRFPutAndDeleteMethods(t *testing.T) { + cfg := &config.Settings{SecureCookies: false} + inner := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + handler := CSRFMiddleware(cfg, inner) + + // GET to get a token + getReq := httptest.NewRequest("GET", "/", nil) + getRR := httptest.NewRecorder() + handler.ServeHTTP(getRR, getReq) + + var csrfToken string + for _, c := range getRR.Result().Cookies() { + if c.Name == "csrf_token" { + csrfToken = c.Value + } + } + + // PUT without token should fail + req := httptest.NewRequest("PUT", "/item/1", nil) + req.AddCookie(&http.Cookie{Name: "csrf_token", Value: csrfToken}) + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + if rr.Code != http.StatusForbidden { + t.Errorf("PUT without CSRF token should return 403, got %d", rr.Code) + } + + // DELETE without token should fail + req = httptest.NewRequest("DELETE", "/feed/1", nil) + req.AddCookie(&http.Cookie{Name: "csrf_token", Value: csrfToken}) + rr = httptest.NewRecorder() + handler.ServeHTTP(rr, req) + if rr.Code != http.StatusForbidden { + t.Errorf("DELETE without CSRF token should return 403, got %d", rr.Code) + } + + // PUT with valid token should succeed + req = httptest.NewRequest("PUT", "/item/1", nil) + req.AddCookie(&http.Cookie{Name: "csrf_token", Value: csrfToken}) + req.Header.Set("X-CSRF-Token", csrfToken) + rr = httptest.NewRecorder() + handler.ServeHTTP(rr, req) + if rr.Code != http.StatusOK { + t.Errorf("PUT with valid CSRF token should succeed, got %d", rr.Code) + } + + // DELETE with valid token should succeed + req = httptest.NewRequest("DELETE", "/feed/1", nil) + req.AddCookie(&http.Cookie{Name: "csrf_token", Value: csrfToken}) + req.Header.Set("X-CSRF-Token", csrfToken) + rr = httptest.NewRecorder() + handler.ServeHTTP(rr, req) + if rr.Code != http.StatusOK { + t.Errorf("DELETE with valid CSRF token should succeed, got %d", rr.Code) + } +} |
