mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-10-28 08:35:33 +08:00
fix(epay): upgrade go-epay to v0.0.5
This commit is contained in:
3 files changed
+119
-3
No files matched your search
@@ -1,10 +1,19 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Calcium-Ion/go-epay/epay"
|
||||
"github.com/QuantumNous/new-api/model"
|
||||
"github.com/QuantumNous/new-api/setting"
|
||||
"github.com/QuantumNous/new-api/setting/operation_setting"
|
||||
"github.com/QuantumNous/new-api/setting/system_setting"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -167,3 +176,110 @@ func TestEpayWebhookEnabledRequiresTopUpAndWebhookConfig(t *testing.T) {
|
||||
operation_setting.PayMethods = nil
|
||||
require.False(t, isEpayWebhookEnabled())
|
||||
}
|
||||
|
||||
func TestEpayCallbacksVerifyBeforeSettlement(t *testing.T) {
|
||||
confirmPaymentComplianceForTest(t)
|
||||
originalPayAddress := operation_setting.PayAddress
|
||||
originalEpayID := operation_setting.EpayId
|
||||
originalEpayKey := operation_setting.EpayKey
|
||||
originalPayMethods := operation_setting.PayMethods
|
||||
originalServerAddress := system_setting.ServerAddress
|
||||
originalDB := model.DB
|
||||
t.Cleanup(func() {
|
||||
operation_setting.PayAddress = originalPayAddress
|
||||
operation_setting.EpayId = originalEpayID
|
||||
operation_setting.EpayKey = originalEpayKey
|
||||
operation_setting.PayMethods = originalPayMethods
|
||||
system_setting.ServerAddress = originalServerAddress
|
||||
model.DB = originalDB
|
||||
})
|
||||
operation_setting.PayAddress = "https://pay.example.com"
|
||||
operation_setting.EpayId = "epay_id"
|
||||
operation_setting.EpayKey = "test-key"
|
||||
operation_setting.PayMethods = []map[string]string{{"type": "alipay"}}
|
||||
system_setting.ServerAddress = "https://dashboard.example.com"
|
||||
// Rejected callbacks and valid non-success events must never reach settlement.
|
||||
// A nil database makes an accidental attempt to settle fail the test.
|
||||
model.DB = nil
|
||||
require.True(t, isEpayWebhookEnabled())
|
||||
|
||||
// Both ambiguous maps below had this same valid signing string in v0.0.4.
|
||||
// This must fail because of parameter ambiguity, not a mismatched signature.
|
||||
ambiguousSign := epay.MD5String("money=1.00&name=item&out_trade_no=other&out_trade_no=order&pid=epay_id&trade_status=TRADE_SUCCESS&type=alipay", "test-key")
|
||||
pendingSign := epay.MD5String("money=1.00&name=item%26other&out_trade_no=order&pid=epay_id&trade_status=WAIT_BUYER_PAY&type=alipay", "test-key")
|
||||
cases := []struct {
|
||||
name string
|
||||
productName string
|
||||
tradeNo string
|
||||
status string
|
||||
sign string
|
||||
validPending bool
|
||||
}{
|
||||
{"separator in product name", "item&out_trade_no=other", "order", epay.StatusTradeSuccess, ambiguousSign, false},
|
||||
{"separator in order number", "item", "other&out_trade_no=order", epay.StatusTradeSuccess, ambiguousSign, false},
|
||||
{"invalid signature", "item", "order", epay.StatusTradeSuccess, "invalid", false},
|
||||
{"missing signature", "item", "order", epay.StatusTradeSuccess, "", false},
|
||||
{"valid pending with literal percent escape", "item%26other", "order", "WAIT_BUYER_PAY", pendingSign, true},
|
||||
}
|
||||
endpoints := []struct {
|
||||
name string
|
||||
path string
|
||||
handler gin.HandlerFunc
|
||||
status int
|
||||
rejectedBody string
|
||||
pendingBody string
|
||||
rejectedLocation string
|
||||
pendingLocation string
|
||||
}{
|
||||
{
|
||||
name: "topup notify", path: "/api/user/epay/notify", handler: EpayNotify,
|
||||
status: http.StatusOK, rejectedBody: "fail", pendingBody: "success",
|
||||
},
|
||||
{
|
||||
name: "subscription notify", path: "/api/subscription/epay/notify", handler: SubscriptionEpayNotify,
|
||||
status: http.StatusOK, rejectedBody: "fail", pendingBody: "fail",
|
||||
},
|
||||
{
|
||||
name: "subscription return", path: "/api/subscription/epay/return", handler: SubscriptionEpayReturn,
|
||||
status: http.StatusFound,
|
||||
rejectedLocation: "https://dashboard.example.com/wallet?pay=fail",
|
||||
pendingLocation: "https://dashboard.example.com/wallet?pay=pending",
|
||||
},
|
||||
}
|
||||
router := gin.New()
|
||||
for _, endpoint := range endpoints {
|
||||
router.Any(endpoint.path, endpoint.handler)
|
||||
}
|
||||
for _, endpoint := range endpoints {
|
||||
for _, method := range []string{http.MethodGet, http.MethodPost} {
|
||||
for _, tc := range cases {
|
||||
t.Run(endpoint.name+"/"+method+"/"+tc.name, func(t *testing.T) {
|
||||
params := url.Values{
|
||||
"pid": {"epay_id"}, "type": {"alipay"}, "money": {"1.00"},
|
||||
"name": {tc.productName}, "out_trade_no": {tc.tradeNo},
|
||||
"trade_status": {tc.status}, "sign_type": {"MD5"},
|
||||
}
|
||||
if tc.sign != "" {
|
||||
params.Set("sign", tc.sign)
|
||||
}
|
||||
request := httptest.NewRequest(method, endpoint.path+"?"+params.Encode(), nil)
|
||||
if method == http.MethodPost {
|
||||
request = httptest.NewRequest(method, endpoint.path, strings.NewReader(params.Encode()))
|
||||
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
}
|
||||
recorder := httptest.NewRecorder()
|
||||
require.NotPanics(t, func() { router.ServeHTTP(recorder, request) })
|
||||
assert.Equal(t, endpoint.status, recorder.Code)
|
||||
wantBody, wantLocation := endpoint.rejectedBody, endpoint.rejectedLocation
|
||||
if tc.validPending {
|
||||
wantBody, wantLocation = endpoint.pendingBody, endpoint.pendingLocation
|
||||
}
|
||||
if wantBody != "" {
|
||||
assert.Equal(t, wantBody, recorder.Body.String())
|
||||
}
|
||||
assert.Equal(t, wantLocation, recorder.Header().Get("Location"))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ module github.com/QuantumNous/new-api
|
||||
go 1.25.1
|
||||
|
||||
require (
|
||||
github.com/Calcium-Ion/go-epay v0.0.4
|
||||
github.com/Calcium-Ion/go-epay v0.0.5
|
||||
github.com/abema/go-mp4 v1.4.1
|
||||
github.com/andybalholm/brotli v1.2.0
|
||||
github.com/anknown/ahocorasick v0.0.0-20190904063843-d75dbd5169c0
|
||||
|
||||
@@ -631,8 +631,8 @@ github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi
|
||||
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
||||
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Calcium-Ion/go-epay v0.0.4 h1:C96M7WfRLadcIVscWzwLiYs8etI1wrDmtFMuK2zP22A=
|
||||
github.com/Calcium-Ion/go-epay v0.0.4/go.mod h1:cxo/ZOg8ClvE3VAnCmEzbuyAZINSq7kFEN9oHj5WQ2U=
|
||||
github.com/Calcium-Ion/go-epay v0.0.5 h1:TgIx44c/bhdFqso4kbmDzZFzgyDJLma5hMDNA6sOXbo=
|
||||
github.com/Calcium-Ion/go-epay v0.0.5/go.mod h1:cxo/ZOg8ClvE3VAnCmEzbuyAZINSq7kFEN9oHj5WQ2U=
|
||||
github.com/Calcium-Ion/moejs v0.1.0-alpha.5 h1:hkTuLRIhtyXMPQciULZHTbdrw/LEJYvO2MDzl+/F1Y8=
|
||||
github.com/Calcium-Ion/moejs v0.1.0-alpha.5/go.mod h1:9YqHj36EV7pzV/vlEYSw49f3oggeJFdmqcjM9TmDpHs=
|
||||
github.com/ClickHouse/ch-go v0.58.2/go.mod h1:Ap/0bEmiLa14gYjCiRkYGbXvbe8vwdrfTYWhsuQ99aw=
|
||||
|
||||
Reference in new issue
Block a user