feat(auth): data-driven password requirement checkers
Release / build-and-push (push) Successful in 3m4s

GET /api/auth/password-rules (public, pre-auth) exposes the ACTIVE
complexity config from the settings registry; password_validation.ts
now fetches it and generates the checklist rows per active rule —
inactive requirements no longer linger as fake tasks, and the min
length mirrors the admin's setting instead of a hardcoded 8.

Surfaces: register, setup, admin create-user (Users page), profile
password change (self + admin variants, now gated on checklist pass;
misleading minlength=6 dropped — the server was always the enforcer).

Verified live: flip min_length=12 / number+special off via the
settings API → endpoint + register/profile/admin checklists re-render
row-for-row; enforcement follows (short rejected, rule-valid accepted
without digits/specials); restore defaults → checklists return.
This commit is contained in:
John O'Keefe committed 2026-10-14 11:08:12 -04:00
1 parent d95814ded3
commit df556d8208
10 files changed
+218 -156

No files matched your search

+2 -20
View File
@@ -49,26 +49,8 @@ templ adminCreateUserForm() {
</div>
<div class="sm:col-span-2 lg:col-span-3" style="color: var(--text-secondary)">
<p class="font-semibold mb-2 text-xs uppercase tracking-wide">Password Requirements</p>
<ul class="grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-1 text-xs">
<li id="req-length" class="flex items-center gap-2">
<span class="requirement-icon">○</span> At least 8 characters
</li>
<li id="req-upper" class="flex items-center gap-2">
<span class="requirement-icon">○</span> One uppercase letter
</li>
<li id="req-lower" class="flex items-center gap-2">
<span class="requirement-icon">○</span> One lowercase letter
</li>
<li id="req-number" class="flex items-center gap-2">
<span class="requirement-icon">○</span> One number
</li>
<li id="req-special" class="flex items-center gap-2">
<span class="requirement-icon">○</span> One special character
</li>
<li id="req-match" class="flex items-center gap-2">
<span class="requirement-icon">○</span> Passwords match
</li>
</ul>
<!-- rows generated from the ACTIVE rules by password_validation.ts -->
<ul id="password-requirements-admin" class="grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-1 text-xs"></ul>
</div>
<div class="sm:col-span-2 lg:col-span-3">
<button type="submit" id="create-user-submit" class="btn btn-primary text-sm px-4 py-2 opacity-50 cursor-not-allowed" disabled>Create User</button>