Made progress on parity for MultiVault

- Deleted some unused items
- Renamed files and paths to match with new locations.
- Modified keyring controller logic to separate concerns.
- Fix account naming issues.
- Enable creation of new vault with default HD keyring.
- Formatting issues.
feature/default_network_editable
Kevin Serrano 8 years ago
parent e2f67a2cb8
commit db356a181a
No known key found for this signature in database
GPG Key ID: 7CC862A58D2889B4
  1. 2
      app/scripts/background.js
  2. 65
      app/scripts/keyring-controller.js
  3. 18
      app/scripts/keyrings/hd.js
  4. 3
      app/scripts/metamask-controller.js
  5. 23
      ui/app/actions.js
  6. 20
      ui/app/app.js
  7. 129
      ui/app/first-time/create-vault.js
  8. 28
      ui/app/first-time/init-menu.js
  9. 4
      ui/app/keychains/hd/recover-seed/confirmation.js
  10. 10
      ui/app/keychains/hd/restore-vault.js

@ -30,7 +30,7 @@ function triggerUi () {
// On first install, open a window to MetaMask website to how-it-works. // On first install, open a window to MetaMask website to how-it-works.
extension.runtime.onInstalled.addListener(function (details) { extension.runtime.onInstalled.addListener(function (details) {
if ((details.reason === 'install') && (!METAMASK_DEBUG)) { if ((details.reason === 'install') && (!METAMASK_DEBUG)) {
extension.tabs.create({url: 'https://metamask.io/#how-it-works'}) extension.tabs.create({url: 'https://metamask.io/#how-it-works'})
} }
}) })

@ -70,6 +70,23 @@ module.exports = class KeyringController extends EventEmitter {
this.ethStore = ethStore this.ethStore = ethStore
} }
createNewVaultAndKeychain(password, entropy, cb) {
this.createNewVault(password, entropy, (err, serialized) => {
if (err) return cb(err)
this.createFirstKeyTree(serialized, password, cb)
})
}
createNewVaultAndRestore(password, seed, cb) {
this.createNewVault(password, '', (err) => {
if (err) return cb(err)
this.addNewKeyring('HD Key Tree', {
mnemonic: seed,
n: 0,
}, cb)
})
}
createNewVault(password, entropy, cb) { createNewVault(password, entropy, cb) {
const salt = this.encryptor.generateSalt() const salt = this.encryptor.generateSalt()
this.configManager.setSalt(salt) this.configManager.setSalt(salt)
@ -89,22 +106,7 @@ module.exports = class KeyringController extends EventEmitter {
}) })
.then((encryptedString) => { .then((encryptedString) => {
this.configManager.setVault(encryptedString) this.configManager.setVault(encryptedString)
cb(null, serialized)
if (!serialized) {
this.addNewKeyring('HD Key Tree', null, (err, newState) => {
const firstKeyring = this.keyrings[0]
const firstAccount = firstKeyring.getAccounts()[0]
const hexAccount = ethUtil.addHexPrefix(firstAccount)
const seedWords = firstKeyring.serialize().mnemonic
this.configManager.setSelectedAccount(hexAccount)
this.configManager.setSeedWords(seedWords)
autoFaucet(hexAccount)
cb(err, newState)
})
} else {
return this.submitPassword(password, cb)
}
// NORMAL BEHAVIOR: // NORMAL BEHAVIOR:
// return cb(null, this.getState()) // return cb(null, this.getState())
}) })
@ -113,6 +115,23 @@ module.exports = class KeyringController extends EventEmitter {
}) })
} }
createFirstKeyTree(serialized, password, cb) {
if (!serialized) {
this.addNewKeyring('HD Key Tree', {n: 1}, (err, newState) => {
const firstKeyring = this.keyrings[0]
const firstAccount = firstKeyring.getAccounts()[0]
const hexAccount = ethUtil.addHexPrefix(firstAccount)
const seedWords = firstKeyring.serialize().mnemonic
this.configManager.setSelectedAccount(hexAccount)
this.configManager.setSeedWords(seedWords)
autoFaucet(hexAccount)
cb(err, this.getState())
})
} else {
return this.submitPassword(password, cb)
}
}
submitPassword(password, cb) { submitPassword(password, cb) {
this.loadKey(password) this.loadKey(password)
.then((key) => { .then((key) => {
@ -139,10 +158,10 @@ module.exports = class KeyringController extends EventEmitter {
addNewKeyring(type, opts, cb) { addNewKeyring(type, opts, cb) {
const Keyring = this.getKeyringClassForType(type) const Keyring = this.getKeyringClassForType(type)
const keyring = new Keyring(opts) const keyring = new Keyring(opts)
const accounts = keyring.addAccounts(1) const accounts = keyring.getAccounts()
this.setupAccounts(accounts)
this.keyrings.push(keyring) this.keyrings.push(keyring)
this.setupAccounts(accounts)
this.persistAllKeyrings() this.persistAllKeyrings()
.then(() => { .then(() => {
cb(null, this.getState()) cb(null, this.getState())
@ -160,17 +179,21 @@ module.exports = class KeyringController extends EventEmitter {
} }
setupAccounts(accounts) { setupAccounts(accounts) {
const i = this.getAccounts().length
accounts.forEach((account) => { accounts.forEach((account) => {
this.loadBalanceAndNickname(account, i) this.loadBalanceAndNickname(account)
}) })
} }
// Takes an account address and an iterator representing // Takes an account address and an iterator representing
// the current number of named accounts. // the current number of named accounts.
loadBalanceAndNickname(account, i) { loadBalanceAndNickname(account) {
const address = ethUtil.addHexPrefix(account) const address = ethUtil.addHexPrefix(account)
this.ethStore.addAccount(address) this.ethStore.addAccount(address)
this.createNickname(address)
}
createNickname(address) {
var i = Object.keys(this.identities).length
const oldNickname = this.configManager.nicknameForWallet(address) const oldNickname = this.configManager.nicknameForWallet(address)
const name = oldNickname || `Account ${++i}` const name = oldNickname || `Account ${++i}`
this.identities[address] = { this.identities[address] = {

@ -17,13 +17,22 @@ module.exports = class HdKeyring extends EventEmitter {
super() super()
this.type = type this.type = type
this.opts = opts || {} this.opts = opts || {}
this.deserialize(opts)
}
deserialize(opts) {
this.wallets = [] this.wallets = []
this.mnemonic = null this.mnemonic = null
} this.root = null
if ('mnemonic' in opts) {
this.initFromMnemonic(opts.mnemonic)
}
if ('n' in opts) {
this.addAccounts(opts.n)
}
deserialize({ mnemonic, n }) {
this.initFromMnemonic(mnemonic || bip39.generateMnemonic())
this.addAccounts(n)
} }
initFromMnemonic(mnemonic) { initFromMnemonic(mnemonic) {
@ -83,4 +92,3 @@ module.exports = class HdKeyring extends EventEmitter {
} }
} }

@ -59,7 +59,8 @@ module.exports = class MetamaskController {
setGasMultiplier: this.setGasMultiplier.bind(this), setGasMultiplier: this.setGasMultiplier.bind(this),
// forward directly to keyringController // forward directly to keyringController
createNewVault: keyringController.createNewVault.bind(keyringController), createNewVaultAndKeychain: keyringController.createNewVaultAndKeychain.bind(keyringController),
createNewVaultAndRestore: keyringController.createNewVaultAndRestore.bind(keyringController),
clearSeedWordCache: keyringController.clearSeedWordCache.bind(keyringController), clearSeedWordCache: keyringController.clearSeedWordCache.bind(keyringController),
addNewKeyring: keyringController.addNewKeyring.bind(keyringController), addNewKeyring: keyringController.addNewKeyring.bind(keyringController),
addNewAccount: keyringController.addNewAccount.bind(keyringController), addNewAccount: keyringController.addNewAccount.bind(keyringController),

@ -23,7 +23,8 @@ var actions = {
showCreateVault: showCreateVault, showCreateVault: showCreateVault,
showRestoreVault: showRestoreVault, showRestoreVault: showRestoreVault,
showInitializeMenu: showInitializeMenu, showInitializeMenu: showInitializeMenu,
createNewVault: createNewVault, createNewVaultAndKeychain: createNewVaultAndKeychain,
createNewVaultAndRestore: createNewVaultAndRestore,
createNewVaultInProgress: createNewVaultInProgress, createNewVaultInProgress: createNewVaultInProgress,
addNewKeyring, addNewKeyring,
addNewAccount, addNewAccount,
@ -188,17 +189,27 @@ function confirmSeedWords () {
} }
} }
function createNewVault (password, entropy) { function createNewVaultAndRestore (password, seed) {
return (dispatch) => { return (dispatch) => {
// dispatch(actions.createNewVaultInProgress()) dispatch(actions.showLoadingIndication())
background.createNewVault(password, entropy, (err, newState) => { background.createNewVaultAndRestore(password, seed, (err, newState) => {
dispatch(actions.hideLoadingIndication())
if (err) return dispatch(actions.displayWarning(err.message))
dispatch(this.updateMetamaskState(newState))
})
}
}
function createNewVaultAndKeychain (password, entropy) {
return (dispatch) => {
background.createNewVaultAndKeychain(password, entropy, (err, newState) => {
if (err) { if (err) {
return dispatch(actions.showWarning(err.message)) return dispatch(actions.showWarning(err.message))
} }
dispatch(this.updateMetamaskState(newState)) dispatch(this.updateMetamaskState(newState))
dispatch(this.showAccountsPage()) dispatch(this.showNewVaultSeed())
dispatch(this.hideLoadingIndication())
}) })
} }
} }

@ -7,7 +7,6 @@ const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
// init // init
const DisclaimerScreen = require('./first-time/disclaimer') const DisclaimerScreen = require('./first-time/disclaimer')
const InitializeMenuScreen = require('./first-time/init-menu') const InitializeMenuScreen = require('./first-time/init-menu')
const CreateVaultScreen = require('./first-time/create-vault')
const NewKeyChainScreen = require('./new-keychain') const NewKeyChainScreen = require('./new-keychain')
// unlock // unlock
const UnlockScreen = require('./unlock') const UnlockScreen = require('./unlock')
@ -28,6 +27,7 @@ const Tooltip = require('./components/tooltip')
const BuyView = require('./components/buy-button-subview') const BuyView = require('./components/buy-button-subview')
const QrView = require('./components/qr-code') const QrView = require('./components/qr-code')
const HDCreateVaultComplete = require('./keychains/hd/create-vault-complete') const HDCreateVaultComplete = require('./keychains/hd/create-vault-complete')
const HDRestoreVaultScreen = require('./keychains/hd/restore-vault')
module.exports = connect(mapStateToProps)(App) module.exports = connect(mapStateToProps)(App)
@ -349,16 +349,6 @@ App.prototype.renderBackToInitButton = function () {
} else if (props.isInitialized) { } else if (props.isInitialized) {
var style var style
switch (props.currentView.name) { switch (props.currentView.name) {
case 'createVault':
style = {
position: 'absolute',
top: '41px',
left: '80px',
fontSize: '21px',
fontFamily: 'Montserrat Bold',
color: 'rgb(174, 174, 174)',
}
return this.renderBackButton(style, true)
case 'restoreVault': case 'restoreVault':
style = { style = {
position: 'absolute', position: 'absolute',
@ -403,8 +393,9 @@ App.prototype.renderPrimary = function () {
// show current view // show current view
switch (props.currentView.name) { switch (props.currentView.name) {
case 'createVault':
return h(CreateVaultScreen, {key: 'createVault'}) case 'restoreVault':
return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'})
default: default:
return h(InitializeMenuScreen, {key: 'menuScreenInit'}) return h(InitializeMenuScreen, {key: 'menuScreenInit'})
@ -440,9 +431,6 @@ App.prototype.renderPrimary = function () {
case 'info': case 'info':
return h(InfoScreen, {key: 'info'}) return h(InfoScreen, {key: 'info'})
case 'createVault':
return h(CreateVaultScreen, {key: 'createVault'})
case 'buyEth': case 'buyEth':
return h(BuyView, {key: 'buyEthView'}) return h(BuyView, {key: 'buyEthView'})

@ -1,129 +0,0 @@
const inherits = require('util').inherits
const Component = require('react').Component
const connect = require('react-redux').connect
const h = require('react-hyperscript')
const actions = require('../actions')
module.exports = connect(mapStateToProps)(CreateVaultScreen)
inherits(CreateVaultScreen, Component)
function CreateVaultScreen () {
Component.call(this)
}
function mapStateToProps (state) {
return {
warning: state.appState.warning,
}
}
CreateVaultScreen.prototype.render = function () {
var state = this.props
return (
h('.initialize-screen.flex-column.flex-center.flex-grow', [
h('h3.flex-center.text-transform-uppercase', {
style: {
background: '#EBEBEB',
color: '#AEAEAE',
marginBottom: 24,
width: '100%',
fontSize: '20px',
padding: 6,
},
}, [
'Create Vault',
]),
// password
h('input.large-input.letter-spacey', {
type: 'password',
id: 'password-box',
placeholder: 'New Password (min 8 chars)',
style: {
width: 260,
marginTop: 12,
},
}),
// confirm password
h('input.large-input.letter-spacey', {
type: 'password',
id: 'password-box-confirm',
placeholder: 'Confirm Password',
onKeyPress: this.createVaultOnEnter.bind(this),
style: {
width: 260,
marginTop: 16,
},
}),
h('.flex-row.flex-space-between', {
style: {
marginTop: 30,
width: '50%',
},
}, [
// cancel
h('button.primary', {
onClick: this.showInitializeMenu.bind(this),
}, 'CANCEL'),
// submit
h('button.primary', {
onClick: this.createNewVault.bind(this),
}, 'OK'),
]),
(!state.inProgress && state.warning) && (
h('span.in-progress-notification', state.warning)
),
state.inProgress && (
h('span.in-progress-notification', 'Generating Seed...')
),
])
)
}
CreateVaultScreen.prototype.componentDidMount = function () {
document.getElementById('password-box').focus()
}
CreateVaultScreen.prototype.showInitializeMenu = function () {
this.props.dispatch(actions.showInitializeMenu())
}
// create vault
CreateVaultScreen.prototype.createVaultOnEnter = function (event) {
if (event.key === 'Enter') {
event.preventDefault()
this.createNewVault()
}
}
CreateVaultScreen.prototype.createNewVault = function () {
var passwordBox = document.getElementById('password-box')
var password = passwordBox.value
var passwordConfirmBox = document.getElementById('password-box-confirm')
var passwordConfirm = passwordConfirmBox.value
// var entropy = document.getElementById('entropy-text-entry').value
if (password.length < 8) {
this.warning = 'password not long enough'
this.props.dispatch(actions.displayWarning(this.warning))
return
}
if (password !== passwordConfirm) {
this.warning = 'passwords don\'t match'
this.props.dispatch(actions.displayWarning(this.warning))
return
}
this.props.dispatch(actions.createNewVault(password, ''/* entropy*/))
}

@ -50,10 +50,10 @@ InitializeMenuScreen.prototype.renderMenu = function (state) {
h('h1', { h('h1', {
style: { style: {
fontSize: '1.7em', fontSize: '1.3em',
textTransform: 'uppercase', textTransform: 'uppercase',
color: '#7F8082', color: '#7F8082',
marginBottom: 20, marginBottom: 10,
}, },
}, 'MetaMask'), }, 'MetaMask'),
@ -82,6 +82,8 @@ InitializeMenuScreen.prototype.renderMenu = function (state) {
]), ]),
]), ]),
h('span.in-progress-notification', state.warning),
// password // password
h('input.large-input.letter-spacey', { h('input.large-input.letter-spacey', {
type: 'password', type: 'password',
@ -91,7 +93,6 @@ InitializeMenuScreen.prototype.renderMenu = function (state) {
style: { style: {
width: 260, width: 260,
marginTop: 12, marginTop: 12,
textAlign: 'center',
}, },
}), }),
@ -105,25 +106,22 @@ InitializeMenuScreen.prototype.renderMenu = function (state) {
style: { style: {
width: 260, width: 260,
marginTop: 16, marginTop: 16,
textAlign: 'center',
}, },
}), }),
h('button.primary', { h('button.primary', {
onClick: this.createNewVault.bind(this), onClick: this.createNewVaultAndKeychain.bind(this),
style: { style: {
margin: 12, margin: 12,
}, },
}, 'Create'), }, 'Create'),
(!state.inProgress && state.warning) && (
h('span.in-progress-notification', state.warning)
),
/*
h('.flex-row.flex-center.flex-grow', [ h('.flex-row.flex-center.flex-grow', [
h('p.pointer', { h('p.pointer', {
onClick: this.showRestoreVault.bind(this),
style: { style: {
fontSize: '0.8em', fontSize: '0.8em',
color: 'rgb(247, 134, 28)', color: 'rgb(247, 134, 28)',
@ -131,7 +129,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) {
}, },
}, 'I already have a DEN that I would like to import'), }, 'I already have a DEN that I would like to import'),
]), ]),
*/
]) ])
) )
@ -140,7 +138,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) {
InitializeMenuScreen.prototype.createVaultOnEnter = function (event) { InitializeMenuScreen.prototype.createVaultOnEnter = function (event) {
if (event.key === 'Enter') { if (event.key === 'Enter') {
event.preventDefault() event.preventDefault()
this.createNewVault() this.createNewVaultAndKeychain()
} }
} }
@ -148,7 +146,11 @@ InitializeMenuScreen.prototype.componentDidMount = function () {
document.getElementById('password-box').focus() document.getElementById('password-box').focus()
} }
InitializeMenuScreen.prototype.createNewVault = function () { InitializeMenuScreen.prototype.showRestoreVault = function () {
this.props.dispatch(actions.showRestoreVault())
}
InitializeMenuScreen.prototype.createNewVaultAndKeychain = function () {
var passwordBox = document.getElementById('password-box') var passwordBox = document.getElementById('password-box')
var password = passwordBox.value var password = passwordBox.value
var passwordConfirmBox = document.getElementById('password-box-confirm') var passwordConfirmBox = document.getElementById('password-box-confirm')
@ -166,7 +168,7 @@ InitializeMenuScreen.prototype.createNewVault = function () {
return return
} }
this.props.dispatch(actions.createNewVault(password, ''/* entropy*/)) this.props.dispatch(actions.createNewVaultAndKeychain(password, ''/* entropy*/))
} }
InitializeMenuScreen.prototype.inputChanged = function (event) { InitializeMenuScreen.prototype.inputChanged = function (event) {

@ -3,7 +3,7 @@ const inherits = require('util').inherits
const Component = require('react').Component const Component = require('react').Component
const connect = require('react-redux').connect const connect = require('react-redux').connect
const h = require('react-hyperscript') const h = require('react-hyperscript')
const actions = require('../actions') const actions = require('../../../actions')
module.exports = connect(mapStateToProps)(RevealSeedConfirmatoin) module.exports = connect(mapStateToProps)(RevealSeedConfirmatoin)
@ -68,7 +68,7 @@ RevealSeedConfirmatoin.prototype.render = function () {
style: { style: {
marginTop: '12px', marginTop: '12px',
}, },
}, 'Enter the phrase "I understand" to proceed.'), }, `Enter the phrase "${this.confirmationPhrase}" to proceed.`),
// confirm confirmation // confirm confirmation
h('input.large-input.letter-spacey', { h('input.large-input.letter-spacey', {

@ -1,8 +1,8 @@
const inherits = require('util').inherits const inherits = require('util').inherits
const PersistentForm = require('../../lib/persistent-form') const PersistentForm = require('../../../lib/persistent-form')
const connect = require('react-redux').connect const connect = require('react-redux').connect
const h = require('react-hyperscript') const h = require('react-hyperscript')
const actions = require('../actions') const actions = require('../../actions')
module.exports = connect(mapStateToProps)(RestoreVaultScreen) module.exports = connect(mapStateToProps)(RestoreVaultScreen)
@ -96,7 +96,7 @@ RestoreVaultScreen.prototype.render = function () {
// submit // submit
h('button.primary', { h('button.primary', {
onClick: this.restoreVault.bind(this), onClick: this.createNewVaultAndRestore.bind(this),
}, 'OK'), }, 'OK'),
]), ]),
@ -116,7 +116,7 @@ RestoreVaultScreen.prototype.onMaybeCreate = function (event) {
} }
} }
RestoreVaultScreen.prototype.restoreVault = function () { RestoreVaultScreen.prototype.createNewVaultAndRestore = function () {
// check password // check password
var passwordBox = document.getElementById('password-box') var passwordBox = document.getElementById('password-box')
var password = passwordBox.value var password = passwordBox.value
@ -144,5 +144,5 @@ RestoreVaultScreen.prototype.restoreVault = function () {
// submit // submit
this.warning = null this.warning = null
this.props.dispatch(actions.displayWarning(this.warning)) this.props.dispatch(actions.displayWarning(this.warning))
this.props.dispatch(actions.recoverFromSeed(password, seed)) this.props.dispatch(actions.createNewVaultAndRestore(password, seed))
} }

Loading…
Cancel
Save