diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b816dead..8aad47072 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ ## Current Master - [#84](https://github.com/poanetwork/metamask-extension/pull/84): (Fix) Change green color +- [#83](https://github.com/poanetwork/metamask-extension/pull/83): (Feature) Changing of password +- [#81](https://github.com/poanetwork/metamask-extension/pull/81): (Feature) Deanonymize private network +- [#80](https://github.com/poanetwork/metamask-extension/pull/80): (Feature) Remove imported account +- [#78](https://github.com/poanetwork/metamask-extension/pull/78): (Fix) Link to POA explorer for POA networks ## 4.8.4 Thu Aug 09 2018 diff --git a/app/scripts/lib/seed-phrase-verifier.js b/app/scripts/lib/seed-phrase-verifier.js index 3b5afb800..83425ceec 100644 --- a/app/scripts/lib/seed-phrase-verifier.js +++ b/app/scripts/lib/seed-phrase-verifier.js @@ -1,4 +1,4 @@ -const KeyringController = require('eth-keyring-controller') +const KeyringController = require('eth-keychain-controller') const log = require('loglevel') const seedPhraseVerifier = { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index b6328b31d..878fefed3 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -19,7 +19,7 @@ const createOriginMiddleware = require('./lib/createOriginMiddleware') const createLoggerMiddleware = require('./lib/createLoggerMiddleware') const createProviderMiddleware = require('./lib/createProviderMiddleware') const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex -const KeyringController = require('eth-keyring-controller') +const KeyringController = require('eth-keychain-controller') const NetworkController = require('./controllers/network') const PreferencesController = require('./controllers/preferences') const CurrencyController = require('./controllers/currency') @@ -370,6 +370,7 @@ module.exports = class MetamaskController extends EventEmitter { verifySeedPhrase: nodeify(this.verifySeedPhrase, this), clearSeedWordCache: this.clearSeedWordCache.bind(this), resetAccount: nodeify(this.resetAccount, this), + changePassword: nodeify(this.changePassword, this), removeAccount: nodeify(this.removeAccount, this), importAccountWithStrategy: nodeify(this.importAccountWithStrategy, this), @@ -770,6 +771,10 @@ module.exports = class MetamaskController extends EventEmitter { return selectedAddress } + async changePassword (oldPassword, newPassword) { + await this.keyringController.changePassword(oldPassword, newPassword) + } + /** * Removes an account from state / storage. * diff --git a/app/scripts/migrations/_multi-keyring.js b/app/scripts/migrations/_multi-keyring.js index 7a4578ea7..4cf27f343 100644 --- a/app/scripts/migrations/_multi-keyring.js +++ b/app/scripts/migrations/_multi-keyring.js @@ -10,7 +10,7 @@ which we dont have access to at the time of this writing. const ObservableStore = require('obs-store') const ConfigManager = require('../../app/scripts/lib/config-manager') const IdentityStoreMigrator = require('../../app/scripts/lib/idStore-migrator') -const KeyringController = require('eth-keyring-controller') +const KeyringController = require('eth-keychain-controller') const password = 'obviously not correct' diff --git a/old-ui/app/app.js b/old-ui/app/app.js index 9f330cdfd..8b627fea6 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -37,6 +37,7 @@ const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation const AccountDropdowns = require('./components/account-dropdowns').AccountDropdowns const DeleteRpc = require('./components/delete-rpc') const DeleteImportedAccount = require('./components/delete-imported-account') +const ConfirmChangePassword = require('./components/confirm-change-password') const ethNetProps = require('eth-net-props') module.exports = connect(mapStateToProps)(App) @@ -656,6 +657,9 @@ App.prototype.renderPrimary = function () { case 'delete-imported-account': log.debug('rendering delete imported account confirmation screen') return h(DeleteImportedAccount, {key: 'delete-imported-account'}) + case 'confirm-change-password': + log.debug('rendering confirm password changing screen') + return h(ConfirmChangePassword, {key: 'confirm-change-password'}) default: log.debug('rendering default, account detail screen') return h(AccountDetailScreen, {key: 'account-detail'}) diff --git a/old-ui/app/components/confirm-change-password.js b/old-ui/app/components/confirm-change-password.js new file mode 100644 index 000000000..f1a48d33f --- /dev/null +++ b/old-ui/app/components/confirm-change-password.js @@ -0,0 +1,147 @@ +const inherits = require('util').inherits +const Component = require('react').Component +const h = require('react-hyperscript') +const connect = require('react-redux').connect +const actions = require('../../../ui/app/actions') + +module.exports = connect(mapStateToProps)(ConfirmChangePassword) + +function mapStateToProps (state) { + return { + metamask: state.metamask, + warning: state.appState.warning, + } +} + +inherits(ConfirmChangePassword, Component) +function ConfirmChangePassword () { + Component.call(this) +} + +ConfirmChangePassword.prototype.render = function () { + const state = this.props + const passwordInputAdditionalStyle = { + width: '100%', + marginTop: 10, + marginBottom: 20, + } + return h('.flex-column.flex-grow', { + style: { + overflowX: 'auto', + overflowY: 'hidden', + }, + }, [ + // subtitle and nav + h('.section-title.flex-row.flex-center', [ + h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { + onClick: () => { + this.props.dispatch(actions.showConfigPage()) + }, + style: { + position: 'absolute', + left: '30px', + }, + }), + h('h2.page-subtitle', 'Change Password'), + ]), + h('div', { + style: { + margin: '0 30px', + }, + }, [ + h('.error', { + style: { + display: state.warning ? 'block' : 'none', + }, + }, state.warning), + h('span', 'Old password'), + h('input.large-input', { + type: 'password', + id: 'old-password-box', + ref: 'OldPasswordBox', + style: passwordInputAdditionalStyle, + }), + h('span', 'New password'), + h('input.large-input', { + type: 'password', + id: 'new-password-box', + ref: 'NewPasswordBox', + style: passwordInputAdditionalStyle, + }), + h('span', 'Confirm new password'), + h('input.large-input', { + type: 'password', + id: 'password-box-confirm', + ref: 'PasswordBoxConfirm', + style: passwordInputAdditionalStyle, + onKeyPress: this.createOnEnter.bind(this), + }), + ]), + h('p.confirm-label', { + style: { + textAlign: 'center', + margin: '0px 30px 20px ', + }, + }, + `Are you sure you want to change the password for unlocking of your wallet?`), + h('.flex-row.flex-right', { + style: { + marginRight: '30px', + }, + }, [ + h('button.btn-violet', + { + style: { + marginRight: '10px', + }, + onClick: () => { + this.props.dispatch(actions.showConfigPage()) + }, + }, + 'No'), + h('button', + { + onClick: () => { + this.ChangePassword() + }, + }, + 'Yes'), + ]), + ]) +} + +ConfirmChangePassword.prototype.createOnEnter = function (event) { + if (event.key === 'Enter') { + this.ChangePassword() + } +} + +ConfirmChangePassword.prototype.ChangePassword = function () { + const oldPasswordBox = this.refs.OldPasswordBox + const oldPassword = oldPasswordBox.value + const newPasswordBox = this.refs.NewPasswordBox + const newPassword = newPasswordBox.value + const newPasswordConfirmBox = this.refs.PasswordBoxConfirm + const newPasswordConfirm = newPasswordConfirmBox.value + + if (newPassword.length < 8) { + this.warning = 'Password not long enough' + + this.props.dispatch(actions.displayWarning(this.warning)) + return + } + if (newPassword !== newPasswordConfirm) { + this.warning = 'Passwords don\'t match' + this.props.dispatch(actions.displayWarning(this.warning)) + return + } + if (newPassword === oldPassword) { + this.warning = 'New password should differ from the current one' + this.props.dispatch(actions.displayWarning(this.warning)) + return + } + this.props.dispatch(actions.changePassword(oldPassword, newPassword)) + .then(() => { + this.props.dispatch(actions.showConfigPage()) + }) +} diff --git a/old-ui/app/config.js b/old-ui/app/config.js index 8641828ec..fae32cb86 100644 --- a/old-ui/app/config.js +++ b/old-ui/app/config.js @@ -192,10 +192,6 @@ ConfigScreen.prototype.render = function () { }, }, [ 'Resetting is for developer use only. ', - h('a', { - href: 'http://metamask.helpscoutdocs.com/article/36-resetting-an-account', - target: '_blank', - }, 'Read more.'), ]), h('br'), @@ -208,8 +204,23 @@ ConfigScreen.prototype.render = function () { state.dispatch(actions.resetAccount()) }, }, 'Reset Account'), - ]), + h('hr.horizontal-line', { + style: { + marginTop: '20px', + }, + }), + + h('button', { + style: { + alignSelf: 'center', + }, + onClick (event) { + event.preventDefault() + state.dispatch(actions.confirmChangePassword()) + }, + }, 'Change password'), + ]), ]), ]), ]) diff --git a/package-lock.json b/package-lock.json index 777038229..434a9f13a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8574,10 +8574,10 @@ } } }, - "eth-keyring-controller": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eth-keyring-controller/-/eth-keyring-controller-4.0.0.tgz", - "integrity": "sha512-D3Uj0b97vzEl/zXvrwYjFUYsz5gB4tnl/iMWqOm8jsvaREuHHbxRkm3iU/LG4fT8NGwS+fG8sLRPNBPu2/wRsA==", + "eth-keychain-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eth-keychain-controller/-/eth-keychain-controller-4.0.1.tgz", + "integrity": "sha512-4SR3+JxSrlCjyM6FfAlH73vr9zZ3n1nWuspAlF0B40fDDipjPouc+KqxKeqXHgQoAYm3Rub2OUVUfj9V0KqiBA==", "dev": true, "requires": { "bip39": "^2.4.0", diff --git a/package.json b/package.json index 1bb75f8c7..e7eacdb49 100644 --- a/package.json +++ b/package.json @@ -245,7 +245,7 @@ "eslint-plugin-mocha": "^5.0.0", "eslint-plugin-react": "^7.4.0", "eth-json-rpc-middleware": "^1.6.0", - "eth-keyring-controller": "^4.0.0", + "eth-keychain-controller": "^4.0.1", "file-loader": "^1.1.11", "fs-promise": "^2.0.3", "ganache-cli": "^6.1.0", diff --git a/test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js b/test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js index cb413545f..e11b11237 100644 --- a/test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js +++ b/test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js @@ -6,7 +6,7 @@ const { KOVAN_CODE, } = require('../../../../../app/scripts/controllers/network/enums') -const KeyringController = require('eth-keyring-controller') +const KeyringController = require('eth-keychain-controller') describe('Recipient Blacklist Checker', function () { diff --git a/test/unit/app/seed-phrase-verifier-test.js b/test/unit/app/seed-phrase-verifier-test.js index d8720d5a0..7f90b6997 100644 --- a/test/unit/app/seed-phrase-verifier-test.js +++ b/test/unit/app/seed-phrase-verifier-test.js @@ -1,6 +1,6 @@ const assert = require('assert') const clone = require('clone') -const KeyringController = require('eth-keyring-controller') +const KeyringController = require('eth-keychain-controller') const firstTimeState = require('../../../app/scripts/first-time-state') const seedPhraseVerifier = require('../../../app/scripts/lib/seed-phrase-verifier') const mockEncryptor = require('../../lib/mock-encryptor') diff --git a/ui/app/actions.js b/ui/app/actions.js index 6a8b1b00d..015bc624c 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -92,6 +92,7 @@ var actions = { NEW_ACCOUNT_SCREEN: 'NEW_ACCOUNT_SCREEN', navigateToNewAccountScreen, resetAccount, + changePassword, removeAccount, showNewVaultSeed: showNewVaultSeed, showInfoPage: showInfoPage, @@ -311,6 +312,8 @@ var actions = { removeCustomRPC, SHOW_DELETE_IMPORTED_ACCOUNT: 'SHOW_DELETE_IMPORTED_ACCOUNT', showDeleteImportedAccount, + CONFIRM_CHANGE_PASSWORD: 'CONFIRM_CHANGE_PASSWORD', + confirmChangePassword, } module.exports = actions @@ -554,6 +557,26 @@ function resetAccount () { } } +function changePassword (oldPassword, newPassword) { + return dispatch => { + dispatch(actions.showLoadingIndication()) + + return new Promise((resolve, reject) => { + background.changePassword(oldPassword, newPassword, (err, account) => { + dispatch(actions.hideLoadingIndication()) + if (err) { + dispatch(actions.displayWarning(err.message)) + return reject(err) + } + + log.info('Password is changed for ' + account) + dispatch(actions.showAccountsPage()) + resolve(account) + }) + }) + } +} + function removeAccount (address) { return dispatch => { dispatch(actions.showLoadingIndication()) @@ -2315,3 +2338,9 @@ function showDeleteImportedAccount (identity, keyring) { keyring, } } + +function confirmChangePassword () { + return { + type: actions.CONFIRM_CHANGE_PASSWORD, + } +} diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index f9e989070..d201642ed 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -729,6 +729,14 @@ function reduceApp (state, action) { identity: action.identity, }) + case actions.CONFIRM_CHANGE_PASSWORD: + return extend(appState, { + currentView: { + name: 'confirm-change-password', + context: appState.currentView.context, + }, + }) + default: return appState }