fix: harden auth and fix frontend issues

- Add builtin admin user with full access, immutable permissions (lib/db.py, lib/auth_users.py, webui/static/pages/users.js)
- Fix passkeys TypeError on string throws (webui/static/pages/passkeys.js)
- Add zero-permission warning in create user modal (webui/static/pages/users.js)
- Restore readonly on proxy paths textarea (webui/static/pages/proxy.js)
- Mask credential ownership errors to prevent enumeration (lib/webauthn.py, tests/test_auth.py)
This commit is contained in:
2026-07-28 18:52:03 +00:00
parent a82578f342
commit 8ae60ab8cf
7 changed files with 78 additions and 22 deletions
+30
View File
@@ -18,6 +18,7 @@ from __future__ import annotations
import logging
import os
import secrets
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Any, ClassVar
@@ -271,11 +272,40 @@ def get_db() -> Database:
_db_instance = SQLiteBackend(path)
Path(path).parent.mkdir(parents=True, exist_ok=True)
_db_instance.init_tables()
_seed_builtin_admin(_db_instance)
else:
raise ValueError(f"Unknown database backend: {backend!r}")
return _db_instance
def _seed_builtin_admin(db: Database) -> None:
"""Create the builtin admin user if they don't exist.
The builtin admin has full (rw) access to all subsystems and cannot
be deleted or have permissions modified through the normal API.
"""
from lib.auth_users import ALL_SUBSYSTEMS, BUILTIN_ADMIN_USERNAME
from lib.password import hash_password
# Check if admin already exists
rows = db.query(Q_SELECT_USER_BY_NAME, (BUILTIN_ADMIN_USERNAME,))
if rows:
return
# Create with a placeholder password that should be changed
placeholder_hash = hash_password("CHANGEME")
jwt_secret = secrets.token_urlsafe(32)
with db.in_transaction() as tx:
tx.run_one(
Q_INSERT_USER, (BUILTIN_ADMIN_USERNAME, placeholder_hash, jwt_secret)
)
for subsystem in ALL_SUBSYSTEMS:
tx.run(Q_UPSERT_PERMISSION, (BUILTIN_ADMIN_USERNAME, subsystem, "rw"))
logger.info("Builtin admin user created with full access")
def reset_db_for_test() -> None:
"""Reset the singleton — only for tests."""
global _db_instance