Block guest-role tokens from online payment routes (RequireNonGuest middleware)
Guests (account_role='guest') have no login flow and never receive a JWT normally, so this is defense-in-depth: any token whose role claim is 'guest' (forged/minted guest tokens or future changes) is refused 403 before the money handlers run. The check reads role from context ONLY — real guests are seeded with account_type='email', so account_type is never the discriminator. A missing role passes through (RequireAuth guarantees presence; same trust model as isVerifiedRole). Wired onto all user-facing money routes: booking payment, apply-redemption, payment-lock POST/DELETE, tip, gift-card redeem and gift-card buy. Admin and till routes (RequireAdmin) are untouched — admin can never be guest. The payment-methods routes gain RequireVerified (verified_email, admin) alongside, so only verified accounts can manage saved cards. Tests: 6 middleware tests (reject guest, allow verified/unverified/admin/ affiliate/missing-role) + 4 integration tests (guest 403 on booking payment with zero side effects, tip, gift-card buy; verified user still pays 200).
This commit is contained in:
+16
-10
@@ -385,22 +385,28 @@ func main() {
|
||||
r.Delete("/bookings/reserve", bookings.CancelReservationHandler)
|
||||
|
||||
// User payment routes
|
||||
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.Post("/user/payment-methods", payments.CreatePaymentMethod)
|
||||
r.Delete("/user/payment-methods/{id}", payments.DeletePaymentMethod)
|
||||
r.Post("/bookings/{id}/tip", payments.CreateTipPayment)
|
||||
// Product rule (security): guests (account_role='guest') must not
|
||||
// pay online — RequireNonGuest 403s any token with a guest role
|
||||
// claim before the money handlers run.
|
||||
r.With(mw.RequireNonGuest).Post("/bookings/{id}/payment", payments.CreateBookingPayment)
|
||||
r.With(mw.RequireNonGuest).Post("/bookings/{id}/apply-redemption", payments.ApplyLoyaltyRedemption)
|
||||
r.With(mw.RequireNonGuest).Post("/bookings/{id}/payment-lock", payments.AcquirePaymentLock)
|
||||
r.With(mw.RequireNonGuest).Delete("/bookings/{id}/payment-lock", payments.ReleasePaymentLock)
|
||||
// Product rule (security): cards may only be saved by verified
|
||||
// accounts — RequireAuth (group mw above) runs first and injects
|
||||
// userID/role into ctx, then RequireVerified 403s the rest.
|
||||
r.With(mw.RequireVerified).Get("/user/payment-methods", payments.GetUserPaymentMethods)
|
||||
r.With(mw.RequireVerified).Post("/user/payment-methods", payments.CreatePaymentMethod)
|
||||
r.With(mw.RequireVerified).Delete("/user/payment-methods/{id}", payments.DeletePaymentMethod)
|
||||
r.With(mw.RequireNonGuest).Post("/bookings/{id}/tip", payments.CreateTipPayment)
|
||||
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
|
||||
r.Post("/user/giftcards/redeem", payments.RedeemGiftCard)
|
||||
r.With(mw.RequireNonGuest).Post("/user/giftcards/redeem", payments.RedeemGiftCard)
|
||||
r.Get("/user/giftcards/balance", payments.GetGiftCardBalance)
|
||||
r.Post("/user/giftcards/buy", payments.BuyGiftCard)
|
||||
r.With(mw.RequireNonGuest).Post("/user/giftcards/buy", payments.BuyGiftCard)
|
||||
})
|
||||
|
||||
r.With(mw.RequireAuth, mw.RequireVerified, limitBody(uploadBodyLimit)).Post("/user/profile-picture", user.UploadProfilePictureHandler)
|
||||
|
||||
Reference in New Issue
Block a user