Files
mcias/web/templates/profile.html
Kyle Isom f262ca7b4e UI: password change enforcement + migration recovery
- Web UI admin password reset now enforces admin role
  server-side (was cookie-auth + CSRF only; any logged-in
  user could previously reset any account's password)
- Added self-service password change UI at GET/PUT /profile:
  current_password + new_password + confirm_password;
  server-side equality check; lockout + Argon2id verification;
  revokes all other sessions on success
- password_change_form.html fragment and profile.html page
- Nav bar actor name now links to /profile
- policy: ActionChangePassword + default rule -7 allowing
  human accounts to change their own password
- openapi.yaml: built-in rules count updated to -7

Migration recovery:
- mciasdb schema force --version N: new subcommand to clear
  dirty migration state without running SQL (break-glass)
- schema subcommands bypass auto-migration on open so the
  tool stays usable when the database is dirty
- Migrate(): shim no longer overrides schema_migrations
  when it already has an entry; duplicate-column error on
  the latest migration is force-cleaned and treated as
  success (handles columns added outside the runner)

Security:
- Admin role is now validated in handleAdminResetPassword
  before any DB access; non-admin receives 403
- handleSelfChangePassword follows identical lockout +
  constant-time Argon2id path as the REST self-service
  handler; current password required to prevent
  token-theft account takeover

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 15:33:19 -07:00

17 lines
537 B
HTML

{{define "profile"}}{{template "base" .}}{{end}}
{{define "title"}}Profile — MCIAS{{end}}
{{define "content"}}
<div class="page-header">
<h1>Profile</h1>
</div>
<div class="card">
<h2 style="font-size:1rem;font-weight:600;margin-bottom:1rem">Change Password</h2>
<p class="text-muted text-small" style="margin-bottom:.75rem">
Enter your current password and choose a new one. Other active sessions will be revoked.
</p>
<div id="password-change-section">
{{template "password_change_form" .}}
</div>
</div>
{{end}}