feat(auth): RequireUser middleware (cookie or bearer)
Resolves /api/* callers from session cookie first, Authorization bearer second. Touches last_seen on success for future active- sessions UI. Adds GetUserByID query used by the middleware. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,8 @@ package auth
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -50,3 +52,38 @@ func TestVerifyPassword(t *testing.T) {
|
||||
t.Error("malformed hash accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequireUser_RejectsWhenNoCookieOrBearer(t *testing.T) {
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
t.Fatal("handler must not be called")
|
||||
})
|
||||
h := RequireUser(nil)(next)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/me", nil)
|
||||
w := httptest.NewRecorder()
|
||||
h.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusUnauthorized {
|
||||
t.Errorf("status = %d, want 401", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractBearerToken(t *testing.T) {
|
||||
cases := []struct {
|
||||
header string
|
||||
want string
|
||||
}{
|
||||
{"", ""},
|
||||
{"Bearer abc", "abc"},
|
||||
{"bearer abc", "abc"},
|
||||
{"Token abc", ""},
|
||||
{"Bearer", ""},
|
||||
{"Bearer whitespace-token ", "whitespace-token"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := extractBearerToken(c.header)
|
||||
if got != c.want {
|
||||
t.Errorf("extractBearerToken(%q) = %q, want %q", c.header, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user