mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-22 17:33:23 +01:00
Merge pull request #1214 from MetaMask/i1181-RemoveLightwallet
Remove eth-lightwallet
This commit is contained in:
commit
0c82c520fe
@ -5,6 +5,7 @@
|
||||
- Allow sending to ENS names in send form on Ropsten.
|
||||
- Added an address book functionality that remembers the last 15 unique addresses sent to.
|
||||
- Can now change network to custom RPC URL from lock screen.
|
||||
- Removed support for old, lightwallet based vault. Users who have not opened app in over a month will need to recover with their seed phrase. This will allow Firefox support sooner.
|
||||
|
||||
## 3.4.0 2017-3-8
|
||||
|
||||
|
@ -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
|
@ -23,7 +23,6 @@ const ConfigManager = require('./lib/config-manager')
|
||||
const extension = require('./lib/extension')
|
||||
const autoFaucet = require('./lib/auto-faucet')
|
||||
const nodeify = require('./lib/nodeify')
|
||||
const IdStoreMigrator = require('./lib/idStore-migrator')
|
||||
const accountImporter = require('./account-import-strategies')
|
||||
|
||||
const version = require('../manifest.json').version
|
||||
@ -115,11 +114,6 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
this.personalMessageManager = new PersonalMessageManager()
|
||||
this.publicConfigStore = this.initPublicConfigStore()
|
||||
|
||||
// TEMPORARY UNTIL FULL DEPRECATION:
|
||||
this.idStoreMigrator = new IdStoreMigrator({
|
||||
configManager: this.configManager,
|
||||
})
|
||||
|
||||
// manual disk state subscriptions
|
||||
this.txManager.store.subscribe((state) => {
|
||||
this.store.updateState({ TransactionManager: state })
|
||||
@ -366,8 +360,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
//
|
||||
|
||||
submitPassword (password, cb) {
|
||||
this.migrateOldVaultIfAny(password)
|
||||
.then(this.keyringController.submitPassword.bind(this.keyringController, password))
|
||||
return this.keyringController.submitPassword(password)
|
||||
.then((newState) => { cb(null, newState) })
|
||||
.catch((reason) => { cb(reason) })
|
||||
}
|
||||
@ -562,35 +555,6 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
cb(null, this.getState())
|
||||
}
|
||||
|
||||
// Migrate Old Vault If Any
|
||||
// @string password
|
||||
//
|
||||
// returns Promise()
|
||||
//
|
||||
// Temporary step used when logging in.
|
||||
// Checks if old style (pre-3.0.0) Metamask Vault exists.
|
||||
// If so, persists that vault in the new vault format
|
||||
// with the provided password, so the other unlock steps
|
||||
// may be completed without interruption.
|
||||
migrateOldVaultIfAny (password) {
|
||||
|
||||
if (!this.checkIfShouldMigrate()) {
|
||||
return Promise.resolve(password)
|
||||
}
|
||||
|
||||
const keyringController = this.keyringController
|
||||
|
||||
return this.idStoreMigrator.migratedVaultForPassword(password)
|
||||
.then(this.restoreOldVaultAccounts.bind(this))
|
||||
.then(this.restoreOldLostAccounts.bind(this))
|
||||
.then(keyringController.persistAllKeyrings.bind(keyringController, password))
|
||||
.then(() => password)
|
||||
}
|
||||
|
||||
checkIfShouldMigrate() {
|
||||
return !!this.configManager.getWallet() && !this.configManager.getVault()
|
||||
}
|
||||
|
||||
restoreOldVaultAccounts(migratorOutput) {
|
||||
const { serialized } = migratorOutput
|
||||
return this.keyringController.restoreKeyring(serialized)
|
||||
|
@ -53,7 +53,6 @@
|
||||
"ensnare": "^1.0.0",
|
||||
"eth-bin-to-ops": "^1.0.1",
|
||||
"eth-hd-keyring": "^1.1.1",
|
||||
"eth-lightwallet": "^2.3.3",
|
||||
"eth-query": "^1.0.3",
|
||||
"eth-sig-util": "^1.1.1",
|
||||
"eth-simple-keyring": "^1.1.1",
|
||||
|
@ -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 }
|
||||
}
|
@ -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
Block a user