fix(payments,portfolio,scheduling): add ID validation hardening
Add validators.IsValidID() checks on URL param IDs to return 404 instead of 400 for invalid IDs. Add offset cap and query length limit in portfolio images handler. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -2,6 +2,7 @@ package payments
|
||||
|
||||
import (
|
||||
"crussell/internal/square"
|
||||
"crussell/internal/validators"
|
||||
"crussell/mw"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -87,8 +88,8 @@ type PaymentSummaryResponse struct {
|
||||
|
||||
func CreateTerminalPayment(w http.ResponseWriter, r *http.Request) {
|
||||
bookingID := chi.URLParam(r, "id")
|
||||
if bookingID == "" {
|
||||
http.Error(w, "Booking ID is required", http.StatusBadRequest)
|
||||
if bookingID == "" || !validators.IsValidID(bookingID) {
|
||||
http.Error(w, "Booking not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -260,8 +261,8 @@ func GetCheckoutStatus(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func CreateBookingPayment(w http.ResponseWriter, r *http.Request) {
|
||||
bookingID := chi.URLParam(r, "id")
|
||||
if bookingID == "" {
|
||||
http.Error(w, "Booking ID is required", http.StatusBadRequest)
|
||||
if bookingID == "" || !validators.IsValidID(bookingID) {
|
||||
http.Error(w, "Booking not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -459,8 +460,8 @@ func GetUserPaymentMethods(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func DeletePaymentMethod(w http.ResponseWriter, r *http.Request) {
|
||||
cardID := chi.URLParam(r, "id")
|
||||
if cardID == "" {
|
||||
http.Error(w, "Card ID is required", http.StatusBadRequest)
|
||||
if cardID == "" || !validators.IsValidID(cardID) {
|
||||
http.Error(w, "Payment method not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -524,8 +525,8 @@ func CreatePaymentMethod(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func RefundPayment(w http.ResponseWriter, r *http.Request) {
|
||||
paymentID := chi.URLParam(r, "payment_id")
|
||||
if paymentID == "" {
|
||||
http.Error(w, "Payment ID is required", http.StatusBadRequest)
|
||||
if paymentID == "" || !validators.IsValidID(paymentID) {
|
||||
http.Error(w, "Payment not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -640,8 +641,8 @@ func RefundPayment(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func CreateTipPayment(w http.ResponseWriter, r *http.Request) {
|
||||
bookingID := chi.URLParam(r, "id")
|
||||
if bookingID == "" {
|
||||
http.Error(w, "Booking ID is required", http.StatusBadRequest)
|
||||
if bookingID == "" || !validators.IsValidID(bookingID) {
|
||||
http.Error(w, "Booking not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -753,8 +754,8 @@ func CreateTipPayment(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func GetBookingPaymentSummary(w http.ResponseWriter, r *http.Request) {
|
||||
bookingID := chi.URLParam(r, "id")
|
||||
if bookingID == "" {
|
||||
http.Error(w, "Booking ID is required", http.StatusBadRequest)
|
||||
if bookingID == "" || !validators.IsValidID(bookingID) {
|
||||
http.Error(w, "Booking not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"crussell/db"
|
||||
"crussell/internal/images"
|
||||
"crussell/internal/s3"
|
||||
"crussell/internal/validators"
|
||||
"crussell/mw"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -114,7 +115,7 @@ func ListImages(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
if o := r.URL.Query().Get("offset"); o != "" {
|
||||
if parsed, err := strconv.Atoi(o); err == nil && parsed >= 0 {
|
||||
if parsed, err := strconv.Atoi(o); err == nil && parsed >= 0 && parsed <= 10000 {
|
||||
offset = parsed
|
||||
}
|
||||
}
|
||||
@@ -264,6 +265,9 @@ func ListImages(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func ListTags(w http.ResponseWriter, r *http.Request) {
|
||||
q := r.URL.Query().Get("q")
|
||||
if len(q) > 100 {
|
||||
q = q[:100]
|
||||
}
|
||||
|
||||
var query string
|
||||
var args []interface{}
|
||||
@@ -694,6 +698,10 @@ func DeleteImage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
imageID := chi.URLParam(r, "id")
|
||||
if imageID == "" || !validators.IsValidID(imageID) {
|
||||
http.Error(w, "Image not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
var url, thumbURL string
|
||||
err := db.DB.QueryRow(r.Context(), `
|
||||
|
||||
@@ -169,8 +169,8 @@ func CreateTimeBlocker(w http.ResponseWriter, r *http.Request) {
|
||||
// DELETE /api/admin/time-blockers/{id}
|
||||
func DeleteTimeBlocker(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
if id == "" {
|
||||
http.Error(w, "missing id parameter", http.StatusBadRequest)
|
||||
if id == "" || !validators.IsValidID(id) {
|
||||
http.Error(w, "time blocker not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user