feat(2fa): auto-submit six-digit TOTP code fields (BUNYIP-331) #323
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/BUNYIP-331-2fa-autosubmit"
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?
What
Six-digit TOTP fields now auto-submit their form the moment a complete code is present (typed, pasted, or platform-autofilled), so the user does not click a button to finish 2FA. Implements BUNYIP-331; realizes the governance Authentication UX Standard from GOV-19.
How
OTP_AUTOSUBMIT_JSin the base document head (bunyip-web/src/views/layout.rs), next to the existing theme/toast blocks. One delegatedinputlistener matchesinput[data-otp-autosubmit]; when the value matches exactly^[0-9]{6}$andform.checkValidity()passes, it sets a per-form in-flight flag and callsform.requestSubmit(). CSP already permits the inline block (script-src 'self' 'unsafe-inline',security.rs)./login/2fa(auth_pages.rs) and the 2FA setup-confirm field (dashboard.rs)./login/2fatrust-device checkbox above the code input so it stays reachable (a complete code now auto-submits before a checkbox below it could be reached on autofill).fillTotpStephelper:setInputValuedispatches a bubblinginputevent, so the form now auto-submits on fill. The helper waits for the navigation off/login/2faand only clicks the submit button as a fallback, so it never double-POSTs (which would trip the2fa_verifyrate limit and TOTP replay).Why these fields only
The combined
totp_codesensitive-op forms (change email/password, disable 2FA, delete account, admin reset) are intentionally NOT opted in: they also accept dashed recovery codes and sit last in multi-input forms, so auto-firing there adds no required behavior. The snippet is generic, so any such field can opt in later by addingdata-otp-autosubmit. The^[0-9]{6}$gate means a recovery code would never auto-submit even if one were opted in.Recovery-code safety
The exact six-digit regex never matches
XXXX-XXXXrecovery codes (verified:ABCD-EFGH,12-3456, partial, and overlong inputs all return false).Verification
just check-container(dockerized):cargo fmt --check,cargo clippy --workspace --all-targets -D warnings, andcargo test --workspace --liball pass (286 tests green). Maud/Rust edits compile clean.node --check; regex validated against sample codes.login.tschange is reviewed but not executed locally (e2enode_modulesnot installed here). It uses standard Playwright APIs; please let CI exercise the auth suite.Related
psa-systems/mokosh-clientsno longer exists), so there is nothing to change there.#BUNYIP-331
Add a shared, opt-in client snippet (OTP_AUTOSUBMIT_JS) to the base document head that submits a form the moment a six-digit TOTP field is complete, so the user no longer clicks a button to finish 2FA. A single delegated input listener matches any input[data-otp-autosubmit] and calls form.requestSubmit() when the value matches exactly ^[0-9]{6}$; the exact-six-digit gate keeps dashed recovery codes from ever auto-submitting, and a form.checkValidity() gate plus a per-form in-flight flag prevent half-submits and double submits. The input event also fires on paste and OS/browser OTP autofill, so a one-tap autofill submits too. CSP already allows the inline block (script-src 'unsafe-inline'). Opt the two dedicated six-digit fields in via data-otp-autosubmit: the /login/2fa challenge and the 2FA setup-confirm field. The combined totp_code sensitive-op forms are intentionally left out (they also accept recovery codes and sit last in multi-field forms); the snippet stays generic so they can opt in later. Reorder the /login/2fa trust-device checkbox above the code input so the choice stays reachable, since a complete code now auto-submits before a checkbox below it could be reached on autofill. Update the e2e fillTotpStep helper: setInputValue dispatches a bubbling input event, so the form now auto-submits on fill; wait for the navigation off /login/2fa and only click the submit button as a fallback, so the helper never double-POSTs (which would trip the 2fa_verify rate limit and TOTP replay). #BUNYIP-331 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>