You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Feature | Recovery code login flow UI (CU-86ba2zp4f)
Close the remaining gaps in the recovery-code MFA login mode.
- onBackToOtp / onUseRecovery clear recoveryCode and errors.recovery along
with the mode switch, so an abandoned attempt is not re-shown when the
user toggles back into recovery mode.
- Recovery field drops autoComplete="one-time-code": that hint makes the OS
offer the e-mailed OTP in the recovery field, which is the wrong
credential and the OTP/recovery confusion risk called out in the ticket.
Added a format hint and copy that distinguishes it from the e-mailed code.
Tests:
- New recovery-code-form.test.js: autocomplete, format hint, disabled
states, inline error, submit, back vs cancel, raw value handed to parent.
- login.mfa.test.js: mode switching + state cleanup, input normalization,
empty/in-flight submits, success redirect, low-codes warning (and its
already-dismissed variant), invalid/used code, mfa_session_expired,
mfa_rate_limit.
- E2E TS-005 fixed (it filled a 16-char code that can never exist) and now
asserts the dash never reaches the endpoint; new TS-009 back-to-OTP,
TS-010 invalid/used code, TS-011 recovery rate limit, TS-012 recovery
session expiry. CI seeds mfa-ts-009..012 for them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: seed mfa-ts-009..012 in the push front-end workflow too
The MFA e2e suite gives every TS-* test its own account because a real
login burns that user's own OTP rate-limit window. TS-009..TS-012 were
added with the seed loop widened only in pull_request_frontend_tests.yml,
so "Front End Tests On Push" logged in as users that do not exist and the
four new tests timed out waiting for the password step.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep the recovery code out of the request URL
verifyRecoveryCode() posted through postRawRequest(), which copies every
param onto the query string in addition to the body (base_actions.js:71).
That writes the recovery code - a credential that completes a login on its
own - into any access log along the path. #146 hit the same trap with
current_password and added the body-only postRawRequestFull() for it;
switch this call to it as well.
TS-005 asserted the code off the query string, which encoded the leak as
the expected contract. It now asserts the body carries the code and the
query string does not, so the fix cannot silently regress.
Also from review:
- the "all 8 tests" comment in the MFA spec had gone stale at 12 tests;
reworded so it does not track a count, and it now states the seed loop
lives in BOTH workflow files (the divergence that broke push CI).
- onBackToOtp()'s comment justified its reset with a clean-field-on-reentry
guarantee that onUseRecovery() already provides; state the real reason,
which is not holding an unspent credential in component state.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
0 commit comments