All checks were successful
check / check (push) Successful in 2m3s
Replace .golangci.yml with the canonical v2-schema config (default: all minus six disabled linters, lll 88, tests included) and bump every golangci-lint pin to v2.12.2: - Dockerfile: golangci/golangci-lint:v2.12.2-alpine (hash-pinned) - script/bootstrap: GOLANGCI_LINT_VERSION 2.12.2 with new linux-amd64/arm64 release-archive sha256 pins Fix all 747 findings the stricter config surfaces, with no behavior changes: t.Parallel() throughout the test suite, static sentinel errors and errors.Is comparisons, checked error returns, context propagation (contextcheck/noctx), 88-column wrapping, extracted constants and helpers for goconst/dupl/funlen/cyclop, exhaustive switch cases replicating existing defaults, and white-box test files renamed to *_internal_test.go for testpackage. Three nolint:tagliatelle directives preserve the existing snake_case JSON wire and on-disk metadata formats.
241 lines
5.1 KiB
Go
241 lines
5.1 KiB
Go
package session_test
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"sneak.berlin/go/pixa/internal/session"
|
|
)
|
|
|
|
func TestManager_CreateAndValidate(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mgr, err := session.NewManager("test-signing-key-12345")
|
|
if err != nil {
|
|
t.Fatalf("NewManager() error = %v", err)
|
|
}
|
|
|
|
// Create a session
|
|
w := httptest.NewRecorder()
|
|
|
|
err = mgr.CreateSession(w)
|
|
if err != nil {
|
|
t.Fatalf("CreateSession() error = %v", err)
|
|
}
|
|
|
|
// Extract the cookie from response
|
|
resp := w.Result()
|
|
|
|
cookies := resp.Cookies()
|
|
if len(cookies) == 0 {
|
|
t.Fatal("CreateSession() did not set a cookie")
|
|
}
|
|
|
|
var sessionCookie *http.Cookie
|
|
|
|
for _, c := range cookies {
|
|
if c.Name == session.CookieName {
|
|
sessionCookie = c
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
if sessionCookie == nil {
|
|
t.Fatalf("CreateSession() did not set cookie named %q", session.CookieName)
|
|
}
|
|
|
|
// Validate the session
|
|
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
|
|
req.AddCookie(sessionCookie)
|
|
|
|
data, err := mgr.ValidateSession(req)
|
|
if err != nil {
|
|
t.Fatalf("ValidateSession() error = %v", err)
|
|
}
|
|
|
|
if !data.Authenticated {
|
|
t.Error("ValidateSession() returned unauthenticated session")
|
|
}
|
|
|
|
if data.ExpiresAt.Before(time.Now()) {
|
|
t.Error("ValidateSession() returned already-expired session")
|
|
}
|
|
}
|
|
|
|
func TestManager_ValidateSession_NoCookie(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mgr, _ := session.NewManager("test-signing-key-12345")
|
|
|
|
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
|
|
|
|
_, err := mgr.ValidateSession(req)
|
|
if err == nil {
|
|
t.Error("ValidateSession() should fail with no cookie")
|
|
}
|
|
|
|
if !errors.Is(err, session.ErrNoSession) {
|
|
t.Errorf("ValidateSession() error = %v, want %v", err, session.ErrNoSession)
|
|
}
|
|
}
|
|
|
|
func TestManager_ValidateSession_TamperedCookie(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mgr, _ := session.NewManager("test-signing-key-12345")
|
|
|
|
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
|
|
req.AddCookie(&http.Cookie{
|
|
Name: session.CookieName,
|
|
Value: "tampered-invalid-cookie-value",
|
|
Secure: true,
|
|
HttpOnly: true,
|
|
SameSite: http.SameSiteStrictMode,
|
|
})
|
|
|
|
_, err := mgr.ValidateSession(req)
|
|
if err == nil {
|
|
t.Error("ValidateSession() should fail with tampered cookie")
|
|
}
|
|
|
|
if !errors.Is(err, session.ErrInvalidSession) {
|
|
t.Errorf("ValidateSession() error = %v, want %v", err, session.ErrInvalidSession)
|
|
}
|
|
}
|
|
|
|
func TestManager_ValidateSession_WrongKey(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mgr1, _ := session.NewManager("signing-key-1")
|
|
mgr2, _ := session.NewManager("signing-key-2")
|
|
|
|
// Create session with mgr1
|
|
w := httptest.NewRecorder()
|
|
_ = mgr1.CreateSession(w)
|
|
|
|
resp := w.Result()
|
|
|
|
var sessionCookie *http.Cookie
|
|
|
|
for _, c := range resp.Cookies() {
|
|
if c.Name == session.CookieName {
|
|
sessionCookie = c
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
// Try to validate with mgr2 (different key)
|
|
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
|
|
req.AddCookie(sessionCookie)
|
|
|
|
_, err := mgr2.ValidateSession(req)
|
|
if err == nil {
|
|
t.Error("ValidateSession() should fail with different signing key")
|
|
}
|
|
}
|
|
|
|
func TestManager_ClearSession(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mgr, _ := session.NewManager("test-signing-key-12345")
|
|
|
|
w := httptest.NewRecorder()
|
|
mgr.ClearSession(w)
|
|
|
|
resp := w.Result()
|
|
cookies := resp.Cookies()
|
|
|
|
var sessionCookie *http.Cookie
|
|
|
|
for _, c := range cookies {
|
|
if c.Name == session.CookieName {
|
|
sessionCookie = c
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
if sessionCookie == nil {
|
|
t.Fatal("ClearSession() did not set a cookie")
|
|
}
|
|
|
|
if sessionCookie.MaxAge != -1 {
|
|
t.Errorf("ClearSession() cookie MaxAge = %d, want -1", sessionCookie.MaxAge)
|
|
}
|
|
}
|
|
|
|
func TestManager_IsAuthenticated(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mgr, _ := session.NewManager("test-signing-key-12345")
|
|
|
|
// No session - should return false
|
|
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
|
|
if mgr.IsAuthenticated(req) {
|
|
t.Error("IsAuthenticated() should return false with no session")
|
|
}
|
|
|
|
// Create session
|
|
w := httptest.NewRecorder()
|
|
_ = mgr.CreateSession(w)
|
|
|
|
resp := w.Result()
|
|
|
|
var sessionCookie *http.Cookie
|
|
|
|
for _, c := range resp.Cookies() {
|
|
if c.Name == session.CookieName {
|
|
sessionCookie = c
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
// With valid session - should return true
|
|
req = httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
|
|
req.AddCookie(sessionCookie)
|
|
|
|
if !mgr.IsAuthenticated(req) {
|
|
t.Error("IsAuthenticated() should return true with valid session")
|
|
}
|
|
}
|
|
|
|
func TestManager_CookieAttributes(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mgr, _ := session.NewManager("test-key")
|
|
|
|
w := httptest.NewRecorder()
|
|
_ = mgr.CreateSession(w)
|
|
|
|
resp := w.Result()
|
|
|
|
var sessionCookie *http.Cookie
|
|
|
|
for _, c := range resp.Cookies() {
|
|
if c.Name == session.CookieName {
|
|
sessionCookie = c
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
if !sessionCookie.HttpOnly {
|
|
t.Error("Cookie should have HttpOnly flag")
|
|
}
|
|
|
|
if !sessionCookie.Secure {
|
|
t.Error("Cookie should have Secure flag when manager created with secure=true")
|
|
}
|
|
|
|
if sessionCookie.SameSite != http.SameSiteStrictMode {
|
|
t.Errorf("Cookie SameSite = %v, want %v",
|
|
sessionCookie.SameSite, http.SameSiteStrictMode)
|
|
}
|
|
}
|