From fad06e352328f0fb1b920d0d0f549c86334c9849 Mon Sep 17 00:00:00 2001 From: sethkfman Date: Fri, 2 Apr 2021 10:27:39 -0600 Subject: [PATCH 1/6] added functionality to persists old account names when resetting password #2002 --- app/components/Views/ResetPassword/index.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/components/Views/ResetPassword/index.js b/app/components/Views/ResetPassword/index.js index dfa5375b828..e02e39f60bc 100644 --- a/app/components/Views/ResetPassword/index.js +++ b/app/components/Views/ResetPassword/index.js @@ -400,6 +400,7 @@ class ResetPassword extends PureComponent { const { originalPassword, password: newPassword } = this.state; const { KeyringController, PreferencesController } = Engine.context; const seedPhrase = await this.getSeedPhrase(); + const oldIdentities = PreferencesController.state.identities; let importedAccounts = []; try { @@ -445,6 +446,12 @@ class ResetPassword extends PureComponent { // Reset preferencesControllerState preferencesControllerState = PreferencesController.state; + //Persist old account names + for (const id in preferencesControllerState.identities) { + const oldName = oldIdentities[id].name; + if (oldName) preferencesControllerState.identities[id].name = oldName; + } + // Set preferencesControllerState again await PreferencesController.update(preferencesControllerState); // Reselect previous selected account if still available From 2e3b7e2c019e54a0ae837a2fd0a8b41d074dc1ca Mon Sep 17 00:00:00 2001 From: sethkfman Date: Tue, 6 Apr 2021 14:07:49 -0600 Subject: [PATCH 2/6] added logic to check for old account/identities and persist their balances and names --- app/core/Vault.js | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/app/core/Vault.js b/app/core/Vault.js index 471e6618d5a..7f87b9b6168 100644 --- a/app/core/Vault.js +++ b/app/core/Vault.js @@ -18,8 +18,10 @@ export const getSeedPhrase = async (password = '') => { * @param password - Password to recreate and set the vault with */ export const recreateVaultWithSamePassword = async (password = '', selectedAddress) => { - const { KeyringController, PreferencesController } = Engine.context; + const { KeyringController, PreferencesController, AccountTrackerController } = Engine.context; const seedPhrase = await getSeedPhrase(password); + const oldIdentities = PreferencesController.state.identities; + const oldAccounts = AccountTrackerController.accounts; let importedAccounts = []; try { @@ -42,7 +44,6 @@ export const recreateVaultWithSamePassword = async (password = '', selectedAddre // Get props to restore vault const hdKeyring = KeyringController.state.keyrings[0]; const existingAccountCount = hdKeyring.accounts.length; - let preferencesControllerState = PreferencesController.state; // Create previous accounts again for (let i = 0; i < existingAccountCount - 1; i++) { @@ -58,11 +59,28 @@ export const recreateVaultWithSamePassword = async (password = '', selectedAddre Logger.error(e, 'error while trying to import accounts on recreate vault'); } - // Reset preferencesControllerState - preferencesControllerState = PreferencesController.state; + //Persist old account/identities names + const preferencesControllerState = PreferencesController.state; + if (oldIdentities) { + for (const id in preferencesControllerState.identities) { + const oldName = oldIdentities[id].name; + if (oldName) preferencesControllerState.identities[id].name = oldName; + } + } + + //Persist old account data + const accounts = AccountTrackerController.accounts; + if (oldAccounts) { + for (const account in accounts) { + const oldAccount = oldAccounts[account]; + if (oldAccount) accounts[account] = oldAccount; + } + } // Set preferencesControllerState again await PreferencesController.update(preferencesControllerState); + await AccountTrackerController.update(accounts); + // Reselect previous selected account if still available if (hdKeyring.accounts.includes(selectedAddress)) { PreferencesController.setSelectedAddress(selectedAddress); From 28f61cb37872e6493795bc5456878aea9031ae11 Mon Sep 17 00:00:00 2001 From: sethkfman Date: Wed, 7 Apr 2021 15:53:54 -0600 Subject: [PATCH 3/6] added check to see if it is not an existing user --- app/components/Views/Login/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/components/Views/Login/index.js b/app/components/Views/Login/index.js index 9ea55a275af..ffe7cc55a07 100644 --- a/app/components/Views/Login/index.js +++ b/app/components/Views/Login/index.js @@ -278,7 +278,8 @@ class Login extends PureComponent { // Restore vault with user entered password await KeyringController.submitPassword(this.state.password); const encryptionLib = await AsyncStorage.getItem(ENCRYPTION_LIB); - if (encryptionLib !== ORIGINAL) { + const existingUser = await AsyncStorage.getItem(EXISTING_USER); + if (encryptionLib !== ORIGINAL && !existingUser) { await recreateVaultWithSamePassword(this.state.password, this.props.selectedAddress); await AsyncStorage.setItem(ENCRYPTION_LIB, ORIGINAL); } From da483b9c16c97346e8929f1abc89436b7f9768a6 Mon Sep 17 00:00:00 2001 From: sethkfman Date: Wed, 7 Apr 2021 16:01:00 -0600 Subject: [PATCH 4/6] added check to see if it is a existing user --- app/components/Views/Login/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/Views/Login/index.js b/app/components/Views/Login/index.js index ffe7cc55a07..4695544d0e2 100644 --- a/app/components/Views/Login/index.js +++ b/app/components/Views/Login/index.js @@ -279,7 +279,7 @@ class Login extends PureComponent { await KeyringController.submitPassword(this.state.password); const encryptionLib = await AsyncStorage.getItem(ENCRYPTION_LIB); const existingUser = await AsyncStorage.getItem(EXISTING_USER); - if (encryptionLib !== ORIGINAL && !existingUser) { + if (encryptionLib !== ORIGINAL && existingUser) { await recreateVaultWithSamePassword(this.state.password, this.props.selectedAddress); await AsyncStorage.setItem(ENCRYPTION_LIB, ORIGINAL); } From 94c1dbf1d0efe16a60ace1d04efea6c951a9e5c7 Mon Sep 17 00:00:00 2001 From: sethkfman Date: Thu, 8 Apr 2021 13:21:14 -0600 Subject: [PATCH 5/6] add sync utility code and test to reduce common code --- app/components/Views/ResetPassword/index.js | 17 ++-- app/components/Views/Wallet/index.js | 2 + app/core/Vault.js | 21 ++-- app/util/sync.js | 37 +++++++ app/util/sync.test.js | 106 ++++++++++++++++++++ 5 files changed, 157 insertions(+), 26 deletions(-) create mode 100644 app/util/sync.js create mode 100644 app/util/sync.test.js diff --git a/app/components/Views/ResetPassword/index.js b/app/components/Views/ResetPassword/index.js index e02e39f60bc..fb8456d3b17 100644 --- a/app/components/Views/ResetPassword/index.js +++ b/app/components/Views/ResetPassword/index.js @@ -37,6 +37,7 @@ import { ONBOARDING, PREVIOUS_SCREEN } from '../../../constants/navigation'; import { EXISTING_USER, TRUE, BIOMETRY_CHOICE_DISABLED } from '../../../constants/storage'; import { getPasswordStrengthWord, passwordRequirementsMet } from '../../../util/password'; import NotificationManager from '../../../core/NotificationManager'; +import { syncPrefs } from '../../../util/sync'; const styles = StyleSheet.create({ mainWrapper: { @@ -400,7 +401,7 @@ class ResetPassword extends PureComponent { const { originalPassword, password: newPassword } = this.state; const { KeyringController, PreferencesController } = Engine.context; const seedPhrase = await this.getSeedPhrase(); - const oldIdentities = PreferencesController.state.identities; + const oldPrefs = PreferencesController.state; let importedAccounts = []; try { @@ -427,7 +428,6 @@ class ResetPassword extends PureComponent { const hdKeyring = KeyringController.state.keyrings[0]; const existingAccountCount = hdKeyring.accounts.length; const selectedAddress = this.props.selectedAddress; - let preferencesControllerState = PreferencesController.state; // Create previous accounts again for (let i = 0; i < existingAccountCount - 1; i++) { @@ -443,17 +443,12 @@ class ResetPassword extends PureComponent { Logger.error(e, 'error while trying to import accounts on recreate vault'); } - // Reset preferencesControllerState - preferencesControllerState = PreferencesController.state; - - //Persist old account names - for (const id in preferencesControllerState.identities) { - const oldName = oldIdentities[id].name; - if (oldName) preferencesControllerState.identities[id].name = oldName; - } + //Persist old account/identities names + const preferencesControllerState = PreferencesController.state; + const prefUpdates = syncPrefs(oldPrefs, preferencesControllerState); // Set preferencesControllerState again - await PreferencesController.update(preferencesControllerState); + await PreferencesController.update(prefUpdates); // Reselect previous selected account if still available if (hdKeyring.accounts.includes(selectedAddress)) { PreferencesController.setSelectedAddress(selectedAddress); diff --git a/app/components/Views/Wallet/index.js b/app/components/Views/Wallet/index.js index d87cf2011b4..bf3dca3e63d 100644 --- a/app/components/Views/Wallet/index.js +++ b/app/components/Views/Wallet/index.js @@ -175,6 +175,8 @@ class Wallet extends PureComponent { ticker } = this.props; + console.log(accounts); + let balance = 0; let assets = tokens; if (accounts[selectedAddress]) { diff --git a/app/core/Vault.js b/app/core/Vault.js index 7f87b9b6168..6c3ef8684d1 100644 --- a/app/core/Vault.js +++ b/app/core/Vault.js @@ -1,5 +1,6 @@ import Engine from './Engine'; import Logger from '../util/Logger'; +import { syncPrefs, syncAccounts } from '../util/sync'; /** * Returns current vault seed phrase @@ -20,7 +21,7 @@ export const getSeedPhrase = async (password = '') => { export const recreateVaultWithSamePassword = async (password = '', selectedAddress) => { const { KeyringController, PreferencesController, AccountTrackerController } = Engine.context; const seedPhrase = await getSeedPhrase(password); - const oldIdentities = PreferencesController.state.identities; + const oldPrefs = PreferencesController.state; const oldAccounts = AccountTrackerController.accounts; let importedAccounts = []; @@ -61,25 +62,15 @@ export const recreateVaultWithSamePassword = async (password = '', selectedAddre //Persist old account/identities names const preferencesControllerState = PreferencesController.state; - if (oldIdentities) { - for (const id in preferencesControllerState.identities) { - const oldName = oldIdentities[id].name; - if (oldName) preferencesControllerState.identities[id].name = oldName; - } - } + const prefUpdates = syncPrefs(oldPrefs, preferencesControllerState); //Persist old account data const accounts = AccountTrackerController.accounts; - if (oldAccounts) { - for (const account in accounts) { - const oldAccount = oldAccounts[account]; - if (oldAccount) accounts[account] = oldAccount; - } - } + const updateAccounts = syncAccounts(oldAccounts, accounts); // Set preferencesControllerState again - await PreferencesController.update(preferencesControllerState); - await AccountTrackerController.update(accounts); + await PreferencesController.update(prefUpdates); + await AccountTrackerController.update(updateAccounts); // Reselect previous selected account if still available if (hdKeyring.accounts.includes(selectedAddress)) { diff --git a/app/util/sync.js b/app/util/sync.js new file mode 100644 index 00000000000..571599b377e --- /dev/null +++ b/app/util/sync.js @@ -0,0 +1,37 @@ +/** + * Function to persist the old account name during an new preferences update + * @param {Object} oldPrefs - old preferences object containing the account names + * @param {Object} updatedPref - preferences object that will be updated with oldPrefs + */ +export async function syncPrefs(oldPrefs, updatedPref) { + try { + Object.keys(oldPrefs.identities).forEach(ids => { + if (updatedPref.identities[ids]) { + updatedPref.identities[ids] = oldPrefs.identities[ids]; + } + }); + + return updatedPref; + } catch (err) { + return updatedPref; + } +} + +/** + * Function to persist the old account balance during an vault update + * @param {Object} oldAccounts - old account object containing the account names + * @param {Object} updatedAccounts - accounts object that will be updated with old accout balance + */ +export async function syncAccounts(oldAccounts, updatedAccounts) { + try { + Object.keys(oldAccounts).forEach(account => { + if (updatedAccounts[account]) { + updatedAccounts[account] = oldAccounts[account]; + } + }); + + return updatedAccounts; + } catch (err) { + return updatedAccounts; + } +} diff --git a/app/util/sync.test.js b/app/util/sync.test.js new file mode 100644 index 00000000000..2fd5f8dfaf9 --- /dev/null +++ b/app/util/sync.test.js @@ -0,0 +1,106 @@ +import { syncPrefs, syncAccounts } from '../util/sync'; + +const OLD_PREFS = { + accountTokens: { + '0x0942890c603273059a11a298F81cb137Be9CF704': { '0x1': [Array], '0x3': [Array] }, + '0x120bfFfa4138fD00A8025a223C350b9ffaDAD8F5': { '0x3': [Array] }, + '0x16C6C3079edE914e83B388a52fFD9255E1c3165': { '0x3': [Array] }, + '0x223367C61c38FAcbdd0b92De5aA7B742e1e5a196': { '0x1': [Array], '0x3': [Array] }, + '0x7b8C6B8363B9E7A77d279dDad49BEF2994a3bf28': { '0x3': [Array] }, + '0x9236413AfD369B2aeb5e52C048f6B30e7308f2e3': { '0x1': [Array], '0x3': [Array] }, + '0x9b07Ba86631bdb74eE2DDb5750440986DECB9e11': { '0x1': [Array], '0x3': [Array] }, + '0xE4D7f194b07B85511973f1FAAB31b8C2F1f9F344': { '0x3': [Array] } + }, + currentLocale: 'en', + featureFlags: {}, + frequentRpcList: [], + identities: { + '0x7f9f9A0e248Ef58298e911219e5B45D610C4B539': { + address: '0x7f9f9A0e248Ef58298e911219e5B45D610C4B539', + name: 'Testy Account' + } + }, + ipfsGateway: 'https://cloudflare-ipfs.com/ipfs/', + lostIdentities: {}, + selectedAddress: '0x7f9f9A0e248Ef58298e911219e5B45D610C4B539', + tokens: [] +}; +const OLD_ACCOUNTS = { + '0x0942890c603273059a11a298F81cb137Be9CF704': { balance: '0x365369025dd23000' }, + '0x120bfFfa4138fD00A8025a223C350b9ffaDAD8F5': { balance: '0x0' }, + '0x16C6C3079edE914e83B388a52fFD9255E1c3165': { balance: '0x0' }, + '0x223367C61c38FAcbdd0b92De5aA7B742e1e5a196': { balance: '0x1bf5ef59d293408b' }, + '0x7b8C6B8363B9E7A77d279dDad49BEF2994a3bf28': { balance: '0x0' }, + '0x9236413AfD369B2aeb5e52C048f6B30e7308f2e3': { balance: '0x0' }, + '0x9b07Ba86631bdb74eE2DDb5750440986DECB9e11': { balance: '0xe8d4a51000' }, + '0xE4D7f194b07B85511973f1FAAB31b8C2F1f9F344': { balance: '0x0' } +}; +const NEW_PREFS = { + accountTokens: { + '0x0942890c603273059a11a298F81cb137Be9CF704': { '0x1': [Array], '0x3': [Array] }, + '0x120bfFfa4138fD00A8025a223C350b9ffaDAD8F5': { '0x3': [Array] }, + '0x16C6C3079edE914e83B388a52fFD9255E1c3165': { '0x3': [Array] }, + '0x223367C61c38FAcbdd0b92De5aA7B742e1e5a196': { '0x1': [Array], '0x3': [Array] }, + '0x7b8C6B8363B9E7A77d279dDad49BEF2994a3bf28': { '0x3': [Array] }, + '0x9236413AfD369B2aeb5e52C048f6B30e7308f2e3': { '0x1': [Array], '0x3': [Array] }, + '0x9b07Ba86631bdb74eE2DDb5750440986DECB9e11': { '0x1': [Array], '0x3': [Array] }, + '0xE4D7f194b07B85511973f1FAAB31b8C2F1f9F344': { '0x3': [Array] } + }, + currentLocale: 'en', + featureFlags: {}, + frequentRpcList: [], + identities: { + '0x7f9f9A0e248Ef58298e911219e5B45D610C4B539': { + address: '0x7f9f9A0e248Ef58298e911219e5B45D610C4B539', + name: 'Account 1' + }, + '0x7f9f9A0e248Ef58298e911219e5B45D610C4B589': { + address: '0x7f9f9A0e248Ef58298e911219e5B45D610C4B589', + name: 'Account 2' + } + }, + ipfsGateway: 'https://cloudflare-ipfs.com/ipfs/', + lostIdentities: {}, + selectedAddress: '0x7f9f9A0e248Ef58298e911219e5B45D610C4B539', + tokens: [] +}; +const NEW_ACCOUNTS = { + '0x0942890c603273059a11a298F81cb137Be9CF704': { balance: '0x0' }, + '0x120bfFfa4138fD00A8025a223C350b9ffaDAD8F5': { balance: '0x0' }, + '0x16C6C3079edE914e83B388a52fFD9255E1c3165': { balance: '0x0' }, + '0x223367C61c38FAcbdd0b92De5aA7B742e1e5a196': { balance: '0x0' }, + '0x7b8C6B8363B9E7A77d279dDad49BEF2994a3bf28': { balance: '0x0' }, + '0x9236413AfD369B2aeb5e52C048f6B30e7308f2e3': { balance: '0x0' }, + '0x9b07Ba86631bdb74eE2DDb5750440986DECB9e11': { balance: '0x0' }, + '0xE4D7f194b07B85511973f1FAAB31b8C2F1f9F344': { balance: '0x0' } +}; + +describe('Success Sync', () => { + it('should succeed sync prefs of varying lengths', async () => { + const syncedPrefs = await syncPrefs(OLD_PREFS, NEW_PREFS); + expect(Object.values(syncedPrefs.identities)[0]).toEqual(Object.values(syncedPrefs.identities)[0]); + expect(Object.values(syncedPrefs.identities)[1]).not.toBeUndefined(); + expect(Object.values(syncedPrefs.identities).length).not.toEqual(Object.values(OLD_PREFS.identities).length); + }); + it('should succeed sync accounts balances', async () => { + const syncedAccounts = await syncAccounts(OLD_ACCOUNTS, NEW_ACCOUNTS); + expect(Object.values(syncedAccounts)[0].balance).toEqual(Object.values(OLD_ACCOUNTS)[0].balance); + expect(Object.values(syncedAccounts)[3].balance).toEqual(Object.values(OLD_ACCOUNTS)[3].balance); + expect(Object.values(syncedAccounts)[6].balance).toEqual(Object.values(OLD_ACCOUNTS)[6].balance); + }); +}); + +describe('Error Syncs', () => { + it('should return undefined sync prefs', async () => { + expect(await syncPrefs(OLD_PREFS, undefined)).toEqual(undefined); + }); + it('should return new sync prefs', async () => { + expect(await syncPrefs(undefined, NEW_PREFS)).toEqual(NEW_PREFS); + }); + it('should return new sync accounts', async () => { + expect(await syncAccounts(undefined, NEW_ACCOUNTS)).toEqual(NEW_ACCOUNTS); + }); + it('should return undefined sync accounts', async () => { + expect(await syncAccounts(OLD_ACCOUNTS, undefined)).toEqual(undefined); + }); +}); From f114d4d2a64746594a6fc4ac2a3f33932c675fdf Mon Sep 17 00:00:00 2001 From: sethkfman Date: Thu, 8 Apr 2021 13:25:26 -0600 Subject: [PATCH 6/6] remove logs --- app/components/Views/Wallet/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/components/Views/Wallet/index.js b/app/components/Views/Wallet/index.js index bf3dca3e63d..d87cf2011b4 100644 --- a/app/components/Views/Wallet/index.js +++ b/app/components/Views/Wallet/index.js @@ -175,8 +175,6 @@ class Wallet extends PureComponent { ticker } = this.props; - console.log(accounts); - let balance = 0; let assets = tokens; if (accounts[selectedAddress]) {