From d8e0d50dcefaaa7884bd0cc15cd8dead7405c6c1 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 14 Aug 2014 18:25:53 -0400 Subject: [PATCH] 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' });