feat(backend): update main entry and test DB utilities
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
+28
-5
@@ -127,12 +127,13 @@ func main() {
|
|||||||
initDav()
|
initDav()
|
||||||
initS3()
|
initS3()
|
||||||
initSquare()
|
initSquare()
|
||||||
|
auth.StartJTICleanup()
|
||||||
|
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
|
|
||||||
// --- Global Middleware ---
|
// --- Global Middleware ---
|
||||||
r.Use(middleware.RequestID)
|
r.Use(middleware.RequestID)
|
||||||
r.Use(middleware.RealIP)
|
r.Use(middleware.ClientIPFromHeader("X-Real-IP"))
|
||||||
r.Use(middleware.Logger)
|
r.Use(middleware.Logger)
|
||||||
r.Use(middleware.Recoverer)
|
r.Use(middleware.Recoverer)
|
||||||
r.Use(middleware.Timeout(15 * time.Second))
|
r.Use(middleware.Timeout(15 * time.Second))
|
||||||
@@ -145,6 +146,23 @@ func main() {
|
|||||||
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
|
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
|
||||||
// TODO: Enable Referrer-Policy in production
|
// TODO: Enable Referrer-Policy in production
|
||||||
w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
|
w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
|
||||||
|
w.Header().Set("Content-Security-Policy", "default-src 'none'; frame-ancestors 'none'")
|
||||||
|
|
||||||
|
// Reflect origin (not wildcard '*') so credentialed cross-origin
|
||||||
|
// requests with Authorization: Bearer work in browsers.
|
||||||
|
origin := r.Header.Get("Origin")
|
||||||
|
if origin != "" {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", origin)
|
||||||
|
w.Header().Set("Vary", "Origin")
|
||||||
|
}
|
||||||
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type, Idempotency-Key")
|
||||||
|
|
||||||
|
if r.Method == http.MethodOptions {
|
||||||
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -159,11 +177,11 @@ func main() {
|
|||||||
r.Get("/services/eligible-for/{user_id}", services.ServicesEligibleForUserHandler)
|
r.Get("/services/eligible-for/{user_id}", services.ServicesEligibleForUserHandler)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Registration: 10/min to prevent spam
|
// Registration: 10/min to prevent spam + progressive per-IP backoff
|
||||||
r.With(mw.RateLimit(10, time.Minute), limitBody(defaultBodyLimit)).Post("/register", authHandlers.RegisterHandler)
|
r.With(mw.ProgressiveRateLimit, mw.RateLimit(10, time.Minute), limitBody(defaultBodyLimit)).Post("/register", authHandlers.RegisterHandler)
|
||||||
|
|
||||||
// Login: Has its own internal rate limiting
|
// Login: Has its own internal rate limiting + progressive per-IP backoff
|
||||||
r.With(mw.RateLimit(10, time.Minute), limitBody(defaultBodyLimit)).Post("/login", authHandlers.LoginHandler)
|
r.With(mw.ProgressiveRateLimit, mw.RateLimit(10, time.Minute), limitBody(defaultBodyLimit)).Post("/login", authHandlers.LoginHandler)
|
||||||
|
|
||||||
// Logout: requires valid token
|
// Logout: requires valid token
|
||||||
r.With(mw.RequireAuth).Post("/logout", authHandlers.LogoutHandler)
|
r.With(mw.RequireAuth).Post("/logout", authHandlers.LogoutHandler)
|
||||||
@@ -257,11 +275,16 @@ func main() {
|
|||||||
|
|
||||||
// User payment routes
|
// User payment routes
|
||||||
r.Post("/bookings/{id}/payment", payments.CreateBookingPayment)
|
r.Post("/bookings/{id}/payment", payments.CreateBookingPayment)
|
||||||
|
r.Post("/bookings/{id}/apply-redemption", payments.ApplyLoyaltyRedemption)
|
||||||
|
r.Post("/bookings/{id}/payment-lock", payments.AcquirePaymentLock)
|
||||||
|
r.Delete("/bookings/{id}/payment-lock", payments.ReleasePaymentLock)
|
||||||
r.Get("/user/payment-methods", payments.GetUserPaymentMethods)
|
r.Get("/user/payment-methods", payments.GetUserPaymentMethods)
|
||||||
r.Post("/user/payment-methods", payments.CreatePaymentMethod)
|
r.Post("/user/payment-methods", payments.CreatePaymentMethod)
|
||||||
r.Delete("/user/payment-methods/{id}", payments.DeletePaymentMethod)
|
r.Delete("/user/payment-methods/{id}", payments.DeletePaymentMethod)
|
||||||
r.Post("/bookings/{id}/tip", payments.CreateTipPayment)
|
r.Post("/bookings/{id}/tip", payments.CreateTipPayment)
|
||||||
r.Get("/bookings/{id}/payment-summary", payments.GetBookingPaymentSummary)
|
r.Get("/bookings/{id}/payment-summary", payments.GetBookingPaymentSummary)
|
||||||
|
r.With(mw.RateLimit(10, time.Minute), limitBody(defaultBodyLimit)).
|
||||||
|
Get("/bookings/{id}/discount-preview", payments.GetDiscountPreviewHandler)
|
||||||
|
|
||||||
// User gift card routes
|
// User gift card routes
|
||||||
r.Post("/user/giftcards/redeem", payments.RedeemGiftCard)
|
r.Post("/user/giftcards/redeem", payments.RedeemGiftCard)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
"github.com/jackc/pgx/v5/pgxpool"
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultTestDSN = "postgres://myuser:mypassword@localhost:5432/crussell_test?sslmode=disable"
|
const defaultTestDSN = "postgres://myuser:mypassword@localhost:5432/crussell_test?sslmode=disable&require_auth=scram-sha-256"
|
||||||
|
|
||||||
func Pool(t *testing.T) *pgxpool.Pool {
|
func Pool(t *testing.T) *pgxpool.Pool {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
@@ -140,6 +140,9 @@ func Migrate(t *testing.T, pool *pgxpool.Pool) {
|
|||||||
"exceptional_working_hours",
|
"exceptional_working_hours",
|
||||||
"exceptional_working_hours_groups",
|
"exceptional_working_hours_groups",
|
||||||
"business_settings",
|
"business_settings",
|
||||||
|
"login_audit",
|
||||||
|
"refresh_tokens",
|
||||||
|
"revoked_jtis",
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, table := range dropOrder {
|
for _, table := range dropOrder {
|
||||||
@@ -312,6 +315,9 @@ func TruncateTables(t *testing.T, pool *pgxpool.Pool) {
|
|||||||
"users",
|
"users",
|
||||||
"images",
|
"images",
|
||||||
"tags",
|
"tags",
|
||||||
|
"login_audit",
|
||||||
|
"refresh_tokens",
|
||||||
|
"revoked_jtis",
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, table := range tables {
|
for _, table := range tables {
|
||||||
|
|||||||
Reference in New Issue
Block a user