diff --git a/js/models/Storage.js b/js/models/Storage.js index 35cf1f976..39f6bd07f 100644 --- a/js/models/Storage.js +++ b/js/models/Storage.js @@ -140,6 +140,23 @@ Storage.prototype._readHelper = function(walletId, k, cb) { }); }; +Storage.prototype.readWallet = function(walletId, cb) { + var self = this; + this.storage.allKeys(function(allKeys) { + var obj = {}; + var keys = _.filter(allKeys, function(k) { + if (k.indexOf(walletId + '::') === 0) return true; + }); + var count = keys.length; + _.each(keys, function(k) { + self._read(k, function(v) { + obj[k.split('::')[1]] = v; + if (--count === 0) return cb(obj); + }) + }); + }); +}; + Storage.prototype.getMany = function(walletId, keys, cb) { preconditions.checkArgument(cb); diff --git a/js/models/WalletFactory.js b/js/models/WalletFactory.js index 7b3d4d103..55216f968 100644 --- a/js/models/WalletFactory.js +++ b/js/models/WalletFactory.js @@ -153,10 +153,10 @@ WalletFactory.prototype.read = function(walletId, skipFields, cb) { err; var obj = {}; - this.storage.getMany(walletId, Wallet.PERSISTED_PROPERTIES, function(ret) { - for (var ii in ret) { - obj[ii] = ret[ii]; - } + this.storage.readWallet(walletId, function(ret) { + _.each(Wallet.PERSISTED_PROPERTIES, function(p) { + obj[p] = ret[p]; + }); if (!_.any(_.values(obj))) return cb(new Error('Wallet not found')); diff --git a/test/test.Storage.js b/test/test.Storage.js index 559dae141..03f5e7916 100644 --- a/test/test.Storage.js +++ b/test/test.Storage.js @@ -1,6 +1,7 @@ 'use strict'; var chai = chai || require('chai'); var sinon = require('sinon'); +var _ = require('underscore'); var should = chai.should(); var is_browser = typeof process == 'undefined' || typeof process.versions === 'undefined'; var copay = copay || require('../copay'); @@ -11,65 +12,65 @@ var timeStamp = Date.now(); describe('Storage model', function() { - var s; - beforeEach(function() { - s = new Storage(require('./mocks/FakeLocalStorage').storageParams); - s.setPassphrase('mysupercoolpassword'); - s.storage.clear(); - s.sessionStorage.clear(); - }); + var s; + beforeEach(function() { + s = new Storage(require('./mocks/FakeLocalStorage').storageParams); + s.setPassphrase('mysupercoolpassword'); + s.storage.clear(); + s.sessionStorage.clear(); + }); - it('should create an instance', function() { - var s2 = new Storage(require('./mocks/FakeLocalStorage').storageParams); - should.exist(s2); + it('should create an instance', function() { + var s2 = new Storage(require('./mocks/FakeLocalStorage').storageParams); + should.exist(s2); + }); + it('should fail when encrypting without a password', function() { + var s2 = new Storage(require('./mocks/FakeLocalStorage').storageParams); + (function() { + s2.set(fakeWallet, timeStamp, 1, function() {}); + }).should.throw('NOPASSPHRASE'); + }); + it('should be able to encrypt and decrypt', function(done) { + s._write(fakeWallet + timeStamp, 'value', function() { + s._read(fakeWallet + timeStamp, function(v) { + v.should.equal('value'); + done(); + }); }); - it('should fail when encrypting without a password', function() { - var s2 = new Storage(require('./mocks/FakeLocalStorage').storageParams); - (function() { - s2.set(fakeWallet, timeStamp, 1, function() {}); - }).should.throw('NOPASSPHRASE'); + }); + it('should be able to set a value', function(done) { + s.set(fakeWallet, timeStamp, 1, function() { + done(); }); - it('should be able to encrypt and decrypt', function(done) { - s._write(fakeWallet + timeStamp, 'value', function() { - s._read(fakeWallet + timeStamp, function(v) { - v.should.equal('value'); + }); + var getSetData = [ + 1, 1000, -15, -1000, + 0.1, -0.5, -0.5e-10, Math.PI, + 'hi', 'auydoaiusyodaisudyoa', '0b5b8556a0c2ce828c9ccfa58b3dd0a1ae879b9b', + '1CjPR7Z5ZSyWk6WtXvSFgkptmpoi4UM9BC', 'OP_DUP OP_HASH160 80ad90d4035', [1, 2, 3, 4, 5, 6], { + x: 1, + y: 2 + }, { + x: 'hi', + y: null + }, { + a: {}, + b: [], + c: [1, 2, 'hi'] + }, + null + ]; + getSetData.forEach(function(obj) { + it('should be able to set a value and get it for ' + JSON.stringify(obj), function(done) { + s.set(fakeWallet, timeStamp, obj, function() { + s.get(fakeWallet, timeStamp, function(obj2) { + JSON.stringify(obj2).should.equal(JSON.stringify(obj)); done(); }); }); }); - it('should be able to set a value', function(done) { - s.set(fakeWallet, timeStamp, 1, function() { - done(); - }); - }); - var getSetData = [ - 1, 1000, -15, -1000, - 0.1, -0.5, -0.5e-10, Math.PI, - 'hi', 'auydoaiusyodaisudyoa', '0b5b8556a0c2ce828c9ccfa58b3dd0a1ae879b9b', - '1CjPR7Z5ZSyWk6WtXvSFgkptmpoi4UM9BC', 'OP_DUP OP_HASH160 80ad90d4035', [1, 2, 3, 4, 5, 6], { - x: 1, - y: 2 - }, { - x: 'hi', - y: null - }, { - a: {}, - b: [], - c: [1, 2, 'hi'] - }, - null - ]; - getSetData.forEach(function(obj) { - it('should be able to set a value and get it for ' + JSON.stringify(obj), function(done) { - s.set(fakeWallet, timeStamp, obj, function() { - s.get(fakeWallet, timeStamp, function(obj2) { - JSON.stringify(obj2).should.equal(JSON.stringify(obj)); - done(); - }); - }); - }); - }); + }); describe('#export', function() { it('should export the encrypted wallet', function(done) { @@ -177,9 +178,9 @@ describe('Storage model', function() { var orig = s.getName.bind(s); s.getName = function(wid, cb) { - setTimeout(function() { + setTimeout(function() { orig(wid, cb); - },1); + }, 1); }; s.getWallets(function(ws) { @@ -197,8 +198,8 @@ describe('Storage model', function() { }); }); }); - }); - + }); + describe('#deleteWallet', function() { it('should fail to delete a unexisting wallet', function(done) { s.set('1', "hola", 'juan', function() { @@ -230,6 +231,30 @@ describe('Storage model', function() { }); }); + describe('#readWallet', function() { + it('should read wallet', function(done) { + var data = { + 'id1::a': 'x', + 'id1::b': 'y', + 'id2::c': 'z', + }; + s.storage.allKeys = sinon.stub().yields(_.keys(data)); + sinon.stub(s, '_read', function(k, cb) { + return cb(data[k]); + }); + s.readWallet('id1', function(w) { + w.should.exist; + w.hasOwnProperty('a').should.be.true; + w.hasOwnProperty('b').should.be.true; + w.hasOwnProperty('c').should.be.false; + w.a.should.equal('x'); + w.b.should.equal('y'); + s._read.restore(); + done(); + }); + }); + }); + describe('#setFromObj', function() { it('set localstorage from an object', function(done) { s.setFromObj('id1', { @@ -286,7 +311,7 @@ describe('Storage model', function() { var wo = s.import(encryptedLegacy1); should.not.exist(wo); }); - + it('should be able to decrypt an old backup', function() { s.setPassphrase(legacyPassword1); var wo = s.import(encryptedLegacy1); diff --git a/test/test.WalletFactory.js b/test/test.WalletFactory.js index ff30c525c..63a392ac0 100644 --- a/test/test.WalletFactory.js +++ b/test/test.WalletFactory.js @@ -246,7 +246,7 @@ describe('WalletFactory model', function() { describe('#read', function() { it('should fail to read unexisting wallet', function(done) { - wf.storage.getMany = sinon.stub().yields({}); + wf.storage.readWallet = sinon.stub().yields({}); wf.read('id', [], function(err, w) { should.not.exist(w); @@ -258,7 +258,7 @@ describe('WalletFactory model', function() { }); }); it('should fail to read broken wallet', function(done) { - wf.storage.getMany = sinon.stub().yields({ + wf.storage.readWallet = sinon.stub().yields({ 'opts': 1 }); wf.read('id', [], function(err, w) { @@ -272,7 +272,7 @@ describe('WalletFactory model', function() { }); it('should read existing wallet', function(done) { var wf = new WalletFactory(config, '0.0.1'); - wf.storage.getMany = sinon.stub().yields({ + wf.storage.readWallet = sinon.stub().yields({ 'opts': 1 }); wf.fromObj = sinon.stub().returns('ok');