feat: sign in with passkeys, no password once an account has one; an account button and dialog in place of the sign-out button

This commit is contained in:
redtea committed 2026-10-14 20:33:31 +03:00
1 parent d2d6fe0100
commit e7b5d28470
9 files changed
+892 -18

No files matched your search

+93
View File
@@ -85,6 +85,16 @@ CREATE TABLE IF NOT EXISTS ufw_rules (
created_at INTEGER NOT NULL,
UNIQUE(port, proto)
);
CREATE TABLE IF NOT EXISTS admin_keys (
id INTEGER PRIMARY KEY AUTOINCREMENT,
admin_id INTEGER NOT NULL REFERENCES admins(id) ON DELETE CASCADE,
cred_id BLOB UNIQUE NOT NULL,
public_key BLOB NOT NULL,
sign_count INTEGER NOT NULL DEFAULT 0,
name TEXT NOT NULL DEFAULT '',
created_at INTEGER NOT NULL,
last_used INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS forward_rules (
id INTEGER PRIMARY KEY AUTOINCREMENT,
agent_id TEXT NOT NULL,
@@ -188,6 +198,89 @@ func (db *DB) DeleteAdmin(id int64) error {
return err
}
// AdminKey is a passkey an admin signs in with.
type AdminKey struct {
ID int64
AdminID int64
CredID []byte
PublicKey []byte // PKIX DER
SignCount uint32
Name string
CreatedAt int64
LastUsed int64
}
func (db *DB) AdminByID(id int64) (*Admin, error) {
a := &Admin{}
err := db.sql.QueryRow(`SELECT id, username, pass_hash FROM admins WHERE id = ?`, id).
Scan(&a.ID, &a.Username, &a.PassHash)
if err == sql.ErrNoRows {
return nil, nil
}
return a, err
}
func (db *DB) AddAdminKey(k AdminKey) error {
_, err := db.sql.Exec(
`INSERT INTO admin_keys(admin_id, cred_id, public_key, sign_count, name, created_at) VALUES(?, ?, ?, ?, ?, ?)`,
k.AdminID, k.CredID, k.PublicKey, k.SignCount, k.Name, time.Now().Unix())
return err
}
func (db *DB) ListAdminKeys(adminID int64) ([]AdminKey, error) {
rows, err := db.sql.Query(
`SELECT id, admin_id, cred_id, public_key, sign_count, name, created_at, last_used
FROM admin_keys WHERE admin_id = ? ORDER BY id`, adminID)
if err != nil {
return nil, err
}
defer rows.Close()
var out []AdminKey
for rows.Next() {
var k AdminKey
if err := rows.Scan(&k.ID, &k.AdminID, &k.CredID, &k.PublicKey, &k.SignCount, &k.Name, &k.CreatedAt, &k.LastUsed); err != nil {
return nil, err
}
out = append(out, k)
}
return out, rows.Err()
}
// CountAdminKeys is how many passkeys an admin has: with any, the password
// no longer signs them in.
func (db *DB) CountAdminKeys(adminID int64) int {
var n int
_ = db.sql.QueryRow(`SELECT COUNT(*) FROM admin_keys WHERE admin_id = ?`, adminID).Scan(&n)
return n
}
func (db *DB) AdminKeyByCredID(credID []byte) (*AdminKey, error) {
k := &AdminKey{}
err := db.sql.QueryRow(
`SELECT id, admin_id, cred_id, public_key, sign_count, name, created_at, last_used
FROM admin_keys WHERE cred_id = ?`, credID).
Scan(&k.ID, &k.AdminID, &k.CredID, &k.PublicKey, &k.SignCount, &k.Name, &k.CreatedAt, &k.LastUsed)
if err == sql.ErrNoRows {
return nil, nil
}
return k, err
}
func (db *DB) UseAdminKey(id int64, signCount uint32) error {
_, err := db.sql.Exec(`UPDATE admin_keys SET sign_count = ?, last_used = ? WHERE id = ?`, signCount, time.Now().Unix(), id)
return err
}
func (db *DB) DeleteAdminKey(adminID, id int64) error {
_, err := db.sql.Exec(`DELETE FROM admin_keys WHERE admin_id = ? AND id = ?`, adminID, id)
return err
}
func (db *DB) DeleteAdminKeys(adminID int64) error {
_, err := db.sql.Exec(`DELETE FROM admin_keys WHERE admin_id = ?`, adminID)
return err
}
// --- admin sessions ---
func (db *DB) CreateSession(id string, adminID int64, ttl time.Duration) error {