1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 01:39:44 +01:00

Added new modular private key import system

Now any strategy for importing a private key that can be described as a pure function can be very easily turned into a MetaMask import strategy.

I've created a generic and reusable UI action called `importNewAccount(strategy, args)`.

The `strategy` is a unique identifier defined in `app/scripts/account-import-strategies`, and the `args` will be passed to the member of the `strategies` array whose key matches the strategy string.

Strategies return private key hex strings, and are used by the metamask-controller to create a new keyring, and select that new account, before calling back.

This also implements @frankiebee's idea of showing the imported account when it's been imported (my oversight!).

This commit only moves us to this architecture, keeping feature parity for private key import, but has some untested code for importing geth-style JSON files as well!
This commit is contained in:
Dan Finlay 2017-01-18 15:17:08 -08:00
parent 28212d167c
commit b52346388b
4 changed files with 65 additions and 2 deletions

View File

@ -0,0 +1,37 @@
const Wallet = require('ethereumjs-wallet')
const importers = require('ethereumjs-wallet/thirdparty')
const ethUtil = require('ethereumjs-util')
const accountImporter = {
importAccount(strategy, args) {
try {
const importer = this.strategies[strategy]
const wallet = importer.apply(null, args)
const privateKeyHex = walletToPrivateKey(wallet)
return Promise.resolve(privateKeyHex)
} catch (e) {
return Promise.reject(e)
}
},
strategies: {
'Private Key': (privateKey) => {
const stripped = ethUtil.stripHexPrefix(privateKey)
const buffer = new Buffer(stripped, 'hex')
return Wallet.fromPrivateKey(buffer)
},
'JSON File': (input, password) => {
const wallet = importers.fromEtherWallet(input, password)
return walletToPrivateKey(wallet)
},
},
}
function walletToPrivateKey (wallet) {
const privateKeyBuffer = wallet.getPrivateKey()
return ethUtil.bufferToHex(privateKeyBuffer)
}
module.exports = accountImporter

View File

@ -13,6 +13,7 @@ const extension = require('./lib/extension')
const autoFaucet = require('./lib/auto-faucet') const autoFaucet = require('./lib/auto-faucet')
const nodeify = require('./lib/nodeify') const nodeify = require('./lib/nodeify')
const IdStoreMigrator = require('./lib/idStore-migrator') const IdStoreMigrator = require('./lib/idStore-migrator')
const accountImporter = require('./account-import-strategies')
const version = require('../manifest.json').version const version = require('../manifest.json').version
module.exports = class MetamaskController extends EventEmitter { module.exports = class MetamaskController extends EventEmitter {
@ -121,6 +122,16 @@ module.exports = class MetamaskController extends EventEmitter {
.then((newState) => { cb(null, newState) }) .then((newState) => { cb(null, newState) })
.catch((reason) => { cb(reason) }) .catch((reason) => { cb(reason) })
}, },
importAccountWithStrategy: (strategy, args, cb) => {
accountImporter.importAccount(strategy, args)
.then((privateKey) => {
return keyringController.addNewKeyring('Simple Key Pair', [ privateKey ])
})
.then(keyring => keyring.getAccounts())
.then((accounts) => keyringController.setSelectedAccount(accounts[0]))
.then(() => { cb(null, keyringController.fullUpdate()) })
.catch((reason) => { cb(reason) })
},
addNewAccount: nodeify(keyringController.addNewAccount).bind(keyringController), addNewAccount: nodeify(keyringController.addNewAccount).bind(keyringController),
setSelectedAccount: nodeify(keyringController.setSelectedAccount).bind(keyringController), setSelectedAccount: nodeify(keyringController.setSelectedAccount).bind(keyringController),
saveAccountLabel: nodeify(keyringController.saveAccountLabel).bind(keyringController), saveAccountLabel: nodeify(keyringController.saveAccountLabel).bind(keyringController),

View File

@ -2,7 +2,6 @@ const inherits = require('util').inherits
const Component = require('react').Component const Component = require('react').Component
const h = require('react-hyperscript') const h = require('react-hyperscript')
const connect = require('react-redux').connect const connect = require('react-redux').connect
const type = 'Simple Key Pair'
const actions = require('../../actions') const actions = require('../../actions')
module.exports = connect(mapStateToProps)(PrivateKeyImportView) module.exports = connect(mapStateToProps)(PrivateKeyImportView)
@ -64,6 +63,6 @@ PrivateKeyImportView.prototype.createKeyringOnEnter = function (event) {
PrivateKeyImportView.prototype.createNewKeychain = function () { PrivateKeyImportView.prototype.createNewKeychain = function () {
const input = document.getElementById('private-key-box') const input = document.getElementById('private-key-box')
const privateKey = input.value const privateKey = input.value
this.props.dispatch(actions.addNewKeyring(type, [ privateKey ])) this.props.dispatch(actions.importNewAccount('Private Key', [ privateKey ]))
} }

View File

@ -43,6 +43,7 @@ var actions = {
createNewVaultAndRestore: createNewVaultAndRestore, createNewVaultAndRestore: createNewVaultAndRestore,
createNewVaultInProgress: createNewVaultInProgress, createNewVaultInProgress: createNewVaultInProgress,
addNewKeyring, addNewKeyring,
importNewAccount,
addNewAccount, addNewAccount,
NEW_ACCOUNT_SCREEN: 'NEW_ACCOUNT_SCREEN', NEW_ACCOUNT_SCREEN: 'NEW_ACCOUNT_SCREEN',
navigateToNewAccountScreen, navigateToNewAccountScreen,
@ -264,6 +265,21 @@ function addNewKeyring (type, opts) {
} }
} }
function importNewAccount (strategy, args) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
background.importAccountWithStrategy(strategy, args, (err, newState) => {
dispatch(actions.hideLoadingIndication())
if (err) return dispatch(actions.displayWarning(err.message))
dispatch(actions.updateMetamaskState(newState))
dispatch({
type: actions.SHOW_ACCOUNT_DETAIL,
value: newState.selectedAccount,
})
})
}
}
function navigateToNewAccountScreen() { function navigateToNewAccountScreen() {
return { return {
type: this.NEW_ACCOUNT_SCREEN, type: this.NEW_ACCOUNT_SCREEN,