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 (
|
import (
|
||||||
"crussell/internal/square"
|
"crussell/internal/square"
|
||||||
|
"crussell/internal/validators"
|
||||||
"crussell/mw"
|
"crussell/mw"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -87,8 +88,8 @@ type PaymentSummaryResponse struct {
|
|||||||
|
|
||||||
func CreateTerminalPayment(w http.ResponseWriter, r *http.Request) {
|
func CreateTerminalPayment(w http.ResponseWriter, r *http.Request) {
|
||||||
bookingID := chi.URLParam(r, "id")
|
bookingID := chi.URLParam(r, "id")
|
||||||
if bookingID == "" {
|
if bookingID == "" || !validators.IsValidID(bookingID) {
|
||||||
http.Error(w, "Booking ID is required", http.StatusBadRequest)
|
http.Error(w, "Booking not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,8 +261,8 @@ func GetCheckoutStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func CreateBookingPayment(w http.ResponseWriter, r *http.Request) {
|
func CreateBookingPayment(w http.ResponseWriter, r *http.Request) {
|
||||||
bookingID := chi.URLParam(r, "id")
|
bookingID := chi.URLParam(r, "id")
|
||||||
if bookingID == "" {
|
if bookingID == "" || !validators.IsValidID(bookingID) {
|
||||||
http.Error(w, "Booking ID is required", http.StatusBadRequest)
|
http.Error(w, "Booking not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,8 +460,8 @@ func GetUserPaymentMethods(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func DeletePaymentMethod(w http.ResponseWriter, r *http.Request) {
|
func DeletePaymentMethod(w http.ResponseWriter, r *http.Request) {
|
||||||
cardID := chi.URLParam(r, "id")
|
cardID := chi.URLParam(r, "id")
|
||||||
if cardID == "" {
|
if cardID == "" || !validators.IsValidID(cardID) {
|
||||||
http.Error(w, "Card ID is required", http.StatusBadRequest)
|
http.Error(w, "Payment method not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -524,8 +525,8 @@ func CreatePaymentMethod(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func RefundPayment(w http.ResponseWriter, r *http.Request) {
|
func RefundPayment(w http.ResponseWriter, r *http.Request) {
|
||||||
paymentID := chi.URLParam(r, "payment_id")
|
paymentID := chi.URLParam(r, "payment_id")
|
||||||
if paymentID == "" {
|
if paymentID == "" || !validators.IsValidID(paymentID) {
|
||||||
http.Error(w, "Payment ID is required", http.StatusBadRequest)
|
http.Error(w, "Payment not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,8 +641,8 @@ func RefundPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func CreateTipPayment(w http.ResponseWriter, r *http.Request) {
|
func CreateTipPayment(w http.ResponseWriter, r *http.Request) {
|
||||||
bookingID := chi.URLParam(r, "id")
|
bookingID := chi.URLParam(r, "id")
|
||||||
if bookingID == "" {
|
if bookingID == "" || !validators.IsValidID(bookingID) {
|
||||||
http.Error(w, "Booking ID is required", http.StatusBadRequest)
|
http.Error(w, "Booking not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,8 +754,8 @@ func CreateTipPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func GetBookingPaymentSummary(w http.ResponseWriter, r *http.Request) {
|
func GetBookingPaymentSummary(w http.ResponseWriter, r *http.Request) {
|
||||||
bookingID := chi.URLParam(r, "id")
|
bookingID := chi.URLParam(r, "id")
|
||||||
if bookingID == "" {
|
if bookingID == "" || !validators.IsValidID(bookingID) {
|
||||||
http.Error(w, "Booking ID is required", http.StatusBadRequest)
|
http.Error(w, "Booking not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"crussell/db"
|
"crussell/db"
|
||||||
"crussell/internal/images"
|
"crussell/internal/images"
|
||||||
"crussell/internal/s3"
|
"crussell/internal/s3"
|
||||||
|
"crussell/internal/validators"
|
||||||
"crussell/mw"
|
"crussell/mw"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -114,7 +115,7 @@ func ListImages(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if o := r.URL.Query().Get("offset"); o != "" {
|
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
|
offset = parsed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,6 +265,9 @@ func ListImages(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func ListTags(w http.ResponseWriter, r *http.Request) {
|
func ListTags(w http.ResponseWriter, r *http.Request) {
|
||||||
q := r.URL.Query().Get("q")
|
q := r.URL.Query().Get("q")
|
||||||
|
if len(q) > 100 {
|
||||||
|
q = q[:100]
|
||||||
|
}
|
||||||
|
|
||||||
var query string
|
var query string
|
||||||
var args []interface{}
|
var args []interface{}
|
||||||
@@ -694,6 +698,10 @@ func DeleteImage(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
imageID := chi.URLParam(r, "id")
|
imageID := chi.URLParam(r, "id")
|
||||||
|
if imageID == "" || !validators.IsValidID(imageID) {
|
||||||
|
http.Error(w, "Image not found", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var url, thumbURL string
|
var url, thumbURL string
|
||||||
err := db.DB.QueryRow(r.Context(), `
|
err := db.DB.QueryRow(r.Context(), `
|
||||||
|
|||||||
@@ -169,8 +169,8 @@ func CreateTimeBlocker(w http.ResponseWriter, r *http.Request) {
|
|||||||
// DELETE /api/admin/time-blockers/{id}
|
// DELETE /api/admin/time-blockers/{id}
|
||||||
func DeleteTimeBlocker(w http.ResponseWriter, r *http.Request) {
|
func DeleteTimeBlocker(w http.ResponseWriter, r *http.Request) {
|
||||||
id := chi.URLParam(r, "id")
|
id := chi.URLParam(r, "id")
|
||||||
if id == "" {
|
if id == "" || !validators.IsValidID(id) {
|
||||||
http.Error(w, "missing id parameter", http.StatusBadRequest)
|
http.Error(w, "time blocker not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user