diff --git a/daemon/handlers/auth.py b/daemon/handlers/auth.py index 6bdf796..b68dc19 100644 --- a/daemon/handlers/auth.py +++ b/daemon/handlers/auth.py @@ -135,7 +135,7 @@ def auth_logout(request: Any, body: Any) -> dict[str, Any]: Success response. """ if not body: - return {} + raise ValueError("Request body is required") jti = body.get("jti") if jti: diff --git a/lib/auth_users.py b/lib/auth_users.py index b6a3abe..f53e9e6 100644 --- a/lib/auth_users.py +++ b/lib/auth_users.py @@ -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: diff --git a/lib/db.py b/lib/db.py index 791f6db..09bfea2 100644 --- a/lib/db.py +++ b/lib/db.py @@ -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" diff --git a/lib/db_sqlite.py b/lib/db_sqlite.py index f99f80a..24fc66f 100644 --- a/lib/db_sqlite.py +++ b/lib/db_sqlite.py @@ -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 diff --git a/lib/webauthn.py b/lib/webauthn.py index aec6141..458a1a0 100644 --- a/lib/webauthn.py +++ b/lib/webauthn.py @@ -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"]