From 18e5173f061c2e21b5acb3e1b329343b5cffc558 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Sat, 29 Oct 2016 02:29:25 -0700 Subject: [PATCH] Now migrating old vaults to new DEN format --- app/scripts/keyring-controller.js | 33 ++++++++++++-- app/scripts/lib/idStore-migrator.js | 48 +++++++++++++++++++ app/scripts/lib/idStore.js | 4 +- test/lib/mock-config-manager.js | 2 +- test/unit/idStore-migration-test.js | 71 +++++++++++++++++++++++++---- 5 files changed, 142 insertions(+), 16 deletions(-) create mode 100644 app/scripts/lib/idStore-migrator.js diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 3ac101ad8..b8066e303 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -9,6 +9,9 @@ const BN = ethUtil.BN const Transaction = require('ethereumjs-tx') const createId = require('web3-provider-engine/util/random-id') +// TEMPORARY UNTIL FULL DEPRECATION: +const IdStoreMigrator = require('./lib/idStore-migrator') + // Keyrings: const SimpleKeyring = require('./keyrings/simple') const HdKeyring = require('./keyrings/hd') @@ -34,6 +37,11 @@ module.exports = class KeyringController extends EventEmitter { this._unconfMsgCbs = {} this.network = null + + // TEMPORARY UNTIL FULL DEPRECATION: + this.idStoreMigrator = new IdStoreMigrator({ + configManager: this.configManager, + }) } getState() { @@ -63,18 +71,32 @@ module.exports = class KeyringController extends EventEmitter { createNewVault(password, entropy, cb) { const salt = this.encryptor.generateSalt() this.configManager.setSalt(salt) - this.loadKey(password) + + let serialized + + this.idStoreMigrator.oldSeedForPassword(password) + .then((oldSerialized) => { + if (oldSerialized) { + serialized = oldSerialized + } + return this.loadKey(password) + }) .then((key) => { - return this.encryptor.encryptWithKey(key, []) + const first = serialized ? [serialized] : [] + return this.encryptor.encryptWithKey(key, first) }) .then((encryptedString) => { this.configManager.setVault(encryptedString) - // TEMPORARY SINGLE-KEYRING CONFIG: - this.addNewKeyring('HD Key Tree', null, cb) + if (!serialized) { + // TEMPORARY SINGLE-KEYRING CONFIG: + return this.addNewKeyring('HD Key Tree', null, cb) + } else { + return this.submitPassword(password, cb) + } // NORMAL BEHAVIOR: - // cb(null, this.getState()) + // return cb(null, this.getState()) }) .catch((err) => { cb(err) @@ -99,6 +121,7 @@ module.exports = class KeyringController extends EventEmitter { return this.encryptor.keyFromPassword(password + salt) .then((key) => { this.key = key + this.configManager.setSalt(salt) return key }) } diff --git a/app/scripts/lib/idStore-migrator.js b/app/scripts/lib/idStore-migrator.js new file mode 100644 index 000000000..f8f7cb51a --- /dev/null +++ b/app/scripts/lib/idStore-migrator.js @@ -0,0 +1,48 @@ +const IdentityStore = require('./idStore') + + +module.exports = class IdentityStoreMigrator { + + constructor ({ configManager }) { + this.configManager = configManager + this.idStore = new IdentityStore({ configManager }) + } + + oldSeedForPassword( password ) { + const isOldVault = this.hasOldVault() + if (!isOldVault) { + console.log('does not seem to have old vault') + console.log('THE DATA:') + console.log(this.configManager.getData()) + 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) + } + }) + }) + } + + serializeVault() { + const mnemonic = this.idStore._idmgmt.getSeed() + console.dir(this.idStore._idmgmt) + const n = this.idStore._getAddresses().length + + return { + type: 'HD Key Tree', + data: { mnemonic, n }, + } + } + + hasOldVault() { + const wallet = this.configManager.getWallet() + console.log('found old wallet: ' + wallet) + return wallet + } +} diff --git a/app/scripts/lib/idStore.js b/app/scripts/lib/idStore.js index 14f25dd1d..8ee2b62dd 100644 --- a/app/scripts/lib/idStore.js +++ b/app/scripts/lib/idStore.js @@ -422,7 +422,9 @@ IdentityStore.prototype._loadIdentities = function () { var addresses = this._getAddresses() addresses.forEach((address, i) => { // // add to ethStore - this._ethStore.addAccount(ethUtil.addHexPrefix(address)) + if (this._ethStore) { + this._ethStore.addAccount(ethUtil.addHexPrefix(address)) + } // add to identities const defaultLabel = 'Wallet ' + (i + 1) const nickname = configManager.nicknameForWallet(address) diff --git a/test/lib/mock-config-manager.js b/test/lib/mock-config-manager.js index fe841f455..ccd518c68 100644 --- a/test/lib/mock-config-manager.js +++ b/test/lib/mock-config-manager.js @@ -1,5 +1,5 @@ var ConfigManager = require('../../app/scripts/lib/config-manager') -const STORAGE_KEY = 'metamask-persistance-key' +const STORAGE_KEY = 'metamask-config' const extend = require('xtend') module.exports = function() { diff --git a/test/unit/idStore-migration-test.js b/test/unit/idStore-migration-test.js index df26c7f31..2455c9b03 100644 --- a/test/unit/idStore-migration-test.js +++ b/test/unit/idStore-migration-test.js @@ -2,11 +2,13 @@ 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 ConfigManager = require('../../app/scripts/lib/config-manager') const delegateCallCode = require('../lib/example-code.json').delegateCallCode // The old way: const IdentityStore = require('../../app/scripts/lib/idStore') +const STORAGE_KEY = 'metamask-config' +const extend = require('xtend') // The new ways: var KeyringController = require('../../app/scripts/keyring-controller') @@ -22,7 +24,7 @@ const mockVault = { describe('IdentityStore to KeyringController migration', function() { // The stars of the show: - let idStore, keyringController, seedWords + let idStore, keyringController, seedWords, configManager let password = 'password123' let entropy = 'entripppppyy duuude' @@ -36,19 +38,21 @@ describe('IdentityStore to KeyringController migration', function() { beforeEach(function(done) { this.sinon = sinon.sandbox.create() window.localStorage = {} // Hacking localStorage support into JSDom - var configManager = configManagerGen() + configManager = new ConfigManager({ + loadData, + setData: (d) => { global.localStorage = d } + }) - window.localStorage = {} // Hacking localStorage support into JSDom idStore = new IdentityStore({ - configManager: configManagerGen(), + configManager: configManager, ethStore: { addAccount(acct) { accounts.push(ethUtil.addHexPrefix(acct)) }, del(acct) { delete accounts[acct] }, }, }) - idStore._createVault(password, mockVault.seed, null, function (err, seeds) { + idStore._createVault(password, mockVault.seed, null, function (err) { assert.ifError(err, 'createNewVault threw error') originalKeystore = idStore._idmgmt.keyStore @@ -58,6 +62,7 @@ describe('IdentityStore to KeyringController migration', function() { configManager, ethStore: { addAccount(acct) { newAccounts.push(ethUtil.addHexPrefix(acct)) }, + del(acct) { delete newAccounts[acct] }, }, }) @@ -71,14 +76,13 @@ describe('IdentityStore to KeyringController migration', function() { describe('creating new vault type', function() { it('should use the password to migrate the old vault', function(done) { + this.timeout(5000) keyringController.createNewVault(password, null, function (err, state) { assert.ifError(err, 'createNewVault threw error') let newAccounts = keyringController.getAccounts() let newAccount = ethUtil.addHexPrefix(newAccounts[0]) - assert.equal(newAccount, accounts[0], 'restored the account') - assert.equal(newAccount, mockVault.account, 'restored the correct account') - + assert.equal(ethUtil.addHexPrefix(newAccount), mockVault.account, 'restored the correct account') const newSeed = keyringController.keyrings[0].mnemonic assert.equal(newSeed, mockVault.seed, 'seed phrase transferred.') @@ -89,3 +93,52 @@ describe('IdentityStore to KeyringController migration', function() { }) }) +function loadData () { + var oldData = getOldStyleData() + var newData + try { + newData = JSON.parse(window.localStorage[STORAGE_KEY]) + } catch (e) {} + + var data = extend({ + meta: { + version: 0, + }, + data: { + config: { + provider: { + type: 'testnet', + }, + }, + }, + }, oldData || null, newData || null) + return data +} + +function setData (data) { + window.localStorage[STORAGE_KEY] = JSON.stringify(data) +} + +function getOldStyleData () { + var config, wallet, seedWords + + var result = { + meta: { version: 0 }, + data: {}, + } + + try { + config = JSON.parse(window.localStorage['config']) + result.data.config = config + } catch (e) {} + try { + wallet = JSON.parse(window.localStorage['lightwallet']) + result.data.wallet = wallet + } catch (e) {} + try { + seedWords = window.localStorage['seedWords'] + result.data.seedWords = seedWords + } catch (e) {} + + return result +}