From 931ae5f64a233b472c3dada8aa6af77e0bffad5e Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 20 Dec 2016 13:53:14 -0800 Subject: Make notices confirmation configurable - Confirm button will now dismiss the lost accounts array. --- app/scripts/keyring-controller.js | 1 - app/scripts/metamask-controller.js | 17 ++++++++++++++++- ui/app/actions.js | 12 ++++++++++++ ui/app/app.js | 16 +++++++++++++++- ui/app/notice.js | 18 ++++++------------ ui/lib/lost-accounts-notice.js | 23 +++++++++++++++++++++++ 6 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 ui/lib/lost-accounts-notice.js diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 2888e58a9..61ee56638 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -114,7 +114,6 @@ module.exports = class KeyringController extends EventEmitter { conversionDate: this.configManager.getConversionDate(), keyringTypes: this.keyringTypes.map(krt => krt.type), identities: this.identities, - lostAccounts: this.configManager.getLostAccounts(), } } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 4b8fa4323..edb25d300 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -52,7 +52,9 @@ module.exports = class MetamaskController { this.ethStore.getState(), this.configManager.getConfig(), this.keyringController.getState(), - this.noticeController.getState() + this.noticeController.getState(), { + lostAccounts: this.configManager.getLostAccounts(), + } ) } @@ -71,6 +73,7 @@ module.exports = class MetamaskController { setTOSHash: this.setTOSHash.bind(this), checkTOSChange: this.checkTOSChange.bind(this), setGasMultiplier: this.setGasMultiplier.bind(this), + markAccountsFound: this.markAccountsFound.bind(this), // forward directly to keyringController createNewVaultAndKeychain: nodeify(keyringController.createNewVaultAndKeychain).bind(keyringController), @@ -410,4 +413,16 @@ module.exports = class MetamaskController { getStateNetwork () { return this.state.network } + + markAccountsFound(cb) { + this.configManager.setLostAccounts([]) + this.keyringController.getAccounts() + .then((accounts) => { + return this.keyringController.setSelectedAccount(accounts[0]) + }) + .then(() => { + this.sendUpdate() + cb(null, this.getState()) + }) + } } diff --git a/ui/app/actions.js b/ui/app/actions.js index 1c32c9bb1..606460314 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -20,6 +20,7 @@ var actions = { showNotice: showNotice, CLEAR_NOTICES: 'CLEAR_NOTICES', clearNotices: clearNotices, + markAccountsFound, // intialize screen AGREE_TO_DISCLAIMER: 'AGREE_TO_DISCLAIMER', agreeToDisclaimer: agreeToDisclaimer, @@ -591,6 +592,17 @@ function clearNotices () { } } +function markAccountsFound() { + return (dispatch) => { + dispatch(this.showLoadingIndication()) + background.markAccountsFound((err, newState) => { + dispatch(this.hideLoadingIndication()) + if (err) return dispatch(this.showWarning(err.message)) + dispatch(actions.updateMetamaskState(newState)) + }) + } +} + // // config // diff --git a/ui/app/app.js b/ui/app/app.js index 2fa6415dd..886bc987a 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -17,6 +17,7 @@ const SendTransactionScreen = require('./send') const ConfirmTxScreen = require('./conf-tx') // notice const NoticeScreen = require('./notice') +const lostAccountsNotice = require('../lib/lost-accounts-notice') // other views const ConfigScreen = require('./config') const InfoScreen = require('./info') @@ -55,6 +56,8 @@ function mapStateToProps (state) { network: state.metamask.network, provider: state.metamask.provider, forgottenPassword: state.appState.forgottenPassword, + lastUnreadNotice: state.metamask.lastUnreadNotice, + lostAccounts: state.metamask.lostAccounts, } } @@ -366,8 +369,19 @@ App.prototype.renderPrimary = function () { } } + // notices if (!props.noActiveNotices) { - return h(NoticeScreen, {key: 'NoticeScreen'}) + return h(NoticeScreen, { + notice: props.lastUnreadNotice, + key: 'NoticeScreen', + onConfirm: () => props.dispatch(actions.markNoticeRead(notice)), + }) + } else if (props.lostAccounts && props.lostAccounts.length > 0) { + return h(NoticeScreen, { + notice: lostAccountsNotice(props.lostAccounts), + key: 'LostAccountsNotice', + onConfirm: () => props.dispatch(actions.markAccountsFound()), + }) } // show current view diff --git a/ui/app/notice.js b/ui/app/notice.js index 3c2c746f2..92c171c4d 100644 --- a/ui/app/notice.js +++ b/ui/app/notice.js @@ -7,13 +7,7 @@ const actions = require('./actions') const linker = require('extension-link-enabler') const findDOMNode = require('react-dom').findDOMNode -module.exports = connect(mapStateToProps)(Notice) - -function mapStateToProps (state) { - return { - lastUnreadNotice: state.metamask.lastUnreadNotice, - } -} +module.exports = Notice inherits(Notice, Component) function Notice () { @@ -21,9 +15,8 @@ function Notice () { } Notice.prototype.render = function () { - const props = this.props - const title = props.lastUnreadNotice.title - const date = props.lastUnreadNotice.date + const { notice, onConfirm } = this.props + const { title, date, body } = notice return ( h('.flex-column.flex-center.flex-grow', [ @@ -59,6 +52,7 @@ Notice.prototype.render = function () { .markdown { overflow-x: hidden; } + .markdown h1, .markdown h2, .markdown h3 { margin: 10px 0; font-weight: bold; @@ -92,13 +86,13 @@ Notice.prototype.render = function () { }, }, [ h(ReactMarkdown, { - source: props.lastUnreadNotice.body, + source: body, skipHtml: true, }), ]), h('button', { - onClick: () => props.dispatch(actions.markNoticeRead(props.lastUnreadNotice)), + onClick: onConfirm, style: { marginTop: '18px', }, diff --git a/ui/lib/lost-accounts-notice.js b/ui/lib/lost-accounts-notice.js new file mode 100644 index 000000000..49b055778 --- /dev/null +++ b/ui/lib/lost-accounts-notice.js @@ -0,0 +1,23 @@ +const summary = require('../app/util').addressSummary + +module.exports = function (lostAccounts) { + return { + date: new Date().toDateString(), + title: 'Account Problem Caught', + body: `MetaMask has fixed a bug where some accounts were previously mis-generated. This was a rare issue, but you were affected! + +We have successfully imported the accounts that were mis-generated, but they will no longer be recovered with your normal seed phrase. + +We have marked the affected accounts as "Loose", and recommend you transfer ether and tokens away from those accounts, or export & back them up elsewhere. + +Your affected accounts are: +${lostAccounts.map(acct => ` - ${summary(acct)}`).join('\n')} + +These accounts have been marked as "Loose" so they will be easy to recognize in the account list. + +For more information, please read [our blog post.][1] + +[1]: https://medium.com/metamask/metamask-3-migration-guide-914b79533cdd#.7d8ktj4h3 + ` + } +} -- cgit v1.2.3 From 553f1769a099ac037cdda489295a96f7dd2c100f Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 20 Dec 2016 15:53:38 -0800 Subject: Add lost accounts ui development state --- development/states/lost-accounts.json | 91 +++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 development/states/lost-accounts.json diff --git a/development/states/lost-accounts.json b/development/states/lost-accounts.json new file mode 100644 index 000000000..9f1764c82 --- /dev/null +++ b/development/states/lost-accounts.json @@ -0,0 +1,91 @@ +{ + "metamask": { + "currentFiat": "USD", + "lostAccounts": [ + "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", + "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b" + ], + "conversionRate": 11.06608791, + "conversionDate": 1470421024, + "isInitialized": true, + "isUnlocked": true, + "currentDomain": "example.com", + "rpcTarget": "https://rawtestrpc.metamask.io/", + "identities": { + "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": { + "name": "Wallet 1", + "address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", + "mayBeFauceting": false + }, + "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b": { + "name": "Wallet 2", + "address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b", + "mayBeFauceting": false + }, + "0xeb9e64b93097bc15f01f13eae97015c57ab64823": { + "name": "Wallet 3", + "address": "0xeb9e64b93097bc15f01f13eae97015c57ab64823", + "mayBeFauceting": false + }, + "0x704107d04affddd9b66ab9de3dd7b095852e9b69": { + "name": "Wallet 4", + "address": "0x704107d04affddd9b66ab9de3dd7b095852e9b69", + "mayBeFauceting": false + } + }, + "unconfTxs": {}, + "accounts": { + "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": { + "code": "0x", + "balance": "0x100000000000", + "nonce": "0x0", + "address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc" + }, + "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b": { + "code": "0x", + "nonce": "0x0", + "balance": "0x100000000000", + "address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b" + }, + "0xeb9e64b93097bc15f01f13eae97015c57ab64823": { + "code": "0x", + "nonce": "0x0", + "balance": "0x100000000000", + "address": "0xeb9e64b93097bc15f01f13eae97015c57ab64823" + }, + "0x704107d04affddd9b66ab9de3dd7b095852e9b69": { + "code": "0x", + "balance": "0x0", + "nonce": "0x0", + "address": "0x704107d04affddd9b66ab9de3dd7b095852e9b69" + } + }, + "transactions": [], + "selectedAccount": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", + "network": "2", + "seedWords": null, + "isDisclaimerConfirmed": true, + "unconfMsgs": {}, + "messages": [], + "provider": { + "type": "testnet" + }, + "selectedAccount": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc" + }, + "appState": { + "menuOpen": false, + "currentView": { + "name": "accountDetail", + "detailView": null, + "context": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc" + }, + "accountDetail": { + "subview": "transactions" + }, + "currentDomain": "127.0.0.1:9966", + "transForward": true, + "isLoading": false, + "warning": null + }, + "identities": {} +} -- cgit v1.2.3 From 11c1004a41a9287c13ef15f28805863aab9fdea9 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 20 Dec 2016 15:54:59 -0800 Subject: Linted --- ui/app/app.js | 4 +- ui/app/components/notice.js | 110 ++++++++++++++++++++++++++++++++++++++++ ui/app/notice.js | 112 ----------------------------------------- ui/lib/lost-accounts-notice.js | 2 +- 4 files changed, 113 insertions(+), 115 deletions(-) create mode 100644 ui/app/components/notice.js delete mode 100644 ui/app/notice.js diff --git a/ui/app/app.js b/ui/app/app.js index 886bc987a..e98e635a2 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -16,7 +16,7 @@ const AccountDetailScreen = require('./account-detail') const SendTransactionScreen = require('./send') const ConfirmTxScreen = require('./conf-tx') // notice -const NoticeScreen = require('./notice') +const NoticeScreen = require('./components/notice') const lostAccountsNotice = require('../lib/lost-accounts-notice') // other views const ConfigScreen = require('./config') @@ -374,7 +374,7 @@ App.prototype.renderPrimary = function () { return h(NoticeScreen, { notice: props.lastUnreadNotice, key: 'NoticeScreen', - onConfirm: () => props.dispatch(actions.markNoticeRead(notice)), + onConfirm: () => props.dispatch(actions.markNoticeRead(props.lastUnreadNotice)), }) } else if (props.lostAccounts && props.lostAccounts.length > 0) { return h(NoticeScreen, { diff --git a/ui/app/components/notice.js b/ui/app/components/notice.js new file mode 100644 index 000000000..00db734d7 --- /dev/null +++ b/ui/app/components/notice.js @@ -0,0 +1,110 @@ +const inherits = require('util').inherits +const Component = require('react').Component +const h = require('react-hyperscript') +const ReactMarkdown = require('react-markdown') +const linker = require('extension-link-enabler') +const findDOMNode = require('react-dom').findDOMNode + +module.exports = Notice + +inherits(Notice, Component) +function Notice () { + Component.call(this) +} + +Notice.prototype.render = function () { + const { notice, onConfirm } = this.props + const { title, date, body } = notice + + return ( + h('.flex-column.flex-center.flex-grow', [ + h('h3.flex-center.text-transform-uppercacse.terms-header', { + style: { + background: '#EBEBEB', + color: '#AEAEAE', + width: '100%', + fontSize: '20px', + textAlign: 'center', + padding: 6, + }, + }, [ + title, + ]), + + h('h5.flex-center.text-transform-uppercacse.terms-header', { + style: { + background: '#EBEBEB', + color: '#AEAEAE', + marginBottom: 24, + width: '100%', + fontSize: '20px', + textAlign: 'center', + padding: 6, + }, + }, [ + date, + ]), + + h('style', ` + + .markdown { + overflow-x: hidden; + } + + .markdown h1, .markdown h2, .markdown h3 { + margin: 10px 0; + font-weight: bold; + } + + .markdown strong { + font-weight: bold; + } + .markdown em { + font-style: italic; + } + + .markdown p { + margin: 10px 0; + } + + .markdown a { + color: #df6b0e; + } + + `), + + h('div.markdown', { + style: { + background: 'rgb(235, 235, 235)', + height: '310px', + padding: '6px', + width: '90%', + overflowY: 'scroll', + scroll: 'auto', + }, + }, [ + h(ReactMarkdown, { + source: body, + skipHtml: true, + }), + ]), + + h('button', { + onClick: onConfirm, + style: { + marginTop: '18px', + }, + }, 'Continue'), + ]) + ) +} + +Notice.prototype.componentDidMount = function () { + var node = findDOMNode(this) + linker.setupListener(node) +} + +Notice.prototype.componentWillUnmount = function () { + var node = findDOMNode(this) + linker.teardownListener(node) +} diff --git a/ui/app/notice.js b/ui/app/notice.js deleted file mode 100644 index 92c171c4d..000000000 --- a/ui/app/notice.js +++ /dev/null @@ -1,112 +0,0 @@ -const inherits = require('util').inherits -const Component = require('react').Component -const h = require('react-hyperscript') -const ReactMarkdown = require('react-markdown') -const connect = require('react-redux').connect -const actions = require('./actions') -const linker = require('extension-link-enabler') -const findDOMNode = require('react-dom').findDOMNode - -module.exports = Notice - -inherits(Notice, Component) -function Notice () { - Component.call(this) -} - -Notice.prototype.render = function () { - const { notice, onConfirm } = this.props - const { title, date, body } = notice - - return ( - h('.flex-column.flex-center.flex-grow', [ - h('h3.flex-center.text-transform-uppercacse.terms-header', { - style: { - background: '#EBEBEB', - color: '#AEAEAE', - width: '100%', - fontSize: '20px', - textAlign: 'center', - padding: 6, - }, - }, [ - title, - ]), - - h('h5.flex-center.text-transform-uppercacse.terms-header', { - style: { - background: '#EBEBEB', - color: '#AEAEAE', - marginBottom: 24, - width: '100%', - fontSize: '20px', - textAlign: 'center', - padding: 6, - }, - }, [ - date, - ]), - - h('style', ` - - .markdown { - overflow-x: hidden; - } - - .markdown h1, .markdown h2, .markdown h3 { - margin: 10px 0; - font-weight: bold; - } - - .markdown strong { - font-weight: bold; - } - .markdown em { - font-style: italic; - } - - .markdown p { - margin: 10px 0; - } - - .markdown a { - color: #df6b0e; - } - - `), - - h('div.markdown', { - style: { - background: 'rgb(235, 235, 235)', - height: '310px', - padding: '6px', - width: '90%', - overflowY: 'scroll', - scroll: 'auto', - }, - }, [ - h(ReactMarkdown, { - source: body, - skipHtml: true, - }), - ]), - - h('button', { - onClick: onConfirm, - style: { - marginTop: '18px', - }, - }, 'Continue'), - ]) - ) -} - -Notice.prototype.componentDidMount = function () { - var node = findDOMNode(this) - linker.setupListener(node) -} - -Notice.prototype.componentWillUnmount = function () { - var node = findDOMNode(this) - linker.teardownListener(node) -} diff --git a/ui/lib/lost-accounts-notice.js b/ui/lib/lost-accounts-notice.js index 49b055778..948b13db6 100644 --- a/ui/lib/lost-accounts-notice.js +++ b/ui/lib/lost-accounts-notice.js @@ -18,6 +18,6 @@ These accounts have been marked as "Loose" so they will be easy to recognize in For more information, please read [our blog post.][1] [1]: https://medium.com/metamask/metamask-3-migration-guide-914b79533cdd#.7d8ktj4h3 - ` + `, } } -- cgit v1.2.3 From afcad53ef974e557c5dc701d364a88157694464f Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 20 Dec 2016 16:11:49 -0800 Subject: Refine a lostAccount test --- test/unit/idStore-migration-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/idStore-migration-test.js b/test/unit/idStore-migration-test.js index 66dd4683d..8532ac914 100644 --- a/test/unit/idStore-migration-test.js +++ b/test/unit/idStore-migration-test.js @@ -83,7 +83,7 @@ describe('IdentityStore to KeyringController migration', function() { keyringController.configManager.setWallet('something') const state = keyringController.getState() assert(state.isInitialized, 'old vault counted as initialized.') - assert.equal(state.lostAccounts.length, 0, 'no lost accounts') + assert(!state.lostAccounts, 'no lost accounts') }) }) }) -- cgit v1.2.3 From b3533f9bf7bc28988d2f2f280ab6ebc04cf66161 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 20 Dec 2016 17:29:44 -0800 Subject: Fixed another lostAccount test --- test/integration/lib/keyring-controller-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/lib/keyring-controller-test.js b/test/integration/lib/keyring-controller-test.js index 666795a6d..4673e65c2 100644 --- a/test/integration/lib/keyring-controller-test.js +++ b/test/integration/lib/keyring-controller-test.js @@ -44,7 +44,7 @@ QUnit.test('keyringController:submitPassword', function (assert) { this.keyringController.submitPassword(PASSWORD) .then((state) => { assert.ok(state.identities[FIRST_ADDRESS]) - assert.equal(state.lostAccounts.length, 0, 'no lost accounts') + assert.ok(state.lostAccounts, 'no lost accounts') done() }) }) -- cgit v1.2.3 From 48f2ae2154b6e804ee60cfc1235025c128a6cfa8 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 21 Dec 2016 11:01:04 -0800 Subject: Move old keystore migration code to metamask controller Allows keyring controller to be more generic, less opinionated, and who knows, maybe sooner publishable as its own thing. --- app/scripts/keyring-controller.js | 46 +---------------------------------- app/scripts/metamask-controller.js | 50 +++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 46 deletions(-) diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 61ee56638..1786f7c24 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -9,7 +9,6 @@ const encryptor = require('browser-passworder') const normalize = require('./lib/sig-util').normalize const messageManager = require('./lib/message-manager') -const IdStoreMigrator = require('./lib/idStore-migrator') const BN = ethUtil.BN // Keyrings: @@ -45,11 +44,6 @@ module.exports = class KeyringController extends EventEmitter { this._unconfMsgCbs = {} this.getNetwork = opts.getNetwork - - // TEMPORARY UNTIL FULL DEPRECATION: - this.idStoreMigrator = new IdStoreMigrator({ - configManager: this.configManager, - }) } // Set Store @@ -221,10 +215,7 @@ module.exports = class KeyringController extends EventEmitter { // Temporarily also migrates any old-style vaults first, as well. // (Pre MetaMask 3.0.0) submitPassword (password) { - return this.migrateOldVaultIfAny(password) - .then(() => { - return this.unlockKeyrings(password) - }) + return this.unlockKeyrings(password) .then((keyrings) => { this.keyrings = keyrings return this.fullUpdate() @@ -610,41 +601,6 @@ module.exports = class KeyringController extends EventEmitter { // THESE METHODS ARE ONLY USED INTERNALLY TO THE KEYRING-CONTROLLER // AND SO MAY BE CHANGED MORE LIBERALLY THAN THE ABOVE METHODS. - // Migrate Old Vault If Any - // @string password - // - // returns Promise() - // - // Temporary step used when logging in. - // Checks if old style (pre-3.0.0) Metamask Vault exists. - // If so, persists that vault in the new vault format - // with the provided password, so the other unlock steps - // may be completed without interruption. - migrateOldVaultIfAny (password) { - const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault() - if (!shouldMigrate) { - return Promise.resolve() - } - - return this.idStoreMigrator.migratedVaultForPassword(password) - .then((result) => { - this.password = password - - if (result && shouldMigrate) { - const { serialized, lostAccounts } = result - this.configManager.setLostAccounts(lostAccounts) - return this.restoreKeyring(serialized) - .then(keyring => keyring.getAccounts()) - .then((accounts) => { - this.configManager.setSelectedAccount(accounts[0]) - return this.persistAllKeyrings() - }) - } else { - return Promise.resolve() - } - }) - } - // Create First Key Tree // returns @Promise // diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index edb25d300..0c772536d 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -10,6 +10,7 @@ const ConfigManager = require('./lib/config-manager') const extension = require('./lib/extension') const autoFaucet = require('./lib/auto-faucet') const nodeify = require('./lib/nodeify') +const IdStoreMigrator = require('./lib/idStore-migrator') module.exports = class MetamaskController { @@ -44,6 +45,11 @@ module.exports = class MetamaskController { this.checkTOSChange() this.scheduleConversionInterval() + + // TEMPORARY UNTIL FULL DEPRECATION: + this.idStoreMigrator = new IdStoreMigrator({ + configManager: this.configManager, + }) } getState () { @@ -61,6 +67,7 @@ module.exports = class MetamaskController { getApi () { const keyringController = this.keyringController const noticeController = this.noticeController + const submitPassword = keyringController.submitPassword.bind(keyringController) return { getState: (cb) => { cb(null, this.getState()) }, @@ -81,7 +88,12 @@ module.exports = class MetamaskController { placeSeedWords: nodeify(keyringController.placeSeedWords).bind(keyringController), clearSeedWordCache: nodeify(keyringController.clearSeedWordCache).bind(keyringController), setLocked: nodeify(keyringController.setLocked).bind(keyringController), - submitPassword: nodeify(keyringController.submitPassword).bind(keyringController), + submitPassword: (password, cb) => { + this.migrateOldVaultIfAny() + .then(submitPassword) + .then((newState) => { cb(null, newState) }) + .catch((reason) => { cb(reason) }) + }, addNewKeyring: nodeify(keyringController.addNewKeyring).bind(keyringController), addNewAccount: nodeify(keyringController.addNewAccount).bind(keyringController), setSelectedAccount: nodeify(keyringController.setSelectedAccount).bind(keyringController), @@ -425,4 +437,40 @@ module.exports = class MetamaskController { cb(null, this.getState()) }) } + + // Migrate Old Vault If Any + // @string password + // + // returns Promise() + // + // Temporary step used when logging in. + // Checks if old style (pre-3.0.0) Metamask Vault exists. + // If so, persists that vault in the new vault format + // with the provided password, so the other unlock steps + // may be completed without interruption. + migrateOldVaultIfAny (password) { + const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault() + if (!shouldMigrate) { + return Promise.resolve(password) + } + + return this.idStoreMigrator.migratedVaultForPassword(password) + .then((result) => { + if (result && shouldMigrate) { + const { serialized, lostAccounts } = result + this.configManager.setLostAccounts(lostAccounts) + return this.keyringController.restoreKeyring(serialized) + .then(keyring => keyring.getAccounts()) + .then((accounts) => { + this.configManager.setSelectedAccount(accounts[0]) + return this.keyringController.persistAllKeyrings() + .then(() => password) + }) + } else { + return Promise.resolve(password) + } + }) + } + + } -- cgit v1.2.3 From 05ce7086f78e344aee23bb95de56d28317074a7d Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 21 Dec 2016 17:19:53 -0800 Subject: Added error when trying to unlock uninitialized vault --- app/scripts/keyring-controller.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 1786f7c24..4e9193ab2 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -721,6 +721,10 @@ module.exports = class KeyringController extends EventEmitter { // initializing the persisted keyrings to RAM. unlockKeyrings (password) { const encryptedVault = this.configManager.getVault() + if (!encryptedVault) { + throw new Error('Cannot unlock without a previous vault.') + } + return this.encryptor.decrypt(password, encryptedVault) .then((vault) => { this.password = password -- cgit v1.2.3 From a3a64afdd5b2ed6bbed8c8dba5cc0f14d4a1ad99 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 21 Dec 2016 17:20:14 -0800 Subject: Return undefined when vault is uninitialized --- app/scripts/lib/config-manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js index d36ccf0db..ede877b76 100644 --- a/app/scripts/lib/config-manager.js +++ b/app/scripts/lib/config-manager.js @@ -121,7 +121,7 @@ ConfigManager.prototype.setVault = function (encryptedString) { ConfigManager.prototype.getVault = function () { var data = this.getData() - return ('vault' in data) && data.vault + return data.vault } ConfigManager.prototype.getKeychains = function () { -- cgit v1.2.3 From ebeaf3b3d6cf79e2e0f251b9b2da765f0fe6d0e1 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 21 Dec 2016 17:21:10 -0800 Subject: Restructured migration Migrator now returns a lostAccount array that includes objects these objects include keys of address and privateKey, this allows the MetamaskController to restore the lost accounts even without customizing the idStore or the KeyringController. Also includes a patch that allows idStore to synchronously export private keys. --- app/scripts/lib/idStore-migrator.js | 7 +- app/scripts/lib/idStore.js | 3 +- app/scripts/metamask-controller.js | 62 ++++++++---- test/integration/lib/first-time.js | 2 +- test/integration/lib/idStore-migrator-test.js | 74 ++++++++++++++ test/integration/lib/keyring-controller-test.js | 122 ------------------------ 6 files changed, 126 insertions(+), 144 deletions(-) create mode 100644 test/integration/lib/idStore-migrator-test.js delete mode 100644 test/integration/lib/keyring-controller-test.js diff --git a/app/scripts/lib/idStore-migrator.js b/app/scripts/lib/idStore-migrator.js index 2e9418376..655aed0af 100644 --- a/app/scripts/lib/idStore-migrator.js +++ b/app/scripts/lib/idStore-migrator.js @@ -63,7 +63,12 @@ module.exports = class IdentityStoreMigrator { return { serialized, - lostAccounts, + lostAccounts: lostAccounts.map((address) => { + return { + address, + privateKey: this.idStore.exportAccount(address), + } + }), } }) } diff --git a/app/scripts/lib/idStore.js b/app/scripts/lib/idStore.js index cf4353e48..66e5d966c 100644 --- a/app/scripts/lib/idStore.js +++ b/app/scripts/lib/idStore.js @@ -202,7 +202,8 @@ IdentityStore.prototype.submitPassword = function (password, cb) { IdentityStore.prototype.exportAccount = function (address, cb) { var privateKey = this._idmgmt.exportPrivateKey(address) - cb(null, privateKey) + if (cb) cb(null, privateKey) + return privateKey } // diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 0c772536d..493ee661a 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -67,7 +67,6 @@ module.exports = class MetamaskController { getApi () { const keyringController = this.keyringController const noticeController = this.noticeController - const submitPassword = keyringController.submitPassword.bind(keyringController) return { getState: (cb) => { cb(null, this.getState()) }, @@ -89,10 +88,10 @@ module.exports = class MetamaskController { clearSeedWordCache: nodeify(keyringController.clearSeedWordCache).bind(keyringController), setLocked: nodeify(keyringController.setLocked).bind(keyringController), submitPassword: (password, cb) => { - this.migrateOldVaultIfAny() - .then(submitPassword) - .then((newState) => { cb(null, newState) }) - .catch((reason) => { cb(reason) }) + this.migrateOldVaultIfAny(password) + .then(keyringController.submitPassword.bind(keyringController)) + .then((newState) => { console.log('succeeded submitting!'); cb(null, newState) }) + .catch((reason) => { console.error(reason); cb(reason) }) }, addNewKeyring: nodeify(keyringController.addNewKeyring).bind(keyringController), addNewAccount: nodeify(keyringController.addNewAccount).bind(keyringController), @@ -456,21 +455,46 @@ module.exports = class MetamaskController { return this.idStoreMigrator.migratedVaultForPassword(password) .then((result) => { - if (result && shouldMigrate) { - const { serialized, lostAccounts } = result - this.configManager.setLostAccounts(lostAccounts) - return this.keyringController.restoreKeyring(serialized) - .then(keyring => keyring.getAccounts()) - .then((accounts) => { - this.configManager.setSelectedAccount(accounts[0]) - return this.keyringController.persistAllKeyrings() - .then(() => password) - }) - } else { - return Promise.resolve(password) + + this.keyringController.password = password + const { serialized, lostAccounts } = result + + // Restore the correct accounts first: + return this.keyringController.restoreKeyring(serialized) + .then(keyring => keyring.getAccounts()) + .then((accounts) => { + this.configManager.setSelectedAccount(accounts[0]) + return result + }) + + }).then((result) => { + + // Now we restore any lost accounts: + const { serialized, lostAccounts } = result + if (result && lostAccounts) { + this.configManager.setLostAccounts(lostAccounts.map((acct) => acct.address)) + return this.importLostAccounts(result) } - }) - } + return Promise.resolve(result) + }).then(() => { + + // Persist all these newly restored items to disk: + return this.keyringController.persistAllKeyrings() + // Ultimately pass the password back for normal unlocking: + }).then((result) => password) + } + // IMPORT LOST ACCOUNTS + // @Object with key lostAccounts: @Array accounts <{ address, privateKey }> + // Uses the array's private keys to create a new Simple Key Pair keychain + // and add it to the keyring controller. + importLostAccounts (result) { + const { serialized, lostAccounts } = result + const privKeys = lostAccounts.map(acct => acct.privateKey) + return this.keyringController.restoreKeyring({ + type: 'Simple Key Pair', + data: privKeys, + }) + } } diff --git a/test/integration/lib/first-time.js b/test/integration/lib/first-time.js index 12c573db1..1811ccbd4 100644 --- a/test/integration/lib/first-time.js +++ b/test/integration/lib/first-time.js @@ -79,7 +79,7 @@ QUnit.test('agree to terms', function (assert) { var createButton = app.find('button.primary')[0] createButton.click() - return wait(1500) + return wait(1000) }).then(function() { var detail = app.find('.account-detail-section')[0] diff --git a/test/integration/lib/idStore-migrator-test.js b/test/integration/lib/idStore-migrator-test.js new file mode 100644 index 000000000..338896171 --- /dev/null +++ b/test/integration/lib/idStore-migrator-test.js @@ -0,0 +1,74 @@ +var KeyringController = require('../../../app/scripts/keyring-controller') +var ConfigManager = require('../../../app/scripts/lib/config-manager') +var IdStoreMigrator = require('../../../app/scripts/lib/idStore-migrator') + +var oldStyleVault = require('../mocks/oldVault.json') +var badStyleVault = require('../mocks/badVault.json') + +var STORAGE_KEY = 'metamask-config' +var PASSWORD = '12345678' +var FIRST_ADDRESS = '0x4dd5d356c5A016A220bCD69e82e5AF680a430d00'.toLowerCase() +var SEED = 'fringe damage bounce extend tunnel afraid alert sound all soldier all dinner' + +var BAD_STYLE_FIRST_ADDRESS = '0xac39b311dceb2a4b2f5d8461c1cdaf756f4f7ae9' + +QUnit.module('Old Style Vaults', { + beforeEach: function () { + window.localStorage[STORAGE_KEY] = JSON.stringify(oldStyleVault) + + this.configManager = new ConfigManager({ + loadData: () => { return JSON.parse(window.localStorage[STORAGE_KEY]) }, + setData: (data) => { window.localStorage[STORAGE_KEY] = JSON.stringify(data) }, + }) + + this.migrator = new IdStoreMigrator({ + configManager: this.configManager, + }) + } +}) + +QUnit.test('migrator:isInitialized', function (assert) { + assert.ok(this.migrator) +}) + +QUnit.test('migrator:migratedVaultForPassword', function (assert) { + var done = assert.async() + + this.migrator.migratedVaultForPassword(PASSWORD) + .then((result) => { + const { serialized, lostAccounts } = result + assert.equal(serialized.data.mnemonic, SEED, 'seed phrase recovered') + assert.equal(lostAccounts.length, 0, 'no lost accounts') + done() + }) +}) + +QUnit.module('Old Style Vaults with bad HD seed', { + beforeEach: function () { + window.localStorage[STORAGE_KEY] = JSON.stringify(badStyleVault) + + this.configManager = new ConfigManager({ + loadData: () => { return JSON.parse(window.localStorage[STORAGE_KEY]) }, + setData: (data) => { window.localStorage[STORAGE_KEY] = JSON.stringify(data) }, + }) + + this.migrator = new IdStoreMigrator({ + configManager: this.configManager, + }) + } +}) + +QUnit.test('migrator:migratedVaultForPassword', function (assert) { + var done = assert.async() + + this.migrator.migratedVaultForPassword(PASSWORD) + .then((result) => { + const { serialized, lostAccounts } = result + + assert.equal(lostAccounts.length, 1, 'one lost account') + assert.equal(lostAccounts[0].address, '0xe15D894BeCB0354c501AE69429B05143679F39e0'.toLowerCase()) + assert.ok(lostAccounts[0].privateKey, 'private key exported') + done() + }) +}) + diff --git a/test/integration/lib/keyring-controller-test.js b/test/integration/lib/keyring-controller-test.js deleted file mode 100644 index 4673e65c2..000000000 --- a/test/integration/lib/keyring-controller-test.js +++ /dev/null @@ -1,122 +0,0 @@ -var KeyringController = require('../../../app/scripts/keyring-controller') -var ConfigManager = require('../../../app/scripts/lib/config-manager') - -var oldStyleVault = require('../mocks/oldVault.json') -var badStyleVault = require('../mocks/badVault.json') - -var STORAGE_KEY = 'metamask-config' -var PASSWORD = '12345678' -var FIRST_ADDRESS = '0x4dd5d356c5A016A220bCD69e82e5AF680a430d00'.toLowerCase() - -var BAD_STYLE_FIRST_ADDRESS = '0xac39b311dceb2a4b2f5d8461c1cdaf756f4f7ae9' - - -QUnit.module('Old Style Vaults', { - beforeEach: function () { - window.localStorage[STORAGE_KEY] = JSON.stringify(oldStyleVault) - - this.configManager = new ConfigManager({ - loadData: () => { return JSON.parse(window.localStorage[STORAGE_KEY]) }, - setData: (data) => { window.localStorage[STORAGE_KEY] = JSON.stringify(data) }, - }) - - this.keyringController = new KeyringController({ - configManager: this.configManager, - getNetwork: () => { return '2' }, - }) - - this.ethStore = { - addAccount: () => {}, - removeAccount: () => {}, - } - - this.keyringController.setStore(this.ethStore) - } -}) - -QUnit.test('keyringController:isInitialized', function (assert) { - assert.ok(this.keyringController.getState().isInitialized) -}) - -QUnit.test('keyringController:submitPassword', function (assert) { - var done = assert.async() - - this.keyringController.submitPassword(PASSWORD) - .then((state) => { - assert.ok(state.identities[FIRST_ADDRESS]) - assert.ok(state.lostAccounts, 'no lost accounts') - done() - }) -}) - -QUnit.test('keyringController:setLocked', function (assert) { - var done = assert.async() - var self = this - - this.keyringController.setLocked() - .then(function() { - assert.notOk(self.keyringController.password, 'password should be deallocated') - assert.deepEqual(self.keyringController.keyrings, [], 'keyrings should be deallocated') - done() - }) - .catch((reason) => { - assert.ifError(reason) - done() - }) -}) - -QUnit.module('Old Style Vaults with bad HD seed', { - beforeEach: function () { - window.localStorage[STORAGE_KEY] = JSON.stringify(badStyleVault) - - this.configManager = new ConfigManager({ - loadData: () => { return JSON.parse(window.localStorage[STORAGE_KEY]) }, - setData: (data) => { window.localStorage[STORAGE_KEY] = JSON.stringify(data) }, - }) - - this.keyringController = new KeyringController({ - configManager: this.configManager, - getNetwork: () => { return '2' }, - }) - - this.ethStore = { - addAccount: () => {}, - removeAccount: () => {}, - } - - this.keyringController.setStore(this.ethStore) - } -}) - -QUnit.test('keyringController:isInitialized', function (assert) { - assert.ok(this.keyringController.getState().isInitialized, 'vault is initialized') -}) - -QUnit.test('keyringController:submitPassword', function (assert) { - var done = assert.async() - - this.keyringController.submitPassword(PASSWORD) - .then((state) => { - assert.ok(state.identities[BAD_STYLE_FIRST_ADDRESS]) - assert.equal(state.lostAccounts.length, 1, 'one lost account') - assert.equal(state.lostAccounts[0], '0xe15D894BeCB0354c501AE69429B05143679F39e0'.toLowerCase()) - assert.deepEqual(this.configManager.getLostAccounts(), state.lostAccounts, 'persisted') - done() - }) -}) - -QUnit.test('keyringController:setLocked', function (assert) { - var done = assert.async() - var self = this - - this.keyringController.setLocked() - .then(function() { - assert.notOk(self.keyringController.password, 'password should be deallocated') - assert.deepEqual(self.keyringController.keyrings, [], 'keyrings should be deallocated') - done() - }) - .catch((reason) => { - assert.ifError(reason) - done() - }) -}) -- cgit v1.2.3 From 0df656850de606b82b4299fffdc812f45a252b69 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 21 Dec 2016 17:30:10 -0800 Subject: Linted --- app/scripts/metamask-controller.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 493ee661a..2dac61a04 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -457,7 +457,7 @@ module.exports = class MetamaskController { .then((result) => { this.keyringController.password = password - const { serialized, lostAccounts } = result + const { serialized } = result // Restore the correct accounts first: return this.keyringController.restoreKeyring(serialized) @@ -470,7 +470,7 @@ module.exports = class MetamaskController { }).then((result) => { // Now we restore any lost accounts: - const { serialized, lostAccounts } = result + const { lostAccounts } = result if (result && lostAccounts) { this.configManager.setLostAccounts(lostAccounts.map((acct) => acct.address)) return this.importLostAccounts(result) @@ -489,8 +489,7 @@ module.exports = class MetamaskController { // @Object with key lostAccounts: @Array accounts <{ address, privateKey }> // Uses the array's private keys to create a new Simple Key Pair keychain // and add it to the keyring controller. - importLostAccounts (result) { - const { serialized, lostAccounts } = result + importLostAccounts ({ lostAccounts }) { const privKeys = lostAccounts.map(acct => acct.privateKey) return this.keyringController.restoreKeyring({ type: 'Simple Key Pair', -- cgit v1.2.3 From cf3951c9dfcc42387b165ae76e0a2abaece06b6c Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 22 Dec 2016 13:40:12 -0800 Subject: Remove logs --- app/scripts/metamask-controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 2dac61a04..8b7713df4 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -90,8 +90,8 @@ module.exports = class MetamaskController { submitPassword: (password, cb) => { this.migrateOldVaultIfAny(password) .then(keyringController.submitPassword.bind(keyringController)) - .then((newState) => { console.log('succeeded submitting!'); cb(null, newState) }) - .catch((reason) => { console.error(reason); cb(reason) }) + .then((newState) => { cb(null, newState) }) + .catch((reason) => { cb(reason) }) }, addNewKeyring: nodeify(keyringController.addNewKeyring).bind(keyringController), addNewAccount: nodeify(keyringController.addNewAccount).bind(keyringController), -- cgit v1.2.3 From 291403c13f0c8f61f29585cc9a80ed618718f60f Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 22 Dec 2016 13:41:31 -0800 Subject: Don't bother changing selected accounts since accounts are recovered --- app/scripts/metamask-controller.js | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 8b7713df4..ab4cb8ed8 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -427,14 +427,8 @@ module.exports = class MetamaskController { markAccountsFound(cb) { this.configManager.setLostAccounts([]) - this.keyringController.getAccounts() - .then((accounts) => { - return this.keyringController.setSelectedAccount(accounts[0]) - }) - .then(() => { - this.sendUpdate() - cb(null, this.getState()) - }) + this.sendUpdate() + cb(null, this.getState()) } // Migrate Old Vault If Any @@ -461,11 +455,7 @@ module.exports = class MetamaskController { // Restore the correct accounts first: return this.keyringController.restoreKeyring(serialized) - .then(keyring => keyring.getAccounts()) - .then((accounts) => { - this.configManager.setSelectedAccount(accounts[0]) - return result - }) + .then(() => result) }).then((result) => { -- cgit v1.2.3 From 9e54e3baa0799e5083a9f9152f128077a2ee0527 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 22 Dec 2016 13:56:45 -0800 Subject: Break up migration function --- app/scripts/metamask-controller.js | 48 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index ab4cb8ed8..983a590d7 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -442,37 +442,37 @@ module.exports = class MetamaskController { // with the provided password, so the other unlock steps // may be completed without interruption. migrateOldVaultIfAny (password) { - const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault() - if (!shouldMigrate) { + + if (!this.checkIfShouldMigrate()) { return Promise.resolve(password) } - return this.idStoreMigrator.migratedVaultForPassword(password) - .then((result) => { - - this.keyringController.password = password - const { serialized } = result - - // Restore the correct accounts first: - return this.keyringController.restoreKeyring(serialized) - .then(() => result) + const keyringController = this.keyringController - }).then((result) => { + return this.idStoreMigrator.migratedVaultForPassword(password) + .then(this.restoreOldVaultAccounts.bind(this)) + .then(this.restoreOldLostAccounts.bind(this)) + .then(keyringController.persistAllKeyrings.bind(keyringController)) + .then(() => password) + } - // Now we restore any lost accounts: - const { lostAccounts } = result - if (result && lostAccounts) { - this.configManager.setLostAccounts(lostAccounts.map((acct) => acct.address)) - return this.importLostAccounts(result) - } - return Promise.resolve(result) - }).then(() => { + checkIfShouldMigrate() { + return !!this.configManager.getWallet() && !this.configManager.getVault() + } - // Persist all these newly restored items to disk: - return this.keyringController.persistAllKeyrings() + restoreOldVaultAccounts(migratorOutput) { + const { serialized } = migratorOutput + return this.keyringController.restoreKeyring(serialized) + .then(() => migratorOutput) + } - // Ultimately pass the password back for normal unlocking: - }).then((result) => password) + restoreOldLostAccounts(migratorOutput) { + const { lostAccounts } = migratorOutput + if (lostAccounts) { + this.configManager.setLostAccounts(lostAccounts.map(acct => acct.address)) + return this.importLostAccounts(migratorOutput) + } + return Promise.resolve(migratorOutput) } // IMPORT LOST ACCOUNTS -- cgit v1.2.3 From d3b2698f341e1d0dda86612cdf331e51067719c5 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 22 Dec 2016 14:09:10 -0800 Subject: Rename function to be an action --- ui/app/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/app/app.js b/ui/app/app.js index e98e635a2..6da0c3b1d 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -17,7 +17,7 @@ const SendTransactionScreen = require('./send') const ConfirmTxScreen = require('./conf-tx') // notice const NoticeScreen = require('./components/notice') -const lostAccountsNotice = require('../lib/lost-accounts-notice') +const generateLostAccountsNotice = require('../lib/lost-accounts-notice') // other views const ConfigScreen = require('./config') const InfoScreen = require('./info') @@ -378,7 +378,7 @@ App.prototype.renderPrimary = function () { }) } else if (props.lostAccounts && props.lostAccounts.length > 0) { return h(NoticeScreen, { - notice: lostAccountsNotice(props.lostAccounts), + notice: generateLostAccountsNotice(props.lostAccounts), key: 'LostAccountsNotice', onConfirm: () => props.dispatch(actions.markAccountsFound()), }) -- cgit v1.2.3 From 98527c1c254fe2d438191c73053dcf3223062ef3 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 22 Dec 2016 14:43:00 -0800 Subject: Fix account injection bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems `selectedAddress` was removed from the keyring-controller’s state, and is used to populate the injected current account. I couldn't help myself, I dug around, I found a PR named [changed all instances of selectedAddress to selectedAccount](https://github.com/MetaMask/metamask-plugin/commit/f5b0795ac5582dd53de728479cf47c43eabfe67c) by @Zanibas. Sorry, Kevin! Had you actually changed all instances, this bug would not have happened. Fixes #908 --- app/scripts/lib/inpage-provider.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/scripts/lib/inpage-provider.js b/app/scripts/lib/inpage-provider.js index 30fcbcb66..ccb592693 100644 --- a/app/scripts/lib/inpage-provider.js +++ b/app/scripts/lib/inpage-provider.js @@ -72,13 +72,13 @@ MetamaskInpageProvider.prototype.send = function (payload) { case 'eth_accounts': // read from localStorage - selectedAccount = self.publicConfigStore.get('selectedAddress') + selectedAccount = self.publicConfigStore.get('selectedAccount') result = selectedAccount ? [selectedAccount] : [] break case 'eth_coinbase': // read from localStorage - selectedAccount = self.publicConfigStore.get('selectedAddress') + selectedAccount = self.publicConfigStore.get('selectedAccount') result = selectedAccount || '0x0000000000000000000000000000000000000000' break @@ -119,6 +119,7 @@ function remoteStoreWithLocalStorageCache (storageKey) { var store = new RemoteStore(initState) // cache the latest state locally store.subscribe(function (state) { + console.log('received state update %s of %s', storageKey, state) localStorage[storageKey] = JSON.stringify(state) }) -- cgit v1.2.3 From 1861bf8e2b29552cf9b4a04107c5392f13a8ddce Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 22 Dec 2016 14:46:14 -0800 Subject: Remove log --- app/scripts/lib/inpage-provider.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/scripts/lib/inpage-provider.js b/app/scripts/lib/inpage-provider.js index ccb592693..a64c745ce 100644 --- a/app/scripts/lib/inpage-provider.js +++ b/app/scripts/lib/inpage-provider.js @@ -119,7 +119,6 @@ function remoteStoreWithLocalStorageCache (storageKey) { var store = new RemoteStore(initState) // cache the latest state locally store.subscribe(function (state) { - console.log('received state update %s of %s', storageKey, state) localStorage[storageKey] = JSON.stringify(state) }) -- cgit v1.2.3