video-flow-toon/src/lib/smsCode.ts
zyc 29867f91c1
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m18s
Fix registration error responses
2026-06-01 17:40:33 +08:00

54 lines
2.0 KiB
TypeScript

import u from "@/utils";
import { hashPassword, verifyPassword } from "@/lib/password";
export type SmsPurpose = "register" | "resetPassword";
const EXPIRES_IN_MS = 5 * 60 * 1000;
const RESEND_INTERVAL_MS = 60 * 1000;
const MAX_ATTEMPTS = 5;
function createSmsCodeError(message: string) {
const error = new Error(message) as Error & { status: number };
error.status = 400;
return error;
}
export function createNumericCode() {
return String(Math.floor(100000 + Math.random() * 900000));
}
export async function assertCanSendSmsCode(phone: string, purpose: SmsPurpose) {
const latest = await u.db("o_smsCode").where({ phone, purpose, used: 0 }).orderBy("createTime", "desc").first();
if (latest?.sentAt && Date.now() - latest.sentAt < RESEND_INTERVAL_MS) {
const waitSeconds = Math.ceil((RESEND_INTERVAL_MS - (Date.now() - latest.sentAt)) / 1000);
throw createSmsCodeError(`验证码发送过于频繁,请 ${waitSeconds} 秒后再试`);
}
}
export async function saveSmsCode(phone: string, purpose: SmsPurpose, code: string) {
await u.db("o_smsCode").insert({
id: Date.now(),
phone,
purpose,
codeHash: await hashPassword(code),
expiresAt: Date.now() + EXPIRES_IN_MS,
used: 0,
attempts: 0,
createTime: Date.now(),
sentAt: Date.now(),
});
}
export async function verifySmsCode(phone: string, purpose: SmsPurpose, code: string) {
const record = await u.db("o_smsCode").where({ phone, purpose, used: 0 }).orderBy("createTime", "desc").first();
if (!record) throw createSmsCodeError("验证码不存在或已失效");
if ((record.attempts ?? 0) >= MAX_ATTEMPTS) throw createSmsCodeError("验证码尝试次数过多,请重新获取");
if ((record.expiresAt ?? 0) < Date.now()) throw createSmsCodeError("验证码已过期");
await u.db("o_smsCode").where("id", record.id).update({ attempts: (record.attempts ?? 0) + 1 });
const matched = await verifyPassword(code, record.codeHash);
if (!matched) throw createSmsCodeError("验证码错误");
await u.db("o_smsCode").where("id", record.id).update({ used: 1 });
}