mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-01 16:12:02 +00:00
The three admin login limiters (5 per address and 50 overall in one reservation, 5 per known device) keep their numbers and still don't count refused attempts, but live in the store: memory in this process as before, or the shared store with several replicas. checkRateLimit and checkDeviceRateLimit are async now; the login route awaits them and answers 503 "Sign-in is temporarily unavailable" when the store can't be reached. The two limiter tests gain await and reset the store's counters, which vi.resetModules no longer clears. The admin code tells a store outage by the error's name, since the store may come from another bundle's copy of the module.
44 lines
1.7 KiB
TypeScript
44 lines
1.7 KiB
TypeScript
import { getStore, type CollectionOptions, type DocCollection } from '@/lib/shared-store';
|
|
import { getConfigDir, getStateDir } from './paths';
|
|
|
|
/**
|
|
* Where the admin dashboard's own documents live (#1066). Local mode: the
|
|
* admin config dir and state dir, with today's file names and temp names
|
|
* (`<file>.tmp`). Shared mode: the shared store, except that read-only
|
|
* config (ADMIN_CONFIG_READONLY) is read from the mounted files.
|
|
*/
|
|
|
|
const fixedTmpName = (target: string) => `${target}.tmp`;
|
|
|
|
/** config.json, policy.json, admin.json, .config-locked. */
|
|
export const ADMIN_CONFIG_COLLECTION = 'admin-config';
|
|
export const adminConfigOptions: CollectionOptions = {
|
|
// Owner-only: config.json carries the session secret, admin.json the password hash.
|
|
local: { dir: () => getConfigDir(), mode: 0o600, tmpName: fixedTmpName },
|
|
configDir: true,
|
|
};
|
|
|
|
/** admin-state.json, and other runtime state of the admin dashboard. */
|
|
export const ADMIN_STATE_COLLECTION = 'admin-state';
|
|
export const adminStateOptions: CollectionOptions = {
|
|
local: { dir: () => getStateDir(), tmpName: fixedTmpName },
|
|
};
|
|
|
|
export function adminConfigDocs(): DocCollection {
|
|
return getStore().collection(ADMIN_CONFIG_COLLECTION, adminConfigOptions);
|
|
}
|
|
|
|
export function adminStateDocs(): DocCollection {
|
|
return getStore().collection(ADMIN_STATE_COLLECTION, adminStateOptions);
|
|
}
|
|
|
|
/**
|
|
* Whether `error` is the shared store's StoreUnavailableError. By name, not
|
|
* instanceof: the store on globalThis may come from another bundle's copy
|
|
* of the shared-store module (proxy, instrumentation, routes), whose class
|
|
* is a different object.
|
|
*/
|
|
export function isStoreUnavailable(error: unknown): boolean {
|
|
return error instanceof Error && error.name === 'StoreUnavailableError';
|
|
}
|