fix: harden payment resume and wxpay webhook routing

This commit is contained in:
IanShaw027
2026-04-21 01:40:56 +08:00
parent 0a461d8248
commit 1d8432b8a4
9 changed files with 526 additions and 31 deletions

View File

@@ -45,11 +45,31 @@ type DefaultLoadBalancer struct {
counter atomic.Uint64
}
type contextKey string
const wxpayJSAPIAppIDContextKey contextKey = "payment.wxpay.jsapi_app_id"
// NewDefaultLoadBalancer creates a new load balancer.
func NewDefaultLoadBalancer(db *dbent.Client, encryptionKey []byte) *DefaultLoadBalancer {
return &DefaultLoadBalancer{db: db, encryptionKey: encryptionKey}
}
func WithWxpayJSAPIAppID(ctx context.Context, appID string) context.Context {
appID = strings.TrimSpace(appID)
if appID == "" {
return ctx
}
return context.WithValue(ctx, wxpayJSAPIAppIDContextKey, appID)
}
func wxpayJSAPIAppIDFromContext(ctx context.Context) string {
if ctx == nil {
return ""
}
appID, _ := ctx.Value(wxpayJSAPIAppIDContextKey).(string)
return strings.TrimSpace(appID)
}
// instanceCandidate pairs an instance with its pre-fetched daily usage.
type instanceCandidate struct {
inst *dbent.PaymentProviderInstance
@@ -116,6 +136,7 @@ func (lb *DefaultLoadBalancer) queryEnabledInstances(
}
var matched []*dbent.PaymentProviderInstance
expectedWxpayJSAPIAppID := wxpayJSAPIAppIDFromContext(ctx)
for _, inst := range instances {
// Stripe: match by provider_key because supported_types lists sub-types (card,link,alipay,wxpay),
// not "stripe" itself. The checkout page aggregates all sub-types under "stripe".
@@ -124,6 +145,16 @@ func (lb *DefaultLoadBalancer) queryEnabledInstances(
matched = append(matched, inst)
}
} else if InstanceSupportsType(inst.SupportedTypes, paymentType) {
if expectedWxpayJSAPIAppID != "" && normalizeVisibleMethodSupportType(paymentType) == TypeWxpay && inst.ProviderKey == TypeWxpay {
config, cfgErr := lb.decryptConfig(inst.Config)
if cfgErr != nil {
slog.Warn("skip wxpay instance with unreadable config during jsapi filtering", "instance_id", inst.ID, "error", cfgErr)
continue
}
if resolveWxpayJSAPIAppID(config) != expectedWxpayJSAPIAppID {
continue
}
}
matched = append(matched, inst)
}
}
@@ -358,6 +389,13 @@ func legacyVisibleMethodAlias(paymentType PaymentType) PaymentType {
}
}
func resolveWxpayJSAPIAppID(config map[string]string) string {
if appID := strings.TrimSpace(config["mpAppId"]); appID != "" {
return appID
}
return strings.TrimSpace(config["appId"])
}
// GetInstanceConfig decrypts and returns the configuration for a provider instance by ID.
func (lb *DefaultLoadBalancer) GetInstanceConfig(ctx context.Context, instanceID int64) (map[string]string, error) {
inst, err := lb.db.PaymentProviderInstance.Get(ctx, instanceID)