From c804083f896cd87ada3910da78aebf9a247722ba Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 14 Aug 2014 17:54:58 -0400 Subject: [PATCH 01/13] rm unused config opts --- config.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/config.js b/config.js index da543f5d9..73fde9550 100644 --- a/config.js +++ b/config.js @@ -39,14 +39,6 @@ var defaultConfig = { maxPeers: 15, debug: 2, - // Network encryption config - sjclParams: { - salt: 'mjuBtGybi/4=', // choose your own salt (base64) - iter: 1000, - mode: 'ccm', - ts: parseInt(64), - }, - // PeerJS internal config object config: { 'iceServers': [ From d8e0d50dcefaaa7884bd0cc15cd8dead7405c6c1 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 14 Aug 2014 18:25:53 -0400 Subject: [PATCH 02/13] add WalletLock class --- copay.js | 1 + js/models/core/WalletLock.js | 47 +++++++++++++++++++++++ test/test.WalletLock.js | 72 ++++++++++++++++++++++++++++++++++++ util/build.js | 34 +++++++++++++++-- 4 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 js/models/core/WalletLock.js create mode 100644 test/test.WalletLock.js diff --git a/copay.js b/copay.js index 87b184170..d9c855cce 100644 --- a/copay.js +++ b/copay.js @@ -15,6 +15,7 @@ var StorageLocalEncrypted = module.exports.StorageLocalEncrypted = require('./js module.exports.WalletFactory = require('./js/models/core/WalletFactory'); module.exports.Wallet = require('./js/models/core/Wallet'); +module.exports.WalletLock = require('./js/models/core/WalletLock'); module.exports.version = require('./version'); // test hack :s, will fix diff --git a/js/models/core/WalletLock.js b/js/models/core/WalletLock.js new file mode 100644 index 000000000..7bdf7d7b5 --- /dev/null +++ b/js/models/core/WalletLock.js @@ -0,0 +1,47 @@ +'use strict'; + +var preconditions = require('preconditions').singleton(); + +function WalletLock(storage, walletId, timeoutMin) { + preconditions.checkArgument(storage); + preconditions.checkArgument(walletId); + + this.sessionId = storage.getSessionId(); + this.storage = storage; + this.timeoutMin = timeoutMin || 5; + this.key = WalletLock._keyFor(walletId); + this.keepAlive(); +} +WalletLock._keyFor = function(walletId) { + return 'lock' + '::' + walletId; +}; + +WalletLock.prototype._isLockedByOther = function() { + var wl = this.storage.getGlobal(this.key); + + if (!wl || wl.expireTs < Date.now() || wl.sessionId === this.sessionId) + return false; + + return true; +}; + + +WalletLock.prototype.keepAlive = function() { + preconditions.checkState(this.sessionId); + + if (this._isLockedByOther()) + throw new Error('Could not adquire lock'); + + this.storage.setGlobal(this.key, { + sessionId: this.sessionId, + expireTs: Date.now() + this.timeoutMin * 60 * 1000, + }); +}; + + +WalletLock.prototype.release = function() { + this.storage.removeGlobal(this.key); +}; + + +module.exports = WalletLock; diff --git a/test/test.WalletLock.js b/test/test.WalletLock.js new file mode 100644 index 000000000..6882086da --- /dev/null +++ b/test/test.WalletLock.js @@ -0,0 +1,72 @@ +'use strict'; + +var chai = chai || require('chai'); +var should = chai.should(); +var sinon = require('sinon'); +var is_browser = (typeof process == 'undefined' || typeof process.versions === 'undefined'); +if (is_browser) { + var copay = require('copay'); //browser +} else { + var copay = require('../copay'); //node +} +var copayConfig = require('../config'); +var WalletLock = copay.WalletLock; + +var PrivateKey = copay.PrivateKey; +var Storage = require('./mocks/FakeStorage'); + +describe('WalletLock model', function() { + var storage = new Storage(); + + it('should fail with missing args', function() { + (function() { + new WalletLock() + }).should.throw('Argument'); + }); + + + it('should fail with missing args (case 2)', function() { + (function() { + new WalletLock(storage) + }).should.throw('Argument'); + }); + + it('should create an instance', function() { + var w = new WalletLock(storage, 'id'); + should.exist(w); + }); + + it('should fail if locked already', function() { + var w = new WalletLock(storage, 'walletId'); + storage.sessionId = 'xxx'; + (function() { + new WalletLock(storage, 'walletId') + }).should.throw('adquire lock'); + }); + + it('should not fail if locked by me', function() { + var s = new Storage(); + var w = new WalletLock(s, 'walletId'); + var w2 = new WalletLock(s, 'walletId') + should.exist(w2); + }); + + it('should not fail if locked by me', function() { + var s = new Storage(); + var w = new WalletLock(s, 'walletId'); + var w2 = new WalletLock(s, 'walletId') + should.exist(w2); + }); + it('should not fail if expired', function() { + var s = new Storage(); + var w = new WalletLock(s, 'walletId'); + s.storage[Object.keys(s.storage)[0]].expireTs = Date.now() - 60 * 6 * 1000; + + s.sessionId = 'xxx'; + var w2 = new WalletLock(s, 'walletId') + should.exist(w2); + }); + + + +}); diff --git a/util/build.js b/util/build.js index 965e01b46..a42a12643 100644 --- a/util/build.js +++ b/util/build.js @@ -38,12 +38,40 @@ var createBundle = function(opts) { expose: '../js/models/core/WalletFactory' }); b.require('./js/models/core/Wallet'); - b.require('./js/models/core/Wallet', { - expose: '../js/models/core/Wallet' - }); b.require('./js/models/core/Wallet', { expose: '../../js/models/core/Wallet' }); +<<<<<<< HEAD +======= + b.require('./js/models/core/WalletLock', { + expose: '../js/models/core/WalletLock' + }); + + b.require('./test/mocks/FakeStorage', { + expose: './mocks/FakeStorage' + }); + b.require('./test/mocks/FakeLocalStorage', { + expose: './mocks/FakeLocalStorage' + }); + b.require('./js/models/core/Message', { + expose: '../js/models/core/Message' + }); + b.require('./test/mocks/FakeBlockchain', { + expose: './mocks/FakeBlockchain' + }); + b.require('./test/mocks/FakeNetwork', { + expose: './mocks/FakeNetwork' + }); + b.require('./test/mocks/FakePayProServer', { + expose: './mocks/FakePayProServer' + }); + b.require('./test/mocks/FakePayProServer', { + expose: '../../mocks/FakePayProServer' + }); + b.require('./test/mocks/FakeBuilder', { + expose: './mocks/FakeBuilder' + }); +>>>>>>> add WalletLock class b.require('./js/models/network/WebRTC', { expose: '../js/models/network/WebRTC' }); From bcb61810d5c19cce45155ffa1987b7684dcf94d9 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 14 Aug 2014 18:46:42 -0400 Subject: [PATCH 03/13] WIP: better lock --- js/controllers/open.js | 77 ++++++++--------- js/models/core/Wallet.js | 125 +++++++++++++--------------- js/models/core/WalletFactory.js | 15 ++-- js/models/storage/LocalEncrypted.js | 17 +++- js/routes.js | 4 +- test/mocks/FakeStorage.js | 5 ++ test/test.Wallet.js | 15 ---- 7 files changed, 120 insertions(+), 138 deletions(-) diff --git a/js/controllers/open.js b/js/controllers/open.js index 9af583833..8f126dcb7 100644 --- a/js/controllers/open.js +++ b/js/controllers/open.js @@ -1,47 +1,44 @@ 'use strict'; -angular.module('copayApp.controllers').controller('OpenController', - function($scope, $rootScope, $location, walletFactory, controllerUtils, Passphrase, notification) { - controllerUtils.redirIfLogged(); +angular.module('copayApp.controllers').controller('OpenController', function($scope, $rootScope, $location, walletFactory, controllerUtils, Passphrase, notification) { + controllerUtils.redirIfLogged(); - var cmp = function(o1, o2) { - var v1 = o1.show.toLowerCase(), - v2 = o2.show.toLowerCase(); - return v1 > v2 ? 1 : (v1 < v2) ? -1 : 0; - }; - $rootScope.fromSetup = false; - $scope.loading = false; - $scope.wallets = walletFactory.getWallets().sort(cmp); - $scope.selectedWalletId = walletFactory.storage.getLastOpened() || ($scope.wallets[0] && $scope.wallets[0].id); - $scope.openPassword = ''; - $scope.isMobile = !!window.cordova; + var cmp = function(o1, o2) { + var v1 = o1.show.toLowerCase(), + v2 = o2.show.toLowerCase(); + return v1 > v2 ? 1 : (v1 < v2) ? -1 : 0; + }; + $rootScope.fromSetup = false; + $scope.loading = false; + $scope.wallets = walletFactory.getWallets().sort(cmp); + $scope.selectedWalletId = walletFactory.storage.getLastOpened() || ($scope.wallets[0] && $scope.wallets[0].id); + $scope.openPassword = ''; + $scope.isMobile = !!window.cordova; - $scope.open = function(form) { - if (form && form.$invalid) { - notification.error('Error', 'Please enter the required fields'); + $scope.open = function(form) { + if (form && form.$invalid) { + notification.error('Error', 'Please enter the required fields'); + return; + } + + $scope.loading = true; + var password = form.openPassword.$modelValue; + + Passphrase.getBase64Async(password, function(passphrase) { + var w, errMsg; + try { + w = walletFactory.open($scope.selectedWalletId, passphrase); + } catch (e) { + errMsg = e.message; + }; + if (!w) { + $scope.loading = false; + notification.error('Error', errMsg || 'Wrong password'); + $rootScope.$digest(); return; } + controllerUtils.startNetwork(w, $scope); + }); + }; - $scope.loading = true; - var password = form.openPassword.$modelValue; - - Passphrase.getBase64Async(password, function(passphrase) { - var w, errMsg; - try { - w = walletFactory.open($scope.selectedWalletId, { - passphrase: passphrase - }); - } catch (e) { - errMsg = e.message; - }; - if (!w) { - $scope.loading = false; - notification.error('Error', errMsg || 'Wrong password'); - $rootScope.$digest(); - return; - } - controllerUtils.startNetwork(w, $scope); - }); - }; - - }); +}); diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 2a4fa7542..daac04995 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -2,10 +2,10 @@ var http = require('http'); var EventEmitter = require('events').EventEmitter; -var nodeUtil = require('util'); var async = require('async'); var preconditions = require('preconditions').singleton(); var parseBitcoinURI = require('./HDPath').parseBitcoinURI; +var util = require('util'); var bitcore = require('bitcore'); var bignum = bitcore.Bignum; @@ -23,6 +23,7 @@ var PublicKeyRing = require('./PublicKeyRing'); var TxProposal = require('./TxProposal'); var TxProposals = require('./TxProposals'); var PrivateKey = require('./PrivateKey'); +var WalletLock = require('./WalletLock'); var copayConfig = require('../../../config'); function Wallet(opts) { @@ -45,9 +46,11 @@ function Wallet(opts) { this.log('creating ' + opts.requiredCopayers + ' of ' + opts.totalCopayers + ' wallet'); this.id = opts.id || Wallet.getRandomId(); + this.lock = new WalletLock(this.storage, this.id, opts.lockTimeOutMin); + + this.name = opts.name; - this.ignoreLock = opts.ignoreLock; this.verbose = opts.verbose; this.publicKeyRing.walletId = this.id; this.txProposals.walletId = this.id; @@ -64,7 +67,7 @@ function Wallet(opts) { this.network.setHexNonces(opts.networkNonces); } -nodeUtil.inherits(Wallet, EventEmitter); +util.inherits(Wallet, EventEmitter); Wallet.builderOpts = { lockTime: null, @@ -98,27 +101,6 @@ Wallet.prototype.connectToAll = function() { } }; -Wallet.prototype.getLock = function() { - return this.storage.getLock(this.id); -}; - -Wallet.prototype.setLock = function() { - return this.storage.setLock(this.id); -}; - -Wallet.prototype.unlock = function() { - this.storage.removeLock(this.id); -}; - -Wallet.prototype.checkAndLock = function() { - if (this.getLock()) { - return true; - } - - this.setLock(); - return false; -}; - Wallet.prototype._handleIndexes = function(senderId, data, isInbound) { this.log('RECV INDEXES:', data); var inIndexes = HDParams.fromList(data.indexes); @@ -438,11 +420,6 @@ Wallet.prototype.netStart = function(callback) { var self = this; var net = this.network; - if (this.checkAndLock() && !this.ignoreLock) { - this.emit('locked'); - return; - } - net.removeAllListeners(); net.on('connect', self._handleConnect.bind(self)); net.on('disconnect', self._handleDisconnect.bind(self)); @@ -519,7 +496,13 @@ Wallet.prototype.getRegisteredPeerIds = function() { return this.registeredPeerIds; }; +Wallet.prototype.keepAlive = function() { + this.lock.keepAlive(); +}; + Wallet.prototype.store = function() { + this.keepAlive(); + var wallet = this.toObj(); this.storage.setFromObj(this.id, wallet); this.log('Wallet stored'); @@ -556,8 +539,8 @@ Wallet.fromObj = function(o, storage, network, blockchain) { opts.storage = storage; opts.network = network; opts.blockchain = blockchain; - var w = new Wallet(opts); - return w; + + return new Wallet(opts); }; Wallet.prototype.toEncryptedObj = function() { @@ -709,7 +692,7 @@ Wallet.prototype.sign = function(ntxid, cb) { var self = this; setTimeout(function() { var myId = self.getMyCopayerId(); - var txp = self.txProposals.get(ntxid); + var txp = self.txProposals.get(ntxid); // if (!txp || txp.rejectedBy[myId] || txp.signedBy[myId]) { // if (cb) cb(false); // } @@ -782,7 +765,9 @@ Wallet.prototype.createPaymentTx = function(options, cb) { var self = this; if (typeof options === 'string') { - options = { uri: options }; + options = { + uri: options + }; } options.uri = options.uri || options.url; @@ -824,7 +809,9 @@ Wallet.prototype.fetchPaymentTx = function(options, cb) { options = options || {}; if (typeof options === 'string') { - options = { uri: options }; + options = { + uri: options + }; } options.uri = options.uri || options.url; options.fetch = true; @@ -980,8 +967,7 @@ Wallet.prototype.sendPaymentTx = function(ntxid, options, cb) { var refund_outputs = []; - options.refund_to = options.refund_to - || this.publicKeyRing.getPubKeys(0, false, this.getMyCopayerId())[0]; + options.refund_to = options.refund_to || this.publicKeyRing.getPubKeys(0, false, this.getMyCopayerId())[0]; if (options.refund_to) { var total = txp.merchant.pr.pd.outputs.reduce(function(total, _, i) { @@ -1003,23 +989,23 @@ Wallet.prototype.sendPaymentTx = function(ntxid, options, cb) { rpo.set('amount', +total.toString(10)); rpo.set('script', - Buffer.concat([ - new Buffer([ - 118, // OP_DUP - 169, // OP_HASH160 - 76, // OP_PUSHDATA1 - 20, // number of bytes - ]), - // needs to be ripesha'd - bitcore.util.sha256ripe160(options.refund_to), - new Buffer([ - 136, // OP_EQUALVERIFY - 172 // OP_CHECKSIG - ]) - ]) - ); + Buffer.concat([ + new Buffer([ + 118, // OP_DUP + 169, // OP_HASH160 + 76, // OP_PUSHDATA1 + 20, // number of bytes + ]), + // needs to be ripesha'd + bitcore.util.sha256ripe160(options.refund_to), + new Buffer([ + 136, // OP_EQUALVERIFY + 172 // OP_CHECKSIG + ]) + ]) + ); - refund_outputs.push(rpo.message); + refund_outputs.push(rpo.message); } // We send this to the serve after receiving a PaymentRequest @@ -1031,8 +1017,7 @@ Wallet.prototype.sendPaymentTx = function(ntxid, options, cb) { pay.set('transactions', [tx.serialize()]); pay.set('refund_to', refund_outputs); - options.memo = options.memo || options.comment - || 'Hi server, I would like to give you some money.'; + options.memo = options.memo || options.comment || 'Hi server, I would like to give you some money.'; pay.set('memo', options.memo); @@ -1188,8 +1173,8 @@ Wallet.prototype.createPaymentTxSync = function(options, merchantData, unspent) merchantData.total = merchantData.total.toString(10); var b = new Builder(opts) - .setUnspent(unspent) - .setOutputs(outs); + .setUnspent(unspent) + .setOutputs(outs); merchantData.pr.pd.outputs.forEach(function(output, i) { var script = { @@ -1250,9 +1235,7 @@ Wallet.prototype.createPaymentTxSync = function(options, merchantData, unspent) Wallet.prototype.verifyPaymentRequest = function(ntxid) { if (!ntxid) return false; - var txp = typeof ntxid !== 'object' - ? this.txProposals.get(ntxid) - : ntxid; + var txp = typeof ntxid !== 'object' ? this.txProposals.get(ntxid) : ntxid; // If we're not a payment protocol proposal, ignore. if (!txp.merchant) return true; @@ -1358,8 +1341,7 @@ Wallet.prototype.verifyPaymentRequest = function(ntxid) { } // Make sure the tx's output script and values match the payment request's. - if (av.toString('hex') !== ev.toString('hex') - || as.toString('hex') !== es.toString('hex')) { + if (av.toString('hex') !== ev.toString('hex') || as.toString('hex') !== es.toString('hex')) { // Verifiable outputs do not match outputs of merchant // data. We should not sign this transaction proposal! return false; @@ -1384,10 +1366,9 @@ Wallet.prototype.verifyPaymentRequest = function(ntxid) { // Actual script var as = new Buffer(ro.script.buffer, 'hex') - .slice(ro.script.offset, ro.script.limit); + .slice(ro.script.offset, ro.script.limit); - if (av.toString('hex') !== ev.toString('hex') - || as.toString('hex') !== es.toString('hex')) { + if (av.toString('hex') !== ev.toString('hex') || as.toString('hex') !== es.toString('hex')) { return false; } } @@ -1506,14 +1487,19 @@ Wallet.prototype.createTx = function(toAddress, amountSatStr, comment, opts, cb) if (typeof amountSatStr === 'function') { var cb = amountSatStr; var merchant = toAddress; - return this.createPaymentTx({ uri: merchant }, cb); + return this.createPaymentTx({ + uri: merchant + }, cb); } if (typeof comment === 'function') { var cb = comment; var merchant = toAddress; var comment = amountSatStr; - return this.createPaymentTx({ uri: merchant, memo: comment }, cb); + return this.createPaymentTx({ + uri: merchant, + memo: comment + }, cb); } if (typeof opts === 'function') { @@ -1779,7 +1765,9 @@ Wallet.prototype.verifySignedJson = function(senderId, payload, signature) { Wallet.request = function(options, callback) { if (typeof options === 'string') { - options = { uri: options }; + options = { + uri: options + }; } options.method = options.method || 'GET'; @@ -1794,8 +1782,7 @@ Wallet.request = function(options, callback) { this._error = cb; return this; }, - _success: function() { - ; + _success: function() {; }, _error: function(_, err) { throw err; diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index f40a02e4d..8d7ef29a4 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -108,6 +108,7 @@ WalletFactory.prototype.create = function(opts) { var requiredCopayers = opts.requiredCopayers || this.walletDefaults.requiredCopayers; var totalCopayers = opts.totalCopayers || this.walletDefaults.totalCopayers; + opts.lockTimeoutMin = this.walletDefaults.idleDurationMin; opts.publicKeyRing = opts.publicKeyRing || new PublicKeyRing({ networkName: this.networkName, @@ -137,6 +138,7 @@ WalletFactory.prototype.create = function(opts) { opts.requiredCopayers = requiredCopayers; opts.totalCopayers = totalCopayers; opts.version = opts.version || this.version; + var w = new Wallet(opts); w.store(); this.storage.setLastOpened(w.id); @@ -166,16 +168,11 @@ WalletFactory.prototype._checkNetwork = function(inNetworkName) { } }; -WalletFactory.prototype.open = function(walletId, opts) { - opts = opts || {}; - opts.id = walletId; - opts.verbose = this.verbose; - this.storage._setPassphrase(opts.passphrase); - - var w = this.read(walletId); - if (w) { +WalletFactory.prototype.open = function(walletId, passphrase) { + this.storage._setPassphrase(passphrase); + var w = this.read(walletId, opts); + if (w) w.store(); - } this.storage.setLastOpened(walletId); return w; diff --git a/js/models/storage/LocalEncrypted.js b/js/models/storage/LocalEncrypted.js index da1d99742..acfcf696f 100644 --- a/js/models/storage/LocalEncrypted.js +++ b/js/models/storage/LocalEncrypted.js @@ -1,7 +1,7 @@ 'use strict'; var CryptoJS = require('node-cryptojs-aes').CryptoJS; - +var bitcore = require('bitcore'); var id = 0; function Storage(opts) { @@ -93,6 +93,15 @@ Storage.prototype.removeGlobal = function(k) { this.localStorage.removeItem(k); }; +Storage.prototype.getSessionId = function() { + var sessionId = this.sessionStorage.getItem('sessionId'); + if (!sessionId) { + sessionId = bitcore.getRandomBuffer(8).toString('hex'); + this.sessionStorage.setItem(sessionId, 'sessionId'); + } + return sessionId; +}; + Storage.prototype._key = function(walletId, k) { return walletId + '::' + k; }; @@ -132,7 +141,8 @@ Storage.prototype.getWalletIds = function() { if (split.length == 2) { var walletId = split[0]; - if (walletId === 'nameFor') continue; + if (walletId === 'nameFor' || walletId === 'lock') + continue; if (typeof uniq[walletId] === 'undefined') { walletIds.push(walletId); @@ -180,8 +190,9 @@ Storage.prototype.getLastOpened = function() { return this.getGlobal('lastOpened'); } +// Lock related Storage.prototype.setLock = function(walletId) { - this.setGlobal(this._key(walletId, 'Lock'), true); + this.setGlobal(this._key(walletId, 'Lock'), this.sessionId()); } Storage.prototype.getLock = function(walletId) { diff --git a/js/routes.js b/js/routes.js index f0d95f93f..152068985 100644 --- a/js/routes.js +++ b/js/routes.js @@ -74,8 +74,8 @@ angular .html5Mode(false) .hashPrefix('!'); // IDLE timeout - $idleProvider.idleDuration(15 * 60); // in seconds - $idleProvider.warningDuration(10); // in seconds + $idleProvider.idleDuration(config.wallet.idleDurationMin * 60); // in seconds + $idleProvider.warningDuration(20); // in seconds }) .run(function($rootScope, $location, $idle) { $idle.watch(); diff --git a/test/mocks/FakeStorage.js b/test/mocks/FakeStorage.js index 56b88c2f4..c83855306 100644 --- a/test/mocks/FakeStorage.js +++ b/test/mocks/FakeStorage.js @@ -35,6 +35,11 @@ FakeStorage.prototype.getLock = function(id) { return this.storage[id + '::lock']; } +FakeStorage.prototype.getSessionId = function() { + return this.sessionId || 'aSessionId'; +}; + + FakeStorage.prototype.removeLock = function(id) { delete this.storage[id + '::lock']; } diff --git a/test/test.Wallet.js b/test/test.Wallet.js index 75a2d9988..da692b12b 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -182,7 +182,6 @@ describe('Wallet model', function() { cachedW2obj.opts.reconnectDelay = 100; } var w = Wallet.fromObj(cachedW2obj, cachedW2.storage, cachedW2.network, cachedW2.blockchain); - w.unlock(); return w; }; @@ -1025,20 +1024,6 @@ describe('Wallet model', function() { w.network.start.getCall(0).args[0].privkey.length.should.equal(64); }); - it('should check if wallet is already opened', function() { - var w = cachedCreateW2(); - should.not.exist(w.getLock()); - w.checkAndLock().should.equal(false); - w.getLock().should.equal(true); - }); - it('should check if wallet is already opened', function() { - var w = cachedCreateW2(); - should.not.exist(w.getLock()); - w.checkAndLock().should.equal(false); - w.getLock().should.equal(true); - }); - - it('should not start if locked', function() { var w = cachedCreateW2(); w.netStart(); From eb9acb958f8733232d66b3e42436a5165690d0ed Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 15 Aug 2014 09:57:47 -0400 Subject: [PATCH 04/13] mocha test passing on console --- js/models/core/Wallet.js | 2 +- js/models/core/WalletFactory.js | 2 +- js/models/storage/LocalEncrypted.js | 15 +- test/mocks/FakeStorage.js | 6 +- test/test.LocalEncrypted.js | 400 +++++++++++++++------------- test/test.Wallet.js | 16 -- test/test.WalletFactory.js | 1 + 7 files changed, 218 insertions(+), 224 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index daac04995..5d6948fdf 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -1670,7 +1670,7 @@ Wallet.prototype.indexDiscovery = function(start, change, cosigner, gap, cb) { Wallet.prototype.disconnect = function() { this.log('## DISCONNECTING'); - this.unlock(); + this.lock.release(); this.network.disconnect(); }; diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index 8d7ef29a4..db1d597ba 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -170,7 +170,7 @@ WalletFactory.prototype._checkNetwork = function(inNetworkName) { WalletFactory.prototype.open = function(walletId, passphrase) { this.storage._setPassphrase(passphrase); - var w = this.read(walletId, opts); + var w = this.read(walletId); if (w) w.store(); diff --git a/js/models/storage/LocalEncrypted.js b/js/models/storage/LocalEncrypted.js index acfcf696f..ac084a948 100644 --- a/js/models/storage/LocalEncrypted.js +++ b/js/models/storage/LocalEncrypted.js @@ -141,7 +141,7 @@ Storage.prototype.getWalletIds = function() { if (split.length == 2) { var walletId = split[0]; - if (walletId === 'nameFor' || walletId === 'lock') + if (!walletId || walletId === 'nameFor') continue; if (typeof uniq[walletId] === 'undefined') { @@ -190,19 +190,6 @@ Storage.prototype.getLastOpened = function() { return this.getGlobal('lastOpened'); } -// Lock related -Storage.prototype.setLock = function(walletId) { - this.setGlobal(this._key(walletId, 'Lock'), this.sessionId()); -} - -Storage.prototype.getLock = function(walletId) { - return this.getGlobal(this._key(walletId, 'Lock')); -} - -Storage.prototype.removeLock = function(walletId) { - this.removeGlobal(this._key(walletId, 'Lock')); -} - //obj contains keys to be set Storage.prototype.setFromObj = function(walletId, obj) { for (var k in obj) { diff --git a/test/mocks/FakeStorage.js b/test/mocks/FakeStorage.js index c83855306..81a0dcbae 100644 --- a/test/mocks/FakeStorage.js +++ b/test/mocks/FakeStorage.js @@ -69,7 +69,11 @@ FakeStorage.prototype.getWalletIds = function() { var split = ii.split('::'); if (split.length == 2) { var walletId = split[0]; - if (walletId !== 'nameFor' && typeof uniq[walletId] === 'undefined') { + + if (!walletId || walletId === 'nameFor' || walletId ==='lock') + continue; + + if (typeof uniq[walletId] === 'undefined') { walletIds.push(walletId); uniq[walletId] = 1; } diff --git a/test/test.LocalEncrypted.js b/test/test.LocalEncrypted.js index 5fcd6068c..f5c96ba98 100644 --- a/test/test.LocalEncrypted.js +++ b/test/test.LocalEncrypted.js @@ -1,14 +1,17 @@ 'use strict'; -var copay = copay || require('../copay'); var chai = chai || require('chai'); var should = chai.should(); -var LocalEncrypted = copay.StorageLocalEncrypted; - - var fakeWallet = 'fake-wallet-id'; var timeStamp = Date.now(); var localMock = require('./mocks/FakeLocalStorage'); +var is_browser = typeof process == 'undefined' || typeof process.versions === 'undefined'; +if (is_browser) { + var copay = require('copay'); //browser +} else { + var copay = require('../copay'); //node +} +var LocalEncrypted = copay.StorageLocalEncrypted; describe('Storage/LocalEncrypted model', function() { var s = new LocalEncrypted({ @@ -22,199 +25,214 @@ describe('Storage/LocalEncrypted model', function() { }); should.exist(s2); }); - it('should fail when encrypting without a password', function() { - var s2 = new LocalEncrypted({ - localStorage: localMock, - }); - (function() { - s2.set(fakeWallet, timeStamp, 1); - }).should.throw(); +}); + +it('should fail when encrypting without a password', function() { + var s2 = new LocalEncrypted({ + localStorage: localMock, }); - it('should be able to encrypt and decrypt', function() { - s._write(fakeWallet + timeStamp, 'value'); - s._read(fakeWallet + timeStamp).should.equal('value'); - localMock.removeItem(fakeWallet + timeStamp); - }); - it('should be able to set a value', function() { - s.set(fakeWallet, timeStamp, 1); + (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'); + localMock.removeItem(fakeWallet + timeStamp); +}); +it('should be able to set a value', function() { + s.set(fakeWallet, timeStamp, 1); + localMock.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)); localMock.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)); - localMock.removeItem(fakeWallet + '::' + timeStamp); +}); + +describe('#export', function() { + it('should export the encrypted wallet', function() { + var storage = new LocalEncrypted({ + localStorage: localMock, + password: 'password', }); + storage.set(fakeWallet, timeStamp, 'testval'); + var obj = { + test: 'testval' + }; + var encrypted = storage.export(obj); + encrypted.length.should.be.greaterThan(10); + localMock.removeItem(fakeWallet + '::' + timeStamp); + //encrypted.slice(0,6).should.equal("53616c"); }); - - describe('#export', function() { - it('should export the encrypted wallet', function() { - var storage = new LocalEncrypted({ - localStorage: localMock, - password: 'password', - }); - storage.set(fakeWallet, timeStamp, 'testval'); - var obj = { - test: 'testval' - }; - var encrypted = storage.export(obj); - encrypted.length.should.be.greaterThan(10); - localMock.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', + localStorage: localMock, }); - }); - - describe('#remove', function() { - it('should remove an item', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - 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({ - localStorage: localMock, - 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({ - localStorage: localMock, - password: 'password' - }); - s.setName(1, 'hola'); - s.getName(1).should.equal('hola'); - }); - }); - - describe('#getLastOpened #setLastOpened', function() { - it('should get/set names', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - password: 'password' - }); - s.setLastOpened('hey'); - s.getLastOpened().should.equal('hey'); - }); - }); - - describe('#WalletLock', function() { - it('should get/set/remove opened', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - password: 'password' - }); - s.setLock('walletId'); - s.getLock('walletId').should.equal(true); - s.removeLock('walletId'); - should.not.exist(s.getLock('walletId')); - }); - }); - - describe('#getWallets', function() { - it('should retreive wallets from storage', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - password: 'password' - }); - 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({ - localStorage: localMock, - 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({ - localStorage: localMock, - 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({ - localStorage: localMock, - 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')); + storage._decryptObj('{"a":"2"}').should.deep.equal({ + a: "2" }); }); }); + + +describe('#remove', function() { + it('should remove an item', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + 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({ + localStorage: localMock, + 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({ + localStorage: localMock, + password: 'password' + }); + s.setName(1, 'hola'); + s.getName(1).should.equal('hola'); + }); +}); + +describe('#getLastOpened #setLastOpened', function() { + it('should get/set names', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + password: 'password' + }); + s.setLastOpened('hey'); + s.getLastOpened().should.equal('hey'); + }); +}); + +if (is_browser) { + describe('#getSessionId', function() { + it('should get SessionId', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + password: 'password' + }); + var sid = s.getSessionId(); + should.exist(sid); + var sid2 = s.getSessionId(); + sid2.should.equal(sid); + }); + }); +} + +describe('#getWallets', function() { + it('should retreive wallets from storage', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + password: 'password' + }); + 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({ + localStorage: localMock, + 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({ + localStorage: localMock, + 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({ + localStorage: localMock, + 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.Wallet.js b/test/test.Wallet.js index da692b12b..52cb41297 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -1024,22 +1024,6 @@ describe('Wallet model', function() { w.network.start.getCall(0).args[0].privkey.length.should.equal(64); }); - it('should not start if locked', function() { - var w = cachedCreateW2(); - w.netStart(); - w.emit = sinon.spy(); - w.netStart(); - w.emit.getCall(0).args[0].should.equal('locked'); - }); - - it('should accept ignoreLocked', function() { - var w = cachedCreateW2(); - w.netStart(); - w.network.start = sinon.spy(); - w.ignoreLock=1; - w.netStart(); - w.network.start.getCall(0).args[0].privkey.length.should.equal(64); - }); }); describe('#forceNetwork in config', function() { diff --git a/test/test.WalletFactory.js b/test/test.WalletFactory.js index d390c2641..0c501d7e4 100644 --- a/test/test.WalletFactory.js +++ b/test/test.WalletFactory.js @@ -298,6 +298,7 @@ describe('WalletFactory model', function() { var w = wf.create({ name: 'test wallet' }); + ws = wf.getWallets(); ws.length.should.equal(1); ws[0].name.should.equal('test wallet'); From 54bc98f0bdabc731f58dffd0c0c8acfb59fcd805 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 15 Aug 2014 10:26:31 -0400 Subject: [PATCH 05/13] add sessionStorage param --- js/models/core/WalletFactory.js | 1 + js/models/storage/LocalEncrypted.js | 16 +- test/test.storage.LocalEncrypted.js | 272 ++++++++++++++++++++++++++++ 3 files changed, 283 insertions(+), 6 deletions(-) create mode 100644 test/test.storage.LocalEncrypted.js diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index db1d597ba..3173fcc31 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -168,6 +168,7 @@ WalletFactory.prototype._checkNetwork = function(inNetworkName) { } }; + WalletFactory.prototype.open = function(walletId, passphrase) { this.storage._setPassphrase(passphrase); var w = this.read(walletId); diff --git a/js/models/storage/LocalEncrypted.js b/js/models/storage/LocalEncrypted.js index ac084a948..8c00452d2 100644 --- a/js/models/storage/LocalEncrypted.js +++ b/js/models/storage/LocalEncrypted.js @@ -11,11 +11,15 @@ function Storage(opts) { if (opts.password) this._setPassphrase(opts.password); - if (opts.localStorage) { - this.localStorage = opts.localStorage; - } else if (localStorage) { - this.localStorage = localStorage; - } + try{ + this.localStorage = opts.localStorage || localStorage; + this.sessionStorage = opts.sessionStorage || sessionStorage; + } catch (e) {}; + + if (!this.localStorage) + throw new Error('no localStorage'); + if (!this.sessionStorage) + throw new Error('no sessionStorage'); } var pps = {}; @@ -141,7 +145,7 @@ Storage.prototype.getWalletIds = function() { if (split.length == 2) { var walletId = split[0]; - if (!walletId || walletId === 'nameFor') + if (!walletId || walletId === 'nameFor' || walletId ==='lock') continue; if (typeof uniq[walletId] === 'undefined') { diff --git a/test/test.storage.LocalEncrypted.js b/test/test.storage.LocalEncrypted.js new file mode 100644 index 000000000..35c0066ad --- /dev/null +++ b/test/test.storage.LocalEncrypted.js @@ -0,0 +1,272 @@ +//Crypto Mock +CryptoJS = {}; +CryptoJS.AES = {}; +CryptoJS.AES.encrypt = function(a) { + return a; +}; + +CryptoJS.enc = { + utf8: '' +}; + +CryptoJS.AES.decrypt = function(a) { + return a; +}; + + + + +'use strict'; +var chai = chai || require('chai'); +var should = chai.should(); +var is_browser = typeof process == 'undefined' + || typeof process.versions === 'undefined'; + if (is_browser) { + var copay = require('copay'); //browser + } else { + var copay = require('../copay'); //node + } + var LocalEncrypted = copay.StorageLocalEncrypted; + + var fakeWallet = 'fake-wallet-id'; + var timeStamp = Date.now(); + var localMock = require('./mocks/FakeLocalStorage'); + var sessionMock = require('./mocks/FakeLocalStorage'); + + + describe('Storage/LocalEncrypted model', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + }); + s._setPassphrase('mysupercoolpassword'); + + it('should create an instance', function() { + var s2 = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + }); + should.exist(s2); + }); + it('should fail when encrypting without a password', function() { + var s2 = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + }); + (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'); + localMock.removeItem(fakeWallet + timeStamp); + }); + it('should be able to set a value', function() { + s.set(fakeWallet, timeStamp, 1); + localMock.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)); + localMock.removeItem(fakeWallet + '::' + timeStamp); + }); + }); + + describe('#export', function() { + it('should export the encrypted wallet', function() { + var storage = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password', + }); + storage.set(fakeWallet, timeStamp, 'testval'); + var obj = { + test: 'testval' + }; + var encrypted = storage.export(obj); + encrypted.length.should.be.greaterThan(10); + localMock.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', + localStorage: localMock, + sessionStorage: sessionMock, + }); + storage._decryptObj('{"a":"2"}').should.deep.equal({ + a: "2" + }); + }); + }); + + + describe('#remove', function() { + it('should remove an item', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + 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({ + localStorage: localMock, + sessionStorage: sessionMock, + 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({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + s.setName(1, 'hola'); + s.getName(1).should.equal('hola'); + }); + }); + + describe('#getLastOpened #setLastOpened', function() { + it('should get/set names', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + s.setLastOpened('hey'); + s.getLastOpened().should.equal('hey'); + }); + }); + + if (is_browser) { + describe('#getSessionId', function() { + it('should get SessionId', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + var sid = s.getSessionId(); + should.exist(sid); + var sid2 = s.getSessionId(); + sid2.should.equal(sid); + }); + }); + } + + describe('#getWallets', function() { + it('should retreive wallets from storage', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + 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({ + localStorage: localMock, + sessionStorage: sessionMock, + 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({ + localStorage: localMock, + sessionStorage: sessionMock, + 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({ + localStorage: localMock, + sessionStorage: sessionMock, + 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')); + }); + }); + }); From 5753f406e045c1f4aff25f503540bf50415eb6c2 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 15 Aug 2014 10:35:25 -0400 Subject: [PATCH 06/13] add tests to getSEssionId --- js/models/storage/LocalEncrypted.js | 2 +- test/test.storage.LocalEncrypted.js | 484 ++++++++++++++-------------- 2 files changed, 249 insertions(+), 237 deletions(-) diff --git a/js/models/storage/LocalEncrypted.js b/js/models/storage/LocalEncrypted.js index 8c00452d2..60fb419c7 100644 --- a/js/models/storage/LocalEncrypted.js +++ b/js/models/storage/LocalEncrypted.js @@ -100,7 +100,7 @@ Storage.prototype.removeGlobal = function(k) { Storage.prototype.getSessionId = function() { var sessionId = this.sessionStorage.getItem('sessionId'); if (!sessionId) { - sessionId = bitcore.getRandomBuffer(8).toString('hex'); + sessionId = bitcore.SecureRandom.getRandomBuffer(8).toString('hex'); this.sessionStorage.setItem(sessionId, 'sessionId'); } return sessionId; diff --git a/test/test.storage.LocalEncrypted.js b/test/test.storage.LocalEncrypted.js index 35c0066ad..3d4e4d3e0 100644 --- a/test/test.storage.LocalEncrypted.js +++ b/test/test.storage.LocalEncrypted.js @@ -19,254 +19,266 @@ CryptoJS.AES.decrypt = function(a) { 'use strict'; var chai = chai || require('chai'); var should = chai.should(); -var is_browser = typeof process == 'undefined' - || typeof process.versions === 'undefined'; - if (is_browser) { - var copay = require('copay'); //browser - } else { - var copay = require('../copay'); //node - } - var LocalEncrypted = copay.StorageLocalEncrypted; +var is_browser = typeof process == 'undefined' || typeof process.versions === 'undefined'; +if (is_browser) { + var copay = require('copay'); //browser +} else { + var copay = require('../copay'); //node +} +var LocalEncrypted = copay.StorageLocalEncrypted; - var fakeWallet = 'fake-wallet-id'; - var timeStamp = Date.now(); - var localMock = require('./mocks/FakeLocalStorage'); - var sessionMock = require('./mocks/FakeLocalStorage'); +var fakeWallet = 'fake-wallet-id'; +var timeStamp = Date.now(); +var localMock = require('./mocks/FakeLocalStorage'); +var sessionMock = require('./mocks/FakeLocalStorage'); - describe('Storage/LocalEncrypted model', function() { - var s = new LocalEncrypted({ +describe('Storage/LocalEncrypted model', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + }); + s._setPassphrase('mysupercoolpassword'); + + it('should create an instance', function() { + var s2 = new LocalEncrypted({ localStorage: localMock, sessionStorage: sessionMock, }); - s._setPassphrase('mysupercoolpassword'); - - it('should create an instance', function() { - var s2 = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - }); - should.exist(s2); + should.exist(s2); + }); + it('should fail when encrypting without a password', function() { + var s2 = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, }); - it('should fail when encrypting without a password', function() { - var s2 = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - }); - (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'); - localMock.removeItem(fakeWallet + timeStamp); - }); - it('should be able to set a value', function() { - s.set(fakeWallet, timeStamp, 1); + (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'); + localMock.removeItem(fakeWallet + timeStamp); + }); + it('should be able to set a value', function() { + s.set(fakeWallet, timeStamp, 1); + localMock.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)); localMock.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)); - localMock.removeItem(fakeWallet + '::' + timeStamp); + }); + + describe('#export', function() { + it('should export the encrypted wallet', function() { + var storage = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password', }); + storage.set(fakeWallet, timeStamp, 'testval'); + var obj = { + test: 'testval' + }; + var encrypted = storage.export(obj); + encrypted.length.should.be.greaterThan(10); + localMock.removeItem(fakeWallet + '::' + timeStamp); + //encrypted.slice(0,6).should.equal("53616c"); }); - - describe('#export', function() { - it('should export the encrypted wallet', function() { - var storage = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - password: 'password', - }); - storage.set(fakeWallet, timeStamp, 'testval'); - var obj = { - test: 'testval' - }; - var encrypted = storage.export(obj); - encrypted.length.should.be.greaterThan(10); - localMock.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', + localStorage: localMock, + sessionStorage: sessionMock, }); - }); - describe('#_decryptObj', function() { - it('should decrypt and Obj', function() { - var storage = new LocalEncrypted({ - password: 'password', - localStorage: localMock, - sessionStorage: sessionMock, - }); - storage._decryptObj('{"a":"2"}').should.deep.equal({ - a: "2" - }); - }); - }); - - - describe('#remove', function() { - it('should remove an item', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - 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({ - localStorage: localMock, - sessionStorage: sessionMock, - 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({ - localStorage: localMock, - sessionStorage: sessionMock, - password: 'password' - }); - s.setName(1, 'hola'); - s.getName(1).should.equal('hola'); - }); - }); - - describe('#getLastOpened #setLastOpened', function() { - it('should get/set names', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - password: 'password' - }); - s.setLastOpened('hey'); - s.getLastOpened().should.equal('hey'); - }); - }); - - if (is_browser) { - describe('#getSessionId', function() { - it('should get SessionId', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - password: 'password' - }); - var sid = s.getSessionId(); - should.exist(sid); - var sid2 = s.getSessionId(); - sid2.should.equal(sid); - }); - }); - } - - describe('#getWallets', function() { - it('should retreive wallets from storage', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - password: 'password' - }); - 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({ - localStorage: localMock, - sessionStorage: sessionMock, - 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({ - localStorage: localMock, - sessionStorage: sessionMock, - 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({ - localStorage: localMock, - sessionStorage: sessionMock, - 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')); + storage._decryptObj('{"a":"2"}').should.deep.equal({ + a: "2" }); }); }); + + + describe('#remove', function() { + it('should remove an item', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + 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({ + localStorage: localMock, + sessionStorage: sessionMock, + 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({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + s.setName(1, 'hola'); + s.getName(1).should.equal('hola'); + }); + }); + + describe('#getLastOpened #setLastOpened', function() { + it('should get/set names', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + s.setLastOpened('hey'); + s.getLastOpened().should.equal('hey'); + }); + }); + + if (is_browser) { + describe('#getSessionId', function() { + it('should get SessionId', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + var sid = s.getSessionId(); + should.exist(sid); + var sid2 = s.getSessionId(); + sid2.should.equal(sid); + }); + }); + } + + describe('#getWallets', function() { + it('should retreive wallets from storage', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + 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({ + localStorage: localMock, + sessionStorage: sessionMock, + 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({ + localStorage: localMock, + sessionStorage: sessionMock, + 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({ + localStorage: localMock, + sessionStorage: sessionMock, + 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')); + }); + }); + + + describe('session storage', function() { + it('should get a session ID', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + s.getSessionId().length.should.equal(16); + (new Buffer(s.getSessionId(),'hex')).length.should.equal(8); + }); + }); +}); From f14d83cee1af61bad1904a06afbc72eee721f6ec Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 15 Aug 2014 10:41:34 -0400 Subject: [PATCH 07/13] redir to home if no wallets at #open --- js/controllers/open.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/controllers/open.js b/js/controllers/open.js index 8f126dcb7..3dbcc2a50 100644 --- a/js/controllers/open.js +++ b/js/controllers/open.js @@ -15,6 +15,10 @@ angular.module('copayApp.controllers').controller('OpenController', function($sc $scope.openPassword = ''; $scope.isMobile = !!window.cordova; + if (!$scope.wallets.length){ + $location.path('/'); + } + $scope.open = function(form) { if (form && form.$invalid) { notification.error('Error', 'Please enter the required fields'); From 18aadede29c9cbbb130b788f38e914c34adbdefd Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 15 Aug 2014 12:43:43 -0400 Subject: [PATCH 08/13] fix tests and stringify for localstorage --- config.js | 77 +++++++++++++++-------------- js/controllers/sidebar.js | 8 ++- js/models/core/Wallet.js | 7 ++- js/models/core/WalletLock.js | 16 +++--- js/models/storage/LocalEncrypted.js | 2 +- js/routes.js | 20 ++------ js/services/controllerUtils.js | 10 +--- test/mocks/FakeStorage.js | 4 +- test/test.WalletLock.js | 7 ++- 9 files changed, 75 insertions(+), 76 deletions(-) diff --git a/config.js b/config.js index 73fde9550..a9a61a6bf 100644 --- a/config.js +++ b/config.js @@ -19,11 +19,11 @@ var defaultConfig = { // Use this to run your own local PeerJS server // with params: ./peerjs -p 10009 -k '6d6d751ea61e26f2' /* - key: '6d6d751ea61e26f2', - host: 'localhost', - port: 10009, - path: '/', - */ +key: '6d6d751ea61e26f2', +host: 'localhost', +port: 10009, +path: '/', +*/ // Use this to connect to bitpay's PeerJS server key: 'satoshirocks', @@ -44,39 +44,39 @@ var defaultConfig = { 'iceServers': [ // Pass in STUN and TURN servers for maximum network compatibility { - url: 'stun:162.242.219.26' - }, { - url: 'turn:162.242.219.26', - username: 'bitcore', - credential: 'bitcore', - } - // { - // url: 'stun:stun.l.google.com:19302' - // }, { - // url: 'stun:stun1.l.google.com:19302' - // }, { - // url: 'stun:stun2.l.google.com:19302' - // }, { - // url: 'stun:stun3.l.google.com:19302' - // }, { - // url: 'stun:stun4.l.google.com:19302' - // }, { - // url: 'stun:stunserver.org' - // } - // // Options fot TURN servers with p2p communications are not possible. - // { - // url: 'turn:numb.viagenie.ca', - // credential: 'muazkh', - // username: 'webrtc@live.com' - // }, { - // url: 'turn:192.158.29.39:3478?transport=udp', - // credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=', - // username: '28224511:1379330808' - // }, { - // url: 'turn:192.158.29.39:3478?transport=tcp', - // credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=', - // username: '28224511:1379330808' - // } + url: 'stun:162.242.219.26' + }, { + url: 'turn:162.242.219.26', + username: 'bitcore', + credential: 'bitcore', + } + // { + // url: 'stun:stun.l.google.com:19302' + // }, { + // url: 'stun:stun1.l.google.com:19302' + // }, { + // url: 'stun:stun2.l.google.com:19302' + // }, { + // url: 'stun:stun3.l.google.com:19302' + // }, { + // url: 'stun:stun4.l.google.com:19302' + // }, { + // url: 'stun:stunserver.org' + // } + // // Options fot TURN servers with p2p communications are not possible. + // { + // url: 'turn:numb.viagenie.ca', + // credential: 'muazkh', + // username: 'webrtc@live.com' + // }, { + // url: 'turn:192.158.29.39:3478?transport=udp', + // credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=', + // username: '28224511:1379330808' + // }, { + // url: 'turn:192.158.29.39:3478?transport=tcp', + // credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=', + // username: '28224511:1379330808' + // } ] } }, @@ -89,6 +89,7 @@ var defaultConfig = { verbose: 1, // will duplicate itself after each try reconnectDelay: 5000, + idleDurationMin: 1 }, // blockchain service API config diff --git a/js/controllers/sidebar.js b/js/controllers/sidebar.js index f0e907cf9..26c3f60f8 100644 --- a/js/controllers/sidebar.js +++ b/js/controllers/sidebar.js @@ -65,13 +65,17 @@ angular.module('copayApp.controllers').controller('SidebarController', function( controllerUtils.setSocketHandlers(); if ($rootScope.wallet) { - $scope.$on('$idleStart', function(a) { - notification.warning('Session will be closed', 'Your session is about to expire due to inactivity'); + $scope.$on('$idleWarn', function(a,countdown) { + if (!(countdown%5)) + notification.warning('Session will be closed', 'Your session is about to expire due to inactivity in ' + countdown + ' seconds'); }); $scope.$on('$idleTimeout', function() { $scope.signout(); notification.warning('Session closed', 'Session closed because a long time of inactivity'); }); + $scope.$on('$keepalive', function() { + $rootScope.wallet.keepAlive(); + }); } }); diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 5d6948fdf..3e68f56d1 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -497,7 +497,12 @@ Wallet.prototype.getRegisteredPeerIds = function() { }; Wallet.prototype.keepAlive = function() { - this.lock.keepAlive(); + try{ + this.lock.keepAlive(); + } catch(e){ + this.log(e); + this.emit('locked',null,'Wallet appears to be openned on other browser instance. Closing this one.' ); + } }; Wallet.prototype.store = function() { diff --git a/js/models/core/WalletLock.js b/js/models/core/WalletLock.js index 7bdf7d7b5..4e57250ca 100644 --- a/js/models/core/WalletLock.js +++ b/js/models/core/WalletLock.js @@ -17,20 +17,24 @@ WalletLock._keyFor = function(walletId) { }; WalletLock.prototype._isLockedByOther = function() { - var wl = this.storage.getGlobal(this.key); - - if (!wl || wl.expireTs < Date.now() || wl.sessionId === this.sessionId) + var json = this.storage.getGlobal(this.key); + var wl = json ? JSON.parse(json) : null; + var t = wl ? (Date.now() - wl.expireTs) : false; + // is not locked? + if (!wl || t > 0 || wl.sessionId === this.sessionId) return false; - return true; + // Seconds remainding + return parseInt(-t/1000.); }; WalletLock.prototype.keepAlive = function() { preconditions.checkState(this.sessionId); - if (this._isLockedByOther()) - throw new Error('Could not adquire lock'); + var t = this._isLockedByOther(); + if (t) + throw new Error('Wallet is already open. Close it to proceed or wait '+ t + ' seconds if you close it already' ); this.storage.setGlobal(this.key, { sessionId: this.sessionId, diff --git a/js/models/storage/LocalEncrypted.js b/js/models/storage/LocalEncrypted.js index 60fb419c7..c45dc1b85 100644 --- a/js/models/storage/LocalEncrypted.js +++ b/js/models/storage/LocalEncrypted.js @@ -101,7 +101,7 @@ Storage.prototype.getSessionId = function() { var sessionId = this.sessionStorage.getItem('sessionId'); if (!sessionId) { sessionId = bitcore.SecureRandom.getRandomBuffer(8).toString('hex'); - this.sessionStorage.setItem(sessionId, 'sessionId'); + this.sessionStorage.setItem('sessionId', sessionId); } return sessionId; }; diff --git a/js/routes.js b/js/routes.js index 152068985..93011afd4 100644 --- a/js/routes.js +++ b/js/routes.js @@ -69,13 +69,15 @@ angular //Setting HTML5 Location Mode angular .module('copayApp') -.config(function($locationProvider, $idleProvider) { +.config(function($locationProvider, $idleProvider, $keepaliveProvider) { $locationProvider .html5Mode(false) .hashPrefix('!'); // IDLE timeout - $idleProvider.idleDuration(config.wallet.idleDurationMin * 60); // in seconds + var timeout = config.wallet.idleDurationMin * 60 || 300; + $idleProvider.idleDuration(timeout); // in seconds $idleProvider.warningDuration(20); // in seconds + $keepaliveProvider.interval(5); // in seconds }) .run(function($rootScope, $location, $idle) { $idle.watch(); @@ -83,20 +85,6 @@ angular if (!util.supports.data) { $location.path('unsupported'); } else { - - // Locked? - if ($rootScope.showLockWarning) { - if ($rootScope.tmp) { - if ($location.path() !== '/warning') { - $location.path('/warning'); - } - else { - delete $rootScope['showLockWarning']; - } - } - return; - } - if ((!$rootScope.wallet || !$rootScope.wallet.id) && next.validate) { $idle.unwatch(); $location.path('/'); diff --git a/js/services/controllerUtils.js b/js/services/controllerUtils.js index ef4c0b861..dfbe4bb45 100644 --- a/js/services/controllerUtils.js +++ b/js/services/controllerUtils.js @@ -26,7 +26,7 @@ angular.module('copayApp.services') Socket.removeAllListeners(); - $rootScope.wallet = $rootScope.tmp = null; + $rootScope.wallet = null; delete $rootScope['wallet']; video.close(); @@ -72,7 +72,6 @@ angular.module('copayApp.services') root.setupRootVariables = function() { uriHandler.register(); $rootScope.unitName = config.unitName; - $rootScope.showLockWarning = false; $rootScope.txAlertCount = 0; $rootScope.insightError = 0; $rootScope.isCollapsed = true; @@ -125,12 +124,6 @@ angular.module('copayApp.services') }; notification.enableHtml5Mode(); // for chrome: if support, enable it - w.on('locked', function() { - $rootScope.tmp = w; - $rootScope.showLockWarning=true; - $location.path('/warning'); - $rootScope.$digest(); - }); w.on('badMessage', function(peerId) { notification.error('Error', 'Received wrong message from peer ' + peerId); @@ -195,6 +188,7 @@ angular.module('copayApp.services') $rootScope.$digest(); }); w.on('close', root.onErrorDigest); + w.on('locked', root.onErrorDigest.bind(this)); w.netStart(); }; diff --git a/test/mocks/FakeStorage.js b/test/mocks/FakeStorage.js index 81a0dcbae..9aea4d2ea 100644 --- a/test/mocks/FakeStorage.js +++ b/test/mocks/FakeStorage.js @@ -11,8 +11,8 @@ FakeStorage.prototype._setPassphrase = function(password) { this.storage.passphrase = password; }; -FakeStorage.prototype.setGlobal = function(id, payload) { - this.storage[id] = payload; +FakeStorage.prototype.setGlobal = function(id, v) { + this.storage[id] = typeof v === 'object' ? JSON.stringify(v) : v; }; FakeStorage.prototype.getGlobal = function(id) { diff --git a/test/test.WalletLock.js b/test/test.WalletLock.js index 6882086da..54ae794e7 100644 --- a/test/test.WalletLock.js +++ b/test/test.WalletLock.js @@ -41,7 +41,7 @@ describe('WalletLock model', function() { storage.sessionId = 'xxx'; (function() { new WalletLock(storage, 'walletId') - }).should.throw('adquire lock'); + }).should.throw('already open'); }); it('should not fail if locked by me', function() { @@ -60,7 +60,10 @@ describe('WalletLock model', function() { it('should not fail if expired', function() { var s = new Storage(); var w = new WalletLock(s, 'walletId'); - s.storage[Object.keys(s.storage)[0]].expireTs = Date.now() - 60 * 6 * 1000; + var k = Object.keys(s.storage)[0]; + var v = JSON.parse(s.storage[k]); + v.expireTs = Date.now() - 60 * 6 * 1000; + s.storage[k] = JSON.stringify(v); s.sessionId = 'xxx'; var w2 = new WalletLock(s, 'walletId') From 1a5a2916c26c17e11c378cbff6b305acc0e582b8 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 15 Aug 2014 12:49:16 -0400 Subject: [PATCH 09/13] give lock preference to the new instance --- config.js | 2 +- js/models/core/WalletLock.js | 16 ++++++++++------ js/routes.js | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/config.js b/config.js index a9a61a6bf..659457933 100644 --- a/config.js +++ b/config.js @@ -89,7 +89,7 @@ path: '/', verbose: 1, // will duplicate itself after each try reconnectDelay: 5000, - idleDurationMin: 1 + idleDurationMin: 4 }, // blockchain service API config diff --git a/js/models/core/WalletLock.js b/js/models/core/WalletLock.js index 4e57250ca..329f5d9eb 100644 --- a/js/models/core/WalletLock.js +++ b/js/models/core/WalletLock.js @@ -10,7 +10,7 @@ function WalletLock(storage, walletId, timeoutMin) { this.storage = storage; this.timeoutMin = timeoutMin || 5; this.key = WalletLock._keyFor(walletId); - this.keepAlive(); + this._setLock(); } WalletLock._keyFor = function(walletId) { return 'lock' + '::' + walletId; @@ -29,17 +29,21 @@ WalletLock.prototype._isLockedByOther = function() { }; +WalletLock.prototype._setLock = function() { + this.storage.setGlobal(this.key, { + sessionId: this.sessionId, + expireTs: Date.now() + this.timeoutMin * 60 * 1000, + }); +}; + + WalletLock.prototype.keepAlive = function() { preconditions.checkState(this.sessionId); var t = this._isLockedByOther(); if (t) throw new Error('Wallet is already open. Close it to proceed or wait '+ t + ' seconds if you close it already' ); - - this.storage.setGlobal(this.key, { - sessionId: this.sessionId, - expireTs: Date.now() + this.timeoutMin * 60 * 1000, - }); + this._setLock(); }; diff --git a/js/routes.js b/js/routes.js index 93011afd4..c40a6179c 100644 --- a/js/routes.js +++ b/js/routes.js @@ -77,7 +77,7 @@ angular var timeout = config.wallet.idleDurationMin * 60 || 300; $idleProvider.idleDuration(timeout); // in seconds $idleProvider.warningDuration(20); // in seconds - $keepaliveProvider.interval(5); // in seconds + $keepaliveProvider.interval(2); // in seconds }) .run(function($rootScope, $location, $idle) { $idle.watch(); From d3b3a786583307ee57e9e4652bc2a554aea9b804 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 15 Aug 2014 13:04:19 -0400 Subject: [PATCH 10/13] fix comment send --- js/controllers/send.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/controllers/send.js b/js/controllers/send.js index 1417002c0..07b50dfa2 100644 --- a/js/controllers/send.js +++ b/js/controllers/send.js @@ -40,6 +40,7 @@ angular.module('copayApp.controllers').controller('SendController', $scope.address = pp.address; var amount = pp.amount / config.unitToSatoshi * 100000000; $scope.amount = amount; + $scope.commentText = pp.message; } navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; From 534895a00927c50bd253853000ddccac98cacc22 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 15 Aug 2014 18:55:26 -0400 Subject: [PATCH 11/13] rebase --- js/models/core/WalletLock.js | 1 + test/test.LocalEncrypted.js | 418 +++++++++++++++------------- test/test.WalletLock.js | 25 +- test/test.storage.LocalEncrypted.js | 284 ------------------- 4 files changed, 240 insertions(+), 488 deletions(-) delete mode 100644 test/test.storage.LocalEncrypted.js diff --git a/js/models/core/WalletLock.js b/js/models/core/WalletLock.js index 329f5d9eb..edd2bf67d 100644 --- a/js/models/core/WalletLock.js +++ b/js/models/core/WalletLock.js @@ -12,6 +12,7 @@ function WalletLock(storage, walletId, timeoutMin) { this.key = WalletLock._keyFor(walletId); this._setLock(); } + WalletLock._keyFor = function(walletId) { return 'lock' + '::' + walletId; }; diff --git a/test/test.LocalEncrypted.js b/test/test.LocalEncrypted.js index f5c96ba98..d010bc805 100644 --- a/test/test.LocalEncrypted.js +++ b/test/test.LocalEncrypted.js @@ -1,11 +1,22 @@ +//Crypto Mock +CryptoJS = {}; +CryptoJS.AES = {}; +CryptoJS.AES.encrypt = function(a) { + return a; +}; + +CryptoJS.enc = { + utf8: '' +}; + +CryptoJS.AES.decrypt = function(a) { + return a; +}; + 'use strict'; var chai = chai || require('chai'); var should = chai.should(); -var fakeWallet = 'fake-wallet-id'; -var timeStamp = Date.now(); -var localMock = require('./mocks/FakeLocalStorage'); var is_browser = typeof process == 'undefined' || typeof process.versions === 'undefined'; - if (is_browser) { var copay = require('copay'); //browser } else { @@ -13,226 +24,245 @@ if (is_browser) { } var LocalEncrypted = copay.StorageLocalEncrypted; +var fakeWallet = 'fake-wallet-id'; +var timeStamp = Date.now(); +var localMock = require('./mocks/FakeLocalStorage'); +var sessionMock = require('./mocks/FakeLocalStorage'); + + describe('Storage/LocalEncrypted model', function() { var s = new LocalEncrypted({ localStorage: localMock, + sessionStorage: sessionMock, }); s._setPassphrase('mysupercoolpassword'); it('should create an instance', function() { var s2 = new LocalEncrypted({ localStorage: localMock, + sessionStorage: sessionMock, }); should.exist(s2); }); -}); - -it('should fail when encrypting without a password', function() { - var s2 = new LocalEncrypted({ - localStorage: localMock, + it('should fail when encrypting without a password', function() { + var s2 = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + }); + (function() { + s2.set(fakeWallet, timeStamp, 1); + }).should.throw(); }); - (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'); - localMock.removeItem(fakeWallet + timeStamp); -}); -it('should be able to set a value', function() { - s.set(fakeWallet, timeStamp, 1); - localMock.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)); + it('should be able to encrypt and decrypt', function() { + s._write(fakeWallet + timeStamp, 'value'); + s._read(fakeWallet + timeStamp).should.equal('value'); + localMock.removeItem(fakeWallet + timeStamp); + }); + it('should be able to set a value', function() { + s.set(fakeWallet, timeStamp, 1); localMock.removeItem(fakeWallet + '::' + timeStamp); }); -}); - -describe('#export', function() { - it('should export the encrypted wallet', function() { - var storage = new LocalEncrypted({ - localStorage: localMock, - password: 'password', - }); - storage.set(fakeWallet, timeStamp, 'testval'); - var obj = { - test: 'testval' - }; - var encrypted = storage.export(obj); - encrypted.length.should.be.greaterThan(10); - localMock.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', - localStorage: localMock, - }); - storage._decryptObj('{"a":"2"}').should.deep.equal({ - a: "2" + 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)); + localMock.removeItem(fakeWallet + '::' + timeStamp); }); }); -}); - -describe('#remove', function() { - it('should remove an item', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - password: 'password' + describe('#export', function() { + it('should export the encrypted wallet', function() { + var storage = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password', + }); + storage.set(fakeWallet, timeStamp, 'testval'); + var obj = { + test: 'testval' + }; + var encrypted = storage.export(obj); + encrypted.length.should.be.greaterThan(10); + localMock.removeItem(fakeWallet + '::' + timeStamp); + //encrypted.slice(0,6).should.equal("53616c"); }); - 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({ - localStorage: localMock, - 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({ - localStorage: localMock, - password: 'password' - }); - s.setName(1, 'hola'); - s.getName(1).should.equal('hola'); - }); -}); - -describe('#getLastOpened #setLastOpened', function() { - it('should get/set names', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - password: 'password' - }); - s.setLastOpened('hey'); - s.getLastOpened().should.equal('hey'); - }); -}); - -if (is_browser) { - describe('#getSessionId', function() { - it('should get SessionId', function() { + describe('#remove', function() { + it('should remove an item', function() { var s = new LocalEncrypted({ localStorage: localMock, + sessionStorage: sessionMock, password: 'password' }); - var sid = s.getSessionId(); - should.exist(sid); - var sid2 = s.getSessionId(); - sid2.should.equal(sid); + s.set('1', "hola", 'juan'); + s.get('1', 'hola').should.equal('juan'); + s.remove('1', 'hola'); + + should.not.exist(s.get('1', 'hola')); }); }); -} -describe('#getWallets', function() { - it('should retreive wallets from storage', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - password: 'password' + + describe('#getWalletIds', function() { + it('should get wallet ids', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + s.set('1', "hola", 'juan'); + s.set('2', "hola", 'juan'); + s.getWalletIds().should.deep.equal(['1', '2']); }); - s.set('1', "hola", 'juan'); - s.set('2', "hola", 'juan'); - s.setName(1, 'hola'); - s.getWallets()[0].should.deep.equal({ - id: '1', - name: 'hola', + }); + + describe('#getName #setName', function() { + it('should get/set names', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + s.setName(1, 'hola'); + s.getName(1).should.equal('hola'); }); - s.getWallets()[1].should.deep.equal({ - id: '2', - name: undefined + }); + + describe('#getLastOpened #setLastOpened', function() { + it('should get/set names', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + s.setLastOpened('hey'); + s.getLastOpened().should.equal('hey'); + }); + }); + + if (is_browser) { + describe('#getSessionId', function() { + it('should get SessionId', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + var sid = s.getSessionId(); + should.exist(sid); + var sid2 = s.getSessionId(); + sid2.should.equal(sid); + }); + }); + } + + describe('#getWallets', function() { + it('should retreive wallets from storage', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + 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({ + localStorage: localMock, + sessionStorage: sessionMock, + 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({ + localStorage: localMock, + sessionStorage: sessionMock, + 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({ + localStorage: localMock, + sessionStorage: sessionMock, + 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')); + }); + }); + + + describe('session storage', function() { + it('should get a session ID', function() { + var s = new LocalEncrypted({ + localStorage: localMock, + sessionStorage: sessionMock, + password: 'password' + }); + s.getSessionId().length.should.equal(16); + (new Buffer(s.getSessionId(),'hex')).length.should.equal(8); }); }); }); -describe('#deleteWallet', function() { - it('should delete a wallet', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - 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({ - localStorage: localMock, - 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({ - localStorage: localMock, - 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.WalletLock.js b/test/test.WalletLock.js index 54ae794e7..f3ccf051d 100644 --- a/test/test.WalletLock.js +++ b/test/test.WalletLock.js @@ -36,27 +36,32 @@ describe('WalletLock model', function() { should.exist(w); }); - it('should fail if locked already', function() { + it('should NOT fail if locked already', function() { var w = new WalletLock(storage, 'walletId'); storage.sessionId = 'xxx'; - (function() { - new WalletLock(storage, 'walletId') - }).should.throw('already open'); + var w2= new WalletLock(storage, 'walletId'); + should.exist(w2); }); + it('should change status of previously openned wallet', function() { + storage.sessionId = 'session1'; + var w = new WalletLock(storage, 'walletId'); + storage.sessionId = 'xxx'; + var w2= new WalletLock(storage, 'walletId'); + w2.keepAlive(); + (function() {w.keepAlive();}).should.throw('already open'); + + }); + + it('should not fail if locked by me', function() { var s = new Storage(); var w = new WalletLock(s, 'walletId'); var w2 = new WalletLock(s, 'walletId') + w2.keepAlive(); should.exist(w2); }); - it('should not fail if locked by me', function() { - var s = new Storage(); - var w = new WalletLock(s, 'walletId'); - var w2 = new WalletLock(s, 'walletId') - should.exist(w2); - }); it('should not fail if expired', function() { var s = new Storage(); var w = new WalletLock(s, 'walletId'); diff --git a/test/test.storage.LocalEncrypted.js b/test/test.storage.LocalEncrypted.js deleted file mode 100644 index 3d4e4d3e0..000000000 --- a/test/test.storage.LocalEncrypted.js +++ /dev/null @@ -1,284 +0,0 @@ -//Crypto Mock -CryptoJS = {}; -CryptoJS.AES = {}; -CryptoJS.AES.encrypt = function(a) { - return a; -}; - -CryptoJS.enc = { - utf8: '' -}; - -CryptoJS.AES.decrypt = function(a) { - return a; -}; - - - - -'use strict'; -var chai = chai || require('chai'); -var should = chai.should(); -var is_browser = typeof process == 'undefined' || typeof process.versions === 'undefined'; -if (is_browser) { - var copay = require('copay'); //browser -} else { - var copay = require('../copay'); //node -} -var LocalEncrypted = copay.StorageLocalEncrypted; - -var fakeWallet = 'fake-wallet-id'; -var timeStamp = Date.now(); -var localMock = require('./mocks/FakeLocalStorage'); -var sessionMock = require('./mocks/FakeLocalStorage'); - - -describe('Storage/LocalEncrypted model', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - }); - s._setPassphrase('mysupercoolpassword'); - - it('should create an instance', function() { - var s2 = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - }); - should.exist(s2); - }); - it('should fail when encrypting without a password', function() { - var s2 = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - }); - (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'); - localMock.removeItem(fakeWallet + timeStamp); - }); - it('should be able to set a value', function() { - s.set(fakeWallet, timeStamp, 1); - localMock.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)); - localMock.removeItem(fakeWallet + '::' + timeStamp); - }); - }); - - describe('#export', function() { - it('should export the encrypted wallet', function() { - var storage = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - password: 'password', - }); - storage.set(fakeWallet, timeStamp, 'testval'); - var obj = { - test: 'testval' - }; - var encrypted = storage.export(obj); - encrypted.length.should.be.greaterThan(10); - localMock.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', - localStorage: localMock, - sessionStorage: sessionMock, - }); - storage._decryptObj('{"a":"2"}').should.deep.equal({ - a: "2" - }); - }); - }); - - - describe('#remove', function() { - it('should remove an item', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - 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({ - localStorage: localMock, - sessionStorage: sessionMock, - 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({ - localStorage: localMock, - sessionStorage: sessionMock, - password: 'password' - }); - s.setName(1, 'hola'); - s.getName(1).should.equal('hola'); - }); - }); - - describe('#getLastOpened #setLastOpened', function() { - it('should get/set names', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - password: 'password' - }); - s.setLastOpened('hey'); - s.getLastOpened().should.equal('hey'); - }); - }); - - if (is_browser) { - describe('#getSessionId', function() { - it('should get SessionId', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - password: 'password' - }); - var sid = s.getSessionId(); - should.exist(sid); - var sid2 = s.getSessionId(); - sid2.should.equal(sid); - }); - }); - } - - describe('#getWallets', function() { - it('should retreive wallets from storage', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - password: 'password' - }); - 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({ - localStorage: localMock, - sessionStorage: sessionMock, - 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({ - localStorage: localMock, - sessionStorage: sessionMock, - 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({ - localStorage: localMock, - sessionStorage: sessionMock, - 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')); - }); - }); - - - describe('session storage', function() { - it('should get a session ID', function() { - var s = new LocalEncrypted({ - localStorage: localMock, - sessionStorage: sessionMock, - password: 'password' - }); - s.getSessionId().length.should.equal(16); - (new Buffer(s.getSessionId(),'hex')).length.should.equal(8); - }); - }); -}); From 53f9036c12d02ce81ae8f4c77abb8b031c7a803b Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 15 Aug 2014 19:33:32 -0400 Subject: [PATCH 12/13] fix build --- util/build.js | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/util/build.js b/util/build.js index a42a12643..4c764fb2b 100644 --- a/util/build.js +++ b/util/build.js @@ -41,37 +41,9 @@ var createBundle = function(opts) { b.require('./js/models/core/Wallet', { expose: '../../js/models/core/Wallet' }); -<<<<<<< HEAD -======= b.require('./js/models/core/WalletLock', { expose: '../js/models/core/WalletLock' }); - - b.require('./test/mocks/FakeStorage', { - expose: './mocks/FakeStorage' - }); - b.require('./test/mocks/FakeLocalStorage', { - expose: './mocks/FakeLocalStorage' - }); - b.require('./js/models/core/Message', { - expose: '../js/models/core/Message' - }); - b.require('./test/mocks/FakeBlockchain', { - expose: './mocks/FakeBlockchain' - }); - b.require('./test/mocks/FakeNetwork', { - expose: './mocks/FakeNetwork' - }); - b.require('./test/mocks/FakePayProServer', { - expose: './mocks/FakePayProServer' - }); - b.require('./test/mocks/FakePayProServer', { - expose: '../../mocks/FakePayProServer' - }); - b.require('./test/mocks/FakeBuilder', { - expose: './mocks/FakeBuilder' - }); ->>>>>>> add WalletLock class b.require('./js/models/network/WebRTC', { expose: '../js/models/network/WebRTC' }); @@ -124,7 +96,7 @@ var createBundle = function(opts) { }); } - if (!opts.dontminify) { + if (!opts.debug) { b.transform({ global: true }, 'uglifyify'); From d4dbeb8b130a9c2598b54a7a90fa6fab531f3618 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 15 Aug 2014 19:54:39 -0400 Subject: [PATCH 13/13] rm unused code --- test/test.LocalEncrypted.js | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/test/test.LocalEncrypted.js b/test/test.LocalEncrypted.js index d010bc805..32149e58f 100644 --- a/test/test.LocalEncrypted.js +++ b/test/test.LocalEncrypted.js @@ -1,27 +1,8 @@ -//Crypto Mock -CryptoJS = {}; -CryptoJS.AES = {}; -CryptoJS.AES.encrypt = function(a) { - return a; -}; - -CryptoJS.enc = { - utf8: '' -}; - -CryptoJS.AES.decrypt = function(a) { - return a; -}; - 'use strict'; var chai = chai || require('chai'); var should = chai.should(); var is_browser = typeof process == 'undefined' || typeof process.versions === 'undefined'; -if (is_browser) { - var copay = require('copay'); //browser -} else { - var copay = require('../copay'); //node -} +var copay = copay || require('../copay'); var LocalEncrypted = copay.StorageLocalEncrypted; var fakeWallet = 'fake-wallet-id';