import { authId, matchingStep, type AuthConfig } from "./auth"; import { openSiteDatabase } from "./site-database"; function database() { const db = openSiteDatabase(); db.exec(`PRAGMA busy_timeout=5000; CREATE TABLE IF NOT EXISTS login_state ( id TEXT PRIMARY KEY, window_start INTEGER NOT NULL, attempts INTEGER NOT NULL DEFAULT 0, last_step INTEGER NOT NULL DEFAULT -1 );`); return db; } // SQLite's write transaction serializes attempts across workers and restarts. export function consumeCode( config: AuthConfig, code: string, now = Date.now(), ): "ok" | "invalid" | "limited" { const db = database(); try { db.exec("BEGIN IMMEDIATE"); const id = authId(config); db.prepare( "INSERT OR IGNORE INTO login_state(id,window_start) VALUES (?,?)", ).run(id, now); const state = db .prepare("SELECT * FROM login_state WHERE id=?") .get(id) as { window_start: number; attempts: number; last_step: number; }; const expired = now - state.window_start >= 300000; const attempts = expired ? 0 : state.attempts; let result: "ok" | "invalid" | "limited" = "limited"; if (attempts < 20) { db.prepare( "UPDATE login_state SET attempts=?,window_start=? WHERE id=?", ).run(attempts + 1, expired ? now : state.window_start, id); const step = matchingStep(config.secret, code, now); result = step !== null && step > state.last_step ? "ok" : "invalid"; if (result === "ok") db.prepare("UPDATE login_state SET last_step=? WHERE id=?").run( step!, id, ); } db.exec("COMMIT"); return result; } catch (error) { try { db.exec("ROLLBACK"); } catch { /* Transaction may not have started. */ } throw error; } finally { db.close(); } } export function initializeStore() { const db = database(); db.close(); }