fix auth: validate logout body, harden WebAuthn, optimize list_users

- Raise ValueError on missing request body in auth_logout
- Add username check in verify_authentication to prevent credential reuse
- Replace N+1 queries in list_users with single JOIN query
This commit is contained in:
2026-08-12 03:58:54 +00:00
parent ba0c7bfa9b
commit 6f728cf853
5 changed files with 24 additions and 13 deletions
+13 -12
View File
@@ -19,9 +19,9 @@ from lib.db import (
Q_DELETE_PERMISSIONS,
Q_DELETE_USER,
Q_INSERT_USER,
Q_SELECT_ALL_USERS,
Q_SELECT_PERMISSIONS,
Q_SELECT_USER_BY_NAME,
Q_SELECT_USERS_WITH_PERMS,
Q_UPDATE_PASSWORD,
Q_UPSERT_PERMISSION,
get_db,
@@ -244,21 +244,22 @@ def list_users() -> list[dict[str, Any]]:
List of user summary dicts.
"""
db = get_db()
rows = db.query(Q_SELECT_ALL_USERS, ())
rows = db.query(Q_SELECT_USERS_WITH_PERMS, ())
result = []
users: dict[int, dict[str, Any]] = {}
for row in rows:
username = row["username"]
permissions = _get_permissions(username)
result.append(
{
"id": row["id"],
"username": username,
"permissions": permissions,
uid = row["id"]
if uid not in users:
users[uid] = {
"id": uid,
"username": row["username"],
"permissions": {},
"created_at": row["created_at"],
}
)
return result
if row["subsystem"] is not None:
users[uid]["permissions"][row["subsystem"]] = row["level"]
return list(users.values())
def delete_user(username: str) -> bool:
+1
View File
@@ -53,6 +53,7 @@ Q_SELECT_WEBAUTHN_COUNTS = "select_webauthn_counts"
Q_DELETE_WEBAUTHN = "delete_webauthn"
Q_UPDATE_WEBAUTHN_SIGN_COUNT = "update_webauthn_sign_count"
Q_SELECT_ALL_USERS = "select_all_users"
Q_SELECT_USERS_WITH_PERMS = "select_users_with_perms"
Q_SELECT_USER_JWT_SECRET = "select_user_jwt_secret"
Q_UPDATE_JWT_SECRET = "update_jwt_secret"
+6
View File
@@ -27,6 +27,7 @@ from lib.db import (
Q_SELECT_USER_BY_ID,
Q_SELECT_USER_BY_NAME,
Q_SELECT_USER_JWT_SECRET,
Q_SELECT_USERS_WITH_PERMS,
Q_SELECT_WEBAUTHN_COUNTS,
Q_SELECT_WEBAUTHN_ID,
Q_SELECT_WEBAUTHN_USER,
@@ -70,6 +71,11 @@ class SQLiteBackend(Database):
Q_SELECT_ALL_USERS: (
"SELECT id, username, created_at FROM users ORDER BY username"
),
Q_SELECT_USERS_WITH_PERMS: (
"SELECT u.id, u.username, u.created_at, p.subsystem, p.level "
"FROM users u LEFT JOIN permissions p ON u.username = p.username "
"ORDER BY u.username"
),
Q_SELECT_USER_JWT_SECRET: ("SELECT jwt_secret FROM users WHERE username = ?"),
Q_UPDATE_JWT_SECRET: ("UPDATE users SET jwt_secret = ? WHERE username = ?"),
# Permissions
+3
View File
@@ -324,6 +324,9 @@ def verify_authentication(
raise ValueError("Credential not found")
cred_row = cred_rows[0]
if cred_row["username"] != username:
raise ValueError("Credential not found")
public_key = b64u_decode(cred_row["public_key"])
old_sign_count = cred_row["sign_count"]