feat(accounts): answer an MFA step-up with a code from the vault - #23
Merged
Conversation
The server's bare STEP_UP_REQUIRED now reads as a password demand, and an account can name a one-time code already in the vault, which the manager uses to satisfy an MFA demand without asking anyone. Only the item id is stored; the seed stays where it is.
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two things, both from the
STEP_UP_REQUIREDtrace on a live endpoint.The bare code was falling through. #22 only matched the typed suffixes, but the generated guard in constructive-db (
guard_step_up.sql,require_step_up.sql) also raises a bareSTEP_UP_REQUIRED, which means "this session has no recent password verification" — so it maps to the password factor:Same fix in
apps/desktop/src/shared/step-up.ts, since an IPC error reaches the renderer as plain text and the server's own code is the only trustworthy thing to key off.The vault now answers the code demand itself. An account can name a one-time code it already holds, and
withStepUpreaches for it before giving up:So a linked account never sees the step-up dialog for
_MFAat all — the request is held and replayed exactly as before, just without a human in the middle. A password demand is deliberately excluded: onlyfresh_authalso accepts a code.What's stored is the item id and nothing else —
totp_item_idon the account item, no copy of the seed, andlinkTotprefuses an item that isn't a code or carries nototp_seedfield. A link whose item has left the vault is dropped on the next read rather than erroring. The code itself is generated per demand and never written anywhere.Surfaces: Link a code / Unlink code on each account card in the app (with the linked code's title shown on the card), and
dcrypt account link-code <email> <code>/unlink-code <email>.Also: the rebuild test compared a TOTP code taken either side of a ~9s rebuild, so it failed whenever the pair straddled a 30s window (it did, on this run). It now compares the decrypted seed, which is what "carried every row across" actually means.
Link to Devin session: https://app.devin.ai/sessions/04636534e07048089ffb6b78142e12cd
Requested by: @pyramation