fix(payment): fully URL-decode EasyPay callback params before signature verification

Upstream proxy double-encodes GET query params. url.ParseQuery only
decodes once, leaving values like %E5%BF%AB instead of actual UTF-8.
Add fullyDecodeURL to repeatedly decode until stable before signing.
This commit is contained in:
erio
2026-04-07 16:39:34 +08:00
parent e2e5c814bc
commit f9e581bb82
3 changed files with 16 additions and 5 deletions
+1 -1
View File
@@ -1 +1 @@
0.1.108.80
0.1.108.81
@@ -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 {
+13 -1
View File
@@ -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
}
}