fix: add PaymentProvider field to prevent cross-gateway callback attacks

EPay allows users to switch payment methods (e.g. wxpay→alipay) during
checkout, causing callback rejection. Replace fragile blocklist guard
with a PaymentProvider field on TopUp and SubscriptionOrder that
identifies which gateway created the order.
This commit is contained in:
CaIon
2026-04-24 22:16:16 +08:00
parent 8993386743
commit a7c38ec851
12 changed files with 163 additions and 180 deletions
+25 -16
View File
@@ -12,15 +12,16 @@ import (
)
type TopUp struct {
Id int `json:"id"`
UserId int `json:"user_id" gorm:"index"`
Amount int64 `json:"amount"`
Money float64 `json:"money"`
TradeNo string `json:"trade_no" gorm:"unique;type:varchar(255);index"`
PaymentMethod string `json:"payment_method" gorm:"type:varchar(50)"`
CreateTime int64 `json:"create_time"`
CompleteTime int64 `json:"complete_time"`
Status string `json:"status"`
Id int `json:"id"`
UserId int `json:"user_id" gorm:"index"`
Amount int64 `json:"amount"`
Money float64 `json:"money"`
TradeNo string `json:"trade_no" gorm:"unique;type:varchar(255);index"`
PaymentMethod string `json:"payment_method" gorm:"type:varchar(50)"`
PaymentProvider string `json:"payment_provider" gorm:"type:varchar(50);default:''"`
CreateTime int64 `json:"create_time"`
CompleteTime int64 `json:"complete_time"`
Status string `json:"status"`
}
const (
@@ -30,6 +31,14 @@ const (
PaymentMethodWaffoPancake = "waffo_pancake"
)
const (
PaymentProviderEpay = "epay"
PaymentProviderStripe = "stripe"
PaymentProviderCreem = "creem"
PaymentProviderWaffo = "waffo"
PaymentProviderWaffoPancake = "waffo_pancake"
)
var (
ErrPaymentMethodMismatch = errors.New("payment method mismatch")
ErrTopUpNotFound = errors.New("topup not found")
@@ -68,7 +77,7 @@ func GetTopUpByTradeNo(tradeNo string) *TopUp {
return topUp
}
func UpdatePendingTopUpStatus(tradeNo string, expectedPaymentMethod string, targetStatus string) error {
func UpdatePendingTopUpStatus(tradeNo string, expectedPaymentProvider string, targetStatus string) error {
if tradeNo == "" {
return errors.New("未提供支付单号")
}
@@ -83,7 +92,7 @@ func UpdatePendingTopUpStatus(tradeNo string, expectedPaymentMethod string, targ
if err := tx.Set("gorm:query_option", "FOR UPDATE").Where(refCol+" = ?", tradeNo).First(topUp).Error; err != nil {
return ErrTopUpNotFound
}
if expectedPaymentMethod != "" && topUp.PaymentMethod != expectedPaymentMethod {
if expectedPaymentProvider != "" && topUp.PaymentProvider != expectedPaymentProvider {
return ErrPaymentMethodMismatch
}
if topUp.Status != common.TopUpStatusPending {
@@ -114,7 +123,7 @@ func Recharge(referenceId string, customerId string, callerIp string) (err error
return errors.New("充值订单不存在")
}
if topUp.PaymentMethod != PaymentMethodStripe {
if topUp.PaymentProvider != PaymentProviderStripe {
return ErrPaymentMethodMismatch
}
@@ -340,7 +349,7 @@ func ManualCompleteTopUp(tradeNo string, callerIp string) error {
// 计算应充值额度:
// - Stripe 订单:Money 代表经分组倍率换算后的美元数量,直接 * QuotaPerUnit
// - 其他订单(如易支付):Amount 为美元数量,* QuotaPerUnit
if topUp.PaymentMethod == PaymentMethodStripe {
if topUp.PaymentProvider == PaymentProviderStripe {
dQuotaPerUnit := decimal.NewFromFloat(common.QuotaPerUnit)
quotaToAdd = int(decimal.NewFromFloat(topUp.Money).Mul(dQuotaPerUnit).IntPart())
} else {
@@ -397,7 +406,7 @@ func RechargeCreem(referenceId string, customerEmail string, customerName string
return errors.New("充值订单不存在")
}
if topUp.PaymentMethod != PaymentMethodCreem {
if topUp.PaymentProvider != PaymentProviderCreem {
return ErrPaymentMethodMismatch
}
@@ -472,7 +481,7 @@ func RechargeWaffo(tradeNo string, callerIp string) (err error) {
return errors.New("充值订单不存在")
}
if topUp.PaymentMethod != PaymentMethodWaffo {
if topUp.PaymentProvider != PaymentProviderWaffo {
return ErrPaymentMethodMismatch
}
@@ -535,7 +544,7 @@ func RechargeWaffoPancake(tradeNo string) (err error) {
return errors.New("充值订单不存在")
}
if topUp.PaymentMethod != PaymentMethodWaffoPancake {
if topUp.PaymentProvider != PaymentProviderWaffoPancake {
return ErrPaymentMethodMismatch
}