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.
 
 
 
 

45 lines
1.0 KiB

// In-memory rate limiter keyed by IP
const loginAttempts = new Map<
string,
{ count: number; resetAt: number }
>();
const WINDOW_MS = 60_000; // 1 minute window
const MAX_ATTEMPTS = 5; // max 5 attempts per window
const LOCKOUT_MS = 15 * 60_000; // 15 minute lockout
function cleanupExpired(now: number): void {
for (const [ip, entry] of loginAttempts.entries()) {
if (now > entry.resetAt) {
loginAttempts.delete(ip);
}
}
}
export function checkRateLimit(ip: string): {
allowed: boolean;
retryAfterMs: number;
} {
const now = Date.now();
cleanupExpired(now);
const entry = loginAttempts.get(ip);
if (!entry || now > entry.resetAt) {
loginAttempts.set(ip, { count: 1, resetAt: now + WINDOW_MS });
return { allowed: true, retryAfterMs: 0 };
}
if (entry.count >= MAX_ATTEMPTS) {
return {
allowed: false,
retryAfterMs: entry.resetAt - now,
};
}
entry.count++;
return { allowed: true, retryAfterMs: 0 };
}
export function clearRateLimit(ip: string): void {
loginAttempts.delete(ip);
}