20c8395c0b
- 新增 NEXT_PUBLIC_SITE_URL 支持及 site-url.ts 工具模块 - 修复 OAuth 回调域名:import.meta.env 统一读取站点 URL - 支付 API 路由新增收款地址校验 - 后端支付服务更新 - middleware 清理 - 新增 paymentSecurity 测试
77 lines
2.8 KiB
TypeScript
77 lines
2.8 KiB
TypeScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
function assert(condition: unknown, message: string) {
|
|
if (!condition) throw new Error(message);
|
|
}
|
|
|
|
const EXPECTED_RECEIVER = "0x351a1bca5f49dd0046a7cf0bafa7e12fa6441c3a";
|
|
|
|
export function runTests() {
|
|
const projectRoot = process.cwd();
|
|
const receiverModulePath = path.join(projectRoot, "lib", "payment-receiver.ts");
|
|
const backendAuthPath = path.join(projectRoot, "lib", "backend-auth.ts");
|
|
const middlewarePath = path.join(projectRoot, "middleware.ts");
|
|
const accountCenterPath = path.join(
|
|
projectRoot,
|
|
"components",
|
|
"account",
|
|
"AccountCenter.tsx",
|
|
);
|
|
const paymentRoutes = [
|
|
"app/api/payments/wallets/challenge/route.ts",
|
|
"app/api/payments/wallets/verify/route.ts",
|
|
"app/api/payments/wallets/route.ts",
|
|
"app/api/payments/intents/route.ts",
|
|
"app/api/payments/intents/[intentId]/submit/route.ts",
|
|
"app/api/payments/intents/[intentId]/confirm/route.ts",
|
|
"app/api/payments/intents/[intentId]/validate/route.ts",
|
|
"app/api/payments/reconcile-latest/route.ts",
|
|
];
|
|
|
|
assert(
|
|
fs.existsSync(receiverModulePath),
|
|
"payment receiver guard module must exist",
|
|
);
|
|
const receiverSource = fs.readFileSync(receiverModulePath, "utf8");
|
|
assert(
|
|
receiverSource.includes(EXPECTED_RECEIVER),
|
|
"payment receiver guard must pin the production receiver address",
|
|
);
|
|
assert(
|
|
receiverSource.includes("assertExpectedPaymentReceiver"),
|
|
"payment receiver guard must expose an assertion helper",
|
|
);
|
|
|
|
const accountCenterSource = fs.readFileSync(accountCenterPath, "utf8");
|
|
assert(
|
|
accountCenterSource.includes("assertExpectedPaymentReceiver"),
|
|
"AccountCenter must validate backend-returned manual payment receiver before displaying it",
|
|
);
|
|
assert(
|
|
accountCenterSource.includes("EXPECTED_PAYMENT_RECEIVER_ADDRESS"),
|
|
"AccountCenter must show the pinned payment receiver address in its payment guard",
|
|
);
|
|
|
|
const backendAuthSource = fs.readFileSync(backendAuthPath, "utf8");
|
|
assert(
|
|
backendAuthSource.includes("requireBackendAuthUser"),
|
|
"backend auth helper must expose a real-user requirement for payment mutations",
|
|
);
|
|
|
|
const middlewareSource = fs.readFileSync(middlewarePath, "utf8");
|
|
assert(
|
|
!middlewareSource.includes("/^bearer\\s+\\S+/i.test(authHeader)") &&
|
|
!middlewareSource.includes("return NextResponse.next();\n }\n }\n\n const response = NextResponse.next"),
|
|
"middleware must not treat the mere presence of a bearer token as authenticated",
|
|
);
|
|
|
|
for (const route of paymentRoutes) {
|
|
const routeSource = fs.readFileSync(path.join(projectRoot, route), "utf8");
|
|
assert(
|
|
routeSource.includes("requireBackendAuthUser"),
|
|
`${route} must reject payment mutations without a real Supabase user`,
|
|
);
|
|
}
|
|
}
|