fix: Map reset-token verification failures to their dedicated variants #75

Merged
rosa merged 1 commit from fix/reset-token-error-mapping into main 2026-07-03 21:41:40 +00:00
Owner

Fixes #54.

reset_password wrapped Confirmation::verify_nouser failures in an anyhow context, funnelling ConfirmationError::Expired and verifier mismatches into ResetPasswordError::Unknown, which the web layer renders as a 500. A user clicking a reset link after the 30-minute window got a generic 500 page instead of a link-expired message.

Changes

  • Added a From<ConfirmationError> for ResetPasswordError conversion: Expired maps to ConfirmationExpired, VerifierMismatch to ConfirmationVerifierMismatch, not-found/ID-mismatch cases to ConfirmationNotFound, InvalidAction to InvalidTokenAction, and Unknown stays Unknown.
  • reset_password now propagates verify_nouser failures through that conversion instead of .with_context(...), so expired/forged tokens render the existing invalid-confirmation (4xx) response. Genuine faults (repository errors, hashing) still surface as Unknown/500.
  • No web-layer changes: the From<ResetPasswordError> for AppError arms already mapped the dedicated variants to AppError::InvalidConfirmation.
  • Checked get_confirmation_by_token (form-rendering path) for consistency: it already returns ConfirmationError directly, which the web layer maps to the invalid-confirmation response, so no change was needed there.

Tests

  • Unit tests for the mapping of each ConfirmationError variant reachable from verify_nouser (Expired, VerifierMismatch, IdMismatch), plus Unknown staying Unknown.
  • Service-level tests: resetting with an expired token yields ConfirmationExpired; presenting the right confirmation ID with the wrong verifier yields ConfirmationVerifierMismatch.
Fixes #54. `reset_password` wrapped `Confirmation::verify_nouser` failures in an anyhow context, funnelling `ConfirmationError::Expired` and verifier mismatches into `ResetPasswordError::Unknown`, which the web layer renders as a 500. A user clicking a reset link after the 30-minute window got a generic 500 page instead of a link-expired message. ## Changes - Added a `From<ConfirmationError> for ResetPasswordError` conversion: `Expired` maps to `ConfirmationExpired`, `VerifierMismatch` to `ConfirmationVerifierMismatch`, not-found/ID-mismatch cases to `ConfirmationNotFound`, `InvalidAction` to `InvalidTokenAction`, and `Unknown` stays `Unknown`. - `reset_password` now propagates `verify_nouser` failures through that conversion instead of `.with_context(...)`, so expired/forged tokens render the existing invalid-confirmation (4xx) response. Genuine faults (repository errors, hashing) still surface as `Unknown`/500. - No web-layer changes: the `From<ResetPasswordError> for AppError` arms already mapped the dedicated variants to `AppError::InvalidConfirmation`. - Checked `get_confirmation_by_token` (form-rendering path) for consistency: it already returns `ConfirmationError` directly, which the web layer maps to the invalid-confirmation response, so no change was needed there. ## Tests - Unit tests for the mapping of each `ConfirmationError` variant reachable from `verify_nouser` (`Expired`, `VerifierMismatch`, `IdMismatch`), plus `Unknown` staying `Unknown`. - Service-level tests: resetting with an expired token yields `ConfirmationExpired`; presenting the right confirmation ID with the wrong verifier yields `ConfirmationVerifierMismatch`.
fix: Map reset-token verification failures to their dedicated variants
Some checks failed
ci/woodpecker/pr/test Pipeline was canceled
ci/woodpecker/push/test Pipeline was successful
b67dec44f9
reset_password wrapped Confirmation::verify_nouser failures in an anyhow
context, funnelling ConfirmationError::Expired and verifier mismatches
into ResetPasswordError::Unknown, which the web layer renders as a 500.
Convert per variant instead, so an expired or forged reset link renders
the existing invalid-confirmation (4xx) response. Genuine faults still
surface as Unknown.

Fixes #54
rosa force-pushed fix/reset-token-error-mapping from b67dec44f9
Some checks failed
ci/woodpecker/pr/test Pipeline was canceled
ci/woodpecker/push/test Pipeline was successful
to 6a0f30d178
Some checks are pending
ci/woodpecker/pr/test Pipeline is pending
ci/woodpecker/push/test Pipeline is pending
2026-07-03 21:41:27 +00:00
Compare
rosa merged commit 2e1fe01d71 into main 2026-07-03 21:41:40 +00:00
rosa deleted branch fix/reset-token-error-mapping 2026-07-03 21:41:40 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
rosa/vernier!75
No description provided.