fix: 后端资金安全修复 — 金额覆盖、过期订单、退款原子性等 9 项

- confirmPayment 不再覆盖 amount,实付金额写入 payAmount
- EXPIRED 订单增加 5 分钟宽限窗口
- 退款流程先扣余额再退款,失败可回滚
- 支付宝签名过滤 sign_type
- executeRecharge 使用 CAS 更新
- createOrder rechargeCode 事务保护
- EasyPay/Sub2API client 添加 10s 超时
- db.ts 统一从 getEnv() 获取 DATABASE_URL
- 添加 paymentType+paidAt 复合索引

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
erio
2026-03-07 04:15:48 +08:00
parent a5e07edda6
commit 4b013370b9
6 changed files with 114 additions and 42 deletions

View File

@@ -14,7 +14,7 @@ function formatPublicKey(key: string): string {
/** 生成 RSA2 签名 */
export function generateSign(params: Record<string, string>, privateKey: string): string {
const filtered = Object.entries(params)
.filter(([key, value]) => key !== 'sign' && value !== '' && value !== undefined && value !== null)
.filter(([key, value]) => key !== 'sign' && key !== 'sign_type' && value !== '' && value !== undefined && value !== null)
.sort(([a], [b]) => a.localeCompare(b));
const signStr = filtered.map(([key, value]) => `${key}=${value}`).join('&');
@@ -27,7 +27,7 @@ export function generateSign(params: Record<string, string>, privateKey: string)
/** 用支付宝公钥验证签名 */
export function verifySign(params: Record<string, string>, alipayPublicKey: string, sign: string): boolean {
const filtered = Object.entries(params)
.filter(([key, value]) => key !== 'sign' && value !== '' && value !== undefined && value !== null)
.filter(([key, value]) => key !== 'sign' && key !== 'sign_type' && value !== '' && value !== undefined && value !== null)
.sort(([a], [b]) => a.localeCompare(b));
const signStr = filtered.map(([key, value]) => `${key}=${value}`).join('&');