The by-id user-management handlers use findById, which has no role
filter, so supplying the synthetic GUEST_USER_ID let an admin delete,
re-role, reset-password, and read/write permissions on the shared guest
principal (privilege-escalation / DoS / credential-login holes).
- web/api/users.ts: 404-guard every :id handler against GUEST_USER_ID
(DELETE, reset-password, role, GET/PUT permissions).
- data/users.ts: defense-in-depth — setRoleIfNotLastAdmin and
deleteUserIfNotLastAdmin return "not_found" for any role=guest row.
- web/api/session.ts: wrap POST /guest createSession in try/catch so a
missing guest row yields 503 instead of an unhandled 500.
- Tests: data-layer guest-protection + users-router 404 by-id guards.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Consolidated fix wave from the final whole-branch review of guest mode.
- FIX 1 (critical): gate /api/favorites mount with requireNotGuest — the
router keys off req.user.id (shared __guest__ principal), so guests could
read/write a shared favorites bucket. Added focused guest-deny tests.
- FIX 2: gate GET /api/auth/status and /api/auth/qrcode/status with
requireNotGuest so config reads no longer leak to guests.
- FIX 3: requireAuthInline in createSessionRouter now rejects guest sessions
with 401 once guest mode is disabled (mirrors createRequireAuth), so /me
stops returning guest data after an admin disables the feature.
- FIX 4: Login guest button now sits BELOW the card (auth-page flex-direction
column + guest-btn width 360px) instead of beside it.
- FIX 5: mobile mini-player transport buttons in App.vue are now per-button
gated for guests (prev/play/next/mode/volume), mirroring Player.vue.
- FIX 6: refreshed stale "gated on player.control" seek comments in Player.vue
and relabeled the now-stale quality-GET test.
npm test: 354/354 pass. npm run build: tsc + vue-tsc + vite all green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds an admin/member role to WebUI auth. /api/users and /api/audit
are now gated by a requireAdmin middleware; all other authenticated
endpoints accept both roles. Schema migration defaults all existing
users to admin to preserve access. POST /api/users defaults new users
to member; first-run setup always creates an admin. Adds PATCH
/api/users/:id/role with last-admin demotion and deletion guards.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>