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

Merge pull request #916 from MetaMask/i894-DetectBadAccounts

I894 detect bad accounts
This commit is contained in:
Dan Finlay 2016-12-20 11:50:26 -08:00 committed by GitHub
commit 674b268982
9 changed files with 124 additions and 57 deletions

View File

@ -114,6 +114,7 @@ module.exports = class KeyringController extends EventEmitter {
conversionDate: this.configManager.getConversionDate(),
keyringTypes: this.keyringTypes.map(krt => krt.type),
identities: this.identities,
lostAccounts: this.configManager.getLostAccounts(),
}
}
@ -622,11 +623,17 @@ module.exports = class KeyringController extends EventEmitter {
// may be completed without interruption.
migrateOldVaultIfAny (password) {
const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault()
if (!shouldMigrate) {
return Promise.resolve()
}
return this.idStoreMigrator.migratedVaultForPassword(password)
.then((serialized) => {
.then((result) => {
this.password = password
if (serialized && shouldMigrate) {
if (result && shouldMigrate) {
const { serialized, lostAccounts } = result
this.configManager.setLostAccounts(lostAccounts)
return this.restoreKeyring(serialized)
.then(keyring => keyring.getAccounts())
.then((accounts) => {

View File

@ -33,15 +33,15 @@ class HdKeyring extends EventEmitter {
this.mnemonic = null
this.root = null
if ('mnemonic' in opts) {
if (opts.mnemonic) {
this._initFromMnemonic(opts.mnemonic)
}
if ('numberOfAccounts' in opts) {
this.addAccounts(opts.numberOfAccounts)
if (opts.numberOfAccounts) {
return this.addAccounts(opts.numberOfAccounts)
}
return Promise.resolve()
return Promise.resolve([])
}
addAccounts (numberOfAccounts = 1) {

View File

@ -432,3 +432,14 @@ ConfigManager.prototype.setGasMultiplier = function (gasMultiplier) {
data.gasMultiplier = gasMultiplier
this.setData(data)
}
ConfigManager.prototype.setLostAccounts = function (lostAccounts) {
var data = this.getData()
data.lostAccounts = lostAccounts
this.setData(data)
}
ConfigManager.prototype.getLostAccounts = function () {
var data = this.getData()
return data.lostAccounts || []
}

View File

@ -1,5 +1,8 @@
const IdentityStore = require('./idStore')
const HdKeyring = require('../keyrings/hd')
const sigUtil = require('./sig-util')
const normalize = sigUtil.normalize
const denodeify = require('denodeify')
module.exports = class IdentityStoreMigrator {
@ -23,15 +26,13 @@ module.exports = class IdentityStoreMigrator {
return Promise.resolve(null)
}
return new Promise((resolve, reject) => {
this.idStore.submitPassword(password, (err) => {
if (err) return reject(err)
try {
resolve(this.serializeVault())
} catch (e) {
reject(e)
}
})
const idStore = this.idStore
const submitPassword = denodeify(idStore.submitPassword.bind(idStore))
return submitPassword(password)
.then(() => {
const serialized = this.serializeVault()
return this.checkForLostAccounts(serialized)
})
}
@ -45,6 +46,28 @@ module.exports = class IdentityStoreMigrator {
}
}
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,
}
})
}
hasOldVault () {
const wallet = this.configManager.getWallet()
return wallet

View File

@ -42,6 +42,7 @@
"clone": "^1.0.2",
"copy-to-clipboard": "^2.0.0",
"debounce": "^1.0.0",
"denodeify": "^1.2.1",
"dnode": "^1.2.2",
"end-of-stream": "^1.1.0",
"ensnare": "^1.0.0",

View File

@ -2,11 +2,14 @@ var KeyringController = require('../../../app/scripts/keyring-controller')
var ConfigManager = require('../../../app/scripts/lib/config-manager')
var oldStyleVault = require('../mocks/oldVault.json')
var badStyleVault = require('../mocks/badVault.json')
var STORAGE_KEY = 'metamask-config'
var PASSWORD = '12345678'
var FIRST_ADDRESS = '0x4dd5d356c5A016A220bCD69e82e5AF680a430d00'.toLowerCase()
var BAD_STYLE_FIRST_ADDRESS = '0xac39b311dceb2a4b2f5d8461c1cdaf756f4f7ae9'
QUnit.module('Old Style Vaults', {
beforeEach: function () {
@ -41,6 +44,63 @@ QUnit.test('keyringController:submitPassword', function (assert) {
this.keyringController.submitPassword(PASSWORD)
.then((state) => {
assert.ok(state.identities[FIRST_ADDRESS])
assert.equal(state.lostAccounts.length, 0, 'no lost accounts')
done()
})
})
QUnit.test('keyringController:setLocked', function (assert) {
var done = assert.async()
var self = this
this.keyringController.setLocked()
.then(function() {
assert.notOk(self.keyringController.password, 'password should be deallocated')
assert.deepEqual(self.keyringController.keyrings, [], 'keyrings should be deallocated')
done()
})
.catch((reason) => {
assert.ifError(reason)
done()
})
})
QUnit.module('Old Style Vaults with bad HD seed', {
beforeEach: function () {
window.localStorage[STORAGE_KEY] = JSON.stringify(badStyleVault)
this.configManager = new ConfigManager({
loadData: () => { return JSON.parse(window.localStorage[STORAGE_KEY]) },
setData: (data) => { window.localStorage[STORAGE_KEY] = JSON.stringify(data) },
})
this.keyringController = new KeyringController({
configManager: this.configManager,
getNetwork: () => { return '2' },
})
this.ethStore = {
addAccount: () => {},
removeAccount: () => {},
}
this.keyringController.setStore(this.ethStore)
}
})
QUnit.test('keyringController:isInitialized', function (assert) {
assert.ok(this.keyringController.getState().isInitialized, 'vault is initialized')
})
QUnit.test('keyringController:submitPassword', function (assert) {
var done = assert.async()
this.keyringController.submitPassword(PASSWORD)
.then((state) => {
assert.ok(state.identities[BAD_STYLE_FIRST_ADDRESS])
assert.equal(state.lostAccounts.length, 1, 'one lost account')
assert.equal(state.lostAccounts[0], '0xe15D894BeCB0354c501AE69429B05143679F39e0'.toLowerCase())
assert.deepEqual(this.configManager.getLostAccounts(), state.lostAccounts, 'persisted')
done()
})
})

View File

@ -0,0 +1 @@
{"meta":{"version":4},"data":{"fiatCurrency":"USD","conversionRate":8.34908448,"conversionDate":1481227505,"isConfirmed":true,"wallet":"{\"encSeed\":{\"encStr\":\"Te2KyAGY3S01bgUJ+7d4y3BOvr/8TKrXrkRZ29cGI6dgyedtN+YgTQxElC2td/pzuoXm7KeSfr+yAoFCvMgqFAJwRcX3arHOsMFQie8kp8mL5I65zwdg/HB2QecB4OJHytrxgApv2zZiKEo0kbu2cs8zYIn5wNlCBIHwgylYmHpUDIJcO1B4zg==\",\"nonce\":\"xnxqk4iy70bjt721F+KPLV4PNfBFNyct\"},\"ksData\":{\"m/44'/60'/0'/0\":{\"info\":{\"curve\":\"secp256k1\",\"purpose\":\"sign\"},\"encHdPathPriv\":{\"encStr\":\"vNrSjekRKLmaGFf77Uca9+aAebmDlvrBwtAV8YthpQ4OX/mXtLSycmnLsYdk4schaByfJvrm6/Mf9fxzOSaScJk+XvKw5XqNXedkDHtbWrmNnxFpuT+9tuB8Nupr3D9GZK9PgXhJD99/7Bn6Wk7/ne+PIDmbtdmx/SWmrdo3pg==\",\"nonce\":\"zqWq/gtJ5zfUVRWQQJkP/zoYjer6Rozj\"},\"hdIndex\":1,\"encPrivKeys\":{\"e15d894becb0354c501ae69429b05143679f39e0\":{\"key\":\"jBLQ9v1l5LOEY1C3kI8z7LpbJKHP1vpVfPAlz90MNSfa8Oe+XlxKQAGYs8Zb4fWm\",\"nonce\":\"fJyrSRo1t0RMNqp2MsneoJnYJWHQnSVY\"}},\"addresses\":[\"e15d894becb0354c501ae69429b05143679f39e0\"]}},\"encHdRootPriv\":{\"encStr\":\"mbvwiFBQGbjj4BJLmdeYzfYi8jb7gtFtwiCQOPfvmyz4h2/KMbHNGzumM16qRKpifioQXkhnBulMIQHaYg0Jwv1MoFsqHxHmuIAT+QP5XvJjz0MRl6708pHowmIVG+R8CZNTLqzE7XS8YkZ4ElRpTvLEM8Wngi5Sg287mQMP9w==\",\"nonce\":\"i5Tp2lQe92rXQzNhjZcu9fNNhfux6Wf4\"},\"salt\":\"FQpA8D9R/5qSp9WtQ94FILyfWZHMI6YZw6RmBYqK0N0=\",\"version\":2}","config":{"provider":{"type":"testnet"},"selectedAccount":"0xe15d894becb0354c501ae69429b05143679f39e0"},"isEthConfirmed":true,"transactions":[],"TOSHash":"a4f4e23f823a7ac51783e7ffba7914a911b09acdb97263296b7e14b527f80c5b","gasMultiplier":1}}

View File

@ -21,6 +21,10 @@ const mockVault = {
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:
@ -79,33 +83,8 @@ describe('IdentityStore to KeyringController migration', function() {
keyringController.configManager.setWallet('something')
const state = keyringController.getState()
assert(state.isInitialized, 'old vault counted as initialized.')
assert.equal(state.lostAccounts.length, 0, 'no lost accounts')
})
/*
it('should use the password to migrate the old vault', function(done) {
this.timeout(5000)
console.log('calling submitPassword')
console.dir(keyringController)
keyringController.submitPassword(password, function (err, state) {
assert.ifError(err, 'submitPassword threw error')
function log(str, dat) { console.log(str + ': ' + JSON.stringify(dat)) }
let newAccounts = keyringController.getAccounts()
log('new accounts: ', newAccounts)
let newAccount = ethUtil.addHexPrefix(newAccounts[0])
assert.equal(ethUtil.addHexPrefix(newAccount), mockVault.account, 'restored the correct account')
const newSeed = keyringController.keyrings[0].mnemonic
log('keyringController keyrings', keyringController.keyrings)
assert.equal(newSeed, mockVault.seed, 'seed phrase transferred.')
assert(configManager.getVault(), 'new type of vault is persisted')
done()
})
})
*/
})
})

View File

@ -95,21 +95,6 @@ describe('KeyringController', function() {
})
})
describe('#migrateOldVaultIfAny', function() {
it('should return and init a new vault', function(done) {
keyringController.migrateOldVaultIfAny(password)
.then(() => {
assert(keyringController.configManager.getVault(), 'now has a vault')
assert(keyringController.password, 'has a password set')
done()
})
.catch((reason) => {
assert.ifError(reason)
done()
})
})
})
describe('#createNickname', function() {
it('should add the address to the identities hash', function() {
const fakeAddress = '0x12345678'