From d522ba10a82634a3f8eec71ffcc43ae5d968a642 Mon Sep 17 00:00:00 2001 From: Jage9 Date: Fri, 27 Feb 2026 19:15:13 -0500 Subject: [PATCH] Protect user role from deletion and use action sound asset --- client/public/version.js | 2 +- client/src/main.ts | 6 +++--- server/app/auth_service.py | 4 ++-- server/tests/test_auth_service.py | 11 +++++++++++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/client/public/version.js b/client/public/version.js index 7ee4608..7d3cc10 100644 --- a/client/public/version.js +++ b/client/public/version.js @@ -1,5 +1,5 @@ // Maintainer-controlled web client version. // Format: YYYY.MM.DD Rn (example: 2026.02.20 R2) -window.CHGRID_WEB_VERSION = "2026.02.27 R294"; +window.CHGRID_WEB_VERSION = "2026.02.27 R295"; // Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid. window.CHGRID_TIME_ZONE = "America/Detroit"; diff --git a/client/src/main.ts b/client/src/main.ts index 9d3d845..255df3d 100644 --- a/client/src/main.ts +++ b/client/src/main.ts @@ -238,7 +238,7 @@ const SYSTEM_SOUND_URLS = { logout: withBase('sounds/logout.ogg'), notify: withBase('sounds/notify.ogg'), } as const; -const ACTION_SOUND_URL = SYSTEM_SOUND_URLS.notify; +const ACTION_SOUND_URL = withBase('sounds/action.ogg'); const FOOTSTEP_SOUND_URLS = Array.from({ length: 11 }, (_, index) => withBase(`sounds/step-${index + 1}.ogg`)); const FOOTSTEP_GAIN = 0.7; const TELEPORT_START_SOUND_URL = withBase('sounds/teleport_start.ogg'); @@ -2803,8 +2803,8 @@ function handleAdminRolePermissionListModeInput(code: string, key: string): void if (control.type === 'select') { const value = entries[adminRolePermissionIndex]; if (value === '__delete_role__') { - if (role.name === 'admin') { - updateStatus('Admin role cannot be deleted.'); + if (role.name === 'admin' || role.name === 'user') { + updateStatus('Admin and user roles cannot be deleted.'); audio.sfxUiCancel(); return; } diff --git a/server/app/auth_service.py b/server/app/auth_service.py index bbe6135..e15c7d5 100644 --- a/server/app/auth_service.py +++ b/server/app/auth_service.py @@ -330,8 +330,8 @@ class AuthService: normalized_role = self._normalize_role_name(role_name) normalized_replacement = self._normalize_role_name(replacement_role_name) - if normalized_role == "admin": - raise AuthError("Admin role cannot be deleted.") + if normalized_role in {"admin", "user"}: + raise AuthError("Admin and user roles cannot be deleted.") if normalized_role == normalized_replacement: raise AuthError("Replacement role must differ from deleted role.") diff --git a/server/tests/test_auth_service.py b/server/tests/test_auth_service.py index afa8aaf..e615fbe 100644 --- a/server/tests/test_auth_service.py +++ b/server/tests/test_auth_service.py @@ -67,3 +67,14 @@ def test_login_missing_user_runs_dummy_verify(monkeypatch: pytest.MonkeyPatch, t assert calls[0][0] == "password99" finally: service.close() + + +def test_delete_role_rejects_admin_and_user(tmp_path: Path) -> None: + service = make_auth_service(tmp_path) + try: + with pytest.raises(AuthError): + service.delete_role("admin", "editor") + with pytest.raises(AuthError): + service.delete_role("user", "editor") + finally: + service.close()