- 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>
35 lines
1.2 KiB
HTML
35 lines
1.2 KiB
HTML
{{define "base"}}<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<title>{{block "title" .}}MCIAS{{end}}</title>
|
|
<link rel="stylesheet" href="/static/style.css">
|
|
</head>
|
|
<body hx-headers='{"X-CSRF-Token": "{{.CSRFToken}}"}'>
|
|
<nav>
|
|
<div class="nav-inner">
|
|
<span class="nav-brand">MCIAS</span>
|
|
<ul class="nav-links">
|
|
<li><a href="/dashboard">Dashboard</a></li>
|
|
<li><a href="/accounts">Accounts</a></li>
|
|
<li><a href="/audit">Audit</a></li>
|
|
<li><a href="/policies">Policies</a></li>
|
|
<li><a href="/pgcreds">PG Creds</a></li>
|
|
{{if .ActorName}}<li><a href="/profile">{{.ActorName}}</a></li>{{end}}
|
|
<li><form method="POST" action="/logout" style="margin:0"><button class="btn btn-sm btn-secondary" type="submit">Logout</button></form></li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
<main>
|
|
<div class="container">
|
|
{{if .Error}}<div class="alert alert-error" role="alert">{{.Error}}</div>{{end}}
|
|
{{if .Flash}}<div class="alert alert-success" role="status">{{.Flash}}</div>{{end}}
|
|
{{block "content" .}}{{end}}
|
|
</div>
|
|
</main>
|
|
<script src="/static/htmx.min.js"></script>
|
|
</body>
|
|
</html>
|
|
{{end}}
|