diff options
Merge branch 'develop' into i3725-refactor-send-component-
Diffstat (limited to 'app')
-rw-r--r-- | app/manifest.json | 6 | ||||
-rw-r--r-- | app/scripts/controllers/preferences.js | 91 | ||||
-rw-r--r-- | app/scripts/controllers/user-actions.js | 17 | ||||
-rw-r--r-- | app/scripts/lib/bug-notifier.js | 22 | ||||
-rw-r--r-- | app/scripts/lib/createErrorMiddleware.js | 1 | ||||
-rw-r--r-- | app/scripts/lib/setupRaven.js | 2 | ||||
-rw-r--r-- | app/scripts/metamask-controller.js | 25 | ||||
-rw-r--r-- | app/scripts/migrations/026.js | 2 |
8 files changed, 158 insertions, 8 deletions
diff --git a/app/manifest.json b/app/manifest.json index 141026d10..c1f26d2ea 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.6.1", + "version": "4.7.2", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", @@ -68,6 +68,8 @@ "matches": [ "https://metamask.io/*" ], - "ids": ["*"] + "ids": [ + "*" + ] } }
\ No newline at end of file diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index a4ff1207e..2fe009f9a 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -1,6 +1,9 @@ const ObservableStore = require('obs-store') const normalizeAddress = require('eth-sig-util').normalize const extend = require('xtend') +const notifier = require('../lib/bug-notifier') +const log = require('loglevel') +const { version } = require('../../manifest.json') class PreferencesController { @@ -28,7 +31,12 @@ class PreferencesController { featureFlags: {}, currentLocale: opts.initLangCode, identities: {}, + lostIdentities: {}, }, opts.initState) + + this.getFirstTimeInfo = opts.getFirstTimeInfo || null + this.notifier = opts.notifier || notifier + this.store = new ObservableStore(initState) } // PUBLIC METHODS @@ -63,6 +71,13 @@ class PreferencesController { this.store.updateState({ currentLocale: key }) } + /** + * Updates identities to only include specified addresses. Removes identities + * not included in addresses array + * + * @param {string[]} addresses An array of hex addresses + * + */ setAddresses (addresses) { const oldIdentities = this.store.getState().identities const identities = addresses.reduce((ids, address, index) => { @@ -74,6 +89,76 @@ class PreferencesController { } /** + * Adds addresses to the identities object without removing identities + * + * @param {string[]} addresses An array of hex addresses + * + */ + addAddresses (addresses) { + const identities = this.store.getState().identities + addresses.forEach((address) => { + // skip if already exists + if (identities[address]) return + // add missing identity + const identityCount = Object.keys(identities).length + identities[address] = { name: `Account ${identityCount + 1}`, address } + }) + this.store.updateState({ identities }) + } + + /* + * Synchronizes identity entries with known accounts. + * Removes any unknown identities, and returns the resulting selected address. + * + * @param {Array<string>} addresses known to the vault. + * @returns {Promise<string>} selectedAddress the selected address. + */ + syncAddresses (addresses) { + let { identities, lostIdentities } = this.store.getState() + + let newlyLost = {} + Object.keys(identities).forEach((identity) => { + if (!addresses.includes(identity)) { + newlyLost[identity] = identities[identity] + delete identities[identity] + } + }) + + // Identities are no longer present. + if (Object.keys(newlyLost).length > 0) { + + // Notify our servers: + const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' + const firstTimeInfo = this.getFirstTimeInfo ? this.getFirstTimeInfo() : {} + this.notifier.notify(uri, { + accounts: Object.keys(newlyLost), + metadata: { + version, + firstTimeInfo, + }, + }) + .catch(log.error) + + for (let key in newlyLost) { + lostIdentities[key] = newlyLost[key] + } + } + + this.store.updateState({ identities, lostIdentities }) + this.addAddresses(addresses) + + // If the selected account is no longer valid, + // select an arbitrary other account: + let selected = this.getSelectedAddress() + if (!addresses.includes(selected)) { + selected = addresses[0] + this.setSelectedAddress(selected) + } + + return selected + } + + /** * Setter for the `selectedAddress` property * * @param {string} _address A new hex address for an account @@ -111,7 +196,7 @@ class PreferencesController { /** * Adds a new token to the token array, or updates the token if passed an address that already exists. * Modifies the existing tokens array from the store. All objects in the tokens array array AddedToken objects. - * @see AddedToken {@link AddedToken} + * @see AddedToken {@link AddedToken} * * @param {string} rawAddress Hex address of the token contract. May or may not be a checksum address. * @param {string} symbol The symbol of the token @@ -197,7 +282,7 @@ class PreferencesController { } /** - * Setter for the `currentAccountTab` property + * Setter for the `currentAccountTab` property * * @param {string} currentAccountTab Specifies the new tab to be marked as current * @returns {Promise<void>} Promise resolves with undefined @@ -215,7 +300,7 @@ class PreferencesController { * The returned list will have a max length of 2. If the _url currently exists it the list, it will be moved to the * end of the list. The current list is modified and returned as a promise. * - * @param {string} _url The rpc url to add to the frequentRpcList. + * @param {string} _url The rpc url to add to the frequentRpcList. * @returns {Promise<array>} The updated frequentRpcList. * */ diff --git a/app/scripts/controllers/user-actions.js b/app/scripts/controllers/user-actions.js new file mode 100644 index 000000000..f777054b8 --- /dev/null +++ b/app/scripts/controllers/user-actions.js @@ -0,0 +1,17 @@ +const MessageManager = require('./lib/message-manager') +const PersonalMessageManager = require('./lib/personal-message-manager') +const TypedMessageManager = require('./lib/typed-message-manager') + +class UserActionController { + + constructor (opts = {}) { + + this.messageManager = new MessageManager() + this.personalMessageManager = new PersonalMessageManager() + this.typedMessageManager = new TypedMessageManager() + + } + +} + +module.exports = UserActionController diff --git a/app/scripts/lib/bug-notifier.js b/app/scripts/lib/bug-notifier.js new file mode 100644 index 000000000..4d305b894 --- /dev/null +++ b/app/scripts/lib/bug-notifier.js @@ -0,0 +1,22 @@ +class BugNotifier { + notify (uri, message) { + return postData(uri, message) + } +} + +function postData(uri, data) { + return fetch(uri, { + body: JSON.stringify(data), // must match 'Content-Type' header + credentials: 'same-origin', // include, same-origin, *omit + headers: { + 'content-type': 'application/json', + }, + method: 'POST', // *GET, POST, PUT, DELETE, etc. + mode: 'cors', // no-cors, cors, *same-origin + }) +} + +const notifier = new BugNotifier() + +module.exports = notifier + diff --git a/app/scripts/lib/createErrorMiddleware.js b/app/scripts/lib/createErrorMiddleware.js index baed99e45..c70beddfd 100644 --- a/app/scripts/lib/createErrorMiddleware.js +++ b/app/scripts/lib/createErrorMiddleware.js @@ -59,6 +59,7 @@ function createErrorMiddleware ({ override = true } = {}) { if (!error) { return done() } sanitizeRPCError(error) log.error(`MetaMask - RPC Error: ${error.message}`, error) + done() }) } } diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupRaven.js index d164827ab..77aefb00a 100644 --- a/app/scripts/lib/setupRaven.js +++ b/app/scripts/lib/setupRaven.js @@ -66,7 +66,7 @@ function simplifyErrorMessages(report) { function rewriteErrorMessages(report, rewriteFn) { // rewrite top level message - report.message = rewriteFn(report.message) + if (report.message) report.message = rewriteFn(report.message) // rewrite each exception message if (report.exception && report.exception.values) { report.exception.values.forEach(item => { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 9db7e186a..80eaafd92 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -85,6 +85,7 @@ module.exports = class MetamaskController extends EventEmitter { this.preferencesController = new PreferencesController({ initState: initState.PreferencesController, initLangCode: opts.initLangCode, + getFirstTimeInfo: () => initState.firstTimeInfo, }) // currency controller @@ -139,6 +140,8 @@ module.exports = class MetamaskController extends EventEmitter { const address = addresses[0] this.preferencesController.setSelectedAddress(address) } + // ensure preferences + identities controller know about all addresses + this.preferencesController.addAddresses(addresses) this.accountTracker.syncWithAddresses(addresses) }) @@ -354,7 +357,7 @@ module.exports = class MetamaskController extends EventEmitter { importAccountWithStrategy: nodeify(this.importAccountWithStrategy, this), // vault management - submitPassword: nodeify(keyringController.submitPassword, keyringController), + submitPassword: nodeify(this.submitPassword, this), // network management setProviderType: nodeify(networkController.setProviderType, networkController), @@ -458,7 +461,11 @@ module.exports = class MetamaskController extends EventEmitter { async createNewVaultAndRestore (password, seed) { const release = await this.createVaultMutex.acquire() try { + // clear known identities + this.preferencesController.setAddresses([]) + // create new vault const vault = await this.keyringController.createNewVaultAndRestore(password, seed) + // set new identities const accounts = await this.keyringController.getAccounts() this.preferencesController.setAddresses(accounts) this.selectFirstIdentity() @@ -470,6 +477,22 @@ module.exports = class MetamaskController extends EventEmitter { } } + /* + * Submits the user's password and attempts to unlock the vault. + * Also synchronizes the preferencesController, to ensure its schema + * is up to date with known accounts once the vault is decrypted. + * + * @param {string} password - The user's password + * @returns {Promise<object>} - The keyringController update. + */ + async submitPassword (password) { + await this.keyringController.submitPassword(password) + const accounts = await this.keyringController.getAccounts() + + await this.preferencesController.syncAddresses(accounts) + return this.keyringController.fullUpdate() + } + /** * @type Identity * @property {string} name - The account nickname. diff --git a/app/scripts/migrations/026.js b/app/scripts/migrations/026.js index 1b8a91a45..4e907e09c 100644 --- a/app/scripts/migrations/026.js +++ b/app/scripts/migrations/026.js @@ -27,7 +27,7 @@ module.exports = { function transformState (state) { if (!state.KeyringController || !state.PreferencesController) { - return + return state } if (!state.KeyringController.walletNicknames) { |