From e0d49554f9b60c06e9df315b074be842a47288a6 Mon Sep 17 00:00:00 2001 From: metamaskbot Date: Fri, 18 Apr 2025 15:18:39 -0600 Subject: [PATCH 1/5] re work back up logic to clear vault before reapplying --- app/core/BackupVault/backupVault.ts | 56 +++++++++++++++++------------ 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/app/core/BackupVault/backupVault.ts b/app/core/BackupVault/backupVault.ts index 145676daf2fd..8be42c83dbba 100644 --- a/app/core/BackupVault/backupVault.ts +++ b/app/core/BackupVault/backupVault.ts @@ -24,6 +24,13 @@ interface KeyringBackupResponse { error?: string; } +/** + * removes the vault backup from react-native-keychain + */ +export const resetVaultBackup = async (): Promise => { + await resetInternetCredentials(VAULT_BACKUP_KEY); +}; + /** * places the vault in react-native-keychain for backup * @returns Promise @@ -38,24 +45,34 @@ export async function backupVault( ): Promise { const keyringVault = keyringState.vault as string; - // Backup vault - const backupResult = await setInternetCredentials( - VAULT_BACKUP_KEY, - VAULT_BACKUP_KEY, - keyringVault, - options, - ); + try { + // Clear any existing vault backup first to prevent "item already exists" errors + await resetVaultBackup(); - // Vault backup failed, throw error - if (!backupResult) { - throw new Error(VAULT_BACKUP_FAILED); - } + // Backup vault + const backupResult = await setInternetCredentials( + VAULT_BACKUP_KEY, + VAULT_BACKUP_KEY, + keyringVault, + options, + ); + + // Vault backup failed, throw error + if (!backupResult) { + throw new Error(VAULT_BACKUP_FAILED); + } - // Vault backup successful, return response - return { - success: true, - vault: keyringState.vault, - }; + return { + success: true, + vault: keyringState.vault, + }; + } catch (error) { + Logger.error(error as Error, 'Vault backup failed'); + return { + success: false, + error: error instanceof Error ? error.message : VAULT_BACKUP_FAILED, + }; + } } /** @@ -76,10 +93,3 @@ export async function getVaultFromBackup(): Promise { Logger.error(vaultFetchError, VAULT_FAILED_TO_GET_VAULT_FROM_BACKUP); return { success: false, error: VAULT_FAILED_TO_GET_VAULT_FROM_BACKUP }; } - -/** - * removes the vault backup from react-native-keychain - */ -export const resetVaultBackup = async (): Promise => { - await resetInternetCredentials(VAULT_BACKUP_KEY); -}; From 31e8ea0676f12c0a2e6969e95a1dc44b65effc09 Mon Sep 17 00:00:00 2001 From: Cal-L Date: Mon, 28 Apr 2025 16:43:07 -0700 Subject: [PATCH 2/5] Fully test backupvault file --- app/constants/error.ts | 5 - app/core/BackupVault/backupVault.test.ts | 212 +++++++++++++++++++---- app/core/BackupVault/backupVault.ts | 5 +- app/core/BackupVault/constants.ts | 4 + 4 files changed, 186 insertions(+), 40 deletions(-) create mode 100644 app/core/BackupVault/constants.ts diff --git a/app/constants/error.ts b/app/constants/error.ts index 7c62a667d4e4..b9153738d1ea 100644 --- a/app/constants/error.ts +++ b/app/constants/error.ts @@ -43,11 +43,6 @@ export const AUTHENTICATION_LOGIN_VAULT_CREATION_FAILED = export const VAULT_CREATION_ERROR = 'Error creating the vault'; export const NO_VAULT_IN_BACKUP_ERROR = 'No vault in backup'; -// backupVault -export const VAULT_BACKUP_FAILED = 'Vault backup failed'; -export const VAULT_FAILED_TO_GET_VAULT_FROM_BACKUP = - 'getVaultFromBackup failed to retrieve vault'; - // RPCMethodMiddleware export const TOKEN_NOT_SUPPORTED_FOR_NETWORK = 'This token is not supported on this network'; diff --git a/app/core/BackupVault/backupVault.test.ts b/app/core/BackupVault/backupVault.test.ts index caad44e22ecc..c0a8a594e096 100644 --- a/app/core/BackupVault/backupVault.test.ts +++ b/app/core/BackupVault/backupVault.test.ts @@ -1,7 +1,50 @@ -import { VAULT_BACKUP_FAILED } from '../../constants/error'; -import { backupVault } from './backupVault'; +import { + VAULT_FAILED_TO_GET_VAULT_FROM_BACKUP, + VAULT_BACKUP_KEY, +} from './constants'; +import { + backupVault, + getVaultFromBackup, + resetVaultBackup, +} from './backupVault'; import { KeyringControllerState } from '@metamask/keyring-controller'; -import { setInternetCredentials } from 'react-native-keychain'; +import { + getInternetCredentials, + Options, + resetInternetCredentials, + Result, + setInternetCredentials, +} from 'react-native-keychain'; + +const mockKeychainState: Record< + string, + { username: string; password: string } +> = {}; + +// Mock the react-native-keychain module +jest.mock('react-native-keychain', () => ({ + ...jest.requireActual('react-native-keychain'), + setInternetCredentials: jest.fn( + async ( + server: string, + username: string, + password: string, + _?: Options, + ): Promise => { + mockKeychainState[server] = { username, password }; + return { + service: 'service', + storage: 'storage', + }; + }, + ), + getInternetCredentials: jest.fn( + async (server: string) => mockKeychainState[server], + ), + resetInternetCredentials: jest.fn( + async (server: string, _?: Options) => delete mockKeychainState[server], + ), +})); //TODO Mock the react-native-keychain module test the other functions inside backupVault /* @@ -12,40 +55,145 @@ import { setInternetCredentials } from 'react-native-keychain'; Documentation for the testing react-native-keychain can be found here: https://github.com/oblador/react-native-keychain#unit-testing-with-jest More information on the issue can be found here: https://github.com/oblador/react-native-keychain/issues/460 */ -describe('backupVault', () => { - it('should throw when vault backup fails', async () => { - // Mock the setInternetCredentials function to return false, which simulates a failed vault backup - (setInternetCredentials as jest.Mock).mockResolvedValue(false); - - const keyringState: KeyringControllerState = { - vault: undefined, - keyrings: [], - isUnlocked: false, - keyringsMetadata: [], - }; - - expect(async () => await backupVault(keyringState)).rejects.toThrow( - VAULT_BACKUP_FAILED, - ); +describe('backupVault file', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('resetVaultBackup', () => { + it('should reset vault backup', async () => { + const dummyPassword = 'dummy-password'; + + await setInternetCredentials( + VAULT_BACKUP_KEY, + VAULT_BACKUP_KEY, + dummyPassword, + ); + + const internetCredentialsBeforeReset = await getInternetCredentials( + VAULT_BACKUP_KEY, + ); + + expect(internetCredentialsBeforeReset).toEqual({ + username: VAULT_BACKUP_KEY, + password: dummyPassword, + }); + + await resetVaultBackup(); + + const internetCredentialsAfterReset = await getInternetCredentials( + VAULT_BACKUP_KEY, + ); + + expect(internetCredentialsAfterReset).toBeUndefined(); + }); + }); + + describe('backupVault', () => { + it('should throw when vault backup fails', async () => { + const mockedFailedResponse = { + error: 'Vault backup failed', + success: false, + }; + + // Mock the setInternetCredentials function to return false, which simulates a failed vault backup + (setInternetCredentials as jest.Mock).mockImplementationOnce(() => false); + + const keyringState: KeyringControllerState = { + vault: undefined, + keyrings: [], + isUnlocked: false, + keyringsMetadata: [], + }; + + const response = await backupVault(keyringState); + + expect(response).toEqual(mockedFailedResponse); + }); + + it('should return success response when vault backup succeeds', async () => { + const mockedSuccessResponse = { success: true }; + + // Mock the setInternetCredentials function to return a success response, which simulates a successful vault backup + (setInternetCredentials as jest.Mock).mockImplementationOnce( + () => mockedSuccessResponse, + ); + + const keyringState: KeyringControllerState = { + vault: undefined, + keyrings: [], + isUnlocked: false, + keyringsMetadata: [], + }; + + const response = await backupVault(keyringState); + + expect(response).toEqual(mockedSuccessResponse); + }); + + it('should reset vault before backup', async () => { + const dummyPassword = 'dummy-password'; + const mockedSuccessResponse = { success: true }; + + await setInternetCredentials( + VAULT_BACKUP_KEY, + VAULT_BACKUP_KEY, + dummyPassword, + ); + + const internetCredentialsBeforeReset = await getInternetCredentials( + VAULT_BACKUP_KEY, + ); + + expect(internetCredentialsBeforeReset).toEqual({ + username: VAULT_BACKUP_KEY, + password: dummyPassword, + }); + + const keyringState: KeyringControllerState = { + vault: undefined, + keyrings: [], + isUnlocked: false, + keyringsMetadata: [], + }; + + const response = await backupVault(keyringState); + + expect(resetInternetCredentials).toHaveBeenCalledTimes(1); + + expect(response).toEqual(mockedSuccessResponse); + }); }); - it('should return success response when vault backup succeeds', async () => { - const mockedSuccessResponse = { success: true }; + describe('getVaultFromBackup', () => { + it('should successfully get vault from backup', async () => { + const dummyPassword = 'dummy-password'; + const mockedSuccessResponse = { success: true, vault: dummyPassword }; + + await setInternetCredentials( + VAULT_BACKUP_KEY, + VAULT_BACKUP_KEY, + dummyPassword, + ); + + const response = await getVaultFromBackup(); + + expect(response).toEqual(mockedSuccessResponse); + }); - // Mock the setInternetCredentials function to return a success response, which simulates a successful vault backup - (setInternetCredentials as jest.Mock).mockResolvedValue( - mockedSuccessResponse, - ); + it('should return error when vault backup fails', async () => { + const mockedFailedResponse = { + error: VAULT_FAILED_TO_GET_VAULT_FROM_BACKUP, + success: false, + }; - const keyringState: KeyringControllerState = { - vault: undefined, - keyrings: [], - isUnlocked: false, - keyringsMetadata: [], - }; + (getInternetCredentials as jest.Mock).mockImplementationOnce( + () => undefined, + ); - const response = await backupVault(keyringState); + const response = await getVaultFromBackup(); - expect(response).toEqual(mockedSuccessResponse); + expect(response).toEqual(mockedFailedResponse); + }); }); }); diff --git a/app/core/BackupVault/backupVault.ts b/app/core/BackupVault/backupVault.ts index 8be42c83dbba..e57602f8f708 100644 --- a/app/core/BackupVault/backupVault.ts +++ b/app/core/BackupVault/backupVault.ts @@ -10,9 +10,8 @@ import { import { VAULT_BACKUP_FAILED, VAULT_FAILED_TO_GET_VAULT_FROM_BACKUP, -} from '../../constants/error'; - -const VAULT_BACKUP_KEY = 'VAULT_BACKUP'; + VAULT_BACKUP_KEY, +} from './constants'; const options: Options = { accessible: ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY, diff --git a/app/core/BackupVault/constants.ts b/app/core/BackupVault/constants.ts new file mode 100644 index 000000000000..4e82505387d2 --- /dev/null +++ b/app/core/BackupVault/constants.ts @@ -0,0 +1,4 @@ +export const VAULT_BACKUP_KEY = 'VAULT_BACKUP'; +export const VAULT_BACKUP_FAILED = 'Vault backup failed'; +export const VAULT_FAILED_TO_GET_VAULT_FROM_BACKUP = + 'getVaultFromBackup failed to retrieve vault'; From 1414332389d8bae98b87c4e88264a6a2513e0469 Mon Sep 17 00:00:00 2001 From: Cal-L Date: Wed, 30 Apr 2025 13:04:52 -0700 Subject: [PATCH 3/5] Clean up back up functions --- .../hooks/DeleteWallet/useDeleteWallet.ts | 4 +- app/core/BackupVault/backupVault.ts | 55 +++++++++++++++++-- app/core/BackupVault/constants.ts | 2 + app/core/BackupVault/index.ts | 2 +- 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/app/components/hooks/DeleteWallet/useDeleteWallet.ts b/app/components/hooks/DeleteWallet/useDeleteWallet.ts index e06b43e74faf..c037d80b3536 100644 --- a/app/components/hooks/DeleteWallet/useDeleteWallet.ts +++ b/app/components/hooks/DeleteWallet/useDeleteWallet.ts @@ -4,7 +4,7 @@ import Logger from '../../../util/Logger'; import { EXISTING_USER } from '../../../constants/storage'; import { Authentication } from '../../../core'; import AUTHENTICATION_TYPE from '../../../constants/userProperties'; -import { resetVaultBackup } from '../../../core/BackupVault/backupVault'; +import { clearAllVaultBackups } from '../../../core/BackupVault'; import { useMetrics } from '../useMetrics'; const useDeleteWallet = () => { @@ -14,7 +14,7 @@ const useDeleteWallet = () => { await Authentication.newWalletAndKeychain(`${Date.now()}`, { currentAuthType: AUTHENTICATION_TYPE.UNKNOWN, }); - await resetVaultBackup(); + await clearAllVaultBackups(); await Authentication.lockApp(); // TODO: Replace "any" with type // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/app/core/BackupVault/backupVault.ts b/app/core/BackupVault/backupVault.ts index e57602f8f708..6b547c13cc3b 100644 --- a/app/core/BackupVault/backupVault.ts +++ b/app/core/BackupVault/backupVault.ts @@ -11,6 +11,8 @@ import { VAULT_BACKUP_FAILED, VAULT_FAILED_TO_GET_VAULT_FROM_BACKUP, VAULT_BACKUP_KEY, + VAULT_BACKUP_TEMP_KEY, + TEMP_VAULT_BACKUP_FAILED, } from './constants'; const options: Options = { @@ -24,12 +26,29 @@ interface KeyringBackupResponse { } /** - * removes the vault backup from react-native-keychain + * Removes the primary vault backup from react-native-keychain */ -export const resetVaultBackup = async (): Promise => { +const _resetVaultBackup = async (): Promise => { + // Clear existing backup await resetInternetCredentials(VAULT_BACKUP_KEY); }; +/** + * Removes the temporary vault backup from react-native-keychain + */ +const _resetTemporaryVaultBackup = async (): Promise => { + // Clear temporary backup + await resetInternetCredentials(VAULT_BACKUP_TEMP_KEY); +}; + +/** + * Clears all vault backups from react-native-keychain + */ +export const clearAllVaultBackups = async (): Promise => { + await _resetVaultBackup(); + await _resetTemporaryVaultBackup(); +}; + /** * places the vault in react-native-keychain for backup * @returns Promise @@ -45,10 +64,33 @@ export async function backupVault( const keyringVault = keyringState.vault as string; try { - // Clear any existing vault backup first to prevent "item already exists" errors - await resetVaultBackup(); + const existingBackup = await getInternetCredentials(VAULT_BACKUP_KEY); - // Backup vault + // An existing backup exists, backup it to the temp key + if (existingBackup && existingBackup.password) { + const existingVault = existingBackup.password; + + // Clear any existing temporary backup + await _resetTemporaryVaultBackup(); + + // Then back up a secondary copy of the vault + const tempBackupResult = await setInternetCredentials( + VAULT_BACKUP_TEMP_KEY, + VAULT_BACKUP_TEMP_KEY, + existingVault, + options, + ); + + // Temporary vault backup failed, throw error + if (!tempBackupResult) { + throw new Error(TEMP_VAULT_BACKUP_FAILED); + } + + // Clear any existing vault backup first to prevent "item already exists" errors + await _resetVaultBackup(); + } + + // Backup primary vault const backupResult = await setInternetCredentials( VAULT_BACKUP_KEY, VAULT_BACKUP_KEY, @@ -61,6 +103,9 @@ export async function backupVault( throw new Error(VAULT_BACKUP_FAILED); } + // Clear the temporary backup + await _resetTemporaryVaultBackup(); + return { success: true, vault: keyringState.vault, diff --git a/app/core/BackupVault/constants.ts b/app/core/BackupVault/constants.ts index 4e82505387d2..439185449a55 100644 --- a/app/core/BackupVault/constants.ts +++ b/app/core/BackupVault/constants.ts @@ -1,4 +1,6 @@ export const VAULT_BACKUP_KEY = 'VAULT_BACKUP'; +export const VAULT_BACKUP_TEMP_KEY = 'VAULT_BACKUP_TEMP'; +export const TEMP_VAULT_BACKUP_FAILED = 'Failed to backup temporary vault'; export const VAULT_BACKUP_FAILED = 'Vault backup failed'; export const VAULT_FAILED_TO_GET_VAULT_FROM_BACKUP = 'getVaultFromBackup failed to retrieve vault'; diff --git a/app/core/BackupVault/index.ts b/app/core/BackupVault/index.ts index 167189763077..01b7de6f3c61 100644 --- a/app/core/BackupVault/index.ts +++ b/app/core/BackupVault/index.ts @@ -1,5 +1,5 @@ export { backupVault, getVaultFromBackup, - resetVaultBackup, + clearAllVaultBackups, } from './backupVault'; From 75e122b9736d88e31dbd3ec3dd8c64f4b168391f Mon Sep 17 00:00:00 2001 From: Cal-L Date: Fri, 2 May 2025 16:09:51 -0700 Subject: [PATCH 4/5] Handle temp vault backup --- app/core/BackupVault/backupVault.ts | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/app/core/BackupVault/backupVault.ts b/app/core/BackupVault/backupVault.ts index 6b547c13cc3b..9aa0b9a63614 100644 --- a/app/core/BackupVault/backupVault.ts +++ b/app/core/BackupVault/backupVault.ts @@ -64,6 +64,7 @@ export async function backupVault( const keyringVault = keyringState.vault as string; try { + // Does a primary backup exist? const existingBackup = await getInternetCredentials(VAULT_BACKUP_KEY); // An existing backup exists, backup it to the temp key @@ -85,11 +86,11 @@ export async function backupVault( if (!tempBackupResult) { throw new Error(TEMP_VAULT_BACKUP_FAILED); } - - // Clear any existing vault backup first to prevent "item already exists" errors - await _resetVaultBackup(); } + // Clear any existing vault backup first to prevent "item already exists" errors + await _resetVaultBackup(); + // Backup primary vault const backupResult = await setInternetCredentials( VAULT_BACKUP_KEY, @@ -129,10 +130,19 @@ export async function backupVault( } */ export async function getVaultFromBackup(): Promise { - const credentials = await getInternetCredentials(VAULT_BACKUP_KEY); - if (credentials) { - return { success: true, vault: credentials.password }; + const primaryVaultCredentials = await getInternetCredentials( + VAULT_BACKUP_KEY, + ); + if (primaryVaultCredentials) { + return { success: true, vault: primaryVaultCredentials.password }; } + const temporaryVaultCredentials = await getInternetCredentials( + VAULT_BACKUP_TEMP_KEY, + ); + if (temporaryVaultCredentials) { + return { success: true, vault: temporaryVaultCredentials.password }; + } + const vaultFetchError = new Error(VAULT_BACKUP_KEY); Logger.error(vaultFetchError, VAULT_FAILED_TO_GET_VAULT_FROM_BACKUP); return { success: false, error: VAULT_FAILED_TO_GET_VAULT_FROM_BACKUP }; From 2d97a7902ffb10736a2670550d1763251f5a0b65 Mon Sep 17 00:00:00 2001 From: Cal-L Date: Fri, 2 May 2025 16:54:45 -0700 Subject: [PATCH 5/5] Fix unit tests for vault backup --- app/core/BackupVault/backupVault.test.ts | 111 ++++++++++++++++++----- app/core/BackupVault/backupVault.ts | 4 +- 2 files changed, 90 insertions(+), 25 deletions(-) diff --git a/app/core/BackupVault/backupVault.test.ts b/app/core/BackupVault/backupVault.test.ts index c0a8a594e096..9c977e47cee2 100644 --- a/app/core/BackupVault/backupVault.test.ts +++ b/app/core/BackupVault/backupVault.test.ts @@ -1,11 +1,12 @@ import { VAULT_FAILED_TO_GET_VAULT_FROM_BACKUP, VAULT_BACKUP_KEY, + VAULT_BACKUP_TEMP_KEY, } from './constants'; import { backupVault, getVaultFromBackup, - resetVaultBackup, + clearAllVaultBackups, } from './backupVault'; import { KeyringControllerState } from '@metamask/keyring-controller'; import { @@ -16,10 +17,8 @@ import { setInternetCredentials, } from 'react-native-keychain'; -const mockKeychainState: Record< - string, - { username: string; password: string } -> = {}; +let mockKeychainState: Record = + {}; // Mock the react-native-keychain module jest.mock('react-native-keychain', () => ({ @@ -56,41 +55,90 @@ jest.mock('react-native-keychain', () => ({ More information on the issue can be found here: https://github.com/oblador/react-native-keychain/issues/460 */ describe('backupVault file', () => { + const dummyPassword = 'dummy-password'; + beforeEach(() => { jest.clearAllMocks(); + mockKeychainState = {}; }); - describe('resetVaultBackup', () => { - it('should reset vault backup', async () => { - const dummyPassword = 'dummy-password'; - + describe('clearAllVaultBackups', () => { + it('should clear all vault backups', async () => { await setInternetCredentials( VAULT_BACKUP_KEY, VAULT_BACKUP_KEY, dummyPassword, ); - const internetCredentialsBeforeReset = await getInternetCredentials( + await setInternetCredentials( + VAULT_BACKUP_TEMP_KEY, + VAULT_BACKUP_TEMP_KEY, + dummyPassword, + ); + + const primaryVaultCredentials = await getInternetCredentials( VAULT_BACKUP_KEY, ); - expect(internetCredentialsBeforeReset).toEqual({ + const temporaryVaultCredentials = await getInternetCredentials( + VAULT_BACKUP_TEMP_KEY, + ); + + expect(primaryVaultCredentials).toEqual({ username: VAULT_BACKUP_KEY, password: dummyPassword, }); - await resetVaultBackup(); + expect(temporaryVaultCredentials).toEqual({ + username: VAULT_BACKUP_TEMP_KEY, + password: dummyPassword, + }); + + await clearAllVaultBackups(); - const internetCredentialsAfterReset = await getInternetCredentials( + const primaryVaultCredentialsAfterReset = await getInternetCredentials( VAULT_BACKUP_KEY, ); - expect(internetCredentialsAfterReset).toBeUndefined(); + const temporaryVaultCredentialsAfterReset = await getInternetCredentials( + VAULT_BACKUP_TEMP_KEY, + ); + + expect(primaryVaultCredentialsAfterReset).toBeUndefined(); + expect(temporaryVaultCredentialsAfterReset).toBeUndefined(); }); }); describe('backupVault', () => { - it('should throw when vault backup fails', async () => { + it('should throw error and skip primary backup if failed to backup temporary vault', async () => { + const mockedFailedResponse = { + error: 'Failed to backup temporary vault', + success: false, + }; + + // Populate primary vault backup + await setInternetCredentials( + VAULT_BACKUP_KEY, + VAULT_BACKUP_KEY, + dummyPassword, + ); + + // Mock the setInternetCredentials function to return false, which simulates a failed vault backup + (setInternetCredentials as jest.Mock).mockImplementationOnce(() => false); + + const keyringState: KeyringControllerState = { + vault: undefined, + keyrings: [], + isUnlocked: false, + keyringsMetadata: [], + }; + + const response = await backupVault(keyringState); + + expect(response).toEqual(mockedFailedResponse); + }); + + it('should throw error when primary vault backup fails', async () => { const mockedFailedResponse = { error: 'Vault backup failed', success: false, @@ -111,12 +159,14 @@ describe('backupVault file', () => { expect(response).toEqual(mockedFailedResponse); }); - it('should return success response when vault backup succeeds', async () => { + it('should successfully backup primary vault', async () => { const mockedSuccessResponse = { success: true }; - // Mock the setInternetCredentials function to return a success response, which simulates a successful vault backup - (setInternetCredentials as jest.Mock).mockImplementationOnce( - () => mockedSuccessResponse, + // Populate primary vault backup + await setInternetCredentials( + VAULT_BACKUP_KEY, + VAULT_BACKUP_KEY, + dummyPassword, ); const keyringState: KeyringControllerState = { @@ -132,7 +182,6 @@ describe('backupVault file', () => { }); it('should reset vault before backup', async () => { - const dummyPassword = 'dummy-password'; const mockedSuccessResponse = { success: true }; await setInternetCredentials( @@ -159,15 +208,15 @@ describe('backupVault file', () => { const response = await backupVault(keyringState); - expect(resetInternetCredentials).toHaveBeenCalledTimes(1); + // First reset temporary, then primary, then temporary again + expect(resetInternetCredentials).toHaveBeenCalledTimes(3); expect(response).toEqual(mockedSuccessResponse); }); }); describe('getVaultFromBackup', () => { - it('should successfully get vault from backup', async () => { - const dummyPassword = 'dummy-password'; + it('should successfully get primary vault from backup', async () => { const mockedSuccessResponse = { success: true, vault: dummyPassword }; await setInternetCredentials( @@ -181,6 +230,22 @@ describe('backupVault file', () => { expect(response).toEqual(mockedSuccessResponse); }); + it('should successfully get temporary vault from backup if primary vault does not exist', async () => { + const tempDummyPassword = 'temp-dummy-password'; + + const mockedSuccessResponse = { success: true, vault: tempDummyPassword }; + + await setInternetCredentials( + VAULT_BACKUP_TEMP_KEY, + VAULT_BACKUP_TEMP_KEY, + tempDummyPassword, + ); + + const response = await getVaultFromBackup(); + + expect(response).toEqual(mockedSuccessResponse); + }); + it('should return error when vault backup fails', async () => { const mockedFailedResponse = { error: VAULT_FAILED_TO_GET_VAULT_FROM_BACKUP, diff --git a/app/core/BackupVault/backupVault.ts b/app/core/BackupVault/backupVault.ts index 9aa0b9a63614..d291d0d5e2fc 100644 --- a/app/core/BackupVault/backupVault.ts +++ b/app/core/BackupVault/backupVault.ts @@ -44,10 +44,10 @@ const _resetTemporaryVaultBackup = async (): Promise => { /** * Clears all vault backups from react-native-keychain */ -export const clearAllVaultBackups = async (): Promise => { +export async function clearAllVaultBackups() { await _resetVaultBackup(); await _resetTemporaryVaultBackup(); -}; +} /** * places the vault in react-native-keychain for backup