From 39e85396db83134d5d8a0bb9f0071abe24398ea7 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Tue, 21 Oct 2014 09:57:54 -0300 Subject: [PATCH] WIP test --- js/models/Identity.js | 55 ++++++++++++++++++++++++++++-------- js/models/Profile.js | 19 +++++++++++++ js/models/Storage.js | 17 +++++++++-- js/models/Wallet.js | 2 +- test/Identity.js | 61 +++++++++++++++++++++++----------------- test/Storage.js | 9 ++++++ test/mocks/FakeWallet.js | 2 +- 7 files changed, 123 insertions(+), 42 deletions(-) diff --git a/js/models/Identity.js b/js/models/Identity.js index 945ccb760..83797c218 100644 --- a/js/models/Identity.js +++ b/js/models/Identity.js @@ -24,7 +24,7 @@ var Storage = module.exports.Storage = require('./Storage'); * @constructor */ -function Identity(email, password, opts) { +function Identity(password, opts) { preconditions.checkArgument(opts); this.storage = Identity._getStorage(opts, password); @@ -133,7 +133,7 @@ Identity.anyWallet = function(opts, cb) { Identity.create = function(email, password, opts, cb) { opts = opts || {}; - var iden = new Identity(email, password, opts); + var iden = new Identity(password, opts); Identity._createProfile(email, password, iden.storage, function(err, profile) { if (err) return cb(err); @@ -183,7 +183,7 @@ Identity.prototype.validate = function(authcode, cb) { * @return {undefined} */ Identity.open = function(email, password, opts, cb) { - var iden = new Identity(email, password, opts); + var iden = new Identity(password, opts); Identity._openProfile(email, password, iden.storage, function(err, profile) { if (err) return cb(err); @@ -301,10 +301,7 @@ Identity.prototype.importWallet = function(base64, password, skipFields, cb) { preconditions.checkArgument(password); preconditions.checkArgument(cb); - this.storage.savePassphrase(); - this.storage.setPassword(password); - var obj = this.storage.decrypt(base64); - this.storage.restorePassphrase(); + var obj = this.storage.decrypt(base64, password); var readOpts = { storage: this.storage, @@ -339,24 +336,60 @@ Identity.prototype.closeWallet = function(wid, cb) { }; + /** * @desc Return a base64 encrypted version of the wallet * @return {string} base64 encoded string */ -Identity.prototype.toEncryptedObj = function() { +Identity.import = function(str, password, opts, cb) { + preconditions.checkArgument(str); +console.log('[Identity.js.347:str::]',str); //TODO + + + var json = JSON.parse(str); + preconditions.checkArgument(_.isNumber(json.iterations)); + + + var iden = new Identity(password, opts); + iden.profile = Profile.import(json.profile, password, iden.storage); + + json.wallets = json.wallets || {}; + + var l = json.wallets.length, + i = 0; + + if (!l) + return cb(null, iden); + + _.each(this.wallets, function(wstr) { + iden.importWallet(wstr, password, skipFields, function(err, w) { + if (err) return cb(err); + log.debug('Wallet ' + w.getId() + ' imported'); + + if (++i == l) + iden.store(cb); + }) + }); +}; + +/** + * @desc Return JSON with base64 encoded strings for wallets and profile, and iteration count + * @return {string} Stringify JSON + */ +Identity.prototype.export = function() { var ret = {}; ret.iterations = this.storage.iterations; + ret.profile = this.profile.export(); ret.wallets = {}; _.each(this.openWallets, function(w) { ret.wallets[w.getId()] = w.toEncryptedObj(); }); - return ret; + var r = JSON.stringify(ret); + return r; }; - - /** * @desc This method prepares options for a new Wallet * diff --git a/js/models/Profile.js b/js/models/Profile.js index 22747ca29..5b5692aa6 100644 --- a/js/models/Profile.js +++ b/js/models/Profile.js @@ -70,6 +70,25 @@ Profile.prototype.toObj = function() { return _.clone(_.pick(this, 'hash', 'email', 'extra', 'walletInfos')); }; + +/* + * @desc Return a base64 encrypted version of the wallet + * @return {string} base64 encoded string + */ +Profile.prototype.export = function() { + var profObj = this.toObj(); + return this.storage.encrypt(profObj); +}; + +/* + * @desc Return a base64 encrypted version of the wallet + * @return {string} base64 encoded string + */ +Profile.import = function(str, password, storage) { + var obj = storage.decrypt(str,password) + return new Profile(obj, storage); +}; + Profile.prototype.getWallet = function(walletId, cb) { return this.walletInfos[walletId]; }; diff --git a/js/models/Storage.js b/js/models/Storage.js index 0927c51be..cf440d561 100644 --- a/js/models/Storage.js +++ b/js/models/Storage.js @@ -230,11 +230,22 @@ Storage.prototype.clearAll = function(cb) { this.db.clear(cb); }; -Storage.prototype.decrypt = function(base64, password) { - // password +Storage.prototype.decrypt = function(base64, password, iterations) { + + if (password) { + this.storage.savePassphrase(); + var opts = iterations ? {iterations: iterations} : {}; + + this.storage.setPassword(password, opts); + } var decryptedStr = this._decrypt(base64); - return JSON.parse(decryptedStr); + var ret = JSON.parse(decryptedStr); + + if (password) + this.storage.restorePassphrase(); + + return ret; }; Storage.prototype.encrypt = function(obj) { diff --git a/js/models/Wallet.js b/js/models/Wallet.js index 7e01394dd..6c358e99b 100644 --- a/js/models/Wallet.js +++ b/js/models/Wallet.js @@ -1169,7 +1169,7 @@ Wallet.fromObj = function(o, readOpts) { * @desc Return a base64 encrypted version of the wallet * @return {string} base64 encoded string */ -Wallet.prototype.toEncryptedObj = function() { +Wallet.prototype.export = function() { var walletObj = this.toObj(); return this.storage.encrypt(walletObj); }; diff --git a/test/Identity.js b/test/Identity.js index 177700453..f40140a9c 100644 --- a/test/Identity.js +++ b/test/Identity.js @@ -304,35 +304,12 @@ describe('Identity model', function() { iden.importWallet("encrypted object", "xxx", [], function(err) { iden.openWallet('ID123', function(err, w) { - iden.storage.savePassphrase.calledOnce.should.equal(true); - iden.storage.restorePassphrase.calledOnce.should.equal(true); should.not.exist(err); should.exist(w); done(); }); }); }); - - - it('should import and update indexes', function() { - var wallet = { - id: "fake wallet", - updateIndexes: function(cb) { - cb(); - } - }; - iden.fromEncryptedObj = sinon.stub().returns(wallet); - - var w = iden.fromEncryptedObj("encrypted", "password"); - - should.exist(w); - wallet.should.equal(w); - }); - it('should import with a wrong password', function() { - iden.fromEncryptedObj = sinon.stub().returns(null); - var w = iden.fromEncryptedObj("encrypted", "passwordasdfasdf"); - should.not.exist(w); - }); }); describe('#listWallets', function() { @@ -356,29 +333,61 @@ describe('Identity model', function() { }); - describe('#toEncryptedObj', function() { + describe('#export', function() { beforeEach(function() { var ws = []; _.each([0, 1, 2, 3, 4], function(i) { var w = sinon.stub(); - w.toEncryptedObj = sinon.stub().returns('enc' + i); + w.export = sinon.stub().returns('enc' + i); w.getId = sinon.stub().returns('wid' + i); ws.push(w); }); iden.openWallets = ws; + iden.profile.export = sinon.stub().returns('penc'); iden.storage.iterations = 13; }); it('should create an encrypted object', function() { - var ret = iden.toEncryptedObj(); + var ret = JSON.parse(iden.export()); ret.iterations.should.equal(13); + ret.profile.should.equal('penc'); _.each([0, 1, 2, 3, 4], function(i) { ret.wallets['wid' + i].should.equal('enc' + i); }); }); }); + describe.only('#import', function() { + + beforeEach(function() { + var ws = []; + _.each([0, 1, 2, 3, 4], function(i) { + var w = sinon.stub(); + w.export = sinon.stub().returns('enc' + i); + w.getId = sinon.stub().returns('wid' + i); + ws.push(w); + }); + iden.openWallets = ws; + iden.profile.export = sinon.stub().returns('penc'); + iden.storage.iterations = 13; + iden.storage.decrypt = sinon.stub().returns({ + email: '1@1.com', + hash: 'hash1234' + }); + }); + + it('should create an encrypted object', function(done) { + Identity.import(JSON.stringify({ + iterations: 10 + }), '1234', config, function(err, ret) { + should.not.exist(err); + should.exist(ret); + done(); + }); + }); + }); + describe('#joinWallet', function() { var opts = { secret: '8WtTuiFTkhP5ao7AF2QErSwV39Cbur6pdMebKzQXFqL59RscXM', diff --git a/test/Storage.js b/test/Storage.js index 33bf30d75..517c1a384 100644 --- a/test/Storage.js +++ b/test/Storage.js @@ -419,6 +419,15 @@ describe('Storage model', function() { var wo = s.decrypt(encryptedLegacy1); should.not.exist(wo); }); + it('should call save / restorePassphrase', function() { + var wo = s.decrypt(encryptedLegacy1, 'xxx'); + s.savePassphrase.calledOnce.should.equal(true); + s.restorePassphrase.calledOnce.should.equal(true); + should.not.exist(wo); + }); + + + it('should be able to decrypt an old backup', function() { s._setPassphrase(legacyPassword1); diff --git a/test/mocks/FakeWallet.js b/test/mocks/FakeWallet.js index c5ecbb244..74ec1b9ff 100644 --- a/test/mocks/FakeWallet.js +++ b/test/mocks/FakeWallet.js @@ -132,7 +132,7 @@ FakeWallet.prototype.setEnc = function(enc) { this.enc = enc; }; -FakeWallet.prototype.toEncryptedObj = function() { +FakeWallet.prototype.export = function() { return this.enc; };