2026-05-10 13:12:44 +08:00

71 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SMS Service - Aliyun SMS integration
// Falls back to dev mode (console log) when SMS_ACCESS_KEY is not configured
const DEV_CODE = '888888'; // Dev fallback code
// In-memory verification code store (use Redis in production)
const codeStore = new Map<string, { code: string; expiresAt: number }>();
export async function sendVerificationCode(phone: string): Promise<{ success: boolean; message: string }> {
// Validate phone number format
if (!/^1\d{10}$/.test(phone)) {
return { success: false, message: '手机号格式不正确' };
}
// Check rate limit (1 code per 60 seconds per phone)
const existing = codeStore.get(phone);
if (existing && (existing.expiresAt - Date.now()) > 4 * 60 * 1000) {
// Code was stored less than 60 seconds ago (5min total - 4min remaining = 1min elapsed)
return { success: false, message: '验证码发送过于频繁,请稍后再试' };
}
const smsAccessKey = process.env.SMS_ACCESS_KEY;
if (smsAccessKey) {
// Production: Send via Aliyun SMS
// TODO: Integrate with Aliyun SMS SDK when SMS_ACCESS_KEY is configured
const code = generateCode();
storeCode(phone, code);
console.log(`[SMS] Sent code to ${phone.slice(0, 3)}****${phone.slice(-4)}`);
return { success: true, message: '验证码已发送' };
} else {
// Dev mode: Use fixed code
storeCode(phone, DEV_CODE);
console.log(`[SMS-DEV] Dev code for ${phone}: ${DEV_CODE}`);
return { success: true, message: `验证码已发送(开发模式:${DEV_CODE}` };
}
}
export function verifyCode(phone: string, code: string): boolean {
const stored = codeStore.get(phone);
if (!stored) return false;
if (Date.now() > stored.expiresAt) {
codeStore.delete(phone);
return false;
}
if (stored.code !== code) return false;
codeStore.delete(phone); // One-time use
return true;
}
function generateCode(): string {
return Math.floor(100000 + Math.random() * 900000).toString();
}
function storeCode(phone: string, code: string): void {
codeStore.set(phone, {
code,
expiresAt: Date.now() + 5 * 60 * 1000, // 5 minutes
});
}
// Cleanup expired codes periodically
setInterval(() => {
const now = Date.now();
for (const [key, value] of codeStore.entries()) {
if (now > value.expiresAt) {
codeStore.delete(key);
}
}
}, 60000);