diff --git a/server/utils/auth/captcha.ts b/server/utils/auth/captcha.ts new file mode 100644 index 0000000..652ab6e --- /dev/null +++ b/server/utils/auth/captcha.ts @@ -0,0 +1,44 @@ +import svgCaptcha from 'svg-captcha' + +interface CaptchaRecord { + text: string + createdAt: number +} + +const captchaStore = new Map() +const CAPTCHA_TTL = 5 * 60 * 1000 + +function cleanupExpired(): void { + const now = Date.now() + for (const [token, record] of captchaStore) { + if (now - record.createdAt > CAPTCHA_TTL) { + captchaStore.delete(token) + } + } +} + +export function generateCaptcha(): { token: string; svg: string } { + cleanupExpired() + const { text, data: svg } = svgCaptcha.create({ + noise: 3, + color: true, + background: '#f8f9fa', + }) + const token = crypto.randomUUID() + captchaStore.set(token, { text, createdAt: Date.now() }) + return { token, svg } +} + +export function verifyCaptcha(token: string, text: string): boolean { + const record = captchaStore.get(token) + if (!record) return false + if (Date.now() - record.createdAt > CAPTCHA_TTL) { + captchaStore.delete(token) + return false + } + const match = record.text.toLowerCase() === text.toLowerCase() + if (match) { + captchaStore.delete(token) + } + return match +}