diff --git a/app/scripts/lib/idStore.js b/app/scripts/lib/idStore.js index 1a3e7e06f..1491effcc 100644 --- a/app/scripts/lib/idStore.js +++ b/app/scripts/lib/idStore.js @@ -53,18 +53,17 @@ IdentityStore.prototype.createNewVault = function(password, entropy, cb){ } IdentityStore.prototype.recoverFromSeed = function(password, seed, cb){ - const self = this - self._createIdmgmt(password, seed, null, function(err){ + this._createIdmgmt(password, seed, null, (err) => { if (err) return cb(err) - self._loadIdentities() - self._didUpdate() + + this._loadIdentities() + this._didUpdate() cb() }) } IdentityStore.prototype.setStore = function(store){ - const self = this - self._ethStore = store + this._ethStore = store } IdentityStore.prototype.clearSeedWordCache = function(cb) { @@ -73,46 +72,40 @@ IdentityStore.prototype.clearSeedWordCache = function(cb) { } IdentityStore.prototype.getState = function(){ - const self = this const cachedSeeds = window.localStorage['seedWords'] - return clone(extend(self._currentState, { + return clone(extend(this._currentState, { isInitialized: !!window.localStorage['lightwallet'] && !cachedSeeds, - isUnlocked: self._isUnlocked(), + isUnlocked: this._isUnlocked(), seedWords: cachedSeeds, })) } IdentityStore.prototype.getSelectedAddress = function(){ - const self = this - return self._currentState.selectedAddress + return this._currentState.selectedAddress } IdentityStore.prototype.setSelectedAddress = function(address){ - const self = this - self._currentState.selectedAddress = address - self._didUpdate() + this._currentState.selectedAddress = address + this._didUpdate() } IdentityStore.prototype.setLocked = function(cb){ - const self = this - delete self._keyStore - delete self._idmgmt + delete this._keyStore + delete this._idmgmt cb() } IdentityStore.prototype.submitPassword = function(password, cb){ - const self = this - self._tryPassword(password, function(err){ + this._tryPassword(password, (err) => { if (err) return cb(err) // load identities before returning... - self._loadIdentities() + this._loadIdentities() cb() }) } // comes from dapp via zero-client hooked-wallet provider IdentityStore.prototype.addUnconfirmedTransaction = function(txParams, cb){ - var self = this // create txData obj with parameters and meta data var time = (new Date()).getTime() @@ -123,55 +116,51 @@ IdentityStore.prototype.addUnconfirmedTransaction = function(txParams, cb){ time: time, status: 'unconfirmed', } - self._currentState.unconfTxs[txId] = txData + this._currentState.unconfTxs[txId] = txData + console.log('addUnconfirmedTransaction:', txData) // keep the cb around for after approval (requires user interaction) - self._unconfTxCbs[txId] = cb + this._unconfTxCbs[txId] = cb // signal update - self._didUpdate() + this._didUpdate() return txId } // comes from metamask ui IdentityStore.prototype.approveTransaction = function(txId, cb){ - const self = this - - var txData = self._currentState.unconfTxs[txId] + var txData = this._currentState.unconfTxs[txId] var txParams = txData.txParams - var approvalCb = self._unconfTxCbs[txId] || noop + var approvalCb = this._unconfTxCbs[txId] || noop // accept tx cb() approvalCb(null, true) // clean up - delete self._currentState.unconfTxs[txId] - delete self._unconfTxCbs[txId] - self._didUpdate() + delete this._currentState.unconfTxs[txId] + delete this._unconfTxCbs[txId] + this._didUpdate() } // comes from metamask ui IdentityStore.prototype.cancelTransaction = function(txId){ - const self = this - - var txData = self._currentState.unconfTxs[txId] - var approvalCb = self._unconfTxCbs[txId] || noop + var txData = this._currentState.unconfTxs[txId] + var approvalCb = this._unconfTxCbs[txId] || noop // reject tx approvalCb(null, false) // clean up - delete self._currentState.unconfTxs[txId] - delete self._unconfTxCbs[txId] - self._didUpdate() + delete this._currentState.unconfTxs[txId] + delete this._unconfTxCbs[txId] + this._didUpdate() } // performs the actual signing, no autofill of params IdentityStore.prototype.signTransaction = function(txParams, cb){ - const self = this try { console.log('signing tx...', txParams) - var rawTx = self._idmgmt.signTx(txParams) + var rawTx = this._idmgmt.signTx(txParams) cb(null, rawTx) } catch (err) { cb(err) @@ -183,13 +172,11 @@ IdentityStore.prototype.signTransaction = function(txParams, cb){ // IdentityStore.prototype._didUpdate = function(){ - const self = this - self.emit('update', self.getState()) + this.emit('update', this.getState()) } IdentityStore.prototype._isUnlocked = function(){ - const self = this - var result = Boolean(self._keyStore) && Boolean(self._idmgmt) + var result = Boolean(this._keyStore) && Boolean(this._idmgmt) return result } @@ -199,22 +186,21 @@ IdentityStore.prototype._cacheSeedWordsUntilConfirmed = function(seedWords) { // load identities from keyStoreet IdentityStore.prototype._loadIdentities = function(){ - const self = this - if (!self._isUnlocked()) throw new Error('not unlocked') + if (!this._isUnlocked()) throw new Error('not unlocked') // get addresses and normalize address hexString - var addresses = self._keyStore.getAddresses(this.hdPathString).map(function(address){ return '0x'+address }) - addresses.forEach(function(address){ + var addresses = this._keyStore.getAddresses(this.hdPathString).map((address) => { return '0x'+address }) + addresses.forEach((address) => { // // add to ethStore - self._ethStore.addAccount(address) + this._ethStore.addAccount(address) // add to identities var identity = { name: 'Wally', img: 'QmW6hcwYzXrNkuHrpvo58YeZvbZxUddv69ATSHY3BHpPdd', address: address, } - self._currentState.identities[address] = identity + this._currentState.identities[address] = identity }) - self._didUpdate() + this._didUpdate() } // @@ -222,8 +208,7 @@ IdentityStore.prototype._loadIdentities = function(){ // IdentityStore.prototype._tryPassword = function(password, cb){ - const self = this - self._createIdmgmt(password, null, null, cb) + this._createIdmgmt(password, null, null, cb) } IdentityStore.prototype._createIdmgmt = function(password, seed, entropy, cb){ @@ -233,7 +218,7 @@ IdentityStore.prototype._createIdmgmt = function(password, seed, entropy, cb){ var serializedKeystore = window.localStorage['lightwallet'] if (seed) { - this._restoreFromSeed(keyStore, seed, derivedKey) + keyStore = this._restoreFromSeed(seed, derivedKey) // returning user, recovering from localStorage } else if (serializedKeystore) { @@ -256,11 +241,12 @@ IdentityStore.prototype._createIdmgmt = function(password, seed, entropy, cb){ }) } -IdentityStore.prototype._restoreFromSeed = function(keyStore, seed, derivedKey) { - keyStore = new LightwalletKeyStore(seed, derivedKey) - keyStore.generateNewAddress(derivedKey, 3, hdPathString) +IdentityStore.prototype._restoreFromSeed = function(seed, derivedKey) { + var keyStore = new LightwalletKeyStore(seed, derivedKey, this.hdPathString) + keyStore.generateNewAddress(derivedKey, 3, this.hdPathString) window.localStorage['lightwallet'] = keyStore.serialize() console.log('restored from seed. saved to keystore localStorage') + return keyStore } IdentityStore.prototype._loadFromLocalStorage = function(serializedKeystore, derivedKey) { diff --git a/package.json b/package.json index da7686c0a..e31f9e09a 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "private": true, "scripts": { "start": "gulp dev", - "test": "mocha --compilers js:babel-register", - "watch": "mocha watch --compilers js:babel-register" + "test": "mocha --compilers js:babel-register --recursive", + "watch": "mocha watch --compilers js:babel-register --recursive" }, "dependencies": { "async": "^1.5.2", @@ -44,6 +44,8 @@ "lodash.assign": "^4.0.6", "mocha": "^2.4.5", "mocha-jsdom": "^1.1.0", + "mocha-sinon": "^1.1.5", + "sinon": "^1.17.3", "tape": "^4.5.1", "vinyl-buffer": "^1.0.0", "vinyl-source-stream": "^1.1.0", diff --git a/test/helper.js b/test/helper.js new file mode 100644 index 000000000..7746b90e0 --- /dev/null +++ b/test/helper.js @@ -0,0 +1,4 @@ +require('mocha-sinon')() +var jsdom = require('mocha-jsdom') +jsdom() + diff --git a/test/index.js b/test/unit/idStore-test.js similarity index 53% rename from test/index.js rename to test/unit/idStore-test.js index 5a8df78b8..4494bf505 100644 --- a/test/index.js +++ b/test/unit/idStore-test.js @@ -1,7 +1,5 @@ var assert = require('assert') -var IdentityStore = require('../app/scripts/lib/idStore') -var jsdom = require('mocha-jsdom') -jsdom() +var IdentityStore = require('../../app/scripts/lib/idStore') describe('IdentityStore', function() { @@ -38,15 +36,46 @@ describe('IdentityStore', function() { }) }) - it('should return the expected keystore', function () { + it('should return the expected keystore', function (done) { idStore.recoverFromSeed(password, seedWords, (err) => { assert.ifError(err) let newKeystore = idStore._idmgmt.keyStore assert.equal(newKeystore, originalKeystore) + done() }) }) }) }) + + describe('#recoverFromSeed BIP44 compliance', function() { + let seedWords = 'picnic injury awful upper eagle junk alert toss flower renew silly vague' + let firstAccount = '0xaceef0221414801dde7f732196b1c9d8ea60b637' + let password = 'secret!' + let accounts = [] + let idStore + + before(function() { + window.localStorage = {} // Hacking localStorage support into JSDom + + idStore = new IdentityStore({ + addAccount(acct) { + console.log(`pushing account ${acct}`) + accounts.push(acct) + }, + }) + }) + + it('should return the expected first account', function (done) { + + idStore.recoverFromSeed(password, seedWords, (err) => { + assert.ifError(err) + + let newKeystore = idStore._idmgmt.keyStore + assert.equal(accounts[0], firstAccount) + done() + }) + }) + }) })