-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
fix: back up logic to clear vault before reapplying #14743
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good! I'd just update/add the proper unit tests
app/core/BackupVault/backupVault.ts
Outdated
); | ||
try { | ||
// Clear any existing vault backup first to prevent "item already exists" errors | ||
await resetVaultBackup(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While talking to @ccharly, he pointed out that this solution would be more robust if we save two copies of the vault. In the edge case that we execute resetVaultBackup
and setInternetCredentials
fails, there will be an extra copy that can still be retrieved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented a temporary secondary backup while reseting the primary for now based on our convo - https://consensys.slack.com/archives/C08PN631R0X/p1745884192737909
…ault-backup-error
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
|
|
Description
Root Cause of the Issue
backupVault
unconditionally callssetInternetCredentials
, failing whenVAULT_BACKUP_KEY
already exists in the keychain due to repeatedKEYRING_STATE_CHANGE_EVENT
triggers.The Engine class is initialized, setting up the vault backup mechanism.
The
Engine
class constructor callsthis.handleVaultBackup()
to subscribe to keyring state changes, initiating the backup process.(See app/core/Engine/Engine.ts)
The Engine subscribes to the KEYRING_STATE_CHANGE_EVENT.
This subscription means that whenever the keyring's state changes, the associated callback function will be executed, potentially triggering a vault backup.
(See app/core/Engine/Engine.ts)
The keyring state changes, and the new state contains a vault.
This event signifies that the keyring's vault data has been loaded or modified, prompting a backup. This could happen on unlock, account creation, or import.
(See app/core/Engine/Engine.ts)
The handleVaultBackup function is triggered, calling backupVault.
The subscription callback in
handleVaultBackup
is executed, leading to the invocation of thebackupVault
function with the current keyring state.(See app/core/Engine/Engine.ts)
The backupVault function attempts to store the vault in the keychain without checking for existing credentials.
The
backupVault
function directly callssetInternetCredentials
withVAULT_BACKUP_KEY
,VAULT_BACKUP_KEY
, and the vault data, without verifying if an entry with that key already exists. This is the most critical step leading to the error.(See app/core/BackupVault/backupVault.ts)
The setInternetCredentials function throws an error because the keychain item already exists.
Since a vault backup already exists in the keychain (from a previous keyring state change),
setInternetCredentials
throws an error, halting the backup process.(See node_modules/react-native-keychain/index.js)
Changes
Back up temporary vault before re-applying primary vault
Since the primary vault needs to be reset before a new one is applied, we added a fail safe (in
backupVault
function) by first backing up a temporary version of the vault. In the event of failure when attempting to reset and/or re-apply the vault, the temporary one would still be available as the fallback. If the vault is successfully re-applied, then the temporary vault is reset immediately afterwards.Clear any existing vault backup before creating a new one to avoid keychain errors.
This line calls the
_resetVaultBackup
function to delete any existing keychain entry associated withVAULT_BACKUP_KEY
before attempting to create a new one. This prevents the "Keychain item already exists" error.(See app/core/BackupVault/backupVault.ts)
Implement error handling to prevent app crashes during vault backup.
This code adds a
try...catch
block around the vault backup logic. If any error occurs during the backup process, it will be caught, logged, and a failure response will be returned, preventing the app from crashing.(See app/core/BackupVault/backupVault.ts)
Debounce
backupVault
calls in KeyringController state change subscriptionSince this event is triggered may be triggered multiple times in quick succession, we added a debounce mechanism to prevent multiple asynchronous calls for updating the vault
Related issues
Fixes: #9419
Manual testing steps
Screenshots/Recordings
Before
After
iOS
vault.backup.mov
Android
Pre-merge author checklist
vault.backup.android.mov
Pre-merge reviewer checklist