Add user management with admin and viewer roles

- data/users.json store; existing single account migrates to first admin
- Roles: admin (settings, import, users) and viewer (read-only, own password)
- Live role/disabled lookup; per-user session epoch so password changes,
  resets and disabling sign that user out everywhere
- Login brute-force lockout (5 fails -> 5 min), constant-time unknown-user check
- /api/users CRUD with last-admin and self-lockout safeguards
- Account page (own password + admin user management); role-aware header
- Min password length 8; recovery token resets the primary admin and clears lockouts

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Nate EmmertandClaude Sonnet 5.5 committed 2026-10-15 12:34:13 -04:00
1 parent b3f1061f5c
commit 1566ac2897
7 files changed
+442 -93

No files matched your search

+2 -2
View File
@@ -38,12 +38,12 @@ button:hover { opacity: 0.88; }
<code>Dashboard recovery token:</code><br>
In CasaOS, open the app's log from the container details panel. The token changes daily.
</div>
<div id="err" class="error" style="display:none">Invalid token or password too short (min 6 chars).</div>
<div id="err" class="error" style="display:none">Invalid token or password too short (min 8 chars). This resets the primary admin account.</div>
<form method="POST" action="/dashboard/recover">
<label>Recovery Token</label>
<input name="token" type="text" autocomplete="off" spellcheck="false" autofocus required placeholder="Paste token from server logs">
<label>New Password</label>
<input name="password" type="password" autocomplete="new-password" required minlength="6">
<input name="password" type="password" autocomplete="new-password" required minlength="8">
<button type="submit">Set New Password</button>
</form>
<a href="/dashboard/login" class="back">← Back to sign in</a>