From 3f4aaa5773fdace3c8cb665571906f40cdb1feca Mon Sep 17 00:00:00 2001 From: npmrun <1549469775@qq.com> Date: Fri, 15 May 2026 10:24:04 +0800 Subject: [PATCH] feat: add captcha generation and verification utility --- server/utils/auth/captcha.ts | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 server/utils/auth/captcha.ts 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 +}