diff --git a/backend/cmd/server/VERSION b/backend/cmd/server/VERSION index 86df8ee5b0..841f70e8cd 100644 --- a/backend/cmd/server/VERSION +++ b/backend/cmd/server/VERSION @@ -1 +1 @@ -0.1.108.80 +0.1.108.81 diff --git a/backend/internal/handler/payment_webhook_handler.go b/backend/internal/handler/payment_webhook_handler.go index ae0aa7f653..78a7ba12e8 100644 --- a/backend/internal/handler/payment_webhook_handler.go +++ b/backend/internal/handler/payment_webhook_handler.go @@ -57,9 +57,8 @@ func (h *PaymentWebhookHandler) StripeWebhook(c *gin.Context) { func (h *PaymentWebhookHandler) handleNotify(c *gin.Context, providerKey string) { var rawBody string if c.Request.Method == http.MethodGet { - // GET callbacks (e.g. EasyPay): RawQuery may be double-encoded by - // upstream proxies, so rebuild from the already-decoded Query(). - rawBody = c.Request.URL.Query().Encode() + // GET callbacks (e.g. EasyPay) pass params as URL query string + rawBody = c.Request.URL.RawQuery } else { body, err := io.ReadAll(io.LimitReader(c.Request.Body, maxWebhookBodySize)) if err != nil { diff --git a/backend/internal/payment/provider/easypay.go b/backend/internal/payment/provider/easypay.go index c5712dc850..190432cba0 100644 --- a/backend/internal/payment/provider/easypay.go +++ b/backend/internal/payment/provider/easypay.go @@ -171,7 +171,7 @@ func (e *EasyPay) VerifyNotification(_ context.Context, rawBody string, _ map[st } params := make(map[string]string) for k := range values { - params[k] = values.Get(k) + params[k] = fullyDecodeURL(values.Get(k)) } sign := params["sign"] if sign == "" { @@ -268,3 +268,15 @@ func easyPaySign(params map[string]string, pkey string) string { func easyPayVerifySign(params map[string]string, pkey string, sign string) bool { return hmac.Equal([]byte(easyPaySign(params, pkey)), []byte(sign)) } + +// fullyDecodeURL repeatedly URL-decodes a string until stable. +// Handles double (or multi) encoding caused by upstream proxies. +func fullyDecodeURL(s string) string { + for { + decoded, err := url.QueryUnescape(s) + if err != nil || decoded == s { + return s + } + s = decoded + } +}