diff options
Merge pull request #81 from MetaMask/MigratableConfig
Migratable config
Diffstat (limited to 'app/scripts/lib')
-rw-r--r-- | app/scripts/lib/config-manager-singleton.js | 3 | ||||
-rw-r--r-- | app/scripts/lib/config-manager.js | 157 | ||||
-rw-r--r-- | app/scripts/lib/idStore.js | 48 |
3 files changed, 186 insertions, 22 deletions
diff --git a/app/scripts/lib/config-manager-singleton.js b/app/scripts/lib/config-manager-singleton.js new file mode 100644 index 000000000..5915c401b --- /dev/null +++ b/app/scripts/lib/config-manager-singleton.js @@ -0,0 +1,3 @@ +var ConfigManager = require('./config-manager') + +module.exports = new ConfigManager() diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js new file mode 100644 index 000000000..682b34637 --- /dev/null +++ b/app/scripts/lib/config-manager.js @@ -0,0 +1,157 @@ +const Migrator = require('pojo-migrator') +const extend = require('xtend') + +const STORAGE_KEY = 'metamask-config' +var DEFAULT_RPC = 'https://rawtestrpc.metamask.io/' + +/* The config-manager is a convenience object + * wrapping a pojo-migrator. + * + * It exists mostly to allow the creation of + * convenience methods to access and persist + * particular portions of the state. + */ +module.exports = ConfigManager +function ConfigManager() { + + /* The migrator exported on the config-manager + * 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. + */ + this.migrator = new Migrator({ + + // 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. + migrations: [], + + // How to load initial config. + // Includes step on migrating pre-pojo-migrator data. + loadData: loadData, + + // How to persist migrated config. + setData: function(data) { + window.localStorage[STORAGE_KEY] = JSON.stringify(data) + }, + }) +} + +ConfigManager.prototype.setConfig = function(config) { + var data = this.migrator.getData() + data.config = config + this.setData(data) +} + +ConfigManager.prototype.setRpcTarget = function(rpcUrl) { + var config = this.getConfig() + config.provider = { + type: 'rpc', + rpcTarget: rpcUrl, + } + this.setConfig(config) +} + +ConfigManager.prototype.getConfig = function() { + var data = this.migrator.getData() + if ('config' in data) { + return data.config + } else { + return { + provider: { + type: 'rpc', + rpcTarget: DEFAULT_RPC, + } + } + } +} + +ConfigManager.prototype.setData = function(data) { + this.migrator.saveData(data) +} + +ConfigManager.prototype.getData = function() { + return this.migrator.getData() +} + +ConfigManager.prototype.setWallet = function(wallet) { + var data = this.migrator.getData() + data.wallet = wallet + this.setData(data) +} + +ConfigManager.prototype.getWallet = function() { + return this.migrator.getData().wallet +} + +// Takes a boolean +ConfigManager.prototype.setShowSeedWords = function(should) { + var data = this.migrator.getData() + data.showSeedWords = should + this.setData(data) +} + +ConfigManager.prototype.getShouldShowSeedWords = function() { + var data = this.migrator.getData() + return data.showSeedWords +} + +ConfigManager.prototype.getCurrentRpcAddress = function() { + var config = this.getConfig() + if (!config) return null + return config.provider && config.provider.rpcTarget ? config.provider.rpcTarget : DEFAULT_RPC +} + +ConfigManager.prototype.clearWallet = function() { + var data = this.getConfig() + delete data.wallet + this.setData(data) +} + +function loadData() { + + var oldData = getOldStyleData() + var newData + try { + newData = JSON.parse(window.localStorage[STORAGE_KEY]) + } catch (e) {} + + var data = extend({ + version: 0, + data: { + config: { + rpcTarget: DEFAULT_RPC, + } + } + }, oldData ? oldData : null, newData ? newData : null) + return 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 +} + diff --git a/app/scripts/lib/idStore.js b/app/scripts/lib/idStore.js index ea873e627..1bc1ebcb2 100644 --- a/app/scripts/lib/idStore.js +++ b/app/scripts/lib/idStore.js @@ -8,6 +8,7 @@ const clone = require('clone') const extend = require('xtend') const createId = require('web3-provider-engine/util/random-id') const autoFaucet = require('./auto-faucet') +const configManager = require('./config-manager-singleton') module.exports = IdentityStore @@ -41,14 +42,16 @@ function IdentityStore(ethStore) { IdentityStore.prototype.createNewVault = function(password, entropy, cb){ delete this._keyStore - delete window.localStorage['lightwallet'] + configManager.clearWallet() this._createIdmgmt(password, null, entropy, (err) => { if (err) return cb(err) - var seedWords = this._idmgmt.getSeed() - this._cacheSeedWordsUntilConfirmed(seedWords) + this._loadIdentities() this._didUpdate() this._autoFaucet() + + configManager.setShowSeedWords(true) + var seedWords = this._idmgmt.getSeed() cb(null, seedWords) }) } @@ -68,19 +71,28 @@ IdentityStore.prototype.setStore = function(store){ } IdentityStore.prototype.clearSeedWordCache = function(cb) { - delete window.localStorage['seedWords'] + configManager.setShowSeedWords(false) cb() } IdentityStore.prototype.getState = function(){ - const cachedSeeds = window.localStorage['seedWords'] + var seedWords = this.getSeedIfUnlocked() + var wallet = configManager.getWallet() return clone(extend(this._currentState, { - isInitialized: !!window.localStorage['lightwallet'] && !cachedSeeds, + isInitialized: !!configManager.getWallet() && !seedWords, isUnlocked: this._isUnlocked(), - seedWords: cachedSeeds, + seedWords: seedWords, })) } +IdentityStore.prototype.getSeedIfUnlocked = function() { + var showSeed = configManager.getShouldShowSeedWords() + var idmgmt = this._idmgmt + var shouldShow = showSeed && !!idmgmt + var seedWords = shouldShow ? idmgmt.getSeed() : null + return seedWords +} + IdentityStore.prototype.getSelectedAddress = function(){ return this._currentState.selectedAddress } @@ -181,10 +193,6 @@ IdentityStore.prototype._isUnlocked = function(){ return result } -IdentityStore.prototype._cacheSeedWordsUntilConfirmed = function(seedWords) { - window.localStorage['seedWords'] = seedWords -} - // load identities from keyStoreet IdentityStore.prototype._loadIdentities = function(){ if (!this._isUnlocked()) throw new Error('not unlocked') @@ -216,14 +224,14 @@ IdentityStore.prototype._createIdmgmt = function(password, seed, entropy, cb){ var keyStore = null LightwalletKeyStore.deriveKeyFromPassword(password, (err, derivedKey) => { if (err) return cb(err) - var serializedKeystore = window.localStorage['lightwallet'] + var serializedKeystore = configManager.getWallet() if (seed) { keyStore = this._restoreFromSeed(password, seed, derivedKey) - // returning user, recovering from localStorage + // returning user, recovering from storage } else if (serializedKeystore) { - keyStore = this._loadFromLocalStorage(serializedKeystore, derivedKey, cb) + keyStore = LightwalletKeyStore.deserialize(serializedKeystore) var isCorrect = keyStore.isDerivedKeyCorrect(derivedKey) if (!isCorrect) return cb(new Error('Lightwallet - password incorrect')) @@ -249,15 +257,11 @@ IdentityStore.prototype._restoreFromSeed = function(password, seed, derivedKey) keyStore.setDefaultHdDerivationPath(this.hdPathString) keyStore.generateNewAddress(derivedKey, 3) - window.localStorage['lightwallet'] = keyStore.serialize() - console.log('restored from seed. saved to keystore localStorage') + configManager.setWallet(keyStore.serialize()) + console.log('restored from seed. saved to keystore') return keyStore } -IdentityStore.prototype._loadFromLocalStorage = function(serializedKeystore, derivedKey) { - return LightwalletKeyStore.deserialize(serializedKeystore) -} - IdentityStore.prototype._createFirstWallet = function(entropy, derivedKey) { var secretSeed = LightwalletKeyStore.generateRandomSeed(entropy) var keyStore = new LightwalletKeyStore(secretSeed, derivedKey, this.hdPathString) @@ -265,8 +269,8 @@ IdentityStore.prototype._createFirstWallet = function(entropy, derivedKey) { keyStore.setDefaultHdDerivationPath(this.hdPathString) keyStore.generateNewAddress(derivedKey, 3) - window.localStorage['lightwallet'] = keyStore.serialize() - console.log('saved to keystore localStorage') + configManager.setWallet(keyStore.serialize()) + console.log('saved to keystore') return keyStore } |