diff --git a/app/scripts/background.js b/app/scripts/background.js index 697417fd2..0e5a76d51 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -3,7 +3,7 @@ const Dnode = require('dnode') const eos = require('end-of-stream') const asyncQ = require('async-q') const Migrator = require('./lib/migrator/') -const migrations = require('./lib/migrations') +const migrations = require('./lib/migrations/') const LocalStorageStore = require('./lib/observable/local-storage') const PortStream = require('./lib/port-stream.js') const notification = require('./lib/notifications.js') @@ -35,10 +35,7 @@ asyncQ.waterfall([ function loadStateFromPersistence() { // migrations let migrator = new Migrator({ migrations }) - let initialState = { - meta: { version: migrator.defaultVersion }, - data: firstTimeState, - } + let initialState = migrator.generateInitialState(firstTimeState) return asyncQ.waterfall([ // read from disk () => Promise.resolve(diskStore.get() || initialState), @@ -68,6 +65,7 @@ function setupController (initState) { // initial state initState, }) + global.metamaskController = controller // setup state persistence controller.store.subscribe((newState) => diskStore) diff --git a/app/scripts/lib/migrator/index.js b/app/scripts/lib/migrator/index.js index 02d8c2335..ab5a757b3 100644 --- a/app/scripts/lib/migrator/index.js +++ b/app/scripts/lib/migrator/index.js @@ -7,22 +7,31 @@ class Migrator { this.migrations = migrations.sort((a, b) => a.version - b.version) let lastMigration = this.migrations.slice(-1)[0] // use specified defaultVersion or highest migration version - this.defaultVersion = opts.defaultVersion || lastMigration && lastMigration.version || 0 + this.defaultVersion = opts.defaultVersion || (lastMigration && lastMigration.version) || 0 } // run all pending migrations on meta in place - migrateData (meta = { version: this.defaultVersion }) { + migrateData (versionedData = this.generateInitialState()) { let remaining = this.migrations.filter(migrationIsPending) return ( - asyncQ.eachSeries(remaining, (migration) => migration.migrate(meta)) - .then(() => meta) + asyncQ.eachSeries(remaining, (migration) => migration.migrate(versionedData)) + .then(() => versionedData) ) // migration is "pending" if hit has a higher // version number than currentVersion function migrationIsPending(migration) { - return migration.version > meta.version + return migration.version > versionedData.meta.version + } + } + + generateInitialState (initState) { + return { + meta: { + version: this.defaultVersion, + }, + data: initState, } } diff --git a/app/scripts/migrations/002.js b/app/scripts/migrations/002.js index 97f427d3a..476b0a43a 100644 --- a/app/scripts/migrations/002.js +++ b/app/scripts/migrations/002.js @@ -3,14 +3,14 @@ const version = 2 module.exports = { version, - migrate: function (meta) { - meta.version = version + migrate: function (versionedData) { + versionedData.meta.version = version try { - if (meta.data.config.provider.type === 'etherscan') { - meta.data.config.provider.type = 'rpc' - meta.data.config.provider.rpcTarget = 'https://rpc.metamask.io/' + if (versionedData.data.config.provider.type === 'etherscan') { + versionedData.data.config.provider.type = 'rpc' + versionedData.data.config.provider.rpcTarget = 'https://rpc.metamask.io/' } } catch (e) {} - return Promise.resolve(meta) + return Promise.resolve(versionedData) }, } diff --git a/app/scripts/migrations/003.js b/app/scripts/migrations/003.js index b25e26e01..eceaeaa4b 100644 --- a/app/scripts/migrations/003.js +++ b/app/scripts/migrations/003.js @@ -5,13 +5,13 @@ const newTestRpc = 'https://testrpc.metamask.io/' module.exports = { version, - migrate: function (meta) { - meta.version = version + migrate: function (versionedData) { + versionedData.meta.version = version try { - if (meta.data.config.provider.rpcTarget === oldTestRpc) { - meta.data.config.provider.rpcTarget = newTestRpc + if (versionedData.data.config.provider.rpcTarget === oldTestRpc) { + versionedData.data.config.provider.rpcTarget = newTestRpc } } catch (e) {} - return Promise.resolve(meta) + return Promise.resolve(versionedData) }, } diff --git a/app/scripts/migrations/004.js b/app/scripts/migrations/004.js index e72eef2b7..0f9850208 100644 --- a/app/scripts/migrations/004.js +++ b/app/scripts/migrations/004.js @@ -3,23 +3,23 @@ const version = 4 module.exports = { version, - migrate: function (meta) { - meta.version = version + migrate: function (versionedData) { + versionedData.meta.version = version try { - if (meta.data.config.provider.type !== 'rpc') return Promise.resolve(meta) - switch (meta.data.config.provider.rpcTarget) { + if (versionedData.data.config.provider.type !== 'rpc') return Promise.resolve(versionedData) + switch (versionedData.data.config.provider.rpcTarget) { case 'https://testrpc.metamask.io/': - meta.data.config.provider = { + versionedData.data.config.provider = { type: 'testnet', } break case 'https://rpc.metamask.io/': - meta.data.config.provider = { + versionedData.data.config.provider = { type: 'mainnet', } break } } catch (_) {} - return Promise.resolve(meta) + return Promise.resolve(versionedData) }, } diff --git a/app/scripts/migrations/005.js b/app/scripts/migrations/005.js new file mode 100644 index 000000000..4c76b1dcf --- /dev/null +++ b/app/scripts/migrations/005.js @@ -0,0 +1,44 @@ +const version = 5 + +const ObservableStore = require('../../app/scripts/lib/observable/') +const ConfigManager = require('../../app/scripts/lib/config-manager') +const IdentityStoreMigrator = require('../../app/scripts/lib/idStore-migrator') +const KeyringController = require('../../app/scripts/lib/keyring-controller') + +const password = 'obviously not correct' + +module.exports = { + version, + + migrate: function (versionedData) { + versionedData.meta.version = version + + let store = new ObservableStore(versionedData.data) + let configManager = new ConfigManager({ store }) + let idStoreMigrator = new IdentityStoreMigrator({ configManager }) + let keyringController = new KeyringController({ + configManager: configManager, + }) + + // attempt to migrate to multiVault + return idStoreMigrator.migratedVaultForPassword(password) + .then((result) => { + // skip if nothing to migrate + if (!result) return Promise.resolve(versionedData) + delete versionedData.data.wallet + // create new keyrings + const privKeys = result.lostAccounts.map(acct => acct.privateKey) + return Promise.all([ + keyringController.restoreKeyring(result.serialized), + keyringController.restoreKeyring({ type: 'Simple Key Pair', data: privKeys }), + ]).then(() => { + return keyringController.persistAllKeyrings(password) + }).then(() => { + // copy result on to state object + versionedData.data = store.get() + return Promise.resolve(versionedData) + }) + }) + + }, +} diff --git a/app/scripts/lib/migrations.js b/app/scripts/migrations/index.js similarity index 82% rename from app/scripts/lib/migrations.js rename to app/scripts/migrations/index.js index 12f60def1..d2ac221b9 100644 --- a/app/scripts/lib/migrations.js +++ b/app/scripts/migrations/index.js @@ -12,7 +12,7 @@ // config data format, and returns the new one. module.exports = [ - require('../migrations/002'), - require('../migrations/003'), - require('../migrations/004'), + require('./002'), + require('./003'), + require('./004'), ]