Files
study-bible-project/server/limiter.js
nmemmertandClaude Sonnet 5.5 9893883b19
Build and Push Docker Image / build-and-push (push) Successful in 5m37s
Split server/index.js into one file per area
Routes move to server/routes/ (auth, account, projects, reader, sharing, admin);
index.js keeps setup only. A smoke test walks 90 API calls against the real
server and compares every status with the pre-split behaviour.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 13:25:52 -04:00

24 lines
1022 B
JavaScript

// In-memory limiter for sign-in style endpoints: 10 FAILED attempts per 15 min, tracked per IP and per
// account (key). Successful sign-ins don't count, so a shared IP doesn't lock everyone out.
const _failures = new Map();
const FAIL_WINDOW = 15 * 60 * 1000;
const FAIL_MAX = 10;
setInterval(() => {
const now = Date.now();
for (const [k, e] of _failures) if (now > e.resetAt) _failures.delete(k);
}, 60 * 60 * 1000).unref();
export function isLimited(...keys) {
const now = Date.now();
return keys.some((k) => { const e = _failures.get(k); return e && now <= e.resetAt && e.count >= FAIL_MAX; });
}
export function recordFailure(...keys) {
const now = Date.now();
for (const k of keys) {
const e = _failures.get(k);
if (!e || now > e.resetAt) _failures.set(k, { count: 1, resetAt: now + FAIL_WINDOW });
else e.count += 1;
}
}
export function clearFailures(...keys) { keys.forEach((k) => _failures.delete(k)); }
export const TOO_MANY = { error: 'Too many attempts. Please wait 15 minutes.' };