839febb83a
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
96 lines
3.0 KiB
Go
96 lines
3.0 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/vasyansk/imap-copier/internal/config"
|
|
"github.com/vasyansk/imap-copier/internal/crypto"
|
|
)
|
|
|
|
func testServer() *Server {
|
|
return &Server{cfg: config.Config{
|
|
AuthUser: "admin", AuthPass: "pw", SessionSecret: []byte("sekret"),
|
|
}}
|
|
}
|
|
|
|
func TestLoginSetsCookie(t *testing.T) {
|
|
s := testServer()
|
|
req := httptest.NewRequest("POST", "/api/login", strings.NewReader(`{"user":"admin","pass":"pw"}`))
|
|
rw := httptest.NewRecorder()
|
|
s.handleLogin(rw, req)
|
|
if rw.Code != http.StatusOK {
|
|
t.Fatalf("code=%d", rw.Code)
|
|
}
|
|
if len(rw.Result().Cookies()) == 0 {
|
|
t.Fatal("no session cookie set")
|
|
}
|
|
}
|
|
|
|
func TestRequireAuthBlocksNoCookie(t *testing.T) {
|
|
s := testServer()
|
|
h := s.requireAuth(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) }))
|
|
rw := httptest.NewRecorder()
|
|
h.ServeHTTP(rw, httptest.NewRequest("GET", "/api/tasks", nil))
|
|
if rw.Code != http.StatusUnauthorized {
|
|
t.Fatalf("want 401, got %d", rw.Code)
|
|
}
|
|
}
|
|
|
|
func TestRequireAuthAllowsValidCookie(t *testing.T) {
|
|
s := testServer()
|
|
// логинимся, забираем cookie, повторяем запрос
|
|
lr := httptest.NewRequest("POST", "/api/login", strings.NewReader(`{"user":"admin","pass":"pw"}`))
|
|
lrw := httptest.NewRecorder()
|
|
s.handleLogin(lrw, lr)
|
|
cookie := lrw.Result().Cookies()[0]
|
|
|
|
h := s.requireAuth(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) }))
|
|
req := httptest.NewRequest("GET", "/api/tasks", nil)
|
|
req.AddCookie(cookie)
|
|
rw := httptest.NewRecorder()
|
|
h.ServeHTTP(rw, req)
|
|
if rw.Code != 200 {
|
|
t.Fatalf("want 200, got %d", rw.Code)
|
|
}
|
|
}
|
|
|
|
func TestLoginRejectsBadCredentials(t *testing.T) {
|
|
s := testServer()
|
|
req := httptest.NewRequest("POST", "/api/login", strings.NewReader(`{"user":"admin","pass":"wrong"}`))
|
|
rw := httptest.NewRecorder()
|
|
s.handleLogin(rw, req)
|
|
if rw.Code != http.StatusUnauthorized {
|
|
t.Fatalf("want 401, got %d", rw.Code)
|
|
}
|
|
}
|
|
|
|
func TestRequireAuthRejectsTamperedCookie(t *testing.T) {
|
|
s := testServer()
|
|
h := s.requireAuth(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) }))
|
|
req := httptest.NewRequest("GET", "/api/tasks", nil)
|
|
req.AddCookie(&http.Cookie{Name: cookieName, Value: "not.a.validtoken"})
|
|
rw := httptest.NewRecorder()
|
|
h.ServeHTTP(rw, req)
|
|
if rw.Code != http.StatusUnauthorized {
|
|
t.Fatalf("want 401, got %d", rw.Code)
|
|
}
|
|
}
|
|
|
|
func TestRequireAuthRejectsTokenForDifferentUser(t *testing.T) {
|
|
s := testServer()
|
|
// token signed for a user that is NOT s.cfg.AuthUser ("admin")
|
|
tok := crypto.SignSession(s.cfg.SessionSecret, "olduser", time.Now().Add(time.Hour))
|
|
h := s.requireAuth(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) }))
|
|
req := httptest.NewRequest("GET", "/api/tasks", nil)
|
|
req.AddCookie(&http.Cookie{Name: cookieName, Value: tok})
|
|
rw := httptest.NewRecorder()
|
|
h.ServeHTTP(rw, req)
|
|
if rw.Code != http.StatusUnauthorized {
|
|
t.Fatalf("stale-user token must be rejected, got %d", rw.Code)
|
|
}
|
|
}
|