adds a /pay/{token} redirect endpoint that generates a short URL
pointing to a stripe checkout sessions in setup mode. The TUI shows a QR
code and URL on the payment page so users can add a card via the browser
instead of entering raw card data over SSH.
the checkout.session.completed webhook saves the card to the database.
the TUI polls GET /api/v1/cards every second and auto-proceeds to
confirmation once the new card is detected.
also adds a dev.sh startup script that runs all four required processes.
(SSH server, API server, Stripe CLI listener, ngrok) in a single
terminal
39 lines
1.2 KiB
Go
39 lines
1.2 KiB
Go
package middleware
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/go-chi/httprate"
|
|
"terminalShop/pkg/utils"
|
|
)
|
|
|
|
// RateLimitByIP returns a per-IP rate limiter for public endpoints.
|
|
func RateLimitByIP(limit int, window time.Duration) func(http.Handler) http.Handler {
|
|
return httprate.Limit(
|
|
limit, window,
|
|
httprate.WithKeyFuncs(httprate.KeyByIP),
|
|
httprate.WithLimitHandler(func(w http.ResponseWriter, r *http.Request) {
|
|
utils.RespondError(w, http.StatusTooManyRequests, "RATE_LIMITED", "too many requests", nil)
|
|
}),
|
|
)
|
|
}
|
|
|
|
// RateLimitByUser returns a per-authenticated-user rate limiter for protected endpoints.
|
|
func RateLimitByUser(limit int, window time.Duration) func(http.Handler) http.Handler {
|
|
return httprate.Limit(
|
|
limit, window,
|
|
httprate.WithKeyFuncs(func(r *http.Request) (string, error) {
|
|
userID := UserIDFromContext(r.Context())
|
|
if userID == 0 {
|
|
// Fall back to IP if no user context (shouldn't happen on protected routes).
|
|
return httprate.KeyByIP(r)
|
|
}
|
|
return http.CanonicalHeaderKey("user") + ":" + string(rune(userID)), nil
|
|
}),
|
|
httprate.WithLimitHandler(func(w http.ResponseWriter, r *http.Request) {
|
|
utils.RespondError(w, http.StatusTooManyRequests, "RATE_LIMITED", "too many requests", nil)
|
|
}),
|
|
)
|
|
}
|