You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
44 lines
1.1 KiB
44 lines
1.1 KiB
import svgCaptcha from 'svg-captcha'
|
|
|
|
interface CaptchaRecord {
|
|
text: string
|
|
createdAt: number
|
|
}
|
|
|
|
const captchaStore = new Map<string, CaptchaRecord>()
|
|
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
|
|
}
|
|
|