VAPP-13: 2FA enrollment UI: TOTP and WebAuthn passkeys #11
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/2fa-enrollment-ui-vapp-13"
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?
VAPP-13: 2FA enrollment UI: TOTP and WebAuthn passkeys
Adds a Security card to Settings that enrolls/confirms/disables TOTP and registers WebAuthn passkeys. Every call proxies vervain-server's session-gated 2FA routes through a server fn that forwards the
vervain_sessiontoken as themc_sessioncookie the server expects (same pattern as the existingloginproxy), because the browser does not hold that cookie on the vervain-server origin.What changed
src/server_fns/mod.rs):get_2fa_statusreads the sentinel-replaceduserinfoframe from the control-channel connect burst (otpsecret->1when set,otphkeys-> passkey count, so no secret crosses the wire);totp_start/totp_confirm/totp_disableproxyPOST /2fa/totp/*;webauthn_register_start/webauthn_register_finishproxyPOST /webauthn/register/*. Sharedpost_authedattaches the forwarded cookie;ok_or_bodyforwards the server's own error bodies (e.g. "code did not verify") to inline UI errors, and a 401 maps to the auth marker so the existing sign-in banner appears.render_totp_qr_svgencodes theotpauthURI with the pure-Rustqrcodecrate (default features off, so neither the image nor svg renderer crate is pulled) and builds a standalone inline SVG by hand from the module matrix.src/webauthn.rs): runs in the wasm client through a small JS shim inlined bywasm-bindgen(bundled into the wasm, no external script). It base64url-decodes thewebauthn-rschallenge into theArrayBuffersnavigator.credentials.createexpects, runs the ceremony, and re-encodes the attestation into theRegisterPublicKeyCredentialJSONregister/finishdeserializes. ANotAllowedError(cancel/timeout) and other browser errors surface inline.web-syswas avoided because its WebAuthn dictionaries are gated behind theweb_sys_unstable_apiscfg, which would change the CI build invocation.src/components/pages/settings.rs):SecurityCarddrives all four flows with busy/error state, a two-click confirm gate for disabling (in place of a JS dialog), the QR + manual-secret + code-confirm enroll panel, and a passkey count that refreshes after each registration. New modelsTwoFactorStatusandTotpEnrollment.Acceptance criteria
/2fa/totp/confirm, which persists the secret so the next login demands a code (login page already prompts)./2fa/totp/disable, removing the requirement.userinfo.otphkeys) refreshes on success.NotAllowedError) render inline errors.Verification
just checkpasses:cargo fmt --check,cargo clippy --all-targets --features server -- -D warnings,cargo check --features server,cargo check --target wasm32-unknown-unknown, andcargo test(added a unit test asserting the TOTP QR SVG is self-contained).Not exercised here: the behavioral criteria (QR scans in a real authenticator, the next login demanding the code, the passkey ceremony completing on real hardware) need a running vervain-server and a browser, which this environment cannot run. Those are left for live review.
🤖 Generated with Claude Code