31 lines
1.2 KiB
TypeScript
31 lines
1.2 KiB
TypeScript
import { resolveUsers } from '../config/env.js';
|
|
import type { RegistryUser } from './users.registry.types.js';
|
|
|
|
// Built once on process start from env. Source of truth for credentials.
|
|
// DB contains only "public" copies (id, username, slug, displayName) — never the hash.
|
|
const users: RegistryUser[] = resolveUsers();
|
|
const byUsername = new Map(users.map((u) => [u.username, u] as const));
|
|
const byId = new Map(users.map((u) => [u.id, u] as const));
|
|
|
|
export const usersRegistry = {
|
|
all(): readonly RegistryUser[] {
|
|
return users;
|
|
},
|
|
findByUsername(username: string): RegistryUser | undefined {
|
|
return byUsername.get(username);
|
|
},
|
|
findById(id: string): RegistryUser | undefined {
|
|
return byId.get(id);
|
|
},
|
|
};
|
|
|
|
// Pre-computed bcrypt hash of a random string, used for timing-safe compare
|
|
// when the requested username does not exist. Generated lazily on first need.
|
|
let dummyHashCache: string | null = null;
|
|
export async function getDummyHash(): Promise<string> {
|
|
if (dummyHashCache) return dummyHashCache;
|
|
const { default: bcrypt } = await import('bcryptjs');
|
|
dummyHashCache = await bcrypt.hash('__not_a_real_password__', 10);
|
|
return dummyHashCache;
|
|
}
|