1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-24 02:58:09 +01:00
metamask-extension/app/scripts/lib/idStore.js

348 lines
9.1 KiB
JavaScript
Raw Normal View History

2016-02-11 02:44:46 +01:00
const EventEmitter = require('events').EventEmitter
const inherits = require('util').inherits
2016-06-17 04:51:34 +02:00
const ethUtil = require('ethereumjs-util')
const KeyStore = require('eth-lightwallet').keystore
2016-02-11 02:44:46 +01:00
const clone = require('clone')
const extend = require('xtend')
const autoFaucet = require('./auto-faucet')
const DEFAULT_RPC = 'https://testrpc.metamask.io/'
const IdManagement = require('./id-management')
2016-12-14 21:55:41 +01:00
2016-02-11 02:44:46 +01:00
module.exports = IdentityStore
inherits(IdentityStore, EventEmitter)
2016-06-21 22:18:32 +02:00
function IdentityStore (opts = {}) {
EventEmitter.call(this)
2016-02-11 02:44:46 +01:00
// we just use the ethStore to auto-add accounts
this._ethStore = opts.ethStore
this.configManager = opts.configManager
2016-03-03 07:58:23 +01:00
// lightwallet key store
this._keyStore = null
2016-03-03 07:58:23 +01:00
// lightwallet wrapper
this._idmgmt = null
this.hdPathString = "m/44'/60'/0'/0"
2016-02-11 02:44:46 +01:00
this._currentState = {
2016-02-11 02:44:46 +01:00
selectedAddress: null,
identities: {},
}
// not part of serilized metamask state - only kept in memory
}
//
// public
//
IdentityStore.prototype.createNewVault = function (password, cb) {
delete this._keyStore
var serializedKeystore = this.configManager.getWallet()
2016-06-25 01:13:27 +02:00
if (serializedKeystore) {
this.configManager.setData({})
}
this.purgeCache()
this._createVault(password, null, (err) => {
2016-03-03 07:58:23 +01:00
if (err) return cb(err)
this._autoFaucet()
this.configManager.setShowSeedWords(true)
var seedWords = this._idmgmt.getSeed()
this._loadIdentities()
2016-03-03 07:58:23 +01:00
cb(null, seedWords)
})
2016-02-17 09:55:57 +01:00
}
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.recoverSeed = function (cb) {
this.configManager.setShowSeedWords(true)
2016-06-03 02:11:10 +02:00
if (!this._idmgmt) return cb(new Error('Unauthenticated. Please sign in.'))
var seedWords = this._idmgmt.getSeed()
cb(null, seedWords)
}
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.recoverFromSeed = function (password, seed, cb) {
this.purgeCache()
this._createVault(password, seed, (err) => {
2016-03-15 21:39:12 +01:00
if (err) return cb(err)
this._loadIdentities()
cb(null, this.getState())
2016-03-15 21:39:12 +01:00
})
}
2016-02-17 09:55:57 +01:00
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.setStore = function (store) {
this._ethStore = store
2016-02-11 02:44:46 +01:00
}
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.clearSeedWordCache = function (cb) {
const configManager = this.configManager
configManager.setShowSeedWords(false)
cb(null, configManager.getSelectedAccount())
}
2016-02-17 09:55:57 +01:00
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.getState = function () {
const configManager = this.configManager
var seedWords = this.getSeedIfUnlocked()
return clone(extend(this._currentState, {
isInitialized: !!configManager.getWallet() && !seedWords,
isUnlocked: this._isUnlocked(),
seedWords: seedWords,
isDisclaimerConfirmed: configManager.getConfirmedDisclaimer(),
selectedAddress: configManager.getSelectedAccount(),
2016-08-18 19:40:35 +02:00
shapeShiftTxList: configManager.getShapeShiftTxList(),
2016-10-13 04:35:09 +02:00
gasMultiplier: configManager.getGasMultiplier(),
2016-02-11 02:44:46 +01:00
}))
}
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.getSeedIfUnlocked = function () {
const configManager = this.configManager
var showSeed = configManager.getShouldShowSeedWords()
var idmgmt = this._idmgmt
var shouldShow = showSeed && !!idmgmt
var seedWords = shouldShow ? idmgmt.getSeed() : null
return seedWords
}
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.getSelectedAddress = function () {
const configManager = this.configManager
return configManager.getSelectedAccount()
2016-02-11 02:44:46 +01:00
}
IdentityStore.prototype.setSelectedAddressSync = function (address) {
const configManager = this.configManager
if (!address) {
var addresses = this._getAddresses()
address = addresses[0]
}
configManager.setSelectedAccount(address)
return address
}
IdentityStore.prototype.setSelectedAddress = function (address, cb) {
const resultAddress = this.setSelectedAddressSync(address)
if (cb) return cb(null, resultAddress)
2016-02-11 02:44:46 +01:00
}
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.revealAccount = function (cb) {
const derivedKey = this._idmgmt.derivedKey
const keyStore = this._keyStore
const configManager = this.configManager
keyStore.setDefaultHdDerivationPath(this.hdPathString)
keyStore.generateNewAddress(derivedKey, 1)
2016-09-12 23:34:45 +02:00
const addresses = keyStore.getAddresses()
const address = addresses[ addresses.length - 1 ]
2016-09-12 23:22:06 +02:00
this._ethStore.addAccount(ethUtil.addHexPrefix(address))
configManager.setWallet(keyStore.serialize())
this._loadIdentities()
this._didUpdate()
cb(null)
}
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.getNetwork = function (err) {
if (err) {
this._currentState.network = 'loading'
2016-06-03 22:58:09 +02:00
this._didUpdate()
2016-05-30 20:22:19 +02:00
}
this.web3.version.getNetwork((err, network) => {
if (err) {
this._currentState.network = 'loading'
return this._didUpdate()
}
2016-08-12 04:44:59 +02:00
if (global.METAMASK_DEBUG) {
console.log('web3.getNetwork returned ' + network)
}
this._currentState.network = network
2016-06-03 22:58:09 +02:00
this._didUpdate()
})
}
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.setLocked = function (cb) {
delete this._keyStore
delete this._idmgmt
cb()
2016-02-11 02:44:46 +01:00
}
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.submitPassword = function (password, cb) {
const configManager = this.configManager
this.tryPassword(password, (err) => {
2016-02-11 02:44:46 +01:00
if (err) return cb(err)
// load identities before returning...
this._loadIdentities()
cb(null, configManager.getSelectedAccount())
2016-02-11 02:44:46 +01:00
})
}
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.exportAccount = function (address, cb) {
2016-04-06 21:01:10 +02:00
var privateKey = this._idmgmt.exportPrivateKey(address)
if (cb) cb(null, privateKey)
return privateKey
2016-04-06 21:01:10 +02:00
}
2016-03-03 07:58:23 +01:00
// private
//
2016-06-21 22:18:32 +02:00
IdentityStore.prototype._didUpdate = function () {
this.emit('update', this.getState())
2016-02-11 02:44:46 +01:00
}
2016-06-21 22:18:32 +02:00
IdentityStore.prototype._isUnlocked = function () {
var result = Boolean(this._keyStore) && Boolean(this._idmgmt)
2016-02-11 02:44:46 +01:00
return result
}
2016-02-17 09:55:57 +01:00
// load identities from keyStoreet
2016-06-21 22:18:32 +02:00
IdentityStore.prototype._loadIdentities = function () {
const configManager = this.configManager
if (!this._isUnlocked()) throw new Error('not unlocked')
var addresses = this._getAddresses()
addresses.forEach((address, i) => {
2016-02-17 09:55:57 +01:00
// // add to ethStore
if (this._ethStore) {
this._ethStore.addAccount(ethUtil.addHexPrefix(address))
}
2016-02-11 02:44:46 +01:00
// add to identities
2016-10-26 01:54:43 +02:00
const defaultLabel = 'Account ' + (i + 1)
const nickname = configManager.nicknameForWallet(address)
2016-02-11 02:44:46 +01:00
var identity = {
name: nickname || defaultLabel,
2016-02-11 02:44:46 +01:00
address: address,
mayBeFauceting: this._mayBeFauceting(i),
2016-02-11 02:44:46 +01:00
}
this._currentState.identities[address] = identity
2016-02-11 02:44:46 +01:00
})
this._didUpdate()
2016-02-11 02:44:46 +01:00
}
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.saveAccountLabel = function (account, label, cb) {
const configManager = this.configManager
configManager.setNicknameForWallet(account, label)
this._loadIdentities()
cb(null, label)
}
// mayBeFauceting
// If on testnet, index 0 may be fauceting.
// The UI will have to check the balance to know.
// If there is no balance and it mayBeFauceting,
// then it is in fact fauceting.
2016-06-21 22:18:32 +02:00
IdentityStore.prototype._mayBeFauceting = function (i) {
const configManager = this.configManager
var config = configManager.getProvider()
if (i === 0 &&
config.type === 'rpc' &&
config.rpcTarget === DEFAULT_RPC) {
return true
}
return false
}
2016-02-11 02:44:46 +01:00
//
// keyStore managment - unlocking + deserialization
//
2016-06-21 22:18:32 +02:00
IdentityStore.prototype.tryPassword = function (password, cb) {
var serializedKeystore = this.configManager.getWallet()
var keyStore = KeyStore.deserialize(serializedKeystore)
keyStore.keyFromPassword(password, (err, pwDerivedKey) => {
2016-03-03 07:58:23 +01:00
if (err) return cb(err)
const isCorrect = keyStore.isDerivedKeyCorrect(pwDerivedKey)
if (!isCorrect) return cb(new Error('Lightwallet - password incorrect'))
2016-09-12 20:25:30 +02:00
this._keyStore = keyStore
2016-09-12 20:21:27 +02:00
this._createIdMgmt(pwDerivedKey)
2016-03-03 07:58:23 +01:00
cb()
})
2016-02-11 02:44:46 +01:00
}
IdentityStore.prototype._createVault = function (password, seedPhrase, cb) {
const opts = {
password,
hdPathString: this.hdPathString,
}
if (seedPhrase) {
opts.seedPhrase = seedPhrase
2016-08-12 04:44:59 +02:00
}
KeyStore.createVault(opts, (err, keyStore) => {
if (err) return cb(err)
this._keyStore = keyStore
keyStore.keyFromPassword(password, (err, derivedKey) => {
if (err) return cb(err)
this.purgeCache()
2016-09-10 20:46:50 +02:00
keyStore.addHdDerivationPath(this.hdPathString, derivedKey, {curve: 'secp256k1', purpose: 'sign'})
this._createFirstWallet(derivedKey)
this._createIdMgmt(derivedKey)
this.setSelectedAddressSync()
cb()
})
})
}
IdentityStore.prototype._createIdMgmt = function (derivedKey) {
this._idmgmt = new IdManagement({
2016-09-12 20:21:27 +02:00
keyStore: this._keyStore,
derivedKey: derivedKey,
configManager: this.configManager,
})
}
IdentityStore.prototype.purgeCache = function () {
this._currentState.identities = {}
2016-09-13 00:26:07 +02:00
let accounts
try {
accounts = Object.keys(this._ethStore._currentState.accounts)
2016-09-13 00:26:07 +02:00
} catch (e) {
accounts = []
}
accounts.forEach((address) => {
this._ethStore.removeAccount(address)
})
}
IdentityStore.prototype._createFirstWallet = function (derivedKey) {
const keyStore = this._keyStore
keyStore.setDefaultHdDerivationPath(this.hdPathString)
keyStore.generateNewAddress(derivedKey, 1)
this.configManager.setWallet(keyStore.serialize())
var addresses = keyStore.getAddresses()
this._ethStore.addAccount(ethUtil.addHexPrefix(addresses[0]))
}
// get addresses and normalize address hexString
2016-06-21 22:18:32 +02:00
IdentityStore.prototype._getAddresses = function () {
return this._keyStore.getAddresses(this.hdPathString).map((address) => {
return ethUtil.addHexPrefix(address)
})
}
2016-06-21 22:18:32 +02:00
IdentityStore.prototype._autoFaucet = function () {
var addresses = this._getAddresses()
autoFaucet(addresses[0])
}
2016-02-11 02:44:46 +01:00
// util