feat(auth): live per-rule password feedback + breach check on /register + /reset-password (BUNYIP-240) #265
No reviewers
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
psa-systems/bunyip!265
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/BUNYIP-240-inline-password-feedback"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
User feedback: clicking Create Account on /register and only then learning the password was rejected (with the field blanked for re-entry) is bad UX. Same on /reset-password. The fix is inline, in-page feedback while the user types.
Restructured
pw_reqs()to render four<li>rows with stable IDs (pw-len,pw-case,pw-digit,pw-breach) and a leading indicator glyph slot. New inlinepassword_live_validation_script()block attaches aninputlistener to the password field and toggles each row between pending (○) / pass (✓ teal) / fail (✗ destructive) on every keystroke. The first three rules mirror the server-sidepassword_ok()rules verbatim (length 12, both cases, digit + special). The fourth row runs a HaveIBeenPwned k-anonymity lookup: SHA-1 the password client-side via Web Crypto, send only the first 5 hex chars to api.pwnedpasswords.com/range/, scan the response for the matching 35-char suffix. The full password never leaves the browser. Debounced 500ms so per-keystroke HIBP traffic is bounded.Confirm-password field gets a live match/mismatch indicator under it. Create Account button is disabled until all four indicators are green AND the confirm matches; server-side
password_ok()stays the non-JS backstop.CSP
connect-srcextended in bunyip-web/src/security.rs withhttps://api.pwnedpasswords.comso the fetch isn't blocked, with a new unit test pinning the substring against future tightening.Email value is preserved on server-side rejection so the user does not have to retype it (the password fields stay blank on re-render, which is the standard pattern - browsers refuse to render persisted password values for autofill safety anyway).
Same treatment applied to /reset-password confirm form (pw_reqs() is reused; the script is reusable as-is since it binds by ID).
#BUNYIP-240