diff --git a/copay.js b/copay.js index 544b0eb45..fe6b4dbbd 100644 --- a/copay.js +++ b/copay.js @@ -10,7 +10,6 @@ module.exports.AddressIndex = require('./js/models/core/AddressIndex'); // components var WebRTC = module.exports.WebRTC = require('./js/models/network/WebRTC'); var Insight = module.exports.Insight = require('./js/models/blockchain/Insight'); -var StorageLocalPlain = module.exports.StorageLocalPlain = require('./js/models/storage/LocalPlain'); var StorageLocalEncrypted = module.exports.StorageLocalEncrypted = require('./js/models/storage/LocalEncrypted'); module.exports.WalletFactory = require('./js/models/core/WalletFactory'); diff --git a/js/models/storage/LocalEncrypted.js b/js/models/storage/LocalEncrypted.js index e47c0194c..802d8934a 100644 --- a/js/models/storage/LocalEncrypted.js +++ b/js/models/storage/LocalEncrypted.js @@ -15,6 +15,9 @@ function Storage(opts) { var pps = {}; Storage.prototype._getPassphrase = function() { + if (!pps[this.__uniqueid]) + throw new Error('No passprase set'); + return pps[this.__uniqueid]; } @@ -37,7 +40,6 @@ Storage.prototype._decrypt = function(base64) { var decryptedStr = null; try { var decrypted = CryptoJS.AES.decrypt(base64, this._getPassphrase()); - if (decrypted) decryptedStr = decrypted.toString(CryptoJS.enc.Utf8); } catch (e) { @@ -78,7 +80,7 @@ Storage.prototype.getGlobal = function(k) { // set value for key Storage.prototype.setGlobal = function(k, v) { - localStorage.setItem(k, JSON.stringify(v)); + localStorage.setItem(k, typeof v === 'object' ? JSON.stringify(v) : v); }; // remove value for key @@ -110,12 +112,15 @@ Storage.prototype.setName = function(walletId, name) { }; Storage.prototype.getName = function(walletId) { - return this.getGlobal('nameFor::' + walletId); + var ret = this.getGlobal('nameFor::' + walletId); + + return ret; }; Storage.prototype.getWalletIds = function() { var walletIds = []; var uniq = {}; + for (var i = 0; i < localStorage.length; i++) { var key = localStorage.key(i); var split = key.split('::'); diff --git a/js/models/storage/LocalPlain.js b/js/models/storage/LocalPlain.js deleted file mode 100644 index 85ebd19bc..000000000 --- a/js/models/storage/LocalPlain.js +++ /dev/null @@ -1,124 +0,0 @@ -'use strict'; - -var imports = require('soop').imports(); - -function Storage() {} - -Storage.prototype._read = function(k) { - var ret; - try { - ret = JSON.parse(localStorage.getItem(k)); - } catch (e) {}; - return ret; -}; - -Storage.prototype._write = function(k, v) { - localStorage.setItem(k, JSON.stringify(v)); -}; - -Storage.prototype._getWalletKeys = function(walletId) { - var keys = []; - - for (var i = 0; i < localStorage.length; i++) { - var key = localStorage.key(i); - var split = key.split('::'); - if (split.length == 3) { - if (walletId = split[0]) - keys.push(split[2]); - } - } - - return keys; -}; - -// get value by key -Storage.prototype.getGlobal = function(k) { - return this._read(k); -}; - -// set value for key -Storage.prototype.setGlobal = function(k, v) { - this._write(k, v); -}; - -// remove value for key -Storage.prototype.removeGlobal = function(k) { - localStorage.removeItem(k); -}; - - - -Storage.prototype._key = function(walletId, k) { - return walletId + '::' + k; -}; -// get value by key -Storage.prototype.get = function(walletId, k) { - return this.getGlobal(this._key(walletId, k)); -}; - -// set value for key -Storage.prototype.set = function(walletId, k, v) { - this.setGlobal(this._key(walletId, k), v); -}; - -// remove value for key -Storage.prototype.remove = function(walletId, k) { - this.removeGlobal(this._key(walletId, k)); -}; - -Storage.prototype.setName = function(walletId, name) { - this.setGlobal('nameFor::' + walletId, name); -}; - -Storage.prototype.getName = function(walletId) { - return this.getGlobal('nameFor::' + walletId); -}; - -Storage.prototype.getWalletIds = function() { - var walletIds = []; - var uniq = {}; - for (var i = 0; i < localStorage.length; i++) { - var key = localStorage.key(i); - var split = key.split('::'); - if (split.length == 2) { - var walletId = split[0]; - - if (walletId === 'nameFor') continue; - - if (typeof uniq[walletId] === 'undefined') { - walletIds.push(walletId); - uniq[walletId] = 1; - } - } - } - return walletIds; -}; - -Storage.prototype.getWallets = function() { - var wallets = []; - var uniq = {}; - var ids = this.getWalletIds(); - - for (var i in ids) { - wallets.push({ - id: ids[i], - name: this.getName(ids[i]), - }); - } - return wallets; -}; - -//obj contains keys to be set -Storage.prototype.setFromObj = function(walletId, obj) { - for (var k in obj) { - this.set(walletId, k, obj[k]); - } - this.setName(walletId, obj.opts.name); -}; - -// remove all values -Storage.prototype.clearAll = function() { - localStorage.clear(); -}; - -module.exports = require('soop')(Storage); diff --git a/test/test.storage.LocalEncrypted.js b/test/test.storage.LocalEncrypted.js index 55477bad6..e36d47c26 100644 --- a/test/test.storage.LocalEncrypted.js +++ b/test/test.storage.LocalEncrypted.js @@ -1,80 +1,232 @@ +//Crypto Mock +CryptoJS = {}; +CryptoJS.AES = {}; +CryptoJS.AES.encrypt = function(a) { + return a; +}; + +CryptoJS.enc = { + utf8: '' +}; + +CryptoJS.AES.decrypt = function(a) { + return a; +}; + + + +//localstorage Mock +ls = {}; +localStorage = {}; +localStorage.length = 0; +localStorage.removeItem = function(key) { + delete ls[key]; + this.length = Object.keys(ls).length; +}; + +localStorage.getItem = function(k) { + return ls[k]; +}; + + +localStorage.key = function(i) { + return Object.keys(ls)[i]; +}; + +localStorage.setItem = function(k, v) { + ls[k] = v; + this.key[this.length] = k; + this.length = Object.keys(ls).length; +}; + 'use strict'; +var chai = chai || require('chai'); +var should = chai.should(); +var copay = copay || require('../copay'); +var LocalEncrypted = copay.StorageLocalEncrypted; -if (typeof process === 'undefined' || !process.version) { - // browser - var chai = chai || require('chai'); - var should = chai.should(); - var copay = copay || require('../copay'); - var LocalEncrypted = copay.StorageLocalEncrypted; +var fakeWallet = 'fake-wallet-id'; +var timeStamp = Date.now(); - var fakeWallet = 'fake-wallet-id'; - var timeStamp = Date.now(); - describe('Storage/LocalEncrypted model', function() { - var s = new LocalEncrypted(); - s._setPassphrase('mysupercoolpassword'); - it('should create an instance', function() { - var s = new LocalEncrypted(); - should.exist(s); - }); - it('should fail when encrypting without a password', function() { - var s = new LocalEncrypted(); - (function() { - s.set(fakeWallet, timeStamp, 1); - localStorage.removeItem(fakeWallet + '::' + timeStamp); - }).should.throw(); - }); - it('should be able to encrypt and decrypt', function() { - s._write(fakeWallet + timeStamp, 'value'); - s._read(fakeWallet + timeStamp).should.equal('value'); - localStorage.removeItem(fakeWallet + timeStamp); - }); - it('should be able to set a value', function() { - s.set(fakeWallet, timeStamp, 1); +describe('Storage/LocalEncrypted model', function() { + var s = new LocalEncrypted(); + s._setPassphrase('mysupercoolpassword'); + + it('should create an instance', function() { + var s2 = new LocalEncrypted(); + should.exist(s2); + }); + it('should fail when encrypting without a password', function() { + var s2 = new LocalEncrypted(); + (function() { + s2.set(fakeWallet, timeStamp, 1); + }).should.throw(); + }); + it('should be able to encrypt and decrypt', function() { + s._write(fakeWallet + timeStamp, 'value'); + s._read(fakeWallet + timeStamp).should.equal('value'); + localStorage.removeItem(fakeWallet + timeStamp); + }); + it('should be able to set a value', function() { + s.set(fakeWallet, timeStamp, 1); + localStorage.removeItem(fakeWallet + '::' + timeStamp); + }); + 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() { + s.set(fakeWallet, timeStamp, obj); + var obj2 = s.get(fakeWallet, timeStamp); + JSON.stringify(obj2).should.equal(JSON.stringify(obj)); localStorage.removeItem(fakeWallet + '::' + timeStamp); }); - 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() { - s.set(fakeWallet, timeStamp, obj); - var obj2 = s.get(fakeWallet, timeStamp); - JSON.stringify(obj2).should.equal(JSON.stringify(obj)); - localStorage.removeItem(fakeWallet + '::' + timeStamp); + }); + + describe('#export', function() { + it('should export the encrypted wallet', function() { + var storage = new LocalEncrypted({ + password: 'password' + }); + storage.set(fakeWallet, timeStamp, 'testval'); + var obj = { + test: 'testval' + }; + var encrypted = storage.export(obj); + encrypted.length.should.be.greaterThan(10); + localStorage.removeItem(fakeWallet + '::' + timeStamp); + //encrypted.slice(0,6).should.equal("53616c"); + }); + }); + describe('#_decryptObj', function() { + it('should decrypt and Obj', function() { + var storage = new LocalEncrypted({ + password: 'password' + }); + storage._decryptObj('{"a":"2"}').should.deep.equal({ + a: "2" }); }); + }); - describe('#export', function() { - it('should export the encrypted wallet', function() { - var storage = new LocalEncrypted({ + + describe('#remove', function() { + it('should remove an item', function() { + var s = new LocalEncrypted({ + password: 'password' + }); + s.set('1', "hola", 'juan'); + s.get('1', 'hola').should.equal('juan'); + s.remove('1', 'hola'); + + should.not.exist(s.get('1', 'hola')); + }); + }); + + + describe('#getWalletIds', function() { + it('should get wallet ids', function() { + var s = new LocalEncrypted({ + password: 'password' + }); + s.set('1', "hola", 'juan'); + s.set('2', "hola", 'juan'); + s.getWalletIds().should.deep.equal(['1', '2']); + }); + }); + + describe('#getName #setName', function() { + it('should get/set names', function() { + var s = new LocalEncrypted({ + password: 'password' + }); + s.setName(1, 'hola'); + s.getName(1).should.equal('hola'); + }); + }); + describe('#getWallets', function() { + it('should retreive wallets from storage', function() { + var s = new LocalEncrypted({ password: 'password' }); - storage.set(fakeWallet, timeStamp, 'testval'); - var obj = { - test: 'testval' - }; - var encrypted = storage.export(obj); - encrypted.length.should.be.greaterThan(10); - localStorage.removeItem(fakeWallet + '::' + timeStamp); - //encrypted.slice(0,6).should.equal("53616c"); + s.set('1', "hola", 'juan'); + s.set('2', "hola", 'juan'); + s.setName(1, 'hola'); + s.getWallets()[0].should.deep.equal({ + id: '1', + name: 'hola', + }); + s.getWallets()[1].should.deep.equal({ + id: '2', + name: undefined + }); + }); + }); + describe('#deleteWallet', function() { + it('should delete a wallet', function() { + var s = new LocalEncrypted({ + password: 'password' + }); + s.set('1', "hola", 'juan'); + s.set('2', "hola", 'juan'); + s.setName(1, 'hola'); + + s.deleteWallet('1'); + s.getWallets().length.should.equal(1); + s.getWallets()[0].should.deep.equal({ + id: '2', + name: undefined + }); }); }); + describe('#setFromObj', function() { + it('set localstorage from an object', function() { + var s = new LocalEncrypted({ + password: 'password' + }); + s.setFromObj('id1', { + 'key': 'val', + 'opts': { + 'name': 'nameid1' + }, + }); + + s.get('id1', 'key').should.equal('val'); + + }); + }); + + + describe('#globals', function() { + it('should set, get and remove keys', function() { + var s = new LocalEncrypted({ + password: 'password' + }); + s.setGlobal('a', { + b: 1 + }); + JSON.parse(s.getGlobal('a')).should.deep.equal({ + b: 1 + }); + s.removeGlobal('a'); + should.not.exist(s.getGlobal('a')); + }); + }); }); -} diff --git a/test/test.storage.LocalPlain.js b/test/test.storage.LocalPlain.js deleted file mode 100644 index 30eaa552f..000000000 --- a/test/test.storage.LocalPlain.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; - -if (typeof process === 'undefined' || !process.version) { - // browser - var chai = chai || require('chai'); - var should = chai.should(); - var copay = copay || require('../copay'); - var LocalPlain = copay.StorageLocalPlain; - - describe('Storage/LocalPlain model', function() { - - it('should create an instance', function() { - var s = new LocalPlain(); - should.exist(s); - }); - - describe('#setFromObj', function() { - it('should set keys from an object', function() { - var fakeWallet = 'fake-wallet-id'; - var timeStamp = Date.now(); - - var obj = { - test: 'testval', - opts: { - name: 'testname' - } - }; - var storage = new LocalPlain(); - storage.setFromObj(fakeWallet + timeStamp, obj); - storage.get(fakeWallet + timeStamp, 'test').should.equal('testval'); - - // Clean data used in localstorage - localStorage.removeItem(fakeWallet + timeStamp + '::test'); - localStorage.removeItem(fakeWallet + timeStamp + '::opts'); - localStorage.removeItem('nameFor::' + fakeWallet + timeStamp); - }); - }); - }); -}