From 89dba4c61672341ba7846b261140c5cd7090f03a Mon Sep 17 00:00:00 2001 From: Matias Pando Date: Wed, 3 Sep 2014 16:51:02 -0300 Subject: [PATCH] Added secret number feature --- js/models/core/Wallet.js | 24 ++++++++++++++-- js/models/core/WalletFactory.js | 5 ++-- js/models/network/Async.js | 15 ++++++++-- test/test.Wallet.js | 7 +++++ test/test.network.Async.js | 51 +++++++++++++++++++++++++++++---- views/copayers.html | 2 +- 6 files changed, 90 insertions(+), 14 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 272e27d11..1856005a7 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -43,6 +43,7 @@ function Wallet(opts) { ' and tried to create a Wallet with network ' + this.getNetworkName()); this.id = opts.id || Wallet.getRandomId(); + this.secretNumber = opts.secretNumber || Wallet.getRandomNumber(); this.lock = new WalletLock(this.storage, this.id, opts.lockTimeOutMin); this.name = opts.name; @@ -50,6 +51,7 @@ function Wallet(opts) { this.publicKeyRing.walletId = this.id; this.txProposals.walletId = this.id; this.network.maxPeers = this.totalCopayers; + this.network.secretNumber = this.secretNumber; this.registeredPeerIds = []; this.addressBook = opts.addressBook || {}; this.publicKey = this.privateKey.publicHex; @@ -78,6 +80,11 @@ Wallet.getRandomId = function() { return r; }; +Wallet.getRandomNumber = function() { + var r = bitcore.SecureRandom.getPseudoRandomBuffer(5).toString('hex'); + return r; +}; + Wallet.prototype.seedCopayer = function(pubKey) { this.seededCopayerId = pubKey; }; @@ -408,18 +415,28 @@ Wallet.prototype.getMyCopayerIdPriv = function() { return this.privateKey.getIdPriv(); //copayer idpriv is hex of a private key }; + +Wallet.prototype.getSecretNumber = function() { + if (this.secretNumber) return this.secretNumber; + this.secretNumber = Wallet.getRandomNumber(); + return this.secretNumber; +}; + Wallet.prototype.getSecret = function() { - var pubkeybuf = new Buffer(this.getMyCopayerId(), 'hex'); - var str = Base58Check.encode(pubkeybuf); + var buf = new Buffer(this.getMyCopayerId() + this.getSecretNumber(), 'hex'); + var str = Base58Check.encode(buf); return str; }; + Wallet.decodeSecret = function(secretB) { var secret = Base58Check.decode(secretB); var pubKeyBuf = secret.slice(0, 33); + var secretNumber = secret.slice(33, 38); return { - pubKey: pubKeyBuf.toString('hex') + pubKey: pubKeyBuf.toString('hex'), + secretNumber : secretNumber.toString('hex') } }; @@ -445,6 +462,7 @@ Wallet.prototype.netStart = function(callback) { privkey: myIdPriv, maxPeers: self.totalCopayers, lastTimestamp: this.lastTimestamp, + secretNumber: self.secretNumber, }; if (this.publicKeyRing.isComplete()) { diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index 2155bb2c1..22340bcb6 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -233,7 +233,8 @@ WalletFactory.prototype.joinCreateSession = function(secret, nickname, passphras var opts = { copayerId: privateKey.getId(), privkey: privateKey.getIdPriv(), - key: privateKey.getIdKey() + key: privateKey.getIdKey(), + secretNumber : s.secretNumber, }; self.network.cleanUp(); @@ -248,7 +249,7 @@ WalletFactory.prototype.joinCreateSession = function(secret, nickname, passphras }); self.network.start(opts, function() { - self.network.greet(s.pubKey); + self.network.greet(s.pubKey,opts.secretNumber); self.network.on('data', function(sender, data) { if (data.type === 'walletId') { if (data.networkName !== self.networkName) { diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 4ba012614..b15ce9087 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -17,6 +17,7 @@ function Network(opts) { this.host = opts.host || 'localhost'; this.port = opts.port || 3001; this.schema = opts.schema || 'https'; + this.secretNumber = opts.secretNumber; this.cleanUp(); } @@ -73,11 +74,12 @@ Network.prototype.connectedCopayers = function() { return ret; }; -Network.prototype._sendHello = function(copayerId) { +Network.prototype._sendHello = function(copayerId,secretNumber) { this.send(copayerId, { type: 'hello', copayerId: this.copayerId, + secretNumber : secretNumber }); }; @@ -193,6 +195,12 @@ Network.prototype._onMessage = function(enc) { var self = this; switch (payload.type) { case 'hello': + + if (typeof payload.secretNumber === 'undefined' || payload.secretNumber !== this.secretNumber) + { + this._deletePeer(enc.pubkey, 'incorrect secret number'); + return; + } // if we locked allowed copayers, check if it belongs if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) { this._deletePeer(sender); @@ -240,8 +248,8 @@ Network.prototype._onError = function(err) { this.criticalError = err.message; }; -Network.prototype.greet = function(copayerId) { - this._sendHello(copayerId); +Network.prototype.greet = function(copayerId,secretNumber) { + this._sendHello(copayerId,secretNumber); var peerId = this.peerFromCopayer(copayerId); this._addCopayerMap(peerId, copayerId); }; @@ -350,6 +358,7 @@ Network.prototype.send = function(dest, payload, cb) { if (to == this.copayerId) continue; log.debug('SEND to: ' + to, this.copayerId, payload); + var message = this.encode(to, payload); this.socket.emit('message', message); } diff --git a/test/test.Wallet.js b/test/test.Wallet.js index 09dc4afe5..20dcfd9d9 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -337,22 +337,29 @@ describe('Wallet model', function() { it('#getSecret decodeSecret', function() { var w = cachedCreateW2(); var id = w.getMyCopayerId(); + var secretNumber = w.getSecretNumber(); var sb = w.getSecret(); should.exist(sb); + var s = Wallet.decodeSecret(sb); s.pubKey.should.equal(id); + s.secretNumber.should.equal(secretNumber); }); + + it('decodeSecret check', function() { (function() { Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoKM'); }).should.not. throw(); + (function() { Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoK'); }).should. throw(); + (function() { Wallet.decodeSecret('12345'); }).should. diff --git a/test/test.network.Async.js b/test/test.network.Async.js index c4273af00..7de41751f 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -27,10 +27,12 @@ describe('Network / Async', function() { privkey: pk || '31701118abde096d166607115ed00ce74a2231f68f43144406c863f5ebf06c32', lastTimestamp: 1, }; + n.secretNumber = 'mySecret'; n.start(opts); return n; }; + it('should create an instance', function() { var n = createN(); should.exist(n); @@ -129,7 +131,8 @@ describe('Network / Async', function() { var message = { type: 'hello', - copayerId: cid1 + copayerId: cid1, + secretNumber : 'mySecret' }; var enc = n1.encode(cid2, message); n2._onMessage(enc); @@ -141,7 +144,8 @@ describe('Network / Async', function() { var message = { type: 'hello', - copayerId: cid3 // MITM + copayerId: cid3, // MITM + secretNumber : 'mySecret' }; var enc = n.encode(cid2, message); @@ -160,7 +164,8 @@ describe('Network / Async', function() { var message = { type: 'hello', - copayerId: cid1 + copayerId: cid1, + secretNumber : 'mySecret' }; var nonce = new Buffer('0000000000000001', 'hex'); var enc = n1.encode(cid2, message, nonce); @@ -176,7 +181,8 @@ describe('Network / Async', function() { var message = { type: 'hello', - copayerId: cid1 + copayerId: cid1, + secretNumber : 'mySecret' }; n2.networkNonces = {}; n2.networkNonces[cid1] = new Buffer('5000000000000001', 'hex'); @@ -195,7 +201,8 @@ describe('Network / Async', function() { var message = { type: 'hello', - copayerId: cid1 + copayerId: cid1, + secretNumber : 'mySecret' }; n2.networkNonces = {}; n2.networkNonces[cid1] = new Buffer('0000000000000002', 'hex'); @@ -205,6 +212,40 @@ describe('Network / Async', function() { n2._deletePeer.calledOnce.should.equal(true); }); + it('should accept join with a correct secret number', function() { + var n1 = createN(pk1); + var n2 = createN(pk2); + n2._deletePeer = sinon.spy(); + + var message = { + type: 'hello', + copayerId: cid1, + secretNumber : 'mySecret' + }; + + var enc = n1.encode(cid2, message); + n2._onMessage(enc); + n2._deletePeer.calledOnce.should.equal(false); + + }); + + it('should reject join with a incorrect secret number', function() { + var n1 = createN(pk1); + var n2 = createN(pk2); + n2._deletePeer = sinon.spy(); + + var message = { + type: 'hello', + copayerId: cid1, + secretNumber : 'otherSecret' + }; + + var enc = n1.encode(cid2, message); + n2._onMessage(enc); + n2._deletePeer.calledOnce.should.equal(true); + + }); + }); describe('#setHexNonce', function() { diff --git a/views/copayers.html b/views/copayers.html index ca50f0075..201ba9a2d 100644 --- a/views/copayers.html +++ b/views/copayers.html @@ -12,7 +12,7 @@

Waiting copayers

Share this secret with your other copayers

- +
{{$root.wallet.getSecret()}}