29 lines
1.5 KiB
TypeScript
29 lines
1.5 KiB
TypeScript
import type Database from 'better-sqlite3';
|
|
const initialized = new WeakSet<Database.Database>();
|
|
export function ensureAuthSchema(handle: Database.Database): void {
|
|
if (initialized.has(handle)) return;
|
|
handle.exec(`
|
|
CREATE TABLE IF NOT EXISTS auth_users (
|
|
id TEXT PRIMARY KEY, username TEXT NOT NULL COLLATE NOCASE UNIQUE,
|
|
display_name TEXT NOT NULL, password_hash TEXT NOT NULL,
|
|
role TEXT NOT NULL CHECK(role IN ('admin','operator','viewer')),
|
|
disabled INTEGER NOT NULL DEFAULT 0, must_change_password INTEGER NOT NULL DEFAULT 0,
|
|
created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, last_login_at INTEGER
|
|
);
|
|
CREATE TABLE IF NOT EXISTS auth_sessions (
|
|
token_hash TEXT PRIMARY KEY, user_id TEXT NOT NULL REFERENCES auth_users(id) ON DELETE CASCADE,
|
|
created_at INTEGER NOT NULL, expires_at INTEGER NOT NULL, last_seen_at INTEGER NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS auth_sessions_user ON auth_sessions(user_id);
|
|
CREATE TABLE IF NOT EXISTS auth_rate_limits (
|
|
key TEXT PRIMARY KEY, window_start INTEGER NOT NULL, attempts INTEGER NOT NULL
|
|
);
|
|
CREATE TABLE IF NOT EXISTS auth_audit (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT, actor_id TEXT, action TEXT NOT NULL,
|
|
target_id TEXT, details TEXT NOT NULL, created_at INTEGER NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS auth_audit_created_at ON auth_audit(created_at);
|
|
`);
|
|
initialized.add(handle);
|
|
}
|