From 0a4ea5563646a4cbbe93c034e17f96c54e29f4c2 Mon Sep 17 00:00:00 2001 From: erio Date: Tue, 7 Apr 2026 14:36:53 +0800 Subject: [PATCH] fix(payment): add Stripe domains to CSP and show upstream payment errors - Add https://*.stripe.com to script-src and frame-src in default CSP policy so Stripe.js can load in the browser - Show upstream payment gateway error details instead of generic "temporarily unavailable" message --- backend/cmd/server/VERSION | 2 +- backend/internal/config/config.go | 2 +- backend/internal/service/payment_service.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/cmd/server/VERSION b/backend/cmd/server/VERSION index 8b4a475023..48fbe79181 100644 --- a/backend/cmd/server/VERSION +++ b/backend/cmd/server/VERSION @@ -1 +1 @@ -0.1.108.73 +0.1.108.74 diff --git a/backend/internal/config/config.go b/backend/internal/config/config.go index 9b43037789..981c52e3e4 100644 --- a/backend/internal/config/config.go +++ b/backend/internal/config/config.go @@ -28,7 +28,7 @@ const ( // DefaultCSPPolicy is the default Content-Security-Policy with nonce support // __CSP_NONCE__ will be replaced with actual nonce at request time by the SecurityHeaders middleware -const DefaultCSPPolicy = "default-src 'self'; script-src 'self' __CSP_NONCE__ https://challenges.cloudflare.com https://static.cloudflareinsights.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https:; font-src 'self' data: https://fonts.gstatic.com; connect-src 'self' https:; frame-src https://challenges.cloudflare.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" +const DefaultCSPPolicy = "default-src 'self'; script-src 'self' __CSP_NONCE__ https://challenges.cloudflare.com https://static.cloudflareinsights.com https://*.stripe.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https:; font-src 'self' data: https://fonts.gstatic.com; connect-src 'self' https:; frame-src https://challenges.cloudflare.com https://*.stripe.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" // UMQ(用户消息队列)模式常量 const ( diff --git a/backend/internal/service/payment_service.go b/backend/internal/service/payment_service.go index 36853babe4..2b126caa7b 100644 --- a/backend/internal/service/payment_service.go +++ b/backend/internal/service/payment_service.go @@ -412,7 +412,7 @@ func (s *PaymentService) invokeProvider(ctx context.Context, order *dbent.Paymen pr, err := prov.CreatePayment(ctx, payment.CreatePaymentRequest{OrderID: formatOrderID(order.ID), Amount: payAmountStr, PaymentType: req.PaymentType, Subject: subject, ClientIP: req.ClientIP, IsMobile: req.IsMobile, InstanceSubMethods: sel.SupportedTypes}) if err != nil { slog.Error("[PaymentService] CreatePayment failed", "provider", providerKey, "instance", sel.InstanceID, "error", err) - return nil, infraerrors.ServiceUnavailable("PAYMENT_GATEWAY_ERROR", "payment method is temporarily unavailable") + return nil, infraerrors.ServiceUnavailable("PAYMENT_GATEWAY_ERROR", fmt.Sprintf("payment gateway error: %s", err.Error())) } _, err = s.entClient.PaymentOrder.UpdateOneID(order.ID).SetNillablePaymentTradeNo(psNilIfEmpty(pr.TradeNo)).SetNillablePayURL(psNilIfEmpty(pr.PayURL)).SetNillableQrCode(psNilIfEmpty(pr.QRCode)).SetNillableProviderInstanceID(psNilIfEmpty(sel.InstanceID)).Save(ctx) if err != nil {