feat(account): change your own password on the Account page (milestone 497)
CI / lint (push) Successful in 3s
CI / integration (push) Successful in 1m10s
CI / unit (push) Successful in 1m31s
CI / publish (push) Successful in 1m26s

Step #5428 "Account page: change your own password" of milestone 497
"Passwords: change your own, and reset it by email". A Password section
in the page's one form, for local accounts: current, new, again. Blank
keeps the password; a new one signs out every other browser
(sessions_since) and keeps this one. A wrong current password counts
toward the login throttle. Audited as account.password_changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 20:14:45 -04:00
co-authored by Claude Opus 5.5
parent ea31deabf9
commit ea523b8c37
5 changed files with 204 additions and 11 deletions
+27 -3
View File
@@ -1,6 +1,7 @@
{# account/index.html — the signed-in user's own account (milestone 490): who
they are, the time zone every page writes its times in, and their email
(milestone 495). One form, one Save. #}
they are, the time zone every page writes its times in, their email
(milestone 495) and a local account's password (milestone 497). One form,
one Save. #}
{% extends "base.html" %}
{% from "_macros.html" import page_header, zone_select %}
{% from "account/_email_choices.html" import email_section with context %}
@@ -13,7 +14,8 @@
· times show in <strong>{{ zone_title }}</strong> ({{ zone_label }})
</p>
{% if error %}<div class="alert alert-error" role="alert">{{ error }}</div>{% endif %}
{% if error %}<div class="alert alert-error" role="alert">{{ error }}</div>
{% elif done %}<div class="alert alert-success" role="status">{{ done }}</div>{% endif %}
<form method="post" action="/account/" class="form-page">{{ csrf_field() }}
<section class="card form-section" aria-labelledby="acct-time">
@@ -27,6 +29,28 @@
{{ email_section(user, defaults, "your time zone") }}
<section class="card form-section" aria-labelledby="acct-password">
<h2 id="acct-password" class="section-title">Password</h2>
{% if user.auth_source == "local" %}
<p class="field-hint">Leave these empty to keep your password. A new one signs you out everywhere else you're signed in.</p>
<div class="field">
<label class="field-label" for="acct-pw-now">Current password</label>
<input class="input" id="acct-pw-now" type="password" name="current_password" autocomplete="current-password">
</div>
<div class="field">
<label class="field-label" for="acct-pw-new">New password</label>
<input class="input" id="acct-pw-new" type="password" name="new_password" minlength="{{ min_password }}" autocomplete="new-password">
<span class="field-hint">At least {{ min_password }} characters.</span>
</div>
<div class="field">
<label class="field-label" for="acct-pw-again">New password again</label>
<input class="input" id="acct-pw-again" type="password" name="new_confirm" autocomplete="new-password">
</div>
{% else %}
<p class="field-hint">You sign in with {{ source }}, so your password is changed there, not in Steward.</p>
{% endif %}
</section>
<div class="form-actions"><button type="submit" class="btn">Save</button></div>
</form>
{% endblock %}