From 55f8ae4edd998a4d3897b9e1dd005f61fabefe37 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 24 Mar 2016 10:32:50 -0700 Subject: Add seed word caching during confirmation screen In order to persist the seed word page until the user clicks the confirmation button, we need to store the seed words in localStorage. To simplify this process I've also reorganized some of the account manager code, broken up one large function into many smaller functions, and created a new class for the IdMgmt object. Again, sorry such a big refactor in one commit, but I really had to break it down to work through it. --- app/images/loading.svg | 1 + app/scripts/background.js | 5 +- app/scripts/lib/idStore.js | 131 +++++++++++++++++++++++++++++---------------- 3 files changed, 88 insertions(+), 49 deletions(-) create mode 100644 app/images/loading.svg (limited to 'app') diff --git a/app/images/loading.svg b/app/images/loading.svg new file mode 100644 index 000000000..854da88dd --- /dev/null +++ b/app/images/loading.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/scripts/background.js b/app/scripts/background.js index aa06f27f1..1a0d36ef8 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -121,10 +121,11 @@ function linkDnode(stream){ approveTransaction: idStore.approveTransaction.bind(idStore), cancelTransaction: idStore.cancelTransaction.bind(idStore), setLocked: idStore.setLocked.bind(idStore), + clearSeedWordCache: idStore.clearSeedWordCache.bind(idStore), }) stream.pipe(connection).pipe(stream) connection.on('remote', function(remote){ - + // push updates to popup ethStore.on('update', sendUpdate) idStore.on('update', sendUpdate) @@ -208,4 +209,4 @@ function jsonStringifyStream(){ }) } -function noop(){} \ No newline at end of file +function noop(){} diff --git a/app/scripts/lib/idStore.js b/app/scripts/lib/idStore.js index 173a1672f..c44429216 100644 --- a/app/scripts/lib/idStore.js +++ b/app/scripts/lib/idStore.js @@ -37,22 +37,22 @@ function IdentityStore(ethStore) { // public // -IdentityStore.prototype.createNewVault = function(password, cb){ - const self = this - delete self._keyStore +IdentityStore.prototype.createNewVault = function(password, entropy, cb){ + delete this._keyStore delete window.localStorage['lightwallet'] - var keyStore = self._createIdmgmt(password, null, function(err){ + this._createIdmgmt(password, null, entropy, (err) => { if (err) return cb(err) - var seedWords = self._idmgmt.getSeed() - self._loadIdentities() - self._didUpdate() + var seedWords = this._idmgmt.getSeed() + this._cacheSeedWordsUntilConfirmed(seedWords) + this._loadIdentities() + this._didUpdate() cb(null, seedWords) }) } IdentityStore.prototype.recoverFromSeed = function(password, seed, cb){ const self = this - self._createIdmgmt(password, seed, function(err){ + self._createIdmgmt(password, seed, null, function(err){ if (err) return cb(err) self._loadIdentities() self._didUpdate() @@ -65,12 +65,18 @@ IdentityStore.prototype.setStore = function(store){ self._ethStore = store } +IdentityStore.prototype.clearSeedWordCache = function(cb) { + delete window.localStorage['seedWords'] + cb() +} IdentityStore.prototype.getState = function(){ const self = this + const cachedSeeds = window.localStorage['seedWords'] return clone(extend(self._currentState, { - isInitialized: !!window.localStorage['lightwallet'], + isInitialized: !!window.localStorage['lightwallet'] && !cachedSeeds, isUnlocked: self._isUnlocked(), + seedWords: cachedSeeds, })) } @@ -185,6 +191,10 @@ IdentityStore.prototype._isUnlocked = function(){ return result } +IdentityStore.prototype._cacheSeedWordsUntilConfirmed = function(seedWords) { + window.localStorage['seedWords'] = seedWords +} + // load identities from keyStoreet IdentityStore.prototype._loadIdentities = function(){ const self = this @@ -211,59 +221,86 @@ IdentityStore.prototype._loadIdentities = function(){ IdentityStore.prototype._tryPassword = function(password, cb){ const self = this - self._createIdmgmt(password, null, cb) + self._createIdmgmt(password, null, null, cb) } -IdentityStore.prototype._createIdmgmt = function(password, seed, cb){ - const self = this +IdentityStore.prototype._createIdmgmt = function(password, seed, entropy, cb){ var keyStore = null - LightwalletKeyStore.deriveKeyFromPassword(password, function(err, derrivedKey){ + LightwalletKeyStore.deriveKeyFromPassword(password, (err, derivedKey) => { if (err) return cb(err) var serializedKeystore = window.localStorage['lightwallet'] - // recovering from seed + if (seed) { - keyStore = new LightwalletKeyStore(seed, derrivedKey) - keyStore.generateNewAddress(derrivedKey, 3) - window.localStorage['lightwallet'] = keyStore.serialize() - console.log('saved to keystore localStorage') + this._restoreFromSeed(keyStore, seed, derivedKey) + // returning user, recovering from localStorage } else if (serializedKeystore) { - keyStore = LightwalletKeyStore.deserialize(serializedKeystore) - var isCorrect = keyStore.isDerivedKeyCorrect(derrivedKey) + keyStore = this._loadFromLocalStorage(serializedKeystore, derivedKey, cb) + var isCorrect = keyStore.isDerivedKeyCorrect(derivedKey) if (!isCorrect) return cb(new Error('Lightwallet - password incorrect')) - // first time here + + // first time here } else { - var secretSeed = LightwalletKeyStore.generateRandomSeed() - keyStore = new LightwalletKeyStore(secretSeed, derrivedKey) - keyStore.generateNewAddress(derrivedKey, 3) - window.localStorage['lightwallet'] = keyStore.serialize() - console.log('saved to keystore localStorage') - } - self._keyStore = keyStore - self._idmgmt = { - getAddresses: function(){ - return keyStore.getAddresses().map(function(address){ return '0x'+address }) - }, - signTx: function(txParams){ - // normalize values - txParams.to = ethUtil.addHexPrefix(txParams.to) - txParams.from = ethUtil.addHexPrefix(txParams.from) - txParams.value = ethUtil.addHexPrefix(txParams.value) - txParams.data = ethUtil.addHexPrefix(txParams.data) - txParams.gasLimit = ethUtil.addHexPrefix(txParams.gasLimit || txParams.gas) - txParams.nonce = ethUtil.addHexPrefix(txParams.nonce) - var tx = new Transaction(txParams) - var rawTx = '0x'+tx.serialize().toString('hex') - return '0x'+LightwalletSigner.signTx(keyStore, derrivedKey, rawTx, txParams.from) - }, - getSeed: function(){ - return keyStore.getSeed(derrivedKey) - }, + keyStore = this._createFirstWallet(entropy, derivedKey) } + + this._keyStore = keyStore + this._idmgmt = new IdManagement({ + keyStore: keyStore, + derivedKey: derivedKey, + }) + cb() }) } +IdentityStore.prototype._restoreFromSeed = function(keyStore, seed, derivedKey) { + keyStore = new LightwalletKeyStore(seed, derivedKey) + keyStore.generateNewAddress(derivedKey, 3) + window.localStorage['lightwallet'] = keyStore.serialize() + console.log('restored from seed. saved to keystore localStorage') +} + +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) + keyStore.generateNewAddress(derivedKey, 3) + window.localStorage['lightwallet'] = keyStore.serialize() + console.log('wallet generated. saved to keystore localStorage') + return keyStore +} + +function IdManagement( opts = { keyStore: null, derivedKey: null } ) { + this.keyStore = opts.keyStore + this.derivedKey = opts.derivedKey + + this.getAddresses = function(){ + return keyStore.getAddresses().map(function(address){ return '0x'+address }) + } + + this.signTx = function(txParams){ + // normalize values + txParams.to = ethUtil.addHexPrefix(txParams.to) + txParams.from = ethUtil.addHexPrefix(txParams.from) + txParams.value = ethUtil.addHexPrefix(txParams.value) + txParams.data = ethUtil.addHexPrefix(txParams.data) + txParams.gasLimit = ethUtil.addHexPrefix(txParams.gasLimit || txParams.gas) + txParams.nonce = ethUtil.addHexPrefix(txParams.nonce) + var tx = new Transaction(txParams) + var rawTx = '0x'+tx.serialize().toString('hex') + return '0x'+LightwalletSigner.signTx(this.keyStore, this.derivedKey, rawTx, txParams.from) + } + + this.getSeed = function(){ + return this.keyStore.getSeed(this.derivedKey) + } +} + + // util function noop(){} -- cgit v1.2.3 From d6aa78e6478daa35c44085d11877d95c163e935a Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 24 Mar 2016 11:05:42 -0700 Subject: Gave lock a callback for better loading indication --- app/scripts/lib/idStore.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/scripts/lib/idStore.js b/app/scripts/lib/idStore.js index c44429216..c4547b07f 100644 --- a/app/scripts/lib/idStore.js +++ b/app/scripts/lib/idStore.js @@ -91,10 +91,11 @@ IdentityStore.prototype.setSelectedAddress = function(address){ self._didUpdate() } -IdentityStore.prototype.setLocked = function(){ +IdentityStore.prototype.setLocked = function(cb){ const self = this delete self._keyStore delete self._idmgmt + cb() } IdentityStore.prototype.submitPassword = function(password, cb){ @@ -270,7 +271,7 @@ IdentityStore.prototype._createFirstWallet = function(entropy, derivedKey) { var keyStore = new LightwalletKeyStore(secretSeed, derivedKey) keyStore.generateNewAddress(derivedKey, 3) window.localStorage['lightwallet'] = keyStore.serialize() - console.log('wallet generated. saved to keystore localStorage') + console.log('saved to keystore localStorage') return keyStore } -- cgit v1.2.3 From 152a66390388b5e388129a0d27e32e928e9ee7a1 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 24 Mar 2016 11:11:47 -0700 Subject: Bump version --- app/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/manifest.json b/app/manifest.json index 9e638dc1b..0777c0c8a 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,6 +1,6 @@ { "name": "__MSG_appName__", - "version": "0.14.0", + "version": "0.15.0", "manifest_version": 2, "description": "__MSG_appDescription__", "icons": { -- cgit v1.2.3