From 80514d73b5bc6887cea877194091c941cfb9a8e6 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 12 Jan 2017 02:24:33 -0800 Subject: migrations - wip - 005 multivault migration --- app/scripts/background.js | 8 +++---- app/scripts/lib/migrations.js | 18 ---------------- app/scripts/lib/migrator/index.js | 19 ++++++++++++----- app/scripts/migrations/002.js | 12 +++++------ app/scripts/migrations/003.js | 10 ++++----- app/scripts/migrations/004.js | 14 ++++++------- app/scripts/migrations/005.js | 44 +++++++++++++++++++++++++++++++++++++++ app/scripts/migrations/index.js | 18 ++++++++++++++++ 8 files changed, 97 insertions(+), 46 deletions(-) delete mode 100644 app/scripts/lib/migrations.js create mode 100644 app/scripts/migrations/005.js create mode 100644 app/scripts/migrations/index.js 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/migrations.js b/app/scripts/lib/migrations.js deleted file mode 100644 index 12f60def1..000000000 --- a/app/scripts/lib/migrations.js +++ /dev/null @@ -1,18 +0,0 @@ -/* The migrator has two methods the user should be concerned with: - * - * getData(), which returns the app-consumable data object - * saveData(), which persists the app-consumable data object. - */ - -// Migrations must start at version 1 or later. -// They are objects with a `version` number -// and a `migrate` function. -// -// The `migrate` function receives the previous -// config data format, and returns the new one. - -module.exports = [ - require('../migrations/002'), - require('../migrations/003'), - require('../migrations/004'), -] 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/migrations/index.js b/app/scripts/migrations/index.js new file mode 100644 index 000000000..d2ac221b9 --- /dev/null +++ b/app/scripts/migrations/index.js @@ -0,0 +1,18 @@ +/* The migrator has two methods the user should be concerned with: + * + * getData(), which returns the app-consumable data object + * saveData(), which persists the app-consumable data object. + */ + +// Migrations must start at version 1 or later. +// They are objects with a `version` number +// and a `migrate` function. +// +// The `migrate` function receives the previous +// config data format, and returns the new one. + +module.exports = [ + require('./002'), + require('./003'), + require('./004'), +] -- cgit v1.2.3