Wallet password protection - #764
Open
dkackman wants to merge 59 commits into
Open
Conversation
Design for issue xch-dev#206: opt-in per-operation password protection for wallet secret access, transaction signing, and hardened key generation. Includes biometric convenience layer design. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
10-task plan covering keychain core changes, API layer modifications, backend endpoint threading, integration tests, and Tauri/frontend skeleton. Includes bincode backward compatibility handling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add password_protected bool field to the Secret variant of KeyData, with LegacyKeyData enum and backward-compatible bincode deserialization in from_bytes(). Update all construction sites to set the flag based on whether a non-empty password was provided. Add is_password_protected() accessor to Keychain. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add change_password() method to Keychain that decrypts with the old password and re-encrypts with a new one, updating the password_protected flag. Add KeyNotFound and NoSecretKey error variants. Include tests for password changing, wrong password rejection, public key rejection, flag-on-import behavior, serialization roundtrip, and legacy format backward compatibility. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add password parameter to sign(), transact(), and transact_with() and thread it from every endpoint request struct through to the keychain. Add change_password endpoint and populate has_password on KeyInfo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace two-step promptIfEnabled + requestPassword auth with unified requestPassword returning string | null | undefined, where undefined means cancelled. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…bels Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Biometric authentication is a global setting (not per-wallet), so it belongs in the Preferences section of GlobalSettings rather than the per-wallet Security section. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dkackman
marked this pull request as draft
March 16, 2026 13:58
Collaborator
Author
Code reviewFound 2 issues:
sage/src/contexts/PasswordContext.tsx Lines 127 to 133 in 815e594
sage/src/components/WalletCard.tsx Lines 81 to 92 in 815e594 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
1. Biometric unlock now works across multiple operations. The skip flag is cleared at the start of requestPassword when the previous keychain password was accepted (i.e., we're called again without a manual dialog entry in between). 2. Delete confirmation dialog now closes when the password prompt is cancelled, matching the Details dialog behavior. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
requestPassword now takes an optional fingerprint parameter for operations on non-active wallets (e.g. WalletCard view details / delete). This ensures keychain lookup and storage use the correct wallet's fingerprint instead of the currently active one. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The skip/lastKeychainFingerprint mechanism had a bug where stale keychain passwords would loop indefinitely (skip cleared on every call, so stale entry retried each time). Removed both refs entirely. The recovery path for stale keychain entries is now: cancel the OS biometric prompt → keychain retrieval fails → password dialog appears → type correct password → handleSubmit updates keychain. Simpler and correct. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the backend rejects a keychain-retrieved password (decrypt error), ErrorContext calls notifyDecryptError() which marks the fingerprint as stale in PasswordContext. The next requestPassword call skips keychain and shows the dialog directly. When the user types the correct password via the dialog, handleSubmit clears the stale flag and updates keychain. This gives the user a recoverable path without needing to know they should cancel the biometric prompt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Collaborator
Author
Code reviewFound 1 issue:
sage/src/contexts/PasswordContext.tsx Lines 158 to 165 in c88b3f9 The fix is to either (a) queue pending requests instead of replacing them, or (b) reject the in-flight request when a new one arrives (so at least the caller fails fast rather than hanging). 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
Remove all keychain password storage — password wallets always use the dialog, biometric is a standalone gate for no-password wallets only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dkackman
marked this pull request as ready for review
March 20, 2026 22:29
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.
fix #206