Initial commit
This commit is contained in:
76
lib/captcha.ts
Normal file
76
lib/captcha.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import crypto from "crypto";
|
||||
|
||||
// Simple in-memory CAPTCHA store (in production, use Redis or database)
|
||||
const captchaStore: Map<string, { code: string; createdAt: number; attempts: number }> = new Map();
|
||||
|
||||
const CAPTCHA_TTL = 5 * 60 * 1000; // 5 minutes
|
||||
const MAX_ATTEMPTS = 5;
|
||||
const CLEANUP_INTERVAL = 10 * 60 * 1000; // 10 minutes
|
||||
|
||||
// Cleanup old captchas periodically
|
||||
setInterval(() => {
|
||||
const now = Date.now();
|
||||
for (const [key, value] of captchaStore.entries()) {
|
||||
if (now - value.createdAt > CAPTCHA_TTL) {
|
||||
captchaStore.delete(key);
|
||||
}
|
||||
}
|
||||
}, CLEANUP_INTERVAL);
|
||||
|
||||
export function generateCaptcha(identifier: string): { id: string; code: string } {
|
||||
const code = Math.random().toString().slice(2, 8); // 6-digit code
|
||||
const id = crypto.randomBytes(16).toString("hex");
|
||||
|
||||
captchaStore.set(id, {
|
||||
code,
|
||||
createdAt: Date.now(),
|
||||
attempts: 0,
|
||||
});
|
||||
|
||||
return { id, code };
|
||||
}
|
||||
|
||||
export interface CaptchaVerificationResult {
|
||||
success: boolean;
|
||||
error?: string;
|
||||
attemptsRemaining?: number;
|
||||
}
|
||||
|
||||
export function verifyCaptcha(id: string, code: string): CaptchaVerificationResult {
|
||||
const captcha = captchaStore.get(id);
|
||||
|
||||
if (!captcha) {
|
||||
return { success: false, error: "CAPTCHA not found or expired. Please reload and try again." };
|
||||
}
|
||||
|
||||
// Check if expired
|
||||
if (Date.now() - captcha.createdAt > CAPTCHA_TTL) {
|
||||
captchaStore.delete(id);
|
||||
return { success: false, error: "CAPTCHA code has expired. Please request a new one." };
|
||||
}
|
||||
|
||||
// Check attempts
|
||||
if (captcha.attempts >= MAX_ATTEMPTS) {
|
||||
captchaStore.delete(id);
|
||||
return { success: false, error: "Too many incorrect attempts. Please request a new CAPTCHA code." };
|
||||
}
|
||||
|
||||
// Verify code
|
||||
if (captcha.code === code) {
|
||||
captchaStore.delete(id);
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
// Increment attempts
|
||||
captcha.attempts++;
|
||||
const remaining = MAX_ATTEMPTS - captcha.attempts;
|
||||
return {
|
||||
success: false,
|
||||
error: `Incorrect CAPTCHA code. ${remaining} attempt${remaining === 1 ? "" : "s"} remaining.`,
|
||||
attemptsRemaining: remaining,
|
||||
};
|
||||
}
|
||||
|
||||
export function getMaxAttempts(): number {
|
||||
return MAX_ATTEMPTS;
|
||||
}
|
||||
Reference in New Issue
Block a user