mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-10-28 15:51:15 +00:00
- Finish Paddle-to-Stripe billing migration; drop paddle/stripe libs - Renumber migrations; add 00012 memberships+manage_token, 00013 location_type_capacity - Add tests: admin, auth, bookings customer service - Remove graphify-out artifacts and stale env files Authored By: TDvorak <[email protected]> Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
118 lines
3.5 KiB
Go
118 lines
3.5 KiB
Go
package admin
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"bookra/apps/backend/internal/auth"
|
|
"bookra/apps/backend/internal/db"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func newTestRouter(t *testing.T, adminSvc *Service, verifier *auth.Verifier, repo db.Repository, demoMode bool) *gin.Engine {
|
|
t.Helper()
|
|
gin.SetMode(gin.TestMode)
|
|
r := gin.New()
|
|
r.Use(RequireAdmin(adminSvc, verifier, repo, demoMode))
|
|
r.GET("/v1/admin/stats", func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"actor": ActorFromContext(c)})
|
|
})
|
|
return r
|
|
}
|
|
|
|
func request(t *testing.T, r *gin.Engine, headers map[string]string) *httptest.ResponseRecorder {
|
|
t.Helper()
|
|
req := httptest.NewRequest(http.MethodGet, "/v1/admin/stats", nil)
|
|
for k, v := range headers {
|
|
req.Header.Set(k, v)
|
|
}
|
|
w := httptest.NewRecorder()
|
|
r.ServeHTTP(w, req)
|
|
return w
|
|
}
|
|
|
|
func TestRequireAdminRejectsUnauthenticated(t *testing.T) {
|
|
repo := db.NewMemoryRepository()
|
|
svc := NewService(repo, "[email protected]", "secret-key")
|
|
verifier, _ := auth.NewVerifier("", "jwt-secret")
|
|
defer verifier.Close()
|
|
r := newTestRouter(t, svc, verifier, repo, false)
|
|
|
|
if w := request(t, r, nil); w.Code != http.StatusForbidden {
|
|
t.Fatalf("expected 403, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestRequireAdminRejectsInvalidHeaderCreds(t *testing.T) {
|
|
repo := db.NewMemoryRepository()
|
|
svc := NewService(repo, "[email protected]", "secret-key")
|
|
verifier, _ := auth.NewVerifier("", "jwt-secret")
|
|
defer verifier.Close()
|
|
r := newTestRouter(t, svc, verifier, repo, false)
|
|
|
|
w := request(t, r, map[string]string{
|
|
"X-Admin-Email": "[email protected]",
|
|
"X-Admin-Key": "wrong-key",
|
|
})
|
|
if w.Code != http.StatusUnauthorized {
|
|
t.Fatalf("expected 401, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestRequireAdminAcceptsHeaderCreds(t *testing.T) {
|
|
repo := db.NewMemoryRepository()
|
|
svc := NewService(repo, "[email protected]", "secret-key")
|
|
verifier, _ := auth.NewVerifier("", "jwt-secret")
|
|
defer verifier.Close()
|
|
r := newTestRouter(t, svc, verifier, repo, false)
|
|
|
|
w := request(t, r, map[string]string{
|
|
"X-Admin-Email": "[email protected]",
|
|
"X-Admin-Key": "secret-key",
|
|
})
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestRequireAdminVerifiesBearerTokenAndRole(t *testing.T) {
|
|
repo := db.NewMemoryRepository()
|
|
secret := "jwt-secret"
|
|
svc := NewService(repo, "[email protected]", "secret-key")
|
|
verifier, _ := auth.NewVerifier("", secret)
|
|
defer verifier.Close()
|
|
r := newTestRouter(t, svc, verifier, repo, false)
|
|
|
|
// A locally issued token for a non-admin subject must be rejected even though
|
|
// the token itself is valid.
|
|
authSvc := auth.NewService(repo, secret)
|
|
_, tokens, err := authSvc.RegisterWithPassword(t.Context(), "[email protected]", "password123", "Regular User")
|
|
if err != nil {
|
|
t.Fatalf("register: %v", err)
|
|
}
|
|
w := request(t, r, map[string]string{"Authorization": "Bearer " + tokens.AccessToken})
|
|
if w.Code != http.StatusForbidden {
|
|
t.Fatalf("expected 403 for non-admin subject, got %d", w.Code)
|
|
}
|
|
|
|
// A forged bearer string must be rejected outright.
|
|
w = request(t, r, map[string]string{"Authorization": "Bearer not-a-token"})
|
|
if w.Code != http.StatusUnauthorized {
|
|
t.Fatalf("expected 401 for invalid token, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestRequireAdminDemoMode(t *testing.T) {
|
|
repo := db.NewMemoryRepository()
|
|
svc := NewService(repo, "", "")
|
|
verifier, _ := auth.NewVerifier("", "jwt-secret")
|
|
defer verifier.Close()
|
|
r := newTestRouter(t, svc, verifier, repo, true)
|
|
|
|
if w := request(t, r, nil); w.Code != http.StatusOK {
|
|
t.Fatalf("expected 200 in demo mode, got %d", w.Code)
|
|
}
|
|
}
|