Add WebAuthn support for admin login and kiosk mode

This commit is contained in:
2026-07-26 21:12:59 +02:00
parent 3c8d9297d7
commit 2b85152bb9
13 changed files with 466 additions and 9 deletions
+28
View File
@@ -105,6 +105,28 @@ function ensureSchema() {
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
) STRICT;
CREATE TABLE IF NOT EXISTS webauthn_credentials (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
credential_id TEXT NOT NULL UNIQUE,
public_key TEXT NOT NULL,
counter INTEGER NOT NULL DEFAULT 0 CHECK (counter >= 0),
transports TEXT,
label TEXT,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_used_at TEXT
) STRICT;
CREATE TABLE IF NOT EXISTS webauthn_challenges (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
challenge TEXT NOT NULL,
purpose TEXT NOT NULL CHECK (purpose IN ('registration', 'authentication')),
expires_at TEXT NOT NULL,
used_at TEXT,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
) STRICT;
CREATE INDEX IF NOT EXISTS idx_maintenance_motorcycle
ON maintenance_events(motorcycle_id, event_date DESC, id DESC);
CREATE INDEX IF NOT EXISTS idx_maintenance_due
@@ -113,6 +135,10 @@ function ensureSchema() {
ON trips(motorcycle_id, trip_date DESC, id DESC);
CREATE INDEX IF NOT EXISTS idx_motorcycle_shares_user
ON motorcycle_shares(user_id, motorcycle_id);
CREATE INDEX IF NOT EXISTS idx_webauthn_credentials_user
ON webauthn_credentials(user_id);
CREATE INDEX IF NOT EXISTS idx_webauthn_challenges_lookup
ON webauthn_challenges(user_id, purpose, expires_at, used_at);
`);
const userColumns = db.prepare("PRAGMA table_info(users)").all() as { name: string }[];
@@ -196,6 +222,8 @@ function ensureSchema() {
}
db.exec("CREATE INDEX IF NOT EXISTS idx_users_active ON users(active, name COLLATE NOCASE)");
db.prepare("DELETE FROM webauthn_challenges WHERE used_at IS NOT NULL OR expires_at < ?")
.run(new Date().toISOString());
}
function ensureInitialAdmin() {