31 lines
1.3 KiB
TypeScript
31 lines
1.3 KiB
TypeScript
// Panic lockdown. The panic password (entered at login, or via /auth/panic) trips this in-memory flag;
|
|
// while it is set, ALL new logins and ALL existing sessions are refused. It is intentionally in-memory
|
|
// only, so the only way to clear it is a manual server restart.
|
|
let locked = false;
|
|
let blockedCount = 0;
|
|
let lastBlockedLog = 0;
|
|
|
|
export const isLockdown = (): boolean => locked;
|
|
|
|
// Activate the panic lockdown. `source` describes where it was tripped from (login form / endpoint,
|
|
// with origin + ip) for the audit log. Logs once — re-triggering while already locked is a no-op.
|
|
export const triggerLockdown = (source: string): void => {
|
|
if (locked) return;
|
|
locked = true;
|
|
blockedCount = 0;
|
|
lastBlockedLog = 0;
|
|
console.warn(`[SECURITY] panic lockdown ACTIVATED — ${source} — ${new Date().toISOString()}`);
|
|
};
|
|
|
|
// Record a request that was refused because of the lockdown. Logs a throttled running total (at most
|
|
// once per 10s) so polling clients hammering the API don't flood the log.
|
|
export const noteBlocked = (what: string): void => {
|
|
if (!locked) return;
|
|
blockedCount++;
|
|
const now = Date.now();
|
|
if (now - lastBlockedLog >= 10_000) {
|
|
lastBlockedLog = now;
|
|
console.warn(`[SECURITY] panic lockdown blocked ${blockedCount} request(s) since activation — latest: ${what}`);
|
|
}
|
|
};
|