commit
8e30acb41a
@ -0,0 +1,79 @@ |
|||||||
|
const ObservableStore = require('obs-store') |
||||||
|
const extend = require('xtend') |
||||||
|
|
||||||
|
class AddressBookController { |
||||||
|
|
||||||
|
|
||||||
|
// Controller in charge of managing the address book functionality from the
|
||||||
|
// recipients field on the send screen. Manages a history of all saved
|
||||||
|
// addresses and all currently owned addresses.
|
||||||
|
constructor (opts = {}, keyringController) { |
||||||
|
const initState = extend({ |
||||||
|
addressBook: [], |
||||||
|
}, opts.initState) |
||||||
|
this.store = new ObservableStore(initState) |
||||||
|
this.keyringController = keyringController |
||||||
|
} |
||||||
|
|
||||||
|
//
|
||||||
|
// PUBLIC METHODS
|
||||||
|
//
|
||||||
|
|
||||||
|
// Sets a new address book in store by accepting a new address and nickname.
|
||||||
|
setAddressBook (address, name) { |
||||||
|
return this._addToAddressBook(address, name) |
||||||
|
.then((addressBook) => { |
||||||
|
this.store.updateState({ |
||||||
|
addressBook, |
||||||
|
}) |
||||||
|
return Promise.resolve() |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
//
|
||||||
|
// PRIVATE METHODS
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
// Performs the logic to add the address and name into the address book. The
|
||||||
|
// pushed object is an object of two fields. Current behavior does not set an
|
||||||
|
// upper limit to the number of addresses.
|
||||||
|
_addToAddressBook (address, name) { |
||||||
|
let addressBook = this._getAddressBook() |
||||||
|
let identities = this._getIdentities() |
||||||
|
|
||||||
|
let addressBookIndex = addressBook.findIndex((element) => { return element.address.toLowerCase() === address.toLowerCase() || element.name === name }) |
||||||
|
let identitiesIndex = Object.keys(identities).findIndex((element) => { return element.toLowerCase() === address.toLowerCase() }) |
||||||
|
// trigger this condition if we own this address--no need to overwrite.
|
||||||
|
if (identitiesIndex !== -1) { |
||||||
|
return Promise.resolve(addressBook) |
||||||
|
// trigger this condition if we've seen this address before--may need to update nickname.
|
||||||
|
} else if (addressBookIndex !== -1) { |
||||||
|
addressBook.splice(addressBookIndex, 1) |
||||||
|
} else if (addressBook.length > 15) { |
||||||
|
addressBook.shift() |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
addressBook.push({ |
||||||
|
address: address, |
||||||
|
name, |
||||||
|
}) |
||||||
|
return Promise.resolve(addressBook) |
||||||
|
} |
||||||
|
|
||||||
|
// Internal method to get the address book. Current persistence behavior
|
||||||
|
// should not require that this method be called from the UI directly.
|
||||||
|
_getAddressBook () { |
||||||
|
return this.store.getState().addressBook |
||||||
|
} |
||||||
|
|
||||||
|
// Retrieves identities from the keyring controller in order to avoid
|
||||||
|
// duplication
|
||||||
|
_getIdentities () { |
||||||
|
return this.keyringController.memStore.getState().identities |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
module.exports = AddressBookController |
@ -1,90 +0,0 @@ |
|||||||
/* ID Management |
|
||||||
* |
|
||||||
* This module exists to hold the decrypted credentials for the current session. |
|
||||||
* It therefore exposes sign methods, because it is able to perform these |
|
||||||
* with noa dditional authentication, because its very instantiation |
|
||||||
* means the vault is unlocked. |
|
||||||
*/ |
|
||||||
|
|
||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
const Transaction = require('ethereumjs-tx') |
|
||||||
|
|
||||||
module.exports = IdManagement |
|
||||||
|
|
||||||
function IdManagement (opts) { |
|
||||||
if (!opts) opts = {} |
|
||||||
|
|
||||||
this.keyStore = opts.keyStore |
|
||||||
this.derivedKey = opts.derivedKey |
|
||||||
this.configManager = opts.configManager |
|
||||||
this.hdPathString = "m/44'/60'/0'/0" |
|
||||||
|
|
||||||
this.getAddresses = function () { |
|
||||||
return this.keyStore.getAddresses(this.hdPathString).map(function (address) { return '0x' + address }) |
|
||||||
} |
|
||||||
|
|
||||||
this.signTx = function (txParams) { |
|
||||||
|
|
||||||
// normalize values
|
|
||||||
txParams.gasPrice = ethUtil.intToHex(txParams.gasPrice) |
|
||||||
txParams.to = ethUtil.addHexPrefix(txParams.to) |
|
||||||
txParams.from = ethUtil.addHexPrefix(txParams.from.toLowerCase()) |
|
||||||
txParams.value = ethUtil.addHexPrefix(txParams.value) |
|
||||||
txParams.data = ethUtil.addHexPrefix(txParams.data) |
|
||||||
txParams.gasLimit = ethUtil.addHexPrefix(txParams.gasLimit || txParams.gas) |
|
||||||
txParams.nonce = ethUtil.addHexPrefix(txParams.nonce) |
|
||||||
var tx = new Transaction(txParams) |
|
||||||
|
|
||||||
// sign tx
|
|
||||||
var privKeyHex = this.exportPrivateKey(txParams.from) |
|
||||||
var privKey = ethUtil.toBuffer(privKeyHex) |
|
||||||
tx.sign(privKey) |
|
||||||
|
|
||||||
// Add the tx hash to the persisted meta-tx object
|
|
||||||
var txHash = ethUtil.bufferToHex(tx.hash()) |
|
||||||
var metaTx = this.configManager.getTx(txParams.metamaskId) |
|
||||||
metaTx.hash = txHash |
|
||||||
this.configManager.updateTx(metaTx) |
|
||||||
|
|
||||||
// return raw serialized tx
|
|
||||||
var rawTx = ethUtil.bufferToHex(tx.serialize()) |
|
||||||
return rawTx |
|
||||||
} |
|
||||||
|
|
||||||
this.signMsg = function (address, message) { |
|
||||||
// sign message
|
|
||||||
var privKeyHex = this.exportPrivateKey(address.toLowerCase()) |
|
||||||
var privKey = ethUtil.toBuffer(privKeyHex) |
|
||||||
var msgSig = ethUtil.ecsign(new Buffer(message.replace('0x', ''), 'hex'), privKey) |
|
||||||
var rawMsgSig = ethUtil.bufferToHex(concatSig(msgSig.v, msgSig.r, msgSig.s)) |
|
||||||
return rawMsgSig |
|
||||||
} |
|
||||||
|
|
||||||
this.getSeed = function () { |
|
||||||
return this.keyStore.getSeed(this.derivedKey) |
|
||||||
} |
|
||||||
|
|
||||||
this.exportPrivateKey = function (address) { |
|
||||||
var privKeyHex = ethUtil.addHexPrefix(this.keyStore.exportPrivateKey(address, this.derivedKey, this.hdPathString)) |
|
||||||
return privKeyHex |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
function padWithZeroes (number, length) { |
|
||||||
var myString = '' + number |
|
||||||
while (myString.length < length) { |
|
||||||
myString = '0' + myString |
|
||||||
} |
|
||||||
return myString |
|
||||||
} |
|
||||||
|
|
||||||
function concatSig (v, r, s) { |
|
||||||
const rSig = ethUtil.fromSigned(r) |
|
||||||
const sSig = ethUtil.fromSigned(s) |
|
||||||
const vSig = ethUtil.bufferToInt(v) |
|
||||||
const rStr = padWithZeroes(ethUtil.toUnsigned(rSig).toString('hex'), 64) |
|
||||||
const sStr = padWithZeroes(ethUtil.toUnsigned(sSig).toString('hex'), 64) |
|
||||||
const vStr = ethUtil.stripHexPrefix(ethUtil.intToHex(vSig)) |
|
||||||
return ethUtil.addHexPrefix(rStr.concat(sStr, vStr)).toString('hex') |
|
||||||
} |
|
||||||
|
|
@ -1,80 +0,0 @@ |
|||||||
const IdentityStore = require('./idStore') |
|
||||||
const HdKeyring = require('eth-hd-keyring') |
|
||||||
const sigUtil = require('eth-sig-util') |
|
||||||
const normalize = sigUtil.normalize |
|
||||||
const denodeify = require('denodeify') |
|
||||||
|
|
||||||
module.exports = class IdentityStoreMigrator { |
|
||||||
|
|
||||||
constructor ({ configManager }) { |
|
||||||
this.configManager = configManager |
|
||||||
const hasOldVault = this.hasOldVault() |
|
||||||
if (!hasOldVault) { |
|
||||||
this.idStore = new IdentityStore({ configManager }) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
migratedVaultForPassword (password) { |
|
||||||
const hasOldVault = this.hasOldVault() |
|
||||||
const configManager = this.configManager |
|
||||||
|
|
||||||
if (!this.idStore) { |
|
||||||
this.idStore = new IdentityStore({ configManager }) |
|
||||||
} |
|
||||||
|
|
||||||
if (!hasOldVault) { |
|
||||||
return Promise.resolve(null) |
|
||||||
} |
|
||||||
|
|
||||||
const idStore = this.idStore |
|
||||||
const submitPassword = denodeify(idStore.submitPassword.bind(idStore)) |
|
||||||
|
|
||||||
return submitPassword(password) |
|
||||||
.then(() => { |
|
||||||
const serialized = this.serializeVault() |
|
||||||
return this.checkForLostAccounts(serialized) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
serializeVault () { |
|
||||||
const mnemonic = this.idStore._idmgmt.getSeed() |
|
||||||
const numberOfAccounts = this.idStore._getAddresses().length |
|
||||||
|
|
||||||
return { |
|
||||||
type: 'HD Key Tree', |
|
||||||
data: { mnemonic, numberOfAccounts }, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
checkForLostAccounts (serialized) { |
|
||||||
const hd = new HdKeyring() |
|
||||||
return hd.deserialize(serialized.data) |
|
||||||
.then((hexAccounts) => { |
|
||||||
const newAccounts = hexAccounts.map(normalize) |
|
||||||
const oldAccounts = this.idStore._getAddresses().map(normalize) |
|
||||||
const lostAccounts = oldAccounts.reduce((result, account) => { |
|
||||||
if (newAccounts.includes(account)) { |
|
||||||
return result |
|
||||||
} else { |
|
||||||
result.push(account) |
|
||||||
return result |
|
||||||
} |
|
||||||
}, []) |
|
||||||
|
|
||||||
return { |
|
||||||
serialized, |
|
||||||
lostAccounts: lostAccounts.map((address) => { |
|
||||||
return { |
|
||||||
address, |
|
||||||
privateKey: this.idStore.exportAccount(address), |
|
||||||
} |
|
||||||
}), |
|
||||||
} |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
hasOldVault () { |
|
||||||
const wallet = this.configManager.getWallet() |
|
||||||
return wallet |
|
||||||
} |
|
||||||
} |
|
@ -1,343 +0,0 @@ |
|||||||
const EventEmitter = require('events').EventEmitter |
|
||||||
const inherits = require('util').inherits |
|
||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
const KeyStore = require('eth-lightwallet').keystore |
|
||||||
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') |
|
||||||
|
|
||||||
|
|
||||||
module.exports = IdentityStore |
|
||||||
|
|
||||||
inherits(IdentityStore, EventEmitter) |
|
||||||
function IdentityStore (opts = {}) { |
|
||||||
EventEmitter.call(this) |
|
||||||
|
|
||||||
// we just use the ethStore to auto-add accounts
|
|
||||||
this._ethStore = opts.ethStore |
|
||||||
this.configManager = opts.configManager |
|
||||||
// lightwallet key store
|
|
||||||
this._keyStore = null |
|
||||||
// lightwallet wrapper
|
|
||||||
this._idmgmt = null |
|
||||||
|
|
||||||
this.hdPathString = "m/44'/60'/0'/0" |
|
||||||
|
|
||||||
this._currentState = { |
|
||||||
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() |
|
||||||
|
|
||||||
if (serializedKeystore) { |
|
||||||
this.configManager.setData({}) |
|
||||||
} |
|
||||||
|
|
||||||
this.purgeCache() |
|
||||||
this._createVault(password, null, (err) => { |
|
||||||
if (err) return cb(err) |
|
||||||
|
|
||||||
this._autoFaucet() |
|
||||||
|
|
||||||
this.configManager.setShowSeedWords(true) |
|
||||||
var seedWords = this._idmgmt.getSeed() |
|
||||||
|
|
||||||
this._loadIdentities() |
|
||||||
|
|
||||||
cb(null, seedWords) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
IdentityStore.prototype.recoverSeed = function (cb) { |
|
||||||
this.configManager.setShowSeedWords(true) |
|
||||||
if (!this._idmgmt) return cb(new Error('Unauthenticated. Please sign in.')) |
|
||||||
var seedWords = this._idmgmt.getSeed() |
|
||||||
cb(null, seedWords) |
|
||||||
} |
|
||||||
|
|
||||||
IdentityStore.prototype.recoverFromSeed = function (password, seed, cb) { |
|
||||||
this.purgeCache() |
|
||||||
|
|
||||||
this._createVault(password, seed, (err) => { |
|
||||||
if (err) return cb(err) |
|
||||||
|
|
||||||
this._loadIdentities() |
|
||||||
cb(null, this.getState()) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
IdentityStore.prototype.setStore = function (store) { |
|
||||||
this._ethStore = store |
|
||||||
} |
|
||||||
|
|
||||||
IdentityStore.prototype.clearSeedWordCache = function (cb) { |
|
||||||
const configManager = this.configManager |
|
||||||
configManager.setShowSeedWords(false) |
|
||||||
cb(null, configManager.getSelectedAccount()) |
|
||||||
} |
|
||||||
|
|
||||||
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, |
|
||||||
selectedAddress: configManager.getSelectedAccount(), |
|
||||||
})) |
|
||||||
} |
|
||||||
|
|
||||||
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 |
|
||||||
} |
|
||||||
|
|
||||||
IdentityStore.prototype.getSelectedAddress = function () { |
|
||||||
const configManager = this.configManager |
|
||||||
return configManager.getSelectedAccount() |
|
||||||
} |
|
||||||
|
|
||||||
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) |
|
||||||
} |
|
||||||
|
|
||||||
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) |
|
||||||
const addresses = keyStore.getAddresses() |
|
||||||
const address = addresses[ addresses.length - 1 ] |
|
||||||
|
|
||||||
this._ethStore.addAccount(ethUtil.addHexPrefix(address)) |
|
||||||
|
|
||||||
configManager.setWallet(keyStore.serialize()) |
|
||||||
|
|
||||||
this._loadIdentities() |
|
||||||
this._didUpdate() |
|
||||||
cb(null) |
|
||||||
} |
|
||||||
|
|
||||||
IdentityStore.prototype.getNetwork = function (err) { |
|
||||||
if (err) { |
|
||||||
this._currentState.network = 'loading' |
|
||||||
this._didUpdate() |
|
||||||
} |
|
||||||
|
|
||||||
this.web3.version.getNetwork((err, network) => { |
|
||||||
if (err) { |
|
||||||
this._currentState.network = 'loading' |
|
||||||
return this._didUpdate() |
|
||||||
} |
|
||||||
if (global.METAMASK_DEBUG) { |
|
||||||
console.log('web3.getNetwork returned ' + network) |
|
||||||
} |
|
||||||
this._currentState.network = network |
|
||||||
this._didUpdate() |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
IdentityStore.prototype.setLocked = function (cb) { |
|
||||||
delete this._keyStore |
|
||||||
delete this._idmgmt |
|
||||||
cb() |
|
||||||
} |
|
||||||
|
|
||||||
IdentityStore.prototype.submitPassword = function (password, cb) { |
|
||||||
const configManager = this.configManager |
|
||||||
this.tryPassword(password, (err) => { |
|
||||||
if (err) return cb(err) |
|
||||||
// load identities before returning...
|
|
||||||
this._loadIdentities() |
|
||||||
cb(null, configManager.getSelectedAccount()) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
IdentityStore.prototype.exportAccount = function (address, cb) { |
|
||||||
var privateKey = this._idmgmt.exportPrivateKey(address) |
|
||||||
if (cb) cb(null, privateKey) |
|
||||||
return privateKey |
|
||||||
} |
|
||||||
|
|
||||||
// private
|
|
||||||
//
|
|
||||||
|
|
||||||
IdentityStore.prototype._didUpdate = function () { |
|
||||||
this.emit('update', this.getState()) |
|
||||||
} |
|
||||||
|
|
||||||
IdentityStore.prototype._isUnlocked = function () { |
|
||||||
var result = Boolean(this._keyStore) && Boolean(this._idmgmt) |
|
||||||
return result |
|
||||||
} |
|
||||||
|
|
||||||
// load identities from keyStoreet
|
|
||||||
IdentityStore.prototype._loadIdentities = function () { |
|
||||||
const configManager = this.configManager |
|
||||||
if (!this._isUnlocked()) throw new Error('not unlocked') |
|
||||||
|
|
||||||
var addresses = this._getAddresses() |
|
||||||
addresses.forEach((address, i) => { |
|
||||||
// // add to ethStore
|
|
||||||
if (this._ethStore) { |
|
||||||
this._ethStore.addAccount(ethUtil.addHexPrefix(address)) |
|
||||||
} |
|
||||||
// add to identities
|
|
||||||
const defaultLabel = 'Account ' + (i + 1) |
|
||||||
const nickname = configManager.nicknameForWallet(address) |
|
||||||
var identity = { |
|
||||||
name: nickname || defaultLabel, |
|
||||||
address: address, |
|
||||||
mayBeFauceting: this._mayBeFauceting(i), |
|
||||||
} |
|
||||||
this._currentState.identities[address] = identity |
|
||||||
}) |
|
||||||
this._didUpdate() |
|
||||||
} |
|
||||||
|
|
||||||
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.
|
|
||||||
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 |
|
||||||
} |
|
||||||
|
|
||||||
//
|
|
||||||
// keyStore managment - unlocking + deserialization
|
|
||||||
//
|
|
||||||
|
|
||||||
IdentityStore.prototype.tryPassword = function (password, cb) { |
|
||||||
var serializedKeystore = this.configManager.getWallet() |
|
||||||
var keyStore = KeyStore.deserialize(serializedKeystore) |
|
||||||
|
|
||||||
keyStore.keyFromPassword(password, (err, pwDerivedKey) => { |
|
||||||
if (err) return cb(err) |
|
||||||
|
|
||||||
const isCorrect = keyStore.isDerivedKeyCorrect(pwDerivedKey) |
|
||||||
if (!isCorrect) return cb(new Error('Lightwallet - password incorrect')) |
|
||||||
|
|
||||||
this._keyStore = keyStore |
|
||||||
this._createIdMgmt(pwDerivedKey) |
|
||||||
cb() |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
IdentityStore.prototype._createVault = function (password, seedPhrase, cb) { |
|
||||||
const opts = { |
|
||||||
password, |
|
||||||
hdPathString: this.hdPathString, |
|
||||||
} |
|
||||||
|
|
||||||
if (seedPhrase) { |
|
||||||
opts.seedPhrase = seedPhrase |
|
||||||
} |
|
||||||
|
|
||||||
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() |
|
||||||
|
|
||||||
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({ |
|
||||||
keyStore: this._keyStore, |
|
||||||
derivedKey: derivedKey, |
|
||||||
configManager: this.configManager, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
IdentityStore.prototype.purgeCache = function () { |
|
||||||
this._currentState.identities = {} |
|
||||||
let accounts |
|
||||||
try { |
|
||||||
accounts = Object.keys(this._ethStore._currentState.accounts) |
|
||||||
} 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
|
|
||||||
IdentityStore.prototype._getAddresses = function () { |
|
||||||
return this._keyStore.getAddresses(this.hdPathString).map((address) => { |
|
||||||
return ethUtil.addHexPrefix(address) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
IdentityStore.prototype._autoFaucet = function () { |
|
||||||
var addresses = this._getAddresses() |
|
||||||
autoFaucet(addresses[0]) |
|
||||||
} |
|
||||||
|
|
||||||
// util
|
|
@ -0,0 +1,70 @@ |
|||||||
|
{ |
||||||
|
"metamask": { |
||||||
|
"isInitialized": true, |
||||||
|
"isUnlocked": true, |
||||||
|
"rpcTarget": "https://rawtestrpc.metamask.io/", |
||||||
|
"identities": { |
||||||
|
"0x07284e146926a4facd0ea60598dc4f001ad620f1": { |
||||||
|
"address": "0x07284e146926a4facd0ea60598dc4f001ad620f1", |
||||||
|
"name": "Account 1" |
||||||
|
} |
||||||
|
}, |
||||||
|
"unapprovedTxs": {}, |
||||||
|
"noActiveNotices": true, |
||||||
|
"frequentRpcList": [], |
||||||
|
"addressBook": [], |
||||||
|
"network": "3", |
||||||
|
"accounts": { |
||||||
|
"0x07284e146926a4facd0ea60598dc4f001ad620f1": { |
||||||
|
"code": "0x", |
||||||
|
"nonce": "0x0", |
||||||
|
"balance": "0x0", |
||||||
|
"address": "0x07284e146926a4facd0ea60598dc4f001ad620f1" |
||||||
|
} |
||||||
|
}, |
||||||
|
"transactions": {}, |
||||||
|
"selectedAddressTxList": [], |
||||||
|
"unapprovedMsgs": {}, |
||||||
|
"unapprovedMsgCount": 0, |
||||||
|
"unapprovedPersonalMsgs": {}, |
||||||
|
"unapprovedPersonalMsgCount": 0, |
||||||
|
"keyringTypes": [ |
||||||
|
"Simple Key Pair", |
||||||
|
"HD Key Tree" |
||||||
|
], |
||||||
|
"keyrings": [ |
||||||
|
{ |
||||||
|
"type": "HD Key Tree", |
||||||
|
"accounts": [ |
||||||
|
"07284e146926a4facd0ea60598dc4f001ad620f1" |
||||||
|
] |
||||||
|
} |
||||||
|
], |
||||||
|
"selectedAddress": "0x07284e146926a4facd0ea60598dc4f001ad620f1", |
||||||
|
"currentCurrency": "USD", |
||||||
|
"conversionRate": 43.35903476, |
||||||
|
"conversionDate": 1490105102, |
||||||
|
"provider": { |
||||||
|
"type": "testnet" |
||||||
|
}, |
||||||
|
"shapeShiftTxList": [], |
||||||
|
"lostAccounts": [], |
||||||
|
"seedWords": null |
||||||
|
}, |
||||||
|
"appState": { |
||||||
|
"menuOpen": false, |
||||||
|
"currentView": { |
||||||
|
"name": "accountDetail", |
||||||
|
"context": "0x07284e146926a4facd0ea60598dc4f001ad620f1" |
||||||
|
}, |
||||||
|
"accountDetail": { |
||||||
|
"subview": "export", |
||||||
|
"accountExport": "completed", |
||||||
|
"privateKey": "549c9638ad06432568969accacad4a02f8548cc358085938071745138ec134b7" |
||||||
|
}, |
||||||
|
"transForward": true, |
||||||
|
"isLoading": false, |
||||||
|
"warning": null |
||||||
|
}, |
||||||
|
"identities": {} |
||||||
|
} |
@ -0,0 +1,69 @@ |
|||||||
|
{ |
||||||
|
"metamask": { |
||||||
|
"isInitialized": true, |
||||||
|
"isUnlocked": true, |
||||||
|
"rpcTarget": "https://rawtestrpc.metamask.io/", |
||||||
|
"identities": { |
||||||
|
"0x07284e146926a4facd0ea60598dc4f001ad620f1": { |
||||||
|
"address": "0x07284e146926a4facd0ea60598dc4f001ad620f1", |
||||||
|
"name": "Account 1" |
||||||
|
} |
||||||
|
}, |
||||||
|
"unapprovedTxs": {}, |
||||||
|
"noActiveNotices": true, |
||||||
|
"frequentRpcList": [], |
||||||
|
"addressBook": [], |
||||||
|
"network": "3", |
||||||
|
"accounts": { |
||||||
|
"0x07284e146926a4facd0ea60598dc4f001ad620f1": { |
||||||
|
"code": "0x", |
||||||
|
"nonce": "0x0", |
||||||
|
"balance": "0x0", |
||||||
|
"address": "0x07284e146926a4facd0ea60598dc4f001ad620f1" |
||||||
|
} |
||||||
|
}, |
||||||
|
"transactions": {}, |
||||||
|
"selectedAddressTxList": [], |
||||||
|
"unapprovedMsgs": {}, |
||||||
|
"unapprovedMsgCount": 0, |
||||||
|
"unapprovedPersonalMsgs": {}, |
||||||
|
"unapprovedPersonalMsgCount": 0, |
||||||
|
"keyringTypes": [ |
||||||
|
"Simple Key Pair", |
||||||
|
"HD Key Tree" |
||||||
|
], |
||||||
|
"keyrings": [ |
||||||
|
{ |
||||||
|
"type": "HD Key Tree", |
||||||
|
"accounts": [ |
||||||
|
"07284e146926a4facd0ea60598dc4f001ad620f1" |
||||||
|
] |
||||||
|
} |
||||||
|
], |
||||||
|
"selectedAddress": "0x07284e146926a4facd0ea60598dc4f001ad620f1", |
||||||
|
"currentCurrency": "USD", |
||||||
|
"conversionRate": 43.35903476, |
||||||
|
"conversionDate": 1490105102, |
||||||
|
"provider": { |
||||||
|
"type": "testnet" |
||||||
|
}, |
||||||
|
"shapeShiftTxList": [], |
||||||
|
"lostAccounts": [], |
||||||
|
"seedWords": null |
||||||
|
}, |
||||||
|
"appState": { |
||||||
|
"menuOpen": false, |
||||||
|
"currentView": { |
||||||
|
"name": "accountDetail", |
||||||
|
"context": "0x07284e146926a4facd0ea60598dc4f001ad620f1" |
||||||
|
}, |
||||||
|
"accountDetail": { |
||||||
|
"subview": "export", |
||||||
|
"accountExport": "requested" |
||||||
|
}, |
||||||
|
"transForward": true, |
||||||
|
"isLoading": false, |
||||||
|
"warning": null |
||||||
|
}, |
||||||
|
"identities": {} |
||||||
|
} |
@ -1,92 +0,0 @@ |
|||||||
const ObservableStore = require('obs-store') |
|
||||||
const ConfigManager = require('../../../app/scripts/lib/config-manager') |
|
||||||
const IdStoreMigrator = require('../../../app/scripts/lib/idStore-migrator') |
|
||||||
const SimpleKeyring = require('eth-simple-keyring') |
|
||||||
const normalize = require('eth-sig-util').normalize |
|
||||||
|
|
||||||
const oldStyleVault = require('../mocks/oldVault.json').data |
|
||||||
const badStyleVault = require('../mocks/badVault.json').data |
|
||||||
|
|
||||||
const PASSWORD = '12345678' |
|
||||||
const FIRST_ADDRESS = '0x4dd5d356c5A016A220bCD69e82e5AF680a430d00'.toLowerCase() |
|
||||||
const BAD_STYLE_FIRST_ADDRESS = '0xac39b311dceb2a4b2f5d8461c1cdaf756f4f7ae9' |
|
||||||
const SEED = 'fringe damage bounce extend tunnel afraid alert sound all soldier all dinner' |
|
||||||
|
|
||||||
QUnit.module('Old Style Vaults', { |
|
||||||
beforeEach: function () { |
|
||||||
let managers = managersFromInitState(oldStyleVault) |
|
||||||
|
|
||||||
this.configManager = managers.configManager |
|
||||||
this.migrator = managers.migrator |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
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) => { |
|
||||||
assert.ok(result, 'migratedVaultForPassword returned 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 () { |
|
||||||
let managers = managersFromInitState(badStyleVault) |
|
||||||
|
|
||||||
this.configManager = managers.configManager |
|
||||||
this.migrator = managers.migrator |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
QUnit.test('migrator:migratedVaultForPassword', function (assert) { |
|
||||||
var done = assert.async() |
|
||||||
|
|
||||||
this.migrator.migratedVaultForPassword(PASSWORD) |
|
||||||
.then((result) => { |
|
||||||
assert.ok(result, 'migratedVaultForPassword returned 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') |
|
||||||
|
|
||||||
var lostAccount = lostAccounts[0] |
|
||||||
var privateKey = lostAccount.privateKey |
|
||||||
|
|
||||||
var simple = new SimpleKeyring() |
|
||||||
simple.deserialize([privateKey]) |
|
||||||
.then(() => { |
|
||||||
return simple.getAccounts() |
|
||||||
}) |
|
||||||
.then((accounts) => { |
|
||||||
assert.equal(normalize(accounts[0]), lostAccount.address, 'recovered address.') |
|
||||||
done() |
|
||||||
}) |
|
||||||
.catch((reason) => { |
|
||||||
assert.ifError(reason) |
|
||||||
done(reason) |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
function managersFromInitState(initState){ |
|
||||||
|
|
||||||
let configManager = new ConfigManager({ |
|
||||||
store: new ObservableStore(initState), |
|
||||||
}) |
|
||||||
|
|
||||||
let migrator = new IdStoreMigrator({ |
|
||||||
configManager: configManager, |
|
||||||
}) |
|
||||||
|
|
||||||
return { configManager, migrator } |
|
||||||
} |
|
@ -0,0 +1,56 @@ |
|||||||
|
const assert = require('assert') |
||||||
|
const extend = require('xtend') |
||||||
|
const AddressBookController = require('../../app/scripts/controllers/address-book') |
||||||
|
|
||||||
|
const mockKeyringController = { |
||||||
|
memStore: { |
||||||
|
getState: function () { |
||||||
|
return { |
||||||
|
identities: { |
||||||
|
'0x0aaa' : { |
||||||
|
address: '0x0aaa', |
||||||
|
name: 'owned', |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
describe('address-book-controller', function() { |
||||||
|
var addressBookController |
||||||
|
|
||||||
|
beforeEach(function() { |
||||||
|
addressBookController = new AddressBookController({}, mockKeyringController) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('addres book management', function () { |
||||||
|
describe('#_getAddressBook', function () { |
||||||
|
it('should be empty by default.', function () { |
||||||
|
assert.equal(addressBookController._getAddressBook().length, 0) |
||||||
|
}) |
||||||
|
}) |
||||||
|
describe('#setAddressBook', function () { |
||||||
|
it('should properly set a new address.', function () { |
||||||
|
addressBookController.setAddressBook('0x01234', 'test') |
||||||
|
var addressBook = addressBookController._getAddressBook() |
||||||
|
assert.equal(addressBook.length, 1, 'incorrect address book length.') |
||||||
|
assert.equal(addressBook[0].address, '0x01234', 'incorrect addresss') |
||||||
|
assert.equal(addressBook[0].name, 'test', 'incorrect nickname') |
||||||
|
}) |
||||||
|
|
||||||
|
it('should reject duplicates.', function () { |
||||||
|
addressBookController.setAddressBook('0x01234', 'test') |
||||||
|
addressBookController.setAddressBook('0x01234', 'test') |
||||||
|
var addressBook = addressBookController._getAddressBook() |
||||||
|
assert.equal(addressBook.length, 1, 'incorrect address book length.') |
||||||
|
}) |
||||||
|
it('should not add any identities that are under user control', function () { |
||||||
|
addressBookController.setAddressBook('0x0aaa', ' ') |
||||||
|
var addressBook = addressBookController._getAddressBook() |
||||||
|
assert.equal(addressBook.length, 0, 'incorrect address book length.') |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
@ -1,35 +0,0 @@ |
|||||||
var assert = require('assert') |
|
||||||
var IdManagement = require('../../app/scripts/lib/id-management') |
|
||||||
var sinon = require('sinon') |
|
||||||
|
|
||||||
describe('IdManagement', function() { |
|
||||||
|
|
||||||
beforeEach(function() { |
|
||||||
// sinon allows stubbing methods that are easily verified
|
|
||||||
this.sinon = sinon.sandbox.create() |
|
||||||
window.localStorage = {} // Hacking localStorage support into JSDom
|
|
||||||
}) |
|
||||||
|
|
||||||
afterEach(function() { |
|
||||||
// sinon requires cleanup otherwise it will overwrite context
|
|
||||||
this.sinon.restore() |
|
||||||
}) |
|
||||||
|
|
||||||
describe('#signMsg', function () { |
|
||||||
it('passes the dennis test', function() { |
|
||||||
const address = '0x9858e7d8b79fc3e6d989636721584498926da38a' |
|
||||||
const message = '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0' |
|
||||||
const privateKey = '0x7dd98753d7b4394095de7d176c58128e2ed6ee600abe97c9f6d9fd65015d9b18' |
|
||||||
const expectedResult = '0x28fcb6768e5110144a55b2e6ce9d1ea5a58103033632d272d2b5cf506906f7941a00b539383fd872109633d8c71c404e13dba87bc84166ee31b0e36061a69e161c' |
|
||||||
|
|
||||||
const idManagement = new IdManagement() |
|
||||||
const exportKeyStub = sinon.stub(idManagement, 'exportPrivateKey', (addr) => { |
|
||||||
assert.equal(addr, address) |
|
||||||
return privateKey |
|
||||||
}) |
|
||||||
|
|
||||||
const result = idManagement.signMsg(address, message) |
|
||||||
assert.equal(result, expectedResult) |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
@ -1,83 +0,0 @@ |
|||||||
const async = require('async') |
|
||||||
const assert = require('assert') |
|
||||||
const ObservableStore = require('obs-store') |
|
||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
const BN = ethUtil.BN |
|
||||||
const ConfigManager = require('../../app/scripts/lib/config-manager') |
|
||||||
const firstTimeState = require('../../app/scripts/first-time-state') |
|
||||||
const delegateCallCode = require('../lib/example-code.json').delegateCallCode |
|
||||||
const clone = require('clone') |
|
||||||
|
|
||||||
// The old way:
|
|
||||||
const IdentityStore = require('../../app/scripts/lib/idStore') |
|
||||||
const STORAGE_KEY = 'metamask-config' |
|
||||||
|
|
||||||
// The new ways:
|
|
||||||
var KeyringController = require('../../app/scripts/keyring-controller') |
|
||||||
const mockEncryptor = require('../lib/mock-encryptor') |
|
||||||
const MockSimpleKeychain = require('../lib/mock-simple-keychain') |
|
||||||
const sinon = require('sinon') |
|
||||||
|
|
||||||
const mockVault = { |
|
||||||
seed: 'picnic injury awful upper eagle junk alert toss flower renew silly vague', |
|
||||||
account: '0x5d8de92c205279c10e5669f797b853ccef4f739a', |
|
||||||
} |
|
||||||
|
|
||||||
const badVault = { |
|
||||||
seed: 'radar blur cabbage chef fix engine embark joy scheme fiction master release', |
|
||||||
} |
|
||||||
|
|
||||||
describe('IdentityStore to KeyringController migration', function() { |
|
||||||
|
|
||||||
// The stars of the show:
|
|
||||||
let idStore, keyringController, seedWords, configManager |
|
||||||
|
|
||||||
let password = 'password123' |
|
||||||
let entropy = 'entripppppyy duuude' |
|
||||||
let accounts = [] |
|
||||||
let newAccounts = [] |
|
||||||
let originalKeystore |
|
||||||
|
|
||||||
// This is a lot of setup, I know!
|
|
||||||
// We have to create an old style vault, populate it,
|
|
||||||
// and THEN create a new one, before we can run tests on it.
|
|
||||||
beforeEach(function(done) { |
|
||||||
this.sinon = sinon.sandbox.create() |
|
||||||
let store = new ObservableStore(clone(firstTimeState)) |
|
||||||
configManager = new ConfigManager({ store }) |
|
||||||
|
|
||||||
idStore = new IdentityStore({ |
|
||||||
configManager: configManager, |
|
||||||
ethStore: { |
|
||||||
addAccount(acct) { accounts.push(ethUtil.addHexPrefix(acct)) }, |
|
||||||
del(acct) { delete accounts[acct] }, |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
idStore._createVault(password, mockVault.seed, (err) => { |
|
||||||
assert.ifError(err, 'createNewVault threw error') |
|
||||||
originalKeystore = idStore._idmgmt.keyStore |
|
||||||
|
|
||||||
idStore.setLocked((err) => { |
|
||||||
assert.ifError(err, 'createNewVault threw error') |
|
||||||
keyringController = new KeyringController({ |
|
||||||
configManager, |
|
||||||
ethStore: { |
|
||||||
addAccount(acct) { newAccounts.push(ethUtil.addHexPrefix(acct)) }, |
|
||||||
del(acct) { delete newAccounts[acct] }, |
|
||||||
}, |
|
||||||
txManager: { |
|
||||||
getTxList: () => [], |
|
||||||
getUnapprovedTxList: () => [] |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
// Stub out the browser crypto for a mock encryptor.
|
|
||||||
// Browser crypto is tested in the integration test suite.
|
|
||||||
keyringController.encryptor = mockEncryptor |
|
||||||
done() |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
}) |
|
@ -1,142 +0,0 @@ |
|||||||
const async = require('async') |
|
||||||
const assert = require('assert') |
|
||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
const BN = ethUtil.BN |
|
||||||
const configManagerGen = require('../lib/mock-config-manager') |
|
||||||
const delegateCallCode = require('../lib/example-code.json').delegateCallCode |
|
||||||
const IdentityStore = require('../../app/scripts/lib/idStore') |
|
||||||
|
|
||||||
describe('IdentityStore', function() { |
|
||||||
|
|
||||||
describe('#createNewVault', function () { |
|
||||||
let idStore |
|
||||||
let password = 'password123' |
|
||||||
let seedWords |
|
||||||
let accounts = [] |
|
||||||
let originalKeystore |
|
||||||
|
|
||||||
before(function(done) { |
|
||||||
window.localStorage = {} // Hacking localStorage support into JSDom
|
|
||||||
|
|
||||||
idStore = new IdentityStore({ |
|
||||||
configManager: configManagerGen(), |
|
||||||
ethStore: { |
|
||||||
addAccount(acct) { accounts.push(ethUtil.addHexPrefix(acct)) }, |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
idStore.createNewVault(password, (err, seeds) => { |
|
||||||
assert.ifError(err, 'createNewVault threw error') |
|
||||||
seedWords = seeds |
|
||||||
originalKeystore = idStore._idmgmt.keyStore |
|
||||||
done() |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('#recoverFromSeed', function() { |
|
||||||
let newAccounts = [] |
|
||||||
|
|
||||||
before(function() { |
|
||||||
window.localStorage = {} // Hacking localStorage support into JSDom
|
|
||||||
|
|
||||||
idStore = new IdentityStore({ |
|
||||||
configManager: configManagerGen(), |
|
||||||
ethStore: { |
|
||||||
addAccount(acct) { newAccounts.push(ethUtil.addHexPrefix(acct)) }, |
|
||||||
}, |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
it('should return the expected keystore', function (done) { |
|
||||||
|
|
||||||
idStore.recoverFromSeed(password, seedWords, (err) => { |
|
||||||
assert.ifError(err) |
|
||||||
|
|
||||||
let newKeystore = idStore._idmgmt.keyStore |
|
||||||
assert.equal(newAccounts[0], accounts[0]) |
|
||||||
done() |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('#recoverFromSeed BIP44 compliance', function() { |
|
||||||
const salt = 'lightwalletSalt' |
|
||||||
|
|
||||||
let password = 'secret!' |
|
||||||
let accounts = {} |
|
||||||
let idStore |
|
||||||
|
|
||||||
var assertions = [ |
|
||||||
{ |
|
||||||
seed: 'picnic injury awful upper eagle junk alert toss flower renew silly vague', |
|
||||||
account: '0x5d8de92c205279c10e5669f797b853ccef4f739a', |
|
||||||
}, |
|
||||||
{ |
|
||||||
seed: 'radar blur cabbage chef fix engine embark joy scheme fiction master release', |
|
||||||
account: '0xe15d894becb0354c501ae69429b05143679f39e0', |
|
||||||
}, |
|
||||||
{ |
|
||||||
seed: 'phone coyote caught pattern found table wedding list tumble broccoli chief swing', |
|
||||||
account: '0xb0e868f24bc7fec2bce2efc2b1c344d7569cd9d2', |
|
||||||
}, |
|
||||||
{ |
|
||||||
seed: 'recycle tag bird palace blue village anxiety census cook soldier example music', |
|
||||||
account: '0xab34a45920afe4af212b96ec51232aaa6a33f663', |
|
||||||
}, |
|
||||||
{ |
|
||||||
seed: 'half glimpse tape cute harvest sweet bike voyage actual floor poet lazy', |
|
||||||
account: '0x28e9044597b625ac4beda7250011670223de43b2', |
|
||||||
}, |
|
||||||
{ |
|
||||||
seed: 'flavor tiger carpet motor angry hungry document inquiry large critic usage liar', |
|
||||||
account: '0xb571be96558940c4e9292e1999461aa7499fb6cd', |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
before(function() { |
|
||||||
window.localStorage = {} // Hacking localStorage support into JSDom
|
|
||||||
|
|
||||||
idStore = new IdentityStore({ |
|
||||||
configManager: configManagerGen(), |
|
||||||
ethStore: { |
|
||||||
addAccount(acct) { accounts[acct] = acct}, |
|
||||||
del(acct) { delete accounts[acct] }, |
|
||||||
}, |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
it('should enforce seed compliance with TestRPC', function (done) { |
|
||||||
this.timeout(10000) |
|
||||||
const tests = assertions.map((assertion) => { |
|
||||||
return function (cb) { |
|
||||||
|
|
||||||
idStore.recoverFromSeed(password, assertion.seed, (err) => { |
|
||||||
assert.ifError(err) |
|
||||||
|
|
||||||
var expected = assertion.account.toLowerCase() |
|
||||||
var received = accounts[expected].toLowerCase() |
|
||||||
assert.equal(received, expected) |
|
||||||
|
|
||||||
idStore.tryPassword(password, function (err) { |
|
||||||
|
|
||||||
assert.ok(idStore._isUnlocked(), 'should unlock the id store') |
|
||||||
|
|
||||||
idStore.submitPassword(password, function(err, account) { |
|
||||||
assert.ifError(err) |
|
||||||
assert.equal(account, expected) |
|
||||||
assert.equal(Object.keys(idStore._getAddresses()).length, 1, 'only one account on restore') |
|
||||||
cb() |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
async.series(tests, function(err, results) { |
|
||||||
assert.ifError(err) |
|
||||||
done() |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
Loading…
Reference in new issue