From 7dc37a272abeeec73b62c0dffbf1595bc0c41733 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 7 Aug 2014 14:49:29 -0300 Subject: [PATCH 01/75] starting with async networking --- js/models/network/Async.js | 410 ++++++++++++++++++++++++++++++ package.json | 5 +- test/test.network.Async.js | 507 +++++++++++++++++++++++++++++++++++++ 3 files changed, 919 insertions(+), 3 deletions(-) create mode 100644 js/models/network/Async.js create mode 100644 test/test.network.Async.js diff --git a/js/models/network/Async.js b/js/models/network/Async.js new file mode 100644 index 000000000..d7cf029a4 --- /dev/null +++ b/js/models/network/Async.js @@ -0,0 +1,410 @@ +'use strict'; + +var imports = require('soop').imports(); +var EventEmitter = imports.EventEmitter || require('events').EventEmitter; +var bitcore = require('bitcore'); +var AuthMessage = bitcore.AuthMessage; +var util = bitcore.util; +var extend = require('util')._extend; +var io = require('socket.io-client'); + +/* + * Emits + * 'connect' + * when network layout has change (new/lost peers, etc) + * + * 'data' + * when an unknown data type arrives + * + * Provides + * send(toPeerIds, {data}, cb?) + * + */ + +function Network(opts) { + var self = this; + opts = opts || {}; + this.host = opts.host || 'localhost'; + this.port = opts.port || 3001; + this.retryDelay = opts.retryDelay || 3000; + this.reconnectAttempts = opts.reconnectAttempts || 3; + this.cleanUp(); +} + +Network.parent = EventEmitter; + +Network.prototype.cleanUp = function() { + this.started = false; + this.connectedPeers = []; + this.peerId = null; + this.privkey = null; + this.key = null; + this.copayerId = null; + this.allowedCopayerIds = null; + this.isInboundPeerAuth = []; + this.copayerForPeer = {}; + this.connections = {}; + this.criticalErr = ''; + this.closing = 0; + this.tries = 0; + this.removeAllListeners(); +}; + +Network.parent = EventEmitter; + +// Array helpers +Network._arrayDiff = function(a, b) { + var seen = []; + var diff = []; + + for (var i = 0; i < b.length; i++) + seen[b[i]] = true; + + for (var j = 0; j < a.length; j++) + if (!seen[a[j]]) + diff.push(a[j]); + + return diff; +}; + +Network._inArray = function(el, array) { + return array.indexOf(el) > -1; +}; + +Network._arrayPushOnce = function(el, array) { + var ret = false; + if (!Network._inArray(el, array)) { + array.push(el); + ret = true; + } + return ret; +}; + +Network._arrayRemove = function(el, array) { + var pos = array.indexOf(el); + if (pos >= 0) array.splice(pos, 1); + return array; +}; + +Network.prototype.connectedCopayers = function() { + var ret = []; + for (var i in this.connectedPeers) { + var copayerId = this.copayerForPeer[this.connectedPeers[i]]; + if (copayerId) ret.push(copayerId); + } + return ret; +}; + +Network.prototype.connectToCopayers = function(copayerIds) { + var self = this; + var arrayDiff = Network._arrayDiff(copayerIds, self.connectedCopayers()); + + arrayDiff.forEach(function(copayerId) { + if (self.allowedCopayerIds && !self.allowedCopayerIds[copayerId]) { + self._deletePeer(self.peerFromCopayer(copayerId)); + } else { + self.connectTo(copayerId); + } + }); +}; + +Network.prototype._sendHello = function(copayerId) { + this.send(copayerId, { + type: 'hello', + copayerId: this.copayerId, + }); +}; + +Network.prototype._deletePeer = function(peerId) { + delete this.isInboundPeerAuth[peerId]; + delete this.copayerForPeer[peerId]; + + if (this.connections[peerId]) { + this.connections[peerId].close(); + } + delete this.connections[peerId]; + this.connectedPeers = Network._arrayRemove(peerId, this.connectedPeers); +}; + +Network.prototype._addConnectedCopayer = function(copayerId, isInbound) { + var peerId = this.peerFromCopayer(copayerId); + this._addCopayerMap(peerId, copayerId); + Network._arrayPushOnce(peerId, this.connectedPeers); + this.emit('connect', copayerId); +}; + +Network.prototype.getKey = function() { + if (!this.key) { + var key = new bitcore.Key(); + key.private = new Buffer(this.privkey, 'hex'); + key.regenerateSync(); + this.key = key; + } + return this.key; +}; + +//hex version of one's own nonce +Network.prototype.setHexNonce = function(networkNonce) { + if (networkNonce) { + if (networkNonce.length !== 16) + throw new Error('incorrect length of hex nonce'); + this.networkNonce = new Buffer(networkNonce, 'hex'); + } else + this.iterateNonce(); +}; + +//hex version of copayers' nonces +Network.prototype.setHexNonces = function(networkNonces) { + for (var i in networkNonces) { + if (!this.networkNonces) + this.networkNonces = {}; + if (networkNonces[i].length === 16) + this.networkNonces[i] = new Buffer(networkNonces[i], 'hex'); + } +}; + +//for oneself +Network.prototype.getHexNonce = function() { + return this.networkNonce.toString('hex'); +}; + +//for copayers +Network.prototype.getHexNonces = function() { + var networkNoncesHex = []; + for (var i in this.networkNonces) { + networkNoncesHex[i] = this.networkNonces[i].toString('hex'); + } + return networkNoncesHex; +}; + +Network.prototype.iterateNonce = function() { + if (!this.networkNonce || this.networkNonce.length !== 8) { + this.networkNonce = new Buffer(8); + this.networkNonce.fill(0); + } + //the first 4 bytes of a nonce is a unix timestamp in seconds + //the second 4 bytes is just an iterated "sub" nonce + //the whole thing is interpreted as one big endian number + var noncep1 = this.networkNonce.slice(0, 4); + noncep1.writeUInt32BE(Math.floor(Date.now() / 1000), 0); + var noncep2uint = this.networkNonce.slice(4, 8).readUInt32BE(0); + var noncep2 = this.networkNonce.slice(4, 8); + noncep2.writeUInt32BE(noncep2uint + 1, 0); + return this.networkNonce; +}; + +Network.prototype._onMessage = function(enc) { + var key = this.getKey(); + + try { + var prevnonce = this.networkNonces ? this.networkNonces[peerId] : undefined; + var opts = { + prevnonce: prevnonce + }; + var decoded = AuthMessage.decode(key, enc, opts); + + //if no error thrown in the last step, we can set the copayer's nonce + if (!this.networkNonces) + this.networkNonces = {}; + this.networkNonces[peerId] = decoded.nonce; + + var payload = decoded.payload; + } catch (e) { + this._deletePeer(peerId); + return; + } + + + if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) { + this._deletePeer(peerId); + return; + } + + + if (!this.copayerForPeer[peerId] || (isInbound && !this.isInboundPeerAuth[peerId])) { + this._deletePeer(peerId); + return; + } + + var self = this; + switch (payload.type) { + case 'disconnect': + this._onClose(peerId); + break; + default: + this.emit('data', self.copayerForPeer[peerId], payload, isInbound); + } +}; + +Network.prototype._checkAnyPeer = function(msg) { + if (this.connectedPeers.length === 1) { + this.emit('onlyYou'); + } +}; + +Network.prototype._setupConnectionHandlers = function(toCopayerId) { + preconditions.checkState(this.socket); + var self = this; + + var isInbound = toCopayerId ? false : true; + + self.socket.on('connect', function() { + console.log('CONNECTED!'); + self.socket.on('disconnect', function() { + console.log('DISCONNECTED'); + self.cleanUp(); + }); + }); + self.socket.on('message', self._onMessage); + self.socket.on('error', self._handlePeerError); + +}; + +Network.prototype._handlePeerError = function(err) { + console.log('RECV ERROR: ', err); + if (err.message.match(/Could\snot\sconnect\sto peer/)) { + this._checkAnyPeer(); + } else { + this.criticalError = err.message; + } +}; + +Network.prototype._addCopayerMap = function(peerId, copayerId) { + if (!this.copayerForPeer[peerId]) { + if (Object.keys(this.copayerForPeer).length < this.maxPeers) { + this.copayerForPeer[peerId] = copayerId; + } else {} + } +}; + +Network.prototype._setInboundPeerAuth = function(peerId, isAuthenticated) { + this.isInboundPeerAuth[peerId] = isAuthenticated; +}; + +Network.prototype.setCopayerId = function(copayerId) { + if (this.started) { + throw new Error('network already started: can not change peerId') + } + this.copayerId = copayerId; + this.copayerIdBuf = new Buffer(copayerId, 'hex'); + this.peerId = this.peerFromCopayer(this.copayerId); + this._addCopayerMap(this.peerId, copayerId); +}; + + +// TODO cache this. +Network.prototype.peerFromCopayer = function(hex) { + var SIN = bitcore.SIN; + return new SIN(new Buffer(hex, 'hex')).toString(); +}; + +Network.prototype.start = function(opts, openCallback) { + opts = opts || {}; + + if (this.started) return openCallback(); + + if (!this.privkey) + this.privkey = opts.privkey; + + this.maxPeers = opts.maxPeers || this.maxPeers; + + if (opts.token) + this.opts.token = opts.token; + + if (!this.copayerId) + this.setCopayerId(opts.copayerId); + + var self = this; + var setupPeer = function() { + if (self.connectedPeers.length > 0) return; // Already connected! + if (self.socket) { + self.socket.destroy(); + self.socket.removeAllListeners(); + } + + if (!self.criticalError && self.tries < self.reconnectAttempts) { + self.tries++; + self.opts.token = util.sha256(self.peerId).toString('hex'); + self.socket = io.connect(self.host, { + port: self.port + }); + self.socket.emit('subscribe', pubkey); + self.socket.emit('sync', ts); + self.started = true; + self._setupConnectionHandlers(self.socket, copayerId); + + setTimeout(setupPeer, self.retryDelay); // Schedule retry + return; + } + if (self.criticalError && self.criticalError.match(/taken/)) { + self.criticalError = ' Looks like you are already connected to this wallet please close all other Copay Wallets ' + } + + self.emit('serverError', self.criticalError); + self.cleanUp(); + } + + this.tries = 0; + setupPeer(); +}; + +Network.prototype.getOnlinePeerIDs = function() { + return this.connectedPeers; +}; + +Network.prototype.getPeer = function() { + return this.peer; +}; + + +Network.prototype.send = function(copayerIds, payload, cb) { + if (!payload) return cb(); + + var self = this; + if (!copayerIds) { + copayerIds = this.connectedCopayers(); + payload.isBroadcast = 1; + } + + if (typeof copayerIds === 'string') + copayerIds = [copayerIds]; + + var l = copayerIds.length; + var i = 0; + copayerIds.forEach(function(copayerId) { + self.iterateNonce(); + var opts = { + nonce: self.networkNonce + }; + var copayerIdBuf = new Buffer(copayerId, 'hex'); + var message = AuthMessage.encode(copayerIdBuf, self.getKey(), payload, opts); + self.socket.emit('message', message); + if (++i === l && typeof cb === 'function') cb(); + }); +}; + + +Network.prototype.isOnline = function() { + return !!this.socket; +}; + + +Network.prototype.lockIncommingConnections = function(allowedCopayerIdsArray) { + this.allowedCopayerIds = {}; + for (var i in allowedCopayerIdsArray) { + this.allowedCopayerIds[allowedCopayerIdsArray[i]] = true; + } +}; + +Network.prototype.disconnect = function(cb, forced) { + var self = this; + self.closing = 1; + self.send(null, { + type: 'disconnect' + }, function() { + self.cleanUp(); + if (typeof cb === 'function') cb(); + }); +}; + +module.exports = require('soop')(Network); diff --git a/package.json b/package.json index 61b315609..74fa2d40d 100644 --- a/package.json +++ b/package.json @@ -53,10 +53,7 @@ "grunt-contrib-uglify": "^0.5.1", "grunt-contrib-watch": "0.5.3", "grunt-markdown": "0.5.0", - "browser-pack": "2.0.1", "bitcore": "0.1.35", - "node-cryptojs-aes": "0.4.0", - "blanket": "1.1.6", "grunt-mocha-test": "0.8.2", "grunt-shell": "0.6.4", "istanbul": "0.2.10", @@ -69,6 +66,8 @@ "mocha-lcov-reporter": "0.0.1", "mock-fs": "^2.3.1", "node-cryptojs-aes": "0.4.0", + "socket.io-client": "^1.0.6", + "soop": "0.1.5", "travis-cov": "0.2.5", "uglifyify": "1.2.3" }, diff --git a/test/test.network.Async.js b/test/test.network.Async.js new file mode 100644 index 000000000..2c3839e70 --- /dev/null +++ b/test/test.network.Async.js @@ -0,0 +1,507 @@ +'use strict'; + +var chai = chai || require('chai'); +var should = chai.should(); +var expect = chai.expect; +var sinon = sinon || require('sinon'); +var bitcore = bitcore || require('bitcore'); +var Async = require('../js/models/network/Async'); + +describe('Network / Async', function() { + + it('should create an instance', function() { + var n = new Async(); + should.exist(n); + }); + + describe('#Async constructor', function() { + + it('should set reconnect attempts', function() { + var n = new Async(); + n.reconnectAttempts.should.equal(3); + }); + + it('should call cleanUp', function() { + var save = Async.prototype.cleanUp; + Async.prototype.cleanUp = sinon.spy(); + var n = new Async(); + n.cleanUp.calledOnce.should.equal(true); + Async.prototype.cleanUp = save; + }); + }); + + describe('#cleanUp', function() { + + it('should not set netKey', function() { + var n = new Async(); + (n.netKey === undefined).should.equal(true); + }); + + it('should set privkey to null', function() { + var n = new Async(); + n.cleanUp(); + expect(n.privkey).to.equal(null); + }); + + it('should remove handlers', function() { + var n = new Async(); + var save = Async.prototype.removeAllListeners; + var spy = Async.prototype.removeAllListeners = sinon.spy(); + n.cleanUp(); + spy.calledOnce.should.equal(true); + Async.prototype.removeAllListeners = save; + }); + }); + + + describe('#_setupPeerHandlers', function() { + var n = new Async(); + n.peer = {}; + var spy = n.peer.on = sinon.spy(); + it('should setup handlers', function() { + n._setupPeerHandlers(); + spy.calledWith('connection').should.equal(true); + spy.calledWith('open').should.equal(true); + spy.calledWith('error').should.equal(true); + }); + }); + + describe('#_handlePeerOpen', function() { + var n = new Async(); + it('should call openCallback handler', function(done) { + n.peerId = 1; + n.copayerId = 2; + n._handlePeerOpen(function() { + n.connectedPeers.should.deep.equal([1]); + n.copayerForPeer.should.deep.equal({ + 1: 2 + }); + done(); + }); + }); + }); + + describe('#_handlePeerError', function() { + var log = console.log; + var n = new Async(); + it('should call _checkAnyPeer on could not connect error', function() { + var save = n._checkAnyPeer; + var spy = n._checkAnyPeer = sinon.spy(); + var logSpy = console.log = sinon.spy(); + n._handlePeerError({ + message: 'Could not connect to peer xxx' + }); + console.log = log; + spy.called.should.equal(true); + logSpy.called.should.equal(true); + n._checkAnyPeer = save; + }); + + it('should call not call _checkAnyPeer other error', function() { + var save = n._checkAnyPeer; + var spy = n._checkAnyPeer = sinon.spy(); + var otherMessage = 'Could connect to peer xxx'; + var logSpy = console.log = sinon.spy(); + n._handlePeerError({ + message: otherMessage, + }); + console.log = log; + spy.called.should.equal(false); + n.criticalError.should.equal(otherMessage); + logSpy.called.should.equal(true); + n._checkAnyPeer = save; + }); + + }); + + + + describe('#_encode', function() { + + it('should encode data successfully', function() { + var n = new Async(); + var data = new bitcore.Buffer('my data to encode'); + var privkeystr = new bitcore.Buffer('test privkey'); + var privkey = bitcore.util.sha256(privkeystr); + var key = new bitcore.Key(); + key.private = privkey; + key.regenerateSync(); + var encoded = n._encode(key.public, key, data); + should.exist(encoded); + encoded.sig.length.should.not.equal(0); + encoded.pubkey.length.should.not.equal(0); + encoded.encrypted.length.should.not.equal(0); + }); + + }); + + describe('#_decode', function() { + + it('should decode that which was encoded', function() { + var n = new Async(); + var data = new bitcore.Buffer('my data to encrypt'); + var privkeystr = new bitcore.Buffer('test privkey'); + var privkey = bitcore.util.sha256(privkeystr); + var key = new bitcore.Key(); + key.private = privkey; + key.regenerateSync(); + var encoded = n._encode(key.public, key, data); + var decoded = n._decode(key, encoded); + encoded.sig.should.not.equal(0); + decoded.payload.toString().should.equal('my data to encrypt'); + }); + + }); + + describe('#send', function() { + + it('should call _sendToOne for a copayer', function(done) { + var n = new Async(); + n.privkey = bitcore.util.sha256('test'); + + var data = new bitcore.Buffer('my data to send'); + + var privkeystr = new bitcore.Buffer('test privkey'); + var privkey = bitcore.util.sha256(privkeystr); + var key = new bitcore.Key(); + key.private = privkey; + key.regenerateSync(); + + var copayerId = key.public.toString('hex'); + n._sendToOne = function(a1, a2, cb) { + cb(); + }; + var opts = {}; + n.send(copayerId, data, function() { + done(); + }); + + }); + + it('should call _sendToOne with encrypted data for a copayer', function(done) { + var n = new Async(); + n.privkey = bitcore.util.sha256('test'); + + var data = new bitcore.Buffer('my data to send'); + + var privkeystr = new bitcore.Buffer('test privkey'); + var privkey = bitcore.util.sha256(privkeystr); + var key = new bitcore.Key(); + key.private = privkey; + key.regenerateSync(); + + var copayerId = key.public.toString('hex'); + n._sendToOne = function(a1, enc, cb) { + var encPayload = JSON.parse(enc.toString()); + encPayload.sig.length.should.be.greaterThan(0); + cb(); + }; + var opts = {}; + n.send(copayerId, data, function() { + done(); + }); + + }); + + it('should call _sendToOne for a list of copayers', function(done) { + var n = new Async(); + n.privkey = bitcore.util.sha256('test'); + + var data = new bitcore.Buffer('my data to send'); + + var privkeystr = new bitcore.Buffer('test privkey'); + var privkey = bitcore.util.sha256(privkeystr); + var key = new bitcore.Key(); + key.private = privkey; + key.regenerateSync(); + + var copayerIds = [key.public.toString('hex')]; + n._sendToOne = function(a1, a2, cb) { + cb(); + }; + var opts = {}; + n.send(copayerIds, data, function() { + done(); + }); + + }); + }); + + describe('#_onData', function() { + var privkey1 = bitcore.util.sha256('test privkey 1'); + var privkey2 = bitcore.util.sha256('test privkey 2'); + var privkey3 = bitcore.util.sha256('test privkey 2'); + + var key1 = new bitcore.Key(); + key1.private = privkey1; + key1.regenerateSync(); + + var key2 = new bitcore.Key(); + key2.private = privkey2; + key2.regenerateSync(); + + var key3 = new bitcore.Key(); + key3.private = privkey3; + key3.regenerateSync(); + + it('should not reject data sent from a peer with hijacked pubkey', function() { + var n = new Async(); + n.privkey = key2.private.toString('hex'); + + var message = { + type: 'hello', + copayerId: key1.public.toString('hex') + }; + var messagestr = JSON.stringify(message); + var messagebuf = new Buffer(messagestr); + + var encoded = n._encode(key2.public, key1, messagebuf); + var encodedstr = JSON.stringify(encoded); + var encodeduint = new Buffer(encodedstr); + + var isInbound = true; + var peerId = new bitcore.SIN(key1.public); + + n._deletePeer = sinon.spy(); + + n._onData(encodeduint, isInbound, peerId); + n._deletePeer.calledOnce.should.equal(false); + }); + + it('should reject data sent from a peer with hijacked pubkey', function() { + var n = new Async(); + n.privkey = key2.private.toString('hex'); + + var message = { + type: 'hello', + copayerId: key3.public.toString('hex') //MITM pubkey 3 + }; + var messagestr = JSON.stringify(message); + var messagebuf = new Buffer(messagestr); + + var encoded = n._encode(key2.public, key1, messagebuf); + var encodedstr = JSON.stringify(encoded); + var encodeduint = new Buffer(encodedstr); + + var isInbound = true; + var peerId = new bitcore.SIN(key1.public); + + n._deletePeer = sinon.spy(); + + n._onData(encodeduint, isInbound, peerId); + n._deletePeer.calledOnce.should.equal(true); + n._deletePeer.getCall(0).args[0].should.equal(peerId); + n._deletePeer.getCall(0).args[1].should.equal('incorrect pubkey for peerId'); + }); + + it('should not reject data sent from a peer with no previously set nonce but who is setting one now', function() { + var n = new Async(); + n.privkey = key2.private.toString('hex'); + //n.networkNonces = {}; + //n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('0000000000000001', 'hex'); //previously used nonce + + var message = { + type: 'hello', + copayerId: key1.public.toString('hex') + }; + var messagestr = JSON.stringify(message); + var messagebuf = new Buffer(messagestr); + + var opts = {nonce: new Buffer('0000000000000001', 'hex')}; //message send with new nonce + var encoded = n._encode(key2.public, key1, messagebuf, opts); + var encodedstr = JSON.stringify(encoded); + var encodeduint = new Buffer(encodedstr); + + var isInbound = true; + var peerId = new bitcore.SIN(key1.public); + + n._deletePeer = sinon.spy(); + + n._onData(encodeduint, isInbound, peerId); + n._deletePeer.calledOnce.should.equal(false); + n.getHexNonces()[(new bitcore.SIN(key1.public)).toString()].toString('hex').should.equal('0000000000000001'); + }); + + it('should not reject data sent from a peer with a really big new nonce', function() { + var n = new Async(); + n.privkey = key2.private.toString('hex'); + n.networkNonces = {}; + n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000001', 'hex'); //previously used nonce + + var message = { + type: 'hello', + copayerId: key1.public.toString('hex') + }; + var messagestr = JSON.stringify(message); + var messagebuf = new Buffer(messagestr); + + var opts = {nonce: new Buffer('5000000000000002', 'hex')}; //message send with new nonce + var encoded = n._encode(key2.public, key1, messagebuf, opts); + var encodedstr = JSON.stringify(encoded); + var encodeduint = new Buffer(encodedstr); + + var isInbound = true; + var peerId = new bitcore.SIN(key1.public); + + n._deletePeer = sinon.spy(); + + n._onData(encodeduint, isInbound, peerId); + n._deletePeer.calledOnce.should.equal(false); + }); + + it('should not reject data sent from a peer with a really big new nonce', function() { + var n = new Async(); + n.privkey = key2.private.toString('hex'); + n.networkNonces = {}; + n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000001', 'hex'); //previously used nonce + + var message = { + type: 'hello', + copayerId: key1.public.toString('hex') + }; + var messagestr = JSON.stringify(message); + var messagebuf = new Buffer(messagestr); + + var opts = {nonce: new Buffer('5000000000000002', 'hex')}; //message send with new nonce + var encoded = n._encode(key2.public, key1, messagebuf, opts); + var encodedstr = JSON.stringify(encoded); + var encodeduint = new Buffer(encodedstr); + + var isInbound = true; + var peerId = new bitcore.SIN(key1.public); + + n._deletePeer = sinon.spy(); + + n._onData(encodeduint, isInbound, peerId); + n._deletePeer.calledOnce.should.equal(false); + }); + + it('should reject data sent from a peer with an outdated nonce', function() { + var n = new Async(); + n.privkey = key2.private.toString('hex'); + n.networkNonces = {}; + n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('0000000000000002', 'hex'); //previously used nonce + + var message = { + type: 'hello', + copayerId: key1.public.toString('hex') + }; + var messagestr = JSON.stringify(message); + var messagebuf = new Buffer(messagestr); + + var opts = {nonce: new Buffer('0000000000000001', 'hex')}; //message send with old nonce + var encoded = n._encode(key2.public, key1, messagebuf, opts); + var encodedstr = JSON.stringify(encoded); + var encodeduint = new Buffer(encodedstr); + + var isInbound = true; + var peerId = new bitcore.SIN(key1.public); + + n._deletePeer = sinon.spy(); + + n._onData(encodeduint, isInbound, peerId); + n._deletePeer.calledOnce.should.equal(true); + }); + + it('should reject data sent from a peer with a really big outdated nonce', function() { + var n = new Async(); + n.privkey = key2.private.toString('hex'); + n.networkNonces = {}; + n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000002', 'hex'); //previously used nonce + + var message = { + type: 'hello', + copayerId: key1.public.toString('hex') + }; + var messagestr = JSON.stringify(message); + var messagebuf = new Buffer(messagestr); + + var opts = {nonce: new Buffer('5000000000000001', 'hex')}; //message send with old nonce + var encoded = n._encode(key2.public, key1, messagebuf, opts); + var encodedstr = JSON.stringify(encoded); + var encodeduint = new Buffer(encodedstr); + + var isInbound = true; + var peerId = new bitcore.SIN(key1.public); + + n._deletePeer = sinon.spy(); + + n._onData(encodeduint, isInbound, peerId); + n._deletePeer.calledOnce.should.equal(true); + }); + + }); + + describe('#setHexNonce', function() { + + it('should set a nonce from a hex value', function() { + var hex = '0000000000000000'; + var n = new Async(); + n.setHexNonce(hex); + n.getHexNonce().should.equal(hex); + n.networkNonce.toString('hex').should.equal(hex); + }); + + }); + + describe('#setHexNonces', function() { + + it('should set a nonce from a hex value', function() { + var hex = '0000000000000000'; + var n = new Async(); + n.setHexNonces({fakeid: hex}); + n.getHexNonces().fakeid.should.equal(hex); + }); + + }); + + describe('#getHexNonce', function() { + + it('should get a nonce hex value', function() { + var hex = '0000000000000000'; + var n = new Async(); + n.setHexNonce(hex); + n.getHexNonce().should.equal(hex); + }); + + }); + + describe('#getHexNonces', function() { + + it('should get a nonce from a hex value', function() { + var hex = '0000000000000000'; + var n = new Async(); + n.setHexNonces({fakeid: hex}); + n.getHexNonces().fakeid.should.equal(hex); + }); + + }); + + describe('#iterateNonce', function() { + + it('should set a nonce not already set', function() { + var n = new Async(); + n.iterateNonce(); + n.networkNonce.slice(4, 8).toString('hex').should.equal('00000001'); + n.networkNonce.slice(0, 4).toString('hex').should.not.equal('00000000'); + }); + + it('called twice should increment', function() { + var n = new Async(); + n.iterateNonce(); + n.networkNonce.slice(4, 8).toString('hex').should.equal('00000001'); + n.iterateNonce(); + n.networkNonce.slice(4, 8).toString('hex').should.equal('00000002'); + }); + + it('should set the first byte to the most significant "now" digit', function() { + var n = new Async(); + n.iterateNonce(); + var buf = new Buffer(4); + buf.writeUInt32BE(Math.floor(Date.now()/1000), 0); + n.networkNonce[0].should.equal(buf[0]); + }); + + }); + +}); From 48dd8549efc6356c7517ea9add8d7866c4dc48c4 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 7 Aug 2014 15:23:17 -0300 Subject: [PATCH 02/75] fixing stuff --- js/models/core/WalletFactory.js | 4 +- js/models/network/Async.js | 50 ++++++----------- test/test.network.Async.js | 99 --------------------------------- 3 files changed, 18 insertions(+), 135 deletions(-) diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index 909fba68f..945a61fdf 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -5,7 +5,7 @@ var PublicKeyRing = require('./PublicKeyRing'); var PrivateKey = require('./PrivateKey'); var Wallet = require('./Wallet'); -var WebRTC = module.exports.WebRTC = require('../network/WebRTC'); +var Async = module.exports.Async = require('../network/Async'); var Insight = module.exports.Insight = require('../blockchain/Insight'); var StorageLocalEncrypted = module.exports.StorageLocalEncrypted = require('../storage/LocalEncrypted'); @@ -19,7 +19,7 @@ function WalletFactory(config, version) { config = config || {}; this.Storage = config.Storage || StorageLocalEncrypted; - this.Network = config.Network || WebRTC; + this.Network = config.Network || Async; this.Blockchain = config.Blockchain || Insight; this.storage = new this.Storage(config.storage); diff --git a/js/models/network/Async.js b/js/models/network/Async.js index d7cf029a4..9d17c621f 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -7,6 +7,7 @@ var AuthMessage = bitcore.AuthMessage; var util = bitcore.util; var extend = require('util')._extend; var io = require('socket.io-client'); +var preconditions = require('preconditions').singleton(); /* * Emits @@ -26,8 +27,6 @@ function Network(opts) { opts = opts || {}; this.host = opts.host || 'localhost'; this.port = opts.port || 3001; - this.retryDelay = opts.retryDelay || 3000; - this.reconnectAttempts = opts.reconnectAttempts || 3; this.cleanUp(); } @@ -46,7 +45,6 @@ Network.prototype.cleanUp = function() { this.connections = {}; this.criticalErr = ''; this.closing = 0; - this.tries = 0; this.removeAllListeners(); }; @@ -232,7 +230,7 @@ Network.prototype._onMessage = function(enc) { this._onClose(peerId); break; default: - this.emit('data', self.copayerForPeer[peerId], payload, isInbound); + this.emit('data', self.copayerForPeer[peerId], payload); } }; @@ -314,38 +312,22 @@ Network.prototype.start = function(opts, openCallback) { if (!this.copayerId) this.setCopayerId(opts.copayerId); - var self = this; - var setupPeer = function() { - if (self.connectedPeers.length > 0) return; // Already connected! - if (self.socket) { - self.socket.destroy(); - self.socket.removeAllListeners(); - } - - if (!self.criticalError && self.tries < self.reconnectAttempts) { - self.tries++; - self.opts.token = util.sha256(self.peerId).toString('hex'); - self.socket = io.connect(self.host, { - port: self.port - }); - self.socket.emit('subscribe', pubkey); - self.socket.emit('sync', ts); - self.started = true; - self._setupConnectionHandlers(self.socket, copayerId); - - setTimeout(setupPeer, self.retryDelay); // Schedule retry - return; - } - if (self.criticalError && self.criticalError.match(/taken/)) { - self.criticalError = ' Looks like you are already connected to this wallet please close all other Copay Wallets ' - } - - self.emit('serverError', self.criticalError); - self.cleanUp(); + if (this.connectedPeers.length > 0) return; // Already connected! + if (this.socket) { + this.socket.destroy(); + this.socket.removeAllListeners(); } - this.tries = 0; - setupPeer(); + this.socket = io.connect(this.host, { + port: this.port + }); + this.socket.emit('subscribe', this.getKey().public.toString('hex')); + this.socket.emit('sync'); + this.started = true; + this._setupConnectionHandlers(this.socket); + + //this.emit('serverError', self.criticalError); + }; Network.prototype.getOnlinePeerIDs = function() { diff --git a/test/test.network.Async.js b/test/test.network.Async.js index 2c3839e70..3f674c3ff 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -54,105 +54,6 @@ describe('Network / Async', function() { }); - describe('#_setupPeerHandlers', function() { - var n = new Async(); - n.peer = {}; - var spy = n.peer.on = sinon.spy(); - it('should setup handlers', function() { - n._setupPeerHandlers(); - spy.calledWith('connection').should.equal(true); - spy.calledWith('open').should.equal(true); - spy.calledWith('error').should.equal(true); - }); - }); - - describe('#_handlePeerOpen', function() { - var n = new Async(); - it('should call openCallback handler', function(done) { - n.peerId = 1; - n.copayerId = 2; - n._handlePeerOpen(function() { - n.connectedPeers.should.deep.equal([1]); - n.copayerForPeer.should.deep.equal({ - 1: 2 - }); - done(); - }); - }); - }); - - describe('#_handlePeerError', function() { - var log = console.log; - var n = new Async(); - it('should call _checkAnyPeer on could not connect error', function() { - var save = n._checkAnyPeer; - var spy = n._checkAnyPeer = sinon.spy(); - var logSpy = console.log = sinon.spy(); - n._handlePeerError({ - message: 'Could not connect to peer xxx' - }); - console.log = log; - spy.called.should.equal(true); - logSpy.called.should.equal(true); - n._checkAnyPeer = save; - }); - - it('should call not call _checkAnyPeer other error', function() { - var save = n._checkAnyPeer; - var spy = n._checkAnyPeer = sinon.spy(); - var otherMessage = 'Could connect to peer xxx'; - var logSpy = console.log = sinon.spy(); - n._handlePeerError({ - message: otherMessage, - }); - console.log = log; - spy.called.should.equal(false); - n.criticalError.should.equal(otherMessage); - logSpy.called.should.equal(true); - n._checkAnyPeer = save; - }); - - }); - - - - describe('#_encode', function() { - - it('should encode data successfully', function() { - var n = new Async(); - var data = new bitcore.Buffer('my data to encode'); - var privkeystr = new bitcore.Buffer('test privkey'); - var privkey = bitcore.util.sha256(privkeystr); - var key = new bitcore.Key(); - key.private = privkey; - key.regenerateSync(); - var encoded = n._encode(key.public, key, data); - should.exist(encoded); - encoded.sig.length.should.not.equal(0); - encoded.pubkey.length.should.not.equal(0); - encoded.encrypted.length.should.not.equal(0); - }); - - }); - - describe('#_decode', function() { - - it('should decode that which was encoded', function() { - var n = new Async(); - var data = new bitcore.Buffer('my data to encrypt'); - var privkeystr = new bitcore.Buffer('test privkey'); - var privkey = bitcore.util.sha256(privkeystr); - var key = new bitcore.Key(); - key.private = privkey; - key.regenerateSync(); - var encoded = n._encode(key.public, key, data); - var decoded = n._decode(key, encoded); - encoded.sig.should.not.equal(0); - decoded.payload.toString().should.equal('my data to encrypt'); - }); - - }); - describe('#send', function() { it('should call _sendToOne for a copayer', function(done) { From 4f359c05cadc3261e1a1357fc67341e9848e6084 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 7 Aug 2014 18:10:02 -0300 Subject: [PATCH 03/75] basic stuff working --- config.js | 73 ++++---------------------------------- js/models/network/Async.js | 11 +++--- 2 files changed, 11 insertions(+), 73 deletions(-) diff --git a/config.js b/config.js index 4da6227cc..73293528c 100644 --- a/config.js +++ b/config.js @@ -1,7 +1,7 @@ 'use strict'; var defaultConfig = { // DEFAULT network (livenet or testnet) - networkName: 'livenet', + networkName: 'testnet', forceNetwork: false, // DEFAULT unit: Bit @@ -15,71 +15,10 @@ var defaultConfig = { minAmountSatoshi: 5400, }, - // network layer (PeerJS) config + // network layer config network: { - // Use this to run your own local PeerJS server - // with params: ./peerjs -p 10009 -k '6d6d751ea61e26f2' - /* -key: '6d6d751ea61e26f2', -host: 'localhost', -port: 10009, -path: '/', -*/ - - // Use this to connect to bitpay's PeerJS server - key: 'satoshirocks', - // host: '162.242.219.26', - // port: 10000, - // secure: false, - host: 'live.copay.io', - port: 9000, - secure: true, - path: '/', - - // other PeerJS config - maxPeers: 15, - debug: 2, - - // PeerJS internal config object - config: { - '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' - // } - ] - } + host: 'localhost', + port: 3001 }, // wallet default config @@ -96,14 +35,14 @@ path: '/', // blockchain service API config blockchain: { schema: 'https', - host: 'insight.bitpay.com', + host: 'test-insight.bitpay.com', port: 443, retryDelay: 1000, }, // socket service API config socket: { schema: 'https', - host: 'insight.bitpay.com', + host: 'test-insight.bitpay.com', port: 443, reconnectDelay: 1000, }, diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 9d17c621f..1558abddc 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -240,16 +240,14 @@ Network.prototype._checkAnyPeer = function(msg) { } }; -Network.prototype._setupConnectionHandlers = function(toCopayerId) { +Network.prototype._setupConnectionHandlers = function() { preconditions.checkState(this.socket); var self = this; - var isInbound = toCopayerId ? false : true; - self.socket.on('connect', function() { - console.log('CONNECTED!'); + alert('CONNECTED!'); self.socket.on('disconnect', function() { - console.log('DISCONNECTED'); + alert('DISCONNECTED'); self.cleanUp(); }); }); @@ -297,6 +295,7 @@ Network.prototype.peerFromCopayer = function(hex) { }; Network.prototype.start = function(opts, openCallback) { + alert('start'); opts = opts || {}; if (this.started) return openCallback(); @@ -324,7 +323,7 @@ Network.prototype.start = function(opts, openCallback) { this.socket.emit('subscribe', this.getKey().public.toString('hex')); this.socket.emit('sync'); this.started = true; - this._setupConnectionHandlers(this.socket); + this._setupConnectionHandlers(); //this.emit('serverError', self.criticalError); From 7c14706e9261bf470e1e023b92400f49ab4db793 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 7 Aug 2014 18:55:13 -0300 Subject: [PATCH 04/75] add socket.io-browserify --- js/models/network/Async.js | 7 ++++--- package.json | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 1558abddc..e779480fa 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -6,7 +6,7 @@ var bitcore = require('bitcore'); var AuthMessage = bitcore.AuthMessage; var util = bitcore.util; var extend = require('util')._extend; -var io = require('socket.io-client'); +var io = require('socket.io-browserify'); var preconditions = require('preconditions').singleton(); /* @@ -244,6 +244,7 @@ Network.prototype._setupConnectionHandlers = function() { preconditions.checkState(this.socket); var self = this; + alert('setup'); self.socket.on('connect', function() { alert('CONNECTED!'); self.socket.on('disconnect', function() { @@ -295,7 +296,6 @@ Network.prototype.peerFromCopayer = function(hex) { }; Network.prototype.start = function(opts, openCallback) { - alert('start'); opts = opts || {}; if (this.started) return openCallback(); @@ -318,7 +318,8 @@ Network.prototype.start = function(opts, openCallback) { } this.socket = io.connect(this.host, { - port: this.port + port: this.port, + reconnection: false }); this.socket.emit('subscribe', this.getKey().public.toString('hex')); this.socket.emit('sync'); diff --git a/package.json b/package.json index 74fa2d40d..d256ffbab 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "mocha-lcov-reporter": "0.0.1", "optimist": "^0.6.1", "preconditions": "^1.0.7", - "sinon": "1.9.1" + "sinon": "1.9.1", + "socket.io-browserify": "^0.9.6" }, "scripts": { "shell": "node shell/scripts/launch.js", From e7980aefaa17be75e66a95e62a756e5b2444e0f0 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 7 Aug 2014 18:58:12 -0300 Subject: [PATCH 05/75] remove onlyYou message --- js/models/core/WalletFactory.js | 3 --- js/models/network/Async.js | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index 945a61fdf..d45213053 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -249,9 +249,6 @@ WalletFactory.prototype.joinCreateSession = function(secret, nickname, passphras self.network.on('connected', function(sender, data) { connectedOnce = true; }); - self.network.on('onlyYou', function(sender, data) { - return cb(connectedOnce ? 'walletFull' : 'joinError'); - }); self.network.on('serverError', function() { return cb('joinError'); diff --git a/js/models/network/Async.js b/js/models/network/Async.js index e779480fa..8fb37bc3e 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -258,6 +258,7 @@ Network.prototype._setupConnectionHandlers = function() { }; Network.prototype._handlePeerError = function(err) { + alert(err); console.log('RECV ERROR: ', err); if (err.message.match(/Could\snot\sconnect\sto peer/)) { this._checkAnyPeer(); From 9c2b9eb23698e7de2ed050d810dd2fcde896f2c3 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 7 Aug 2014 18:58:36 -0300 Subject: [PATCH 06/75] only you --- js/models/network/Async.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 8fb37bc3e..35b08ca97 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -234,12 +234,6 @@ Network.prototype._onMessage = function(enc) { } }; -Network.prototype._checkAnyPeer = function(msg) { - if (this.connectedPeers.length === 1) { - this.emit('onlyYou'); - } -}; - Network.prototype._setupConnectionHandlers = function() { preconditions.checkState(this.socket); var self = this; From 3793023c81cbfd996504ad5d17968609652e37c1 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 7 Aug 2014 19:02:01 -0300 Subject: [PATCH 07/75] fix error handling --- js/models/network/Async.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 35b08ca97..945119a32 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -247,18 +247,13 @@ Network.prototype._setupConnectionHandlers = function() { }); }); self.socket.on('message', self._onMessage); - self.socket.on('error', self._handlePeerError); + self.socket.on('error', self._handleError); }; -Network.prototype._handlePeerError = function(err) { - alert(err); +Network.prototype._handleError = function(err) { console.log('RECV ERROR: ', err); - if (err.message.match(/Could\snot\sconnect\sto peer/)) { - this._checkAnyPeer(); - } else { - this.criticalError = err.message; - } + this.criticalError = err.message; }; Network.prototype._addCopayerMap = function(peerId, copayerId) { From 0ceaea9f958146dbc60d5ca7cf43e4510208504e Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 7 Aug 2014 19:34:48 -0300 Subject: [PATCH 08/75] =?UTF-8?q?socket.io+browserify=3D=F0=9F=98=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/models/network/Async.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 945119a32..0d0e3550e 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -6,7 +6,7 @@ var bitcore = require('bitcore'); var AuthMessage = bitcore.AuthMessage; var util = bitcore.util; var extend = require('util')._extend; -var io = require('socket.io-browserify'); +var io = require('socket.io-client'); var preconditions = require('preconditions').singleton(); /* @@ -238,7 +238,6 @@ Network.prototype._setupConnectionHandlers = function() { preconditions.checkState(this.socket); var self = this; - alert('setup'); self.socket.on('connect', function() { alert('CONNECTED!'); self.socket.on('disconnect', function() { @@ -307,9 +306,8 @@ Network.prototype.start = function(opts, openCallback) { this.socket.removeAllListeners(); } - this.socket = io.connect(this.host, { - port: this.port, - reconnection: false + this.socket = io.connect(this.host + ':' + this.port, { + //reconnection: false, }); this.socket.emit('subscribe', this.getKey().public.toString('hex')); this.socket.emit('sync'); From bfd4bbe0213d776d566e7506e867c325b1410817 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 7 Aug 2014 20:15:55 -0300 Subject: [PATCH 09/75] getting to intermediate screen! --- js/models/core/Wallet.js | 4 +++- js/models/network/Async.js | 13 +++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index f2bb28c6b..14725c060 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -451,10 +451,12 @@ Wallet.prototype.netStart = function(callback) { } net.start(startOpts, function() { + alert('start callback!'); self.emit('ready', net.getPeer()); setTimeout(function() { self.emit('publicKeyRingUpdated', true); - self.scheduleConnect(); + //self.scheduleConnect(); + // no connection logic for now self.emit('txProposalsUpdated'); }, 10); }); diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 0d0e3550e..cacd57122 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -234,7 +234,7 @@ Network.prototype._onMessage = function(enc) { } }; -Network.prototype._setupConnectionHandlers = function() { +Network.prototype._setupConnectionHandlers = function(cb) { preconditions.checkState(this.socket); var self = this; @@ -244,6 +244,7 @@ Network.prototype._setupConnectionHandlers = function() { alert('DISCONNECTED'); self.cleanUp(); }); + if (typeof cb === 'function') cb(); }); self.socket.on('message', self._onMessage); self.socket.on('error', self._handleError); @@ -300,7 +301,10 @@ Network.prototype.start = function(opts, openCallback) { if (!this.copayerId) this.setCopayerId(opts.copayerId); - if (this.connectedPeers.length > 0) return; // Already connected! + if (this.connectedPeers.length > 0) { + // already connected + return; + } if (this.socket) { this.socket.destroy(); this.socket.removeAllListeners(); @@ -309,10 +313,11 @@ Network.prototype.start = function(opts, openCallback) { this.socket = io.connect(this.host + ':' + this.port, { //reconnection: false, }); - this.socket.emit('subscribe', this.getKey().public.toString('hex')); + this._setupConnectionHandlers(openCallback); + var pubkey = this.getKey().public.toString('hex'); + this.socket.emit('subscribe', pubkey); this.socket.emit('sync'); this.started = true; - this._setupConnectionHandlers(); //this.emit('serverError', self.criticalError); From 3ebacd50cc7630452c2234e7caf21bbff94e53df Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 12 Aug 2014 16:41:45 -0400 Subject: [PATCH 10/75] working towards refactoring network --- js/models/core/Wallet.js | 6 ++- js/models/core/WalletFactory.js | 2 +- js/models/network/Async.js | 70 +++++++++++++++++---------------- package.json | 5 +-- test/test.network.Async.js | 44 ++++++++++++--------- 5 files changed, 70 insertions(+), 57 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 14725c060..9ab95fa7e 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -89,6 +89,7 @@ Wallet.prototype.seedCopayer = function(pubKey) { this.seededCopayerId = pubKey; }; +// not being used now Wallet.prototype.connectToAll = function() { var all = this.publicKeyRing.getAllCopayerIds(); @@ -317,7 +318,7 @@ Wallet.prototype._handleAddressBook = function(senderId, data, isInbound) { Wallet.prototype._handleData = function(senderId, data, isInbound) { - // TODO check message signature + alert('data '+JSON.stringify(data)); if (data.type !== 'walletId' && this.id !== data.walletId) { this.emit('badMessage', senderId); @@ -451,7 +452,6 @@ Wallet.prototype.netStart = function(callback) { } net.start(startOpts, function() { - alert('start callback!'); self.emit('ready', net.getPeer()); setTimeout(function() { self.emit('publicKeyRingUpdated', true); @@ -462,6 +462,8 @@ Wallet.prototype.netStart = function(callback) { }); }; + +// not being used now Wallet.prototype.scheduleConnect = function() { var self = this; if (self.network.isOnline()) { diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index d45213053..c9e32ed06 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -255,7 +255,7 @@ WalletFactory.prototype.joinCreateSession = function(secret, nickname, passphras }); self.network.start(opts, function() { - self.network.connectTo(s.pubKey); + self.network.greet(s.pubKey); self.network.on('data', function(sender, data) { if (data.type === 'walletId') { diff --git a/js/models/network/Async.js b/js/models/network/Async.js index cacd57122..a3e9bbd53 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -93,19 +93,6 @@ Network.prototype.connectedCopayers = function() { return ret; }; -Network.prototype.connectToCopayers = function(copayerIds) { - var self = this; - var arrayDiff = Network._arrayDiff(copayerIds, self.connectedCopayers()); - - arrayDiff.forEach(function(copayerId) { - if (self.allowedCopayerIds && !self.allowedCopayerIds[copayerId]) { - self._deletePeer(self.peerFromCopayer(copayerId)); - } else { - self.connectTo(copayerId); - } - }); -}; - Network.prototype._sendHello = function(copayerId) { this.send(copayerId, { type: 'hello', @@ -193,9 +180,9 @@ Network.prototype.iterateNonce = function() { Network.prototype._onMessage = function(enc) { var key = this.getKey(); - + var sender = enc.pubkey; try { - var prevnonce = this.networkNonces ? this.networkNonces[peerId] : undefined; + var prevnonce = this.networkNonces ? this.networkNonces[sender] : undefined; var opts = { prevnonce: prevnonce }; @@ -204,33 +191,43 @@ Network.prototype._onMessage = function(enc) { //if no error thrown in the last step, we can set the copayer's nonce if (!this.networkNonces) this.networkNonces = {}; - this.networkNonces[peerId] = decoded.nonce; + this.networkNonces[sender] = decoded.nonce; var payload = decoded.payload; } catch (e) { - this._deletePeer(peerId); + this._deletePeer(sender); + alert('quit 1'); return; } if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) { - this._deletePeer(peerId); + this._deletePeer(sender); + alert('quit 2'); return; } - if (!this.copayerForPeer[peerId] || (isInbound && !this.isInboundPeerAuth[peerId])) { - this._deletePeer(peerId); + + // TODO + /* + if (!this.copayerForPeer[sender] || (isInbound && !this.isInboundPeerAuth[sender])) { + this._deletePeer(sender); + alert('quit 3'); return; } + */ var self = this; switch (payload.type) { case 'disconnect': - this._onClose(peerId); + this._onClose(sender); + break; + case 'hello': + this._addConnectedCopayer(payload.copayerId); break; default: - this.emit('data', self.copayerForPeer[peerId], payload); + this.emit('data', self.copayerForPeer[sender], payload); } }; @@ -239,23 +236,28 @@ Network.prototype._setupConnectionHandlers = function(cb) { var self = this; self.socket.on('connect', function() { - alert('CONNECTED!'); self.socket.on('disconnect', function() { - alert('DISCONNECTED'); self.cleanUp(); }); if (typeof cb === 'function') cb(); }); - self.socket.on('message', self._onMessage); - self.socket.on('error', self._handleError); + self.socket.on('message', self._onMessage.bind(self)); + self.socket.on('error', self._onError.bind(self)); }; -Network.prototype._handleError = function(err) { +Network.prototype._onError = function(err) { console.log('RECV ERROR: ', err); + console.log(err.stack); this.criticalError = err.message; }; +Network.prototype.greet = function(copayerId) { + this._sendHello(copayerId); + var peerId = this.peerFromCopayer(copayerId); + this._addCopayerMap(peerId, copayerId); +}; + Network.prototype._addCopayerMap = function(peerId, copayerId) { if (!this.copayerForPeer[peerId]) { if (Object.keys(this.copayerForPeer).length < this.maxPeers) { @@ -264,8 +266,8 @@ Network.prototype._addCopayerMap = function(peerId, copayerId) { } }; -Network.prototype._setInboundPeerAuth = function(peerId, isAuthenticated) { - this.isInboundPeerAuth[peerId] = isAuthenticated; +Network.prototype._setInboundPeerAuth = function(peerId) { + this.isInboundPeerAuth[peerId] = true; }; Network.prototype.setCopayerId = function(copayerId) { @@ -311,12 +313,12 @@ Network.prototype.start = function(opts, openCallback) { } this.socket = io.connect(this.host + ':' + this.port, { - //reconnection: false, + reconnection: false, }); this._setupConnectionHandlers(openCallback); var pubkey = this.getKey().public.toString('hex'); this.socket.emit('subscribe', pubkey); - this.socket.emit('sync'); + //this.socket.emit('sync'); this.started = true; //this.emit('serverError', self.criticalError); @@ -333,7 +335,7 @@ Network.prototype.getPeer = function() { Network.prototype.send = function(copayerIds, payload, cb) { - if (!payload) return cb(); + preconditions.checkArgument(payload); var self = this; if (!copayerIds) { @@ -353,9 +355,11 @@ Network.prototype.send = function(copayerIds, payload, cb) { }; var copayerIdBuf = new Buffer(copayerId, 'hex'); var message = AuthMessage.encode(copayerIdBuf, self.getKey(), payload, opts); + console.log(JSON.stringify(payload)); + console.log(JSON.stringify(message)); self.socket.emit('message', message); - if (++i === l && typeof cb === 'function') cb(); }); + if (typeof cb === 'function') cb(); }; diff --git a/package.json b/package.json index d256ffbab..d68f10f9f 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,7 @@ "mocha-lcov-reporter": "0.0.1", "optimist": "^0.6.1", "preconditions": "^1.0.7", - "sinon": "1.9.1", - "socket.io-browserify": "^0.9.6" + "sinon": "1.9.1" }, "scripts": { "shell": "node shell/scripts/launch.js", @@ -67,7 +66,7 @@ "mocha-lcov-reporter": "0.0.1", "mock-fs": "^2.3.1", "node-cryptojs-aes": "0.4.0", - "socket.io-client": "^1.0.6", + "socket.io-client": "1.0.6", "soop": "0.1.5", "travis-cov": "0.2.5", "uglifyify": "1.2.3" diff --git a/test/test.network.Async.js b/test/test.network.Async.js index 3f674c3ff..89fce1cd4 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -16,11 +16,6 @@ describe('Network / Async', function() { describe('#Async constructor', function() { - it('should set reconnect attempts', function() { - var n = new Async(); - n.reconnectAttempts.should.equal(3); - }); - it('should call cleanUp', function() { var save = Async.prototype.cleanUp; Async.prototype.cleanUp = sinon.spy(); @@ -53,7 +48,6 @@ describe('Network / Async', function() { }); }); - describe('#send', function() { it('should call _sendToOne for a copayer', function(done) { @@ -208,7 +202,9 @@ describe('Network / Async', function() { var messagestr = JSON.stringify(message); var messagebuf = new Buffer(messagestr); - var opts = {nonce: new Buffer('0000000000000001', 'hex')}; //message send with new nonce + var opts = { + nonce: new Buffer('0000000000000001', 'hex') + }; //message send with new nonce var encoded = n._encode(key2.public, key1, messagebuf, opts); var encodedstr = JSON.stringify(encoded); var encodeduint = new Buffer(encodedstr); @@ -236,7 +232,9 @@ describe('Network / Async', function() { var messagestr = JSON.stringify(message); var messagebuf = new Buffer(messagestr); - var opts = {nonce: new Buffer('5000000000000002', 'hex')}; //message send with new nonce + var opts = { + nonce: new Buffer('5000000000000002', 'hex') + }; //message send with new nonce var encoded = n._encode(key2.public, key1, messagebuf, opts); var encodedstr = JSON.stringify(encoded); var encodeduint = new Buffer(encodedstr); @@ -263,7 +261,9 @@ describe('Network / Async', function() { var messagestr = JSON.stringify(message); var messagebuf = new Buffer(messagestr); - var opts = {nonce: new Buffer('5000000000000002', 'hex')}; //message send with new nonce + var opts = { + nonce: new Buffer('5000000000000002', 'hex') + }; //message send with new nonce var encoded = n._encode(key2.public, key1, messagebuf, opts); var encodedstr = JSON.stringify(encoded); var encodeduint = new Buffer(encodedstr); @@ -290,7 +290,9 @@ describe('Network / Async', function() { var messagestr = JSON.stringify(message); var messagebuf = new Buffer(messagestr); - var opts = {nonce: new Buffer('0000000000000001', 'hex')}; //message send with old nonce + var opts = { + nonce: new Buffer('0000000000000001', 'hex') + }; //message send with old nonce var encoded = n._encode(key2.public, key1, messagebuf, opts); var encodedstr = JSON.stringify(encoded); var encodeduint = new Buffer(encodedstr); @@ -317,7 +319,9 @@ describe('Network / Async', function() { var messagestr = JSON.stringify(message); var messagebuf = new Buffer(messagestr); - var opts = {nonce: new Buffer('5000000000000001', 'hex')}; //message send with old nonce + var opts = { + nonce: new Buffer('5000000000000001', 'hex') + }; //message send with old nonce var encoded = n._encode(key2.public, key1, messagebuf, opts); var encodedstr = JSON.stringify(encoded); var encodeduint = new Buffer(encodedstr); @@ -334,7 +338,7 @@ describe('Network / Async', function() { }); describe('#setHexNonce', function() { - + it('should set a nonce from a hex value', function() { var hex = '0000000000000000'; var n = new Async(); @@ -346,18 +350,20 @@ describe('Network / Async', function() { }); describe('#setHexNonces', function() { - + it('should set a nonce from a hex value', function() { var hex = '0000000000000000'; var n = new Async(); - n.setHexNonces({fakeid: hex}); + n.setHexNonces({ + fakeid: hex + }); n.getHexNonces().fakeid.should.equal(hex); }); }); describe('#getHexNonce', function() { - + it('should get a nonce hex value', function() { var hex = '0000000000000000'; var n = new Async(); @@ -368,11 +374,13 @@ describe('Network / Async', function() { }); describe('#getHexNonces', function() { - + it('should get a nonce from a hex value', function() { var hex = '0000000000000000'; var n = new Async(); - n.setHexNonces({fakeid: hex}); + n.setHexNonces({ + fakeid: hex + }); n.getHexNonces().fakeid.should.equal(hex); }); @@ -399,7 +407,7 @@ describe('Network / Async', function() { var n = new Async(); n.iterateNonce(); var buf = new Buffer(4); - buf.writeUInt32BE(Math.floor(Date.now()/1000), 0); + buf.writeUInt32BE(Math.floor(Date.now() / 1000), 0); n.networkNonce[0].should.equal(buf[0]); }); From 7e286d88d8343e6f44889e1d47ed4b7c79ec3fc2 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 12 Aug 2014 17:08:08 -0400 Subject: [PATCH 11/75] remove alerts --- js/models/core/Wallet.js | 3 +-- js/models/network/Async.js | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 9ab95fa7e..d86999b59 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -318,8 +318,6 @@ Wallet.prototype._handleAddressBook = function(senderId, data, isInbound) { Wallet.prototype._handleData = function(senderId, data, isInbound) { - alert('data '+JSON.stringify(data)); - if (data.type !== 'walletId' && this.id !== data.walletId) { this.emit('badMessage', senderId); this.log('badMessage FROM:', senderId); @@ -358,6 +356,7 @@ Wallet.prototype._handleData = function(senderId, data, isInbound) { }; Wallet.prototype._handleConnect = function(newCopayerId) { + alert(newCopayerId); if (newCopayerId) { this.log('#### Setting new COPAYER:', newCopayerId); this.sendWalletId(newCopayerId); diff --git a/js/models/network/Async.js b/js/models/network/Async.js index a3e9bbd53..ba852a0cc 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -196,14 +196,12 @@ Network.prototype._onMessage = function(enc) { var payload = decoded.payload; } catch (e) { this._deletePeer(sender); - alert('quit 1'); return; } if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) { this._deletePeer(sender); - alert('quit 2'); return; } @@ -213,7 +211,6 @@ Network.prototype._onMessage = function(enc) { /* if (!this.copayerForPeer[sender] || (isInbound && !this.isInboundPeerAuth[sender])) { this._deletePeer(sender); - alert('quit 3'); return; } */ From cae11776acd32b35a549386c53600ebee5d28468 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Wed, 13 Aug 2014 17:27:33 -0400 Subject: [PATCH 12/75] trying to get past intermediate screen --- js/models/core/PublicKeyRing.js | 1 + js/models/core/Wallet.js | 7 +++++-- js/models/network/Async.js | 9 ++++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/js/models/core/PublicKeyRing.js b/js/models/core/PublicKeyRing.js index b86f18277..360ebd491 100644 --- a/js/models/core/PublicKeyRing.js +++ b/js/models/core/PublicKeyRing.js @@ -377,6 +377,7 @@ PublicKeyRing.prototype._checkInPKR = function(inPKR, ignoreId) { PublicKeyRing.prototype._mergePubkeys = function(inPKR) { + alert('merge pubkeys'); var self = this; var hasChanged = false; diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index d86999b59..ffbb245a7 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -318,15 +318,19 @@ Wallet.prototype._handleAddressBook = function(senderId, data, isInbound) { Wallet.prototype._handleData = function(senderId, data, isInbound) { + + alert(JSON.stringify(data)); if (data.type !== 'walletId' && this.id !== data.walletId) { this.emit('badMessage', senderId); this.log('badMessage FROM:', senderId); + alert('fuck'); return; } switch (data.type) { // This handler is repeaded on WalletFactory (#join). TODO case 'walletId': + alert('walletID received'); this.sendWalletReady(senderId); break; case 'walletReady': @@ -356,7 +360,6 @@ Wallet.prototype._handleData = function(senderId, data, isInbound) { }; Wallet.prototype._handleConnect = function(newCopayerId) { - alert(newCopayerId); if (newCopayerId) { this.log('#### Setting new COPAYER:', newCopayerId); this.sendWalletId(newCopayerId); @@ -1727,7 +1730,7 @@ Wallet.prototype.indexDiscovery = function(start, change, copayerIndex, gap, cb) function _while() { return hasActivity; }, - function _finnaly(err) { + function _finally(err) { if (err) return cb(err); cb(null, lastActive); } diff --git a/js/models/network/Async.js b/js/models/network/Async.js index ba852a0cc..9f6559eaf 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -199,14 +199,11 @@ Network.prototype._onMessage = function(enc) { return; } - if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) { this._deletePeer(sender); return; } - - // TODO /* if (!this.copayerForPeer[sender] || (isInbound && !this.isInboundPeerAuth[sender])) { @@ -215,6 +212,9 @@ Network.prototype._onMessage = function(enc) { } */ + + console.log('receiving '+JSON.stringify(payload)); + var self = this; switch (payload.type) { case 'disconnect': @@ -352,8 +352,7 @@ Network.prototype.send = function(copayerIds, payload, cb) { }; var copayerIdBuf = new Buffer(copayerId, 'hex'); var message = AuthMessage.encode(copayerIdBuf, self.getKey(), payload, opts); - console.log(JSON.stringify(payload)); - console.log(JSON.stringify(message)); + console.log('sending '+JSON.stringify(payload)); self.socket.emit('message', message); }); if (typeof cb === 'function') cb(); From fd9d8d9e2ee599390556de543786e21029814b90 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 18 Aug 2014 10:33:00 -0400 Subject: [PATCH 13/75] fix Async to remove soop --- js/models/network/Async.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 9f6559eaf..77b751d6c 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -1,11 +1,11 @@ 'use strict'; -var imports = require('soop').imports(); -var EventEmitter = imports.EventEmitter || require('events').EventEmitter; +var EventEmitter = require('events').EventEmitter; var bitcore = require('bitcore'); var AuthMessage = bitcore.AuthMessage; var util = bitcore.util; -var extend = require('util')._extend; +var nodeUtil = require('util'); +var extend = nodeUtil._extend; var io = require('socket.io-client'); var preconditions = require('preconditions').singleton(); @@ -30,7 +30,7 @@ function Network(opts) { this.cleanUp(); } -Network.parent = EventEmitter; +nodeUtil.inherits(Network, EventEmitter); Network.prototype.cleanUp = function() { this.started = false; @@ -213,7 +213,7 @@ Network.prototype._onMessage = function(enc) { */ - console.log('receiving '+JSON.stringify(payload)); + console.log('receiving ' + JSON.stringify(payload)); var self = this; switch (payload.type) { @@ -352,7 +352,7 @@ Network.prototype.send = function(copayerIds, payload, cb) { }; var copayerIdBuf = new Buffer(copayerId, 'hex'); var message = AuthMessage.encode(copayerIdBuf, self.getKey(), payload, opts); - console.log('sending '+JSON.stringify(payload)); + console.log('sending ' + JSON.stringify(payload)); self.socket.emit('message', message); }); if (typeof cb === 'function') cb(); @@ -382,4 +382,4 @@ Network.prototype.disconnect = function(cb, forced) { }); }; -module.exports = require('soop')(Network); +module.exports = Network; From 652726dbe96aa05024b7b1b00d9f4265692ba9e3 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 18 Aug 2014 12:46:51 -0400 Subject: [PATCH 14/75] some connection in intermediate screen --- js/models/core/Wallet.js | 2 ++ js/models/core/WalletFactory.js | 3 ++- js/models/network/Async.js | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index ffbb245a7..e61b4d699 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -633,7 +633,9 @@ Wallet.prototype.sendReject = function(ntxid) { }); }; + Wallet.prototype.sendWalletReady = function(recipients) { + preconditions.checkArgument(recipients); this.log('### SENDING WalletReady TO:', recipients); this.send(recipients, { diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index c9e32ed06..86f3c8065 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -268,7 +268,8 @@ WalletFactory.prototype.joinCreateSession = function(secret, nickname, passphras data.opts.passphrase = passphrase; data.opts.id = data.walletId; var w = self.create(data.opts); - w.seedCopayer(s.pubKey); + w.sendWalletReady(s.pubKey); + //w.seedCopayer(s.pubKey); return cb(null, w); } }); diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 77b751d6c..194eda462 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -309,7 +309,8 @@ Network.prototype.start = function(opts, openCallback) { this.socket.removeAllListeners(); } - this.socket = io.connect(this.host + ':' + this.port, { + var hostPort = this.host + ':' + this.port; + this.socket = io.connect(hostPort, { reconnection: false, }); this._setupConnectionHandlers(openCallback); From 497a93991e519e808fb760de6bf600e92aa73f32 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 18 Aug 2014 13:13:22 -0400 Subject: [PATCH 15/75] remove alerts --- js/models/core/PublicKeyRing.js | 1 - js/models/core/Wallet.js | 3 --- 2 files changed, 4 deletions(-) diff --git a/js/models/core/PublicKeyRing.js b/js/models/core/PublicKeyRing.js index 360ebd491..b86f18277 100644 --- a/js/models/core/PublicKeyRing.js +++ b/js/models/core/PublicKeyRing.js @@ -377,7 +377,6 @@ PublicKeyRing.prototype._checkInPKR = function(inPKR, ignoreId) { PublicKeyRing.prototype._mergePubkeys = function(inPKR) { - alert('merge pubkeys'); var self = this; var hasChanged = false; diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index e61b4d699..7e4172e5c 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -318,8 +318,6 @@ Wallet.prototype._handleAddressBook = function(senderId, data, isInbound) { Wallet.prototype._handleData = function(senderId, data, isInbound) { - - alert(JSON.stringify(data)); if (data.type !== 'walletId' && this.id !== data.walletId) { this.emit('badMessage', senderId); this.log('badMessage FROM:', senderId); @@ -330,7 +328,6 @@ Wallet.prototype._handleData = function(senderId, data, isInbound) { switch (data.type) { // This handler is repeaded on WalletFactory (#join). TODO case 'walletId': - alert('walletID received'); this.sendWalletReady(senderId); break; case 'walletReady': From 8b6c2df6bdb7b7c0fe5ca45077c3ef75149c0996 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 18 Aug 2014 14:24:58 -0400 Subject: [PATCH 16/75] pubkeyring syncing, w00t --- js/models/core/Wallet.js | 1 - js/models/network/Async.js | 21 ++++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 7e4172e5c..14544d1f6 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -321,7 +321,6 @@ Wallet.prototype._handleData = function(senderId, data, isInbound) { if (data.type !== 'walletId' && this.id !== data.walletId) { this.emit('badMessage', senderId); this.log('badMessage FROM:', senderId); - alert('fuck'); return; } diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 194eda462..c7142f91a 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -25,6 +25,7 @@ var preconditions = require('preconditions').singleton(); function Network(opts) { var self = this; opts = opts || {}; + this.maxPeers = opts.maxPeers || 12; this.host = opts.host || 'localhost'; this.port = opts.port || 3001; this.cleanUp(); @@ -259,7 +260,7 @@ Network.prototype._addCopayerMap = function(peerId, copayerId) { if (!this.copayerForPeer[peerId]) { if (Object.keys(this.copayerForPeer).length < this.maxPeers) { this.copayerForPeer[peerId] = copayerId; - } else {} + } } }; @@ -332,12 +333,25 @@ Network.prototype.getPeer = function() { }; +Network.prototype.getCopayerIds = function() { + if (this.allowedCopayerIds) { + return Object.keys(this.allowedCopayerIds); + } else { + var copayerIds = []; + for (var peerId in this.copayerForPeer) { + copayerIds.push(this.copayerForPeer[peerId]); + } + return copayerIds; + } +}; + + Network.prototype.send = function(copayerIds, payload, cb) { preconditions.checkArgument(payload); var self = this; if (!copayerIds) { - copayerIds = this.connectedCopayers(); + copayerIds = this.getCopayerIds(); payload.isBroadcast = 1; } @@ -346,14 +360,15 @@ Network.prototype.send = function(copayerIds, payload, cb) { var l = copayerIds.length; var i = 0; + console.log('sending ' + JSON.stringify(payload)); copayerIds.forEach(function(copayerId) { + console.log('\t to ' + copayerId); self.iterateNonce(); var opts = { nonce: self.networkNonce }; var copayerIdBuf = new Buffer(copayerId, 'hex'); var message = AuthMessage.encode(copayerIdBuf, self.getKey(), payload, opts); - console.log('sending ' + JSON.stringify(payload)); self.socket.emit('message', message); }); if (typeof cb === 'function') cb(); From b0d32463c6f7bb1b2368380b05d7ddb8b17f0105 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 18 Aug 2014 15:32:49 -0400 Subject: [PATCH 17/75] entering wallet successfully --- js/models/network/Async.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index c7142f91a..b5fd72fba 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -196,11 +196,7 @@ Network.prototype._onMessage = function(enc) { var payload = decoded.payload; } catch (e) { - this._deletePeer(sender); - return; - } - - if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) { + alert('caught :' + e); this._deletePeer(sender); return; } @@ -222,6 +218,11 @@ Network.prototype._onMessage = function(enc) { this._onClose(sender); break; case 'hello': + if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) { + this._deletePeer(sender); + return; + } + this._addConnectedCopayer(payload.copayerId); break; default: From dfd2df7534bdb625081c6fdc3518c9d0f44e03cd Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 18 Aug 2014 15:38:11 -0400 Subject: [PATCH 18/75] fixed refresh button --- js/models/core/Wallet.js | 2 ++ js/models/network/Async.js | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 14544d1f6..6000057a2 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -91,6 +91,8 @@ Wallet.prototype.seedCopayer = function(pubKey) { // not being used now Wallet.prototype.connectToAll = function() { + // not being used now + return; var all = this.publicKeyRing.getAllCopayerIds(); this.network.connectToCopayers(all); diff --git a/js/models/network/Async.js b/js/models/network/Async.js index b5fd72fba..684b8e255 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -196,7 +196,6 @@ Network.prototype._onMessage = function(enc) { var payload = decoded.payload; } catch (e) { - alert('caught :' + e); this._deletePeer(sender); return; } From 6be6f1e23c6d43aa2ea07f522d7c485c87bd0ec4 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 18 Aug 2014 15:59:30 -0400 Subject: [PATCH 19/75] fix disconect error --- js/models/network/Async.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 684b8e255..9fe201129 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -229,6 +229,10 @@ Network.prototype._onMessage = function(enc) { } }; +Network.prototype._onClose = function(copayerId) { + // TODO +}; + Network.prototype._setupConnectionHandlers = function(cb) { preconditions.checkState(this.socket); var self = this; From 4d59d7cfd5ac371a0893471a953bdda66c8392e0 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 18 Aug 2014 18:19:54 -0400 Subject: [PATCH 20/75] trying to fix the connection status --- js/models/core/Wallet.js | 17 ++++++++++++++++- js/models/network/Async.js | 21 ++++++++++++--------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 6000057a2..cc3badfef 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -319,6 +319,9 @@ Wallet.prototype._handleAddressBook = function(senderId, data, isInbound) { }; Wallet.prototype._handleData = function(senderId, data, isInbound) { + preconditions.checkArgument(senderId); + preconditions.checkArgument(data); + preconditions.checkArgument(data.type); if (data.type !== 'walletId' && this.id !== data.walletId) { this.emit('badMessage', senderId); @@ -453,6 +456,7 @@ Wallet.prototype.netStart = function(callback) { net.start(startOpts, function() { self.emit('ready', net.getPeer()); + self.fakeConnections(); setTimeout(function() { self.emit('publicKeyRingUpdated', true); //self.scheduleConnect(); @@ -463,6 +467,17 @@ Wallet.prototype.netStart = function(callback) { }; +// TODO temporary method. should remove this when we refactor peerID out +Wallet.prototype.fakeConnections = function() { + var all = this.publicKeyRing.getAllCopayerIds(); + for (var i = 0; i < all.length; i++) { + var copayerID = all[i]; + var peerID = this.network.peerFromCopayer(copayerID); + this.network._addCopayerMap(peerID, copayerID); + } +}; + + // not being used now Wallet.prototype.scheduleConnect = function() { var self = this; @@ -713,7 +728,7 @@ Wallet.prototype.getTxProposals = function() { txp.finallyRejected = true; } - if (txp.readonly && !txp.finallyRejected && !txp.sentTs) {} else { + if (!txp.readonly || txp.finallyRejected || txp.sentTs) { ret.push(txp); } } diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 9fe201129..0c84f3915 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -112,7 +112,7 @@ Network.prototype._deletePeer = function(peerId) { this.connectedPeers = Network._arrayRemove(peerId, this.connectedPeers); }; -Network.prototype._addConnectedCopayer = function(copayerId, isInbound) { +Network.prototype._addConnectedCopayer = function(copayerId) { var peerId = this.peerFromCopayer(copayerId); this._addCopayerMap(peerId, copayerId); Network._arrayPushOnce(peerId, this.connectedPeers); @@ -221,10 +221,11 @@ Network.prototype._onMessage = function(enc) { this._deletePeer(sender); return; } - this._addConnectedCopayer(payload.copayerId); break; - default: + default: + console.log(JSON.stringify(self.copayerForPeer)); + console.log('data from '+sender+' '+self.copayerForPeer[sender]); this.emit('data', self.copayerForPeer[sender], payload); } }; @@ -243,7 +244,12 @@ Network.prototype._setupConnectionHandlers = function(cb) { }); if (typeof cb === 'function') cb(); }); - self.socket.on('message', self._onMessage.bind(self)); + self.socket.on('message', function (m) { + // delay execution, to improve error handling + setTimeout(function() { + self._onMessage(m); + }, 1); + }); self.socket.on('error', self._onError.bind(self)); }; @@ -273,9 +279,8 @@ Network.prototype._setInboundPeerAuth = function(peerId) { }; Network.prototype.setCopayerId = function(copayerId) { - if (this.started) { - throw new Error('network already started: can not change peerId') - } + preconditions.checkState(!this.started, 'network already started: can not change peerId'); + this.copayerId = copayerId; this.copayerIdBuf = new Buffer(copayerId, 'hex'); this.peerId = this.peerFromCopayer(this.copayerId); @@ -324,8 +329,6 @@ Network.prototype.start = function(opts, openCallback) { //this.socket.emit('sync'); this.started = true; - //this.emit('serverError', self.criticalError); - }; Network.prototype.getOnlinePeerIDs = function() { From 884d0b594552980b6c4178e8e0219e00b8a99bb3 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 18 Aug 2014 18:41:39 -0400 Subject: [PATCH 21/75] sending tx works --- js/models/core/Wallet.js | 12 ------------ js/models/network/Async.js | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index cc3badfef..6c1b0d64e 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -456,7 +456,6 @@ Wallet.prototype.netStart = function(callback) { net.start(startOpts, function() { self.emit('ready', net.getPeer()); - self.fakeConnections(); setTimeout(function() { self.emit('publicKeyRingUpdated', true); //self.scheduleConnect(); @@ -467,17 +466,6 @@ Wallet.prototype.netStart = function(callback) { }; -// TODO temporary method. should remove this when we refactor peerID out -Wallet.prototype.fakeConnections = function() { - var all = this.publicKeyRing.getAllCopayerIds(); - for (var i = 0; i < all.length; i++) { - var copayerID = all[i]; - var peerID = this.network.peerFromCopayer(copayerID); - this.network._addCopayerMap(peerID, copayerID); - } -}; - - // not being used now Wallet.prototype.scheduleConnect = function() { var self = this; diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 0c84f3915..d3a08b331 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -226,7 +226,7 @@ Network.prototype._onMessage = function(enc) { default: console.log(JSON.stringify(self.copayerForPeer)); console.log('data from '+sender+' '+self.copayerForPeer[sender]); - this.emit('data', self.copayerForPeer[sender], payload); + this.emit('data', sender, payload); } }; From fb69da38062278e3c889913fe6b23769f1fa0715 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 18 Aug 2014 18:44:54 -0400 Subject: [PATCH 22/75] remove alerts --- js/models/network/Async.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index d3a08b331..b199af262 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -224,8 +224,6 @@ Network.prototype._onMessage = function(enc) { this._addConnectedCopayer(payload.copayerId); break; default: - console.log(JSON.stringify(self.copayerForPeer)); - console.log('data from '+sender+' '+self.copayerForPeer[sender]); this.emit('data', sender, payload); } }; From 1c3c7f0bdeedec8c082d43d5abb21e8c610999c2 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 10:04:13 -0400 Subject: [PATCH 23/75] remove whitespace --- js/models/core/PublicKeyRing.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/models/core/PublicKeyRing.js b/js/models/core/PublicKeyRing.js index b86f18277..9a734e5ac 100644 --- a/js/models/core/PublicKeyRing.js +++ b/js/models/core/PublicKeyRing.js @@ -1,6 +1,5 @@ 'use strict'; - var preconditions = require('preconditions').instance(); var bitcore = require('bitcore'); var HK = bitcore.HierarchicalKey; From 28e00b24cce050b3ead9161041d2aa6c3de32da6 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 10:20:35 -0400 Subject: [PATCH 24/75] wallet refactor --- js/models/core/Wallet.js | 18 +++++++++--------- js/models/network/Async.js | 2 ++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 6c1b0d64e..7d3c4042f 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -33,20 +33,16 @@ function Wallet(opts) { 'publicKeyRing', 'txProposals', 'privateKey', 'version', 'reconnectDelay' ].forEach(function(k) { - if (typeof opts[k] === 'undefined') - throw new Error('missing required option for Wallet: ' + k); + preconditions.checkArgument(typeof opts[k] !== 'undefined', + 'missing required option for Wallet: ' + k); self[k] = opts[k]; }); - if (copayConfig.forceNetwork && this.getNetworkName() !== copayConfig.networkName) - throw new Error('Network forced to ' + copayConfig.networkName + - ' and tried to create a Wallet with network ' + this.getNetworkName()); - - this.log('creating ' + opts.requiredCopayers + ' of ' + opts.totalCopayers + ' wallet'); + preconditions.checkArgument(!copayConfig.forceNetwork || this.getNetworkName() === copayConfig.networkName, + 'Network forced to ' + copayConfig.networkName + + ' and tried to create a Wallet with network ' + this.getNetworkName()); this.id = opts.id || Wallet.getRandomId(); this.lock = new WalletLock(this.storage, this.id, opts.lockTimeOutMin); - - this.name = opts.name; this.verbose = opts.verbose; @@ -56,6 +52,7 @@ function Wallet(opts) { this.registeredPeerIds = []; this.addressBook = opts.addressBook || {}; this.publicKey = this.privateKey.publicHex; + this.lastTimestamp = opts.lastTimestamp || undefined; this.paymentRequests = opts.paymentRequests || {}; @@ -540,6 +537,7 @@ Wallet.prototype.toObj = function() { txProposals: this.txProposals.toObj(), privateKey: this.privateKey ? this.privateKey.toObj() : undefined, addressBook: this.addressBook, + lastTimestamp: this.lastTimestamp, }; return walletObj; @@ -578,6 +576,8 @@ Wallet.fromObj = function(o, storage, network, blockchain) { opts.txProposals = new TxProposals({ networkName: this.networkName, }); + + opts.lastTimestamp = o.lastTimestamp; opts.storage = storage; opts.network = network; diff --git a/js/models/network/Async.js b/js/models/network/Async.js index b199af262..6e1835bbe 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -23,6 +23,7 @@ var preconditions = require('preconditions').singleton(); */ function Network(opts) { + preconditions.checkArgument(opts); var self = this; opts = opts || {}; this.maxPeers = opts.maxPeers || 12; @@ -121,6 +122,7 @@ Network.prototype._addConnectedCopayer = function(copayerId) { Network.prototype.getKey = function() { if (!this.key) { + preconditions.checkState(this.privkey); var key = new bitcore.Key(); key.private = new Buffer(this.privkey, 'hex'); key.regenerateSync(); From 605e2c7d495f421d53cf5ad10a45d90d7f437d05 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 10:25:03 -0400 Subject: [PATCH 25/75] network handler refactor, remove 'close' --- js/models/core/Wallet.js | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 7d3c4042f..c43e39f5e 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -99,7 +99,7 @@ Wallet.prototype.connectToAll = function() { } }; -Wallet.prototype._handleIndexes = function(senderId, data, isInbound) { +Wallet.prototype._onIndexes = function(senderId, data, isInbound) { this.log('RECV INDEXES:', data); var inIndexes = HDParams.fromList(data.indexes); var hasChanged = this.publicKeyRing.mergeIndexes(inIndexes); @@ -109,7 +109,7 @@ Wallet.prototype._handleIndexes = function(senderId, data, isInbound) { } }; -Wallet.prototype._handlePublicKeyRing = function(senderId, data, isInbound) { +Wallet.prototype._onPublicKeyRing = function(senderId, data, isInbound) { this.log('RECV PUBLICKEYRING:', data); var inPKR = PublicKeyRing.fromObj(data.publicKeyRing); @@ -217,7 +217,7 @@ Wallet.prototype._checkSentTx = function(ntxid, cb) { }; -Wallet.prototype._handleTxProposal = function(senderId, data) { +Wallet.prototype._onTxProposal = function(senderId, data) { var self = this; this.log('RECV TXPROPOSAL: ', data); var m; @@ -254,7 +254,7 @@ Wallet.prototype._handleTxProposal = function(senderId, data) { }; -Wallet.prototype._handleReject = function(senderId, data, isInbound) { +Wallet.prototype._onReject = function(senderId, data, isInbound) { preconditions.checkState(data.ntxid); this.log('RECV REJECT:', data); @@ -277,7 +277,7 @@ Wallet.prototype._handleReject = function(senderId, data, isInbound) { }); }; -Wallet.prototype._handleSeen = function(senderId, data, isInbound) { +Wallet.prototype._onSeen = function(senderId, data, isInbound) { preconditions.checkState(data.ntxid); this.log('RECV SEEN:', data); @@ -295,7 +295,7 @@ Wallet.prototype._handleSeen = function(senderId, data, isInbound) { -Wallet.prototype._handleAddressBook = function(senderId, data, isInbound) { +Wallet.prototype._onAddressBook = function(senderId, data, isInbound) { preconditions.checkState(data.addressBook); this.log('RECV ADDRESSBOOK:', data); var rcv = data.addressBook; @@ -315,7 +315,7 @@ Wallet.prototype._handleAddressBook = function(senderId, data, isInbound) { } }; -Wallet.prototype._handleData = function(senderId, data, isInbound) { +Wallet.prototype._onData = function(senderId, data, isInbound) { preconditions.checkArgument(senderId); preconditions.checkArgument(data); preconditions.checkArgument(data.type); @@ -337,27 +337,27 @@ Wallet.prototype._handleData = function(senderId, data, isInbound) { this.sendAllTxProposals(senderId); // send old txps break; case 'publicKeyRing': - this._handlePublicKeyRing(senderId, data, isInbound); + this._onPublicKeyRing(senderId, data, isInbound); break; case 'reject': - this._handleReject(senderId, data, isInbound); + this._onReject(senderId, data, isInbound); break; case 'seen': - this._handleSeen(senderId, data, isInbound); + this._onSeen(senderId, data, isInbound); break; case 'txProposal': - this._handleTxProposal(senderId, data, isInbound); + this._onTxProposal(senderId, data, isInbound); break; case 'indexes': - this._handleIndexes(senderId, data, isInbound); + this._onIndexes(senderId, data, isInbound); break; case 'addressbook': - this._handleAddressBook(senderId, data, isInbound); + this._onAddressBook(senderId, data, isInbound); break; } }; -Wallet.prototype._handleConnect = function(newCopayerId) { +Wallet.prototype._onConnect = function(newCopayerId) { if (newCopayerId) { this.log('#### Setting new COPAYER:', newCopayerId); this.sendWalletId(newCopayerId); @@ -366,7 +366,7 @@ Wallet.prototype._handleConnect = function(newCopayerId) { this.emit('connect', peerID); }; -Wallet.prototype._handleDisconnect = function(peerID) { +Wallet.prototype._onDisconnect = function(peerID) { this.currentDelay = null; this.emit('disconnect', peerID); }; @@ -428,12 +428,9 @@ Wallet.prototype.netStart = function(callback) { var net = this.network; net.removeAllListeners(); - net.on('connect', self._handleConnect.bind(self)); - net.on('disconnect', self._handleDisconnect.bind(self)); - net.on('data', self._handleData.bind(self)); - net.on('close', function() { - self.emit('close'); - }); + net.on('connect', self._onConnect.bind(self)); + net.on('disconnect', self._onDisconnect.bind(self)); + net.on('data', self._onData.bind(self)); net.on('serverError', function(msg) { self.emit('serverError', msg); }); From 1b783df70a1d2c915b29156be2a3ade610e54460 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 10:32:51 -0400 Subject: [PATCH 26/75] remove 'serverError' event --- js/models/core/Wallet.js | 3 --- js/services/controllerUtils.js | 5 ----- 2 files changed, 8 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index c43e39f5e..1ae29657e 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -431,9 +431,6 @@ Wallet.prototype.netStart = function(callback) { net.on('connect', self._onConnect.bind(self)); net.on('disconnect', self._onDisconnect.bind(self)); net.on('data', self._onData.bind(self)); - net.on('serverError', function(msg) { - self.emit('serverError', msg); - }); var myId = self.getMyCopayerId(); var myIdPriv = self.getMyCopayerIdPriv(); diff --git a/js/services/controllerUtils.js b/js/services/controllerUtils.js index dfbe4bb45..463ee0a16 100644 --- a/js/services/controllerUtils.js +++ b/js/services/controllerUtils.js @@ -59,11 +59,6 @@ angular.module('copayApp.services') notification.error('PeerJS Error', message); root.onErrorDigest($scope); }); - wallet.on('serverError', function(m) { - var message = m || 'The PeerJS server is not responding, please try again'; - $location.path('receive'); - root.onErrorDigest($scope, message); - }); wallet.on('ready', function() { $scope.loading = false; }); From 981c56f09163a8bc4182a039cbaf2d4ffb72854f Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 10:43:23 -0400 Subject: [PATCH 27/75] add timestamp sync --- js/models/core/Wallet.js | 11 ++++++++++- js/models/network/Async.js | 2 +- package.json | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 1ae29657e..395f952d3 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -4,6 +4,7 @@ var EventEmitter = require('events').EventEmitter; var async = require('async'); var preconditions = require('preconditions').singleton(); var util = require('util'); +var microtime = require('microtime'); var bitcore = require('bitcore'); var bignum = bitcore.Bignum; @@ -315,6 +316,11 @@ Wallet.prototype._onAddressBook = function(senderId, data, isInbound) { } }; + +Wallet.prototype.updateTimestamp = function() { + this.lastTimestamp = microtime.now(); +}; + Wallet.prototype._onData = function(senderId, data, isInbound) { preconditions.checkArgument(senderId); preconditions.checkArgument(data); @@ -326,6 +332,8 @@ Wallet.prototype._onData = function(senderId, data, isInbound) { return; } + this.updateTimestamp(); + switch (data.type) { // This handler is repeaded on WalletFactory (#join). TODO case 'walletId': @@ -438,7 +446,8 @@ Wallet.prototype.netStart = function(callback) { var startOpts = { copayerId: myId, privkey: myIdPriv, - maxPeers: self.totalCopayers + maxPeers: self.totalCopayers, + lastTimestamp: this.lastTimestamp, }; if (this.publicKeyRing.isComplete()) { diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 6e1835bbe..195773b27 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -326,7 +326,7 @@ Network.prototype.start = function(opts, openCallback) { this._setupConnectionHandlers(openCallback); var pubkey = this.getKey().public.toString('hex'); this.socket.emit('subscribe', pubkey); - //this.socket.emit('sync'); + this.socket.emit('sync', opts.lastTimestamp); this.started = true; }; diff --git a/package.json b/package.json index d68f10f9f..fe84e9ba1 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "version": "0.4.7", "dependencies": { + "microtime": "^1.0.1", "mocha": "^1.18.2", "mocha-lcov-reporter": "0.0.1", "optimist": "^0.6.1", From 477875d309dbec5b0e517eb55880cff6d0919541 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 10:49:13 -0400 Subject: [PATCH 28/75] fix timestamp method --- js/models/core/Wallet.js | 2 +- package.json | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 395f952d3..efba503dc 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -318,7 +318,7 @@ Wallet.prototype._onAddressBook = function(senderId, data, isInbound) { Wallet.prototype.updateTimestamp = function() { - this.lastTimestamp = microtime.now(); + this.lastTimestamp = new Date().getTime() * 1000; }; Wallet.prototype._onData = function(senderId, data, isInbound) { diff --git a/package.json b/package.json index fe84e9ba1..d68f10f9f 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ }, "version": "0.4.7", "dependencies": { - "microtime": "^1.0.1", "mocha": "^1.18.2", "mocha-lcov-reporter": "0.0.1", "optimist": "^0.6.1", From 86a4ce96ad60a750f85a4390b99ea2dcb0ca1024 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 10:49:26 -0400 Subject: [PATCH 29/75] fix timestamp method 2 --- js/models/core/Wallet.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index efba503dc..afdb85462 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -4,7 +4,6 @@ var EventEmitter = require('events').EventEmitter; var async = require('async'); var preconditions = require('preconditions').singleton(); var util = require('util'); -var microtime = require('microtime'); var bitcore = require('bitcore'); var bignum = bitcore.Bignum; From 789388af3ce2a2972ad60a922a5de2e54573cdd3 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 11:18:38 -0400 Subject: [PATCH 30/75] historic sync working yay :D --- js/models/core/Wallet.js | 5 +++-- js/models/core/WalletFactory.js | 1 + js/models/network/Async.js | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index afdb85462..a86e6a177 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -317,7 +317,8 @@ Wallet.prototype._onAddressBook = function(senderId, data, isInbound) { Wallet.prototype.updateTimestamp = function() { - this.lastTimestamp = new Date().getTime() * 1000; + this.lastTimestamp = (new Date().getTime()) * 1000; + this.store(); }; Wallet.prototype._onData = function(senderId, data, isInbound) { @@ -330,7 +331,6 @@ Wallet.prototype._onData = function(senderId, data, isInbound) { this.log('badMessage FROM:', senderId); return; } - this.updateTimestamp(); switch (data.type) { @@ -362,6 +362,7 @@ Wallet.prototype._onData = function(senderId, data, isInbound) { this._onAddressBook(senderId, data, isInbound); break; } + }; Wallet.prototype._onConnect = function(newCopayerId) { diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index 86f3c8065..3b4d9d77e 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -104,6 +104,7 @@ WalletFactory.prototype.read = function(walletId, skipFields) { obj.privateKey = s.get(walletId, 'privateKey'); obj.addressBook = s.get(walletId, 'addressBook'); obj.backupOffered = s.get(walletId, 'backupOffered'); + obj.lastTimestamp = s.get(walletId, 'lastTimestamp'); var w = this.fromObj(obj, skipFields); return w; diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 195773b27..ab7f843f9 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -321,7 +321,7 @@ Network.prototype.start = function(opts, openCallback) { var hostPort = this.host + ':' + this.port; this.socket = io.connect(hostPort, { - reconnection: false, + reconnection: true, }); this._setupConnectionHandlers(openCallback); var pubkey = this.getKey().public.toString('hex'); From f219da9740061b22d62995497ffd21ab7c01f9d4 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 11:38:53 -0400 Subject: [PATCH 31/75] refactored disconnect as one more message --- js/models/core/Wallet.js | 18 +++++++++++++----- js/models/network/Async.js | 25 +++---------------------- js/services/controllerUtils.js | 4 ++-- 3 files changed, 18 insertions(+), 29 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index a86e6a177..a9c9584af 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -326,12 +326,12 @@ Wallet.prototype._onData = function(senderId, data, isInbound) { preconditions.checkArgument(data); preconditions.checkArgument(data.type); + this.updateTimestamp(); + if (data.type !== 'walletId' && this.id !== data.walletId) { - this.emit('badMessage', senderId); - this.log('badMessage FROM:', senderId); + this.emit('corrupt', senderId); return; } - this.updateTimestamp(); switch (data.type) { // This handler is repeaded on WalletFactory (#join). TODO @@ -361,6 +361,9 @@ Wallet.prototype._onData = function(senderId, data, isInbound) { case 'addressbook': this._onAddressBook(senderId, data, isInbound); break; + case 'disconnect': + this._onDisconnect(senderId, data, isInbound); + break; } }; @@ -437,7 +440,6 @@ Wallet.prototype.netStart = function(callback) { net.removeAllListeners(); net.on('connect', self._onConnect.bind(self)); - net.on('disconnect', self._onDisconnect.bind(self)); net.on('data', self._onData.bind(self)); var myId = self.getMyCopayerId(); @@ -1747,7 +1749,13 @@ Wallet.prototype.indexDiscovery = function(start, change, copayerIndex, gap, cb) Wallet.prototype.disconnect = function() { this.log('## DISCONNECTING'); this.lock.release(); - this.network.disconnect(); + var self = this; + self.send(null, { + type: 'disconnect', + walletId: this.id, + }, function() { + self.network.cleanUp(); + }); }; Wallet.prototype.getNetwork = function() { diff --git a/js/models/network/Async.js b/js/models/network/Async.js index ab7f843f9..994761bfa 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -46,7 +46,6 @@ Network.prototype.cleanUp = function() { this.copayerForPeer = {}; this.connections = {}; this.criticalErr = ''; - this.closing = 0; this.removeAllListeners(); }; @@ -215,9 +214,6 @@ Network.prototype._onMessage = function(enc) { var self = this; switch (payload.type) { - case 'disconnect': - this._onClose(sender); - break; case 'hello': if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) { this._deletePeer(sender); @@ -225,15 +221,11 @@ Network.prototype._onMessage = function(enc) { } this._addConnectedCopayer(payload.copayerId); break; - default: + default: this.emit('data', sender, payload); } }; -Network.prototype._onClose = function(copayerId) { - // TODO -}; - Network.prototype._setupConnectionHandlers = function(cb) { preconditions.checkState(this.socket); var self = this; @@ -244,7 +236,7 @@ Network.prototype._setupConnectionHandlers = function(cb) { }); if (typeof cb === 'function') cb(); }); - self.socket.on('message', function (m) { + self.socket.on('message', function(m) { // delay execution, to improve error handling setTimeout(function() { self._onMessage(m); @@ -280,7 +272,7 @@ Network.prototype._setInboundPeerAuth = function(peerId) { Network.prototype.setCopayerId = function(copayerId) { preconditions.checkState(!this.started, 'network already started: can not change peerId'); - + this.copayerId = copayerId; this.copayerIdBuf = new Buffer(copayerId, 'hex'); this.peerId = this.peerFromCopayer(this.copayerId); @@ -394,15 +386,4 @@ Network.prototype.lockIncommingConnections = function(allowedCopayerIdsArray) { } }; -Network.prototype.disconnect = function(cb, forced) { - var self = this; - self.closing = 1; - self.send(null, { - type: 'disconnect' - }, function() { - self.cleanUp(); - if (typeof cb === 'function') cb(); - }); -}; - module.exports = Network; diff --git a/js/services/controllerUtils.js b/js/services/controllerUtils.js index 463ee0a16..48ab8049f 100644 --- a/js/services/controllerUtils.js +++ b/js/services/controllerUtils.js @@ -120,8 +120,8 @@ angular.module('copayApp.services') notification.enableHtml5Mode(); // for chrome: if support, enable it - w.on('badMessage', function(peerId) { - notification.error('Error', 'Received wrong message from peer ' + peerId); + w.on('corrupt', function(peerId) { + notification.error('Error', 'Received corrupt message from ' + peerId); }); w.on('ready', function(myPeerID) { $rootScope.wallet = w; From 1ae700f80579ddabcaaa2df8d51690cd6c702fa6 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 11:59:37 -0400 Subject: [PATCH 32/75] comment logs on networking --- js/models/network/Async.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 994761bfa..5da895e08 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -210,7 +210,7 @@ Network.prototype._onMessage = function(enc) { */ - console.log('receiving ' + JSON.stringify(payload)); + //console.log('receiving ' + JSON.stringify(payload)); var self = this; switch (payload.type) { @@ -359,9 +359,9 @@ Network.prototype.send = function(copayerIds, payload, cb) { var l = copayerIds.length; var i = 0; - console.log('sending ' + JSON.stringify(payload)); + //console.log('sending ' + JSON.stringify(payload)); copayerIds.forEach(function(copayerId) { - console.log('\t to ' + copayerId); + //console.log('\t to ' + copayerId); self.iterateNonce(); var opts = { nonce: self.networkNonce From e0b8f3319fa048b2119c3c69ced0a0697854c49b Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 12:46:20 -0400 Subject: [PATCH 33/75] remove WebRTC --- js/models/network/WebRTC.js | 525 ------------------------------------ test/index.html | 2 +- test/test.network.WebRTC.js | 507 ---------------------------------- 3 files changed, 1 insertion(+), 1033 deletions(-) delete mode 100644 js/models/network/WebRTC.js delete mode 100644 test/test.network.WebRTC.js diff --git a/js/models/network/WebRTC.js b/js/models/network/WebRTC.js deleted file mode 100644 index 256bc3ec7..000000000 --- a/js/models/network/WebRTC.js +++ /dev/null @@ -1,525 +0,0 @@ -'use strict'; - -var EventEmitter = require('events').EventEmitter; -var bitcore = require('bitcore'); -var util = bitcore.util; -var nodeUtil = require('util'); -var Message = require('../core/Message'); -/* - * Emits - * 'connect' - * when network layout has change (new/lost peers, etc) - * - * 'data' - * when an unknown data type arrives - * - * Provides - * send(toPeerIds, {data}, cb?) - * - */ - -function Network(opts) { - var self = this; - opts = opts || {}; - this.apiKey = opts.apiKey || 'lwjd5qra8257b9'; - this.debug = opts.debug || 3; - this.maxPeers = opts.maxPeers || 10; - this.reconnectAttempts = opts.reconnectAttempts || 3; - this.sjclParams = opts.sjclParams || { - salt: 'f28bfb49ef70573c', - iter: 500, - mode: 'ccm', - ts: parseInt(64), - }; - this.opts = {}; - ['config', 'port', 'host', 'path', 'debug', 'key', 'secure'].forEach(function(k) { - if (opts.hasOwnProperty(k)) self.opts[k] = opts[k]; - }); - this.cleanUp(); -} - -nodeUtil.inherits(Network, EventEmitter); - -Network.prototype.cleanUp = function() { - this.started = false; - this.connectedPeers = []; - this.peerId = null; - this.privkey = null; //TODO: hide privkey in a closure - this.key = null; - this.copayerId = null; - this.allowedCopayerIds = null; - this.isInboundPeerAuth = []; - this.copayerForPeer = {}; - this.connections = {}; - this.criticalErr = ''; - if (this.peer) { - this.peer.disconnect(); - this.peer.destroy(); - this.peer.removeAllListeners(); - this.peer = null; - } - this.closing = 0; - this.tries = 0; - this.removeAllListeners(); -}; - - -// Array helpers -Network._arrayDiff = function(a, b) { - var seen = []; - var diff = []; - - for (var i = 0; i < b.length; i++) - seen[b[i]] = true; - - for (var j = 0; j < a.length; j++) - if (!seen[a[j]]) - diff.push(a[j]); - - return diff; -}; - -Network._inArray = function(el, array) { - return array.indexOf(el) > -1; -}; - -Network._arrayPushOnce = function(el, array) { - var ret = false; - if (!Network._inArray(el, array)) { - array.push(el); - ret = true; - } - return ret; -}; - -Network._arrayRemove = function(el, array) { - var pos = array.indexOf(el); - if (pos >= 0) array.splice(pos, 1); - return array; -}; - -Network.prototype.connectedCopayers = function() { - var ret = []; - for (var i in this.connectedPeers) { - var copayerId = this.copayerForPeer[this.connectedPeers[i]]; - if (copayerId) ret.push(copayerId); - } - return ret; -}; - -Network.prototype._deletePeer = function(peerId) { - - delete this.isInboundPeerAuth[peerId]; - delete this.copayerForPeer[peerId]; - - if (this.connections[peerId]) { - this.connections[peerId].close(); - } - delete this.connections[peerId]; - this.connectedPeers = Network._arrayRemove(peerId, this.connectedPeers); -}; - -Network.prototype._onClose = function(peerID) { - this._deletePeer(peerID); - this.emit('disconnect', peerID); -}; - -Network.prototype.connectToCopayers = function(copayerIds) { - var self = this; - var arrayDiff = Network._arrayDiff(copayerIds, self.connectedCopayers()); - - arrayDiff.forEach(function(copayerId) { - if (self.allowedCopayerIds && !self.allowedCopayerIds[copayerId]) { - self._deletePeer(self.peerFromCopayer(copayerId)); - } else { - self.connectTo(copayerId); - } - }); -}; - -Network.prototype._sendHello = function(copayerId) { - this.send(copayerId, { - type: 'hello', - copayerId: this.copayerId, - }); -}; - -Network.prototype._addConnectedCopayer = function(copayerId, isInbound) { - var peerId = this.peerFromCopayer(copayerId); - this._addCopayerMap(peerId, copayerId); - Network._arrayPushOnce(peerId, this.connectedPeers); - this.emit('connect', copayerId); -}; - -Network.prototype.getKey = function() { - if (!this.key) { - var key = new bitcore.Key(); - key.private = new Buffer(this.privkey, 'hex'); - key.regenerateSync(); - this.key = key; - } - return this.key; -}; - -//hex version of one's own nonce -Network.prototype.setHexNonce = function(networkNonce) { - if (networkNonce) { - if (networkNonce.length !== 16) - throw new Error('incorrect length of hex nonce'); - this.networkNonce = new Buffer(networkNonce, 'hex'); - } - else - this.iterateNonce(); -}; - -//hex version of copayers' nonces -Network.prototype.setHexNonces = function(networkNonces) { - for (var i in networkNonces) { - if (!this.networkNonces) - this.networkNonces = {}; - if (networkNonces[i].length === 16) - this.networkNonces[i] = new Buffer(networkNonces[i], 'hex'); - } -}; - -//for oneself -Network.prototype.getHexNonce = function() { - return this.networkNonce.toString('hex'); -}; - -//for copayers -Network.prototype.getHexNonces = function() { - var networkNoncesHex = []; - for (var i in this.networkNonces) { - networkNoncesHex[i] = this.networkNonces[i].toString('hex'); - } - return networkNoncesHex; -}; - -Network.prototype.iterateNonce = function() { - if (!this.networkNonce || this.networkNonce.length !== 8) { - this.networkNonce = new Buffer(8); - this.networkNonce.fill(0); - } - //the first 4 bytes of a nonce is a unix timestamp in seconds - //the second 4 bytes is just an iterated "sub" nonce - //the whole thing is interpreted as one big endian number - var noncep1 = this.networkNonce.slice(0, 4); - noncep1.writeUInt32BE(Math.floor(Date.now()/1000), 0); - var noncep2uint = this.networkNonce.slice(4, 8).readUInt32BE(0); - var noncep2 = this.networkNonce.slice(4, 8); - noncep2.writeUInt32BE(noncep2uint + 1, 0); - return this.networkNonce; -}; - -Network.prototype._onData = function(enc, isInbound, peerId) { - var encUint8Array = new Uint8Array(enc); - var encbuf = new Buffer(encUint8Array); - var encstr = encbuf.toString(); - - var privkey = this.privkey; - var key = this.getKey(); - - try { - var encoded = JSON.parse(encstr); - var prevnonce = this.networkNonces ? this.networkNonces[peerId] : undefined; - var opts = {prevnonce: prevnonce}; - var decoded = this._decode(key, encoded, opts); - - //if no error thrown in the last step, we can set the copayer's nonce - if (!this.networkNonces) - this.networkNonces = {}; - this.networkNonces[peerId] = decoded.nonce; - - var databuf = decoded.payload; - var datastr = databuf.toString(); - var payload = JSON.parse(datastr); - } catch (e) { - this._deletePeer(peerId); - return; - } - - if (isInbound && payload.type === 'hello') { - var payloadStr = JSON.stringify(payload); - - //ensure claimed public key is actually the public key of the peer - //e.g., their public key should hash to be their peerId - if (peerId.toString() !== this.peerFromCopayer(payload.copayerId) || peerId.toString() !== this.peerFromCopayer(encoded.pubkey)) { - this._deletePeer(peerId, 'incorrect pubkey for peerId'); - return; - } - - if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) { - this._deletePeer(peerId); - return; - } - - this._addConnectedCopayer(payload.copayerId, isInbound); - this._setInboundPeerAuth(peerId, true); - return; - } - - if (!this.copayerForPeer[peerId] || (isInbound && !this.isInboundPeerAuth[peerId])) { - this._deletePeer(peerId); - return; - } - - var self = this; - switch (payload.type) { - case 'disconnect': - this._onClose(peerId); - break; - default: - this.emit('data', self.copayerForPeer[peerId], payload, isInbound); - } -}; - -Network.prototype._checkAnyPeer = function(msg) { - if (this.connectedPeers.length === 1) { - this.emit('onlyYou'); - } -}; - -Network.prototype._setupConnectionHandlers = function(dataConn, toCopayerId) { - var self = this; - - var isInbound = toCopayerId ? false : true; - - dataConn.on('open', function() { - if (!Network._inArray(dataConn.peer, self.connectedPeers) && - !self.connections[dataConn.peer]) { - - self.connections[dataConn.peer] = dataConn; - - // The connecting peer send hello - if (toCopayerId) { - self.emit('connected'); - self._sendHello(toCopayerId); - self._addConnectedCopayer(toCopayerId); - } - } - }); - - dataConn.on('data', function(data) { - self._onData(data, isInbound, dataConn.peer); - }); - - dataConn.on('error', function(e) { - self._onClose(dataConn.peer); - self._checkAnyPeer(); - self.emit('dataError'); - }); - - dataConn.on('close', function() { - if (self.closing) return; - - self._onClose(dataConn.peer); - self._checkAnyPeer(); - }); -}; - -Network.prototype._handlePeerOpen = function(openCallback) { - this.connectedPeers = [this.peerId]; - this.copayerForPeer[this.peerId] = this.copayerId; - return openCallback(); -}; - -Network.prototype._handlePeerError = function(err) { - console.log('RECV ERROR: ', err); - if (err.message.match(/Could\snot\sconnect\sto peer/)) { - this._checkAnyPeer(); - } else { - this.criticalError = err.message; - } -}; - -Network.prototype._handlePeerConnection = function(dataConn) { - if (this.connectedPeers.length >= self.maxPeers) { - dataConn.on('open', function() { - dataConn.close(); - }); - } else { - this._setInboundPeerAuth(dataConn.peer, false); - this._setupConnectionHandlers(dataConn); - } -}; - -Network.prototype._setupPeerHandlers = function(openCallback) { - var p = this.peer; - p.on('open', this._handlePeerOpen.bind(this, openCallback)); - p.on('error', this._handlePeerError.bind(this)); - p.on('connection', this._handlePeerConnection.bind(this)); -}; - -Network.prototype._addCopayerMap = function(peerId, copayerId) { - if (!this.copayerForPeer[peerId]) { - if (Object.keys(this.copayerForPeer).length < this.maxPeers) { - this.copayerForPeer[peerId] = copayerId; - } else {} - } -}; - -Network.prototype._setInboundPeerAuth = function(peerId, isAuthenticated) { - this.isInboundPeerAuth[peerId] = isAuthenticated; -}; - -Network.prototype.setCopayerId = function(copayerId) { - if (this.started) { - throw new Error('network already started: can not change peerId') - } - this.copayerId = copayerId; - this.copayerIdBuf = new Buffer(copayerId, 'hex'); - this.peerId = this.peerFromCopayer(this.copayerId); - this._addCopayerMap(this.peerId, copayerId); -}; - - -// TODO cache this. -Network.prototype.peerFromCopayer = function(hex) { - var SIN = bitcore.SIN; - return new SIN(new Buffer(hex, 'hex')).toString(); -}; - -Network.prototype.start = function(opts, openCallback) { - opts = opts || {}; - - if (this.started) return openCallback(); - - if (!this.privkey) - this.privkey = opts.privkey; - - this.maxPeers = opts.maxPeers || this.maxPeers; - - if (opts.token) - this.opts.token = opts.token; - - if (!this.copayerId) - this.setCopayerId(opts.copayerId); - - var self = this; - var setupPeer = function() { - if (self.connectedPeers.length > 0) return; // Already connected! - if (self.peer) { - self.peer.destroy(); - self.peer.removeAllListeners(); - } - - if (!self.criticalError && self.tries < self.reconnectAttempts) { - self.tries++; - self.opts.token = util.sha256(self.peerId).toString('hex'); - self.peer = new Peer(self.peerId, self.opts); - self.started = true; - self._setupPeerHandlers(openCallback); - - setTimeout(setupPeer, 3000); // Schedule retry - return; - } - if (self.criticalError && self.criticalError.match(/taken/)) { - self.criticalError = ' Looks like you are already connected to this wallet please close all other Copay Wallets ' - } - - self.emit('serverError', self.criticalError); - self.cleanUp(); - } - - this.tries = 0; - setupPeer(); -}; - -Network.prototype.getOnlinePeerIDs = function() { - return this.connectedPeers; -}; - -Network.prototype.getPeer = function() { - return this.peer; -}; - -Network.prototype._encode = function(topubkey, fromkey, payload, opts) { - var encoded = Message.encode(topubkey, fromkey, payload, opts); - return encoded; -}; - - -Network.prototype._decode = function(key, encoded, opts) { - var decoded = Message.decode(key, encoded, opts); - return decoded; -}; - -Network.prototype._sendToOne = function(copayerId, payload, cb) { - if (!Buffer.isBuffer(payload)) - throw new Error('payload must be a buffer'); - - var peerId = this.peerFromCopayer(copayerId); - if (peerId !== this.peerId) { - var dataConn = this.connections[peerId]; - if (dataConn) { - dataConn.send(payload); - } - } - if (typeof cb === 'function') cb(); -}; - -Network.prototype.send = function(copayerIds, payload, cb) { - if (!payload) return cb(); - - var self = this; - if (!copayerIds) { - copayerIds = this.connectedCopayers(); - payload.isBroadcast = 1; - } - - if (typeof copayerIds === 'string') - copayerIds = [copayerIds]; - - var payloadStr = JSON.stringify(payload); - var payloadBuf = new Buffer(payloadStr); - - var l = copayerIds.length; - var i = 0; - copayerIds.forEach(function(copayerId) { - self.iterateNonce(); - var opts = {nonce: self.networkNonce}; - var copayerIdBuf = new Buffer(copayerId, 'hex'); - var encPayload = self._encode(copayerIdBuf, self.getKey(), payloadBuf, opts); - var enc = new Buffer(JSON.stringify(encPayload)); - self._sendToOne(copayerId, enc, function() { - if (++i === l && typeof cb === 'function') cb(); - }); - }); -}; - - -Network.prototype.isOnline = function() { - return !!this.peer; -}; - -Network.prototype.connectTo = function(copayerId) { - var self = this; - - var peerId = this.peerFromCopayer(copayerId); - var dataConn = this.peer.connect(peerId, { - serialization: 'none', - reliable: true, - }); - self._setupConnectionHandlers(dataConn, copayerId); -}; - -Network.prototype.lockIncommingConnections = function(allowedCopayerIdsArray) { - this.allowedCopayerIds = {}; - for (var i in allowedCopayerIdsArray) { - this.allowedCopayerIds[allowedCopayerIdsArray[i]] = true; - } -}; - -Network.prototype.disconnect = function(cb, forced) { - var self = this; - self.closing = 1; - self.send(null, { - type: 'disconnect' - }, function() { - self.cleanUp(); - if (typeof cb === 'function') cb(); - }); -}; - -module.exports = Network; diff --git a/test/index.html b/test/index.html index 6d75f29c7..3b99beef9 100644 --- a/test/index.html +++ b/test/index.html @@ -16,7 +16,7 @@ - + diff --git a/test/test.network.WebRTC.js b/test/test.network.WebRTC.js deleted file mode 100644 index 8231991dc..000000000 --- a/test/test.network.WebRTC.js +++ /dev/null @@ -1,507 +0,0 @@ -'use strict'; - -var chai = chai || require('chai'); -var should = chai.should(); -var expect = chai.expect; -var sinon = sinon || require('sinon'); -var bitcore = bitcore || require('bitcore'); -var WebRTC = require('../js/models/network/WebRTC'); - -describe('Network / WebRTC', function() { - - it('should create an instance', function() { - var n = new WebRTC(); - should.exist(n); - }); - - describe('#WebRTC constructor', function() { - - it('should set reconnect attempts', function() { - var n = new WebRTC(); - n.reconnectAttempts.should.equal(3); - }); - - it('should call cleanUp', function() { - var save = WebRTC.prototype.cleanUp; - WebRTC.prototype.cleanUp = sinon.spy(); - var n = new WebRTC(); - n.cleanUp.calledOnce.should.equal(true); - WebRTC.prototype.cleanUp = save; - }); - }); - - describe('#cleanUp', function() { - - it('should not set netKey', function() { - var n = new WebRTC(); - (n.netKey === undefined).should.equal(true); - }); - - it('should set privkey to null', function() { - var n = new WebRTC(); - n.cleanUp(); - expect(n.privkey).to.equal(null); - }); - - it('should remove handlers', function() { - var n = new WebRTC(); - var save = WebRTC.prototype.removeAllListeners; - var spy = WebRTC.prototype.removeAllListeners = sinon.spy(); - n.cleanUp(); - spy.calledOnce.should.equal(true); - WebRTC.prototype.removeAllListeners = save; - }); - }); - - - describe('#_setupPeerHandlers', function() { - var n = new WebRTC(); - n.peer = {}; - var spy = n.peer.on = sinon.spy(); - it('should setup handlers', function() { - n._setupPeerHandlers(); - spy.calledWith('connection').should.equal(true); - spy.calledWith('open').should.equal(true); - spy.calledWith('error').should.equal(true); - }); - }); - - describe('#_handlePeerOpen', function() { - var n = new WebRTC(); - it('should call openCallback handler', function(done) { - n.peerId = 1; - n.copayerId = 2; - n._handlePeerOpen(function() { - n.connectedPeers.should.deep.equal([1]); - n.copayerForPeer.should.deep.equal({ - 1: 2 - }); - done(); - }); - }); - }); - - describe('#_handlePeerError', function() { - var log = console.log; - var n = new WebRTC(); - it('should call _checkAnyPeer on could not connect error', function() { - var save = n._checkAnyPeer; - var spy = n._checkAnyPeer = sinon.spy(); - var logSpy = console.log = sinon.spy(); - n._handlePeerError({ - message: 'Could not connect to peer xxx' - }); - console.log = log; - spy.called.should.equal(true); - logSpy.called.should.equal(true); - n._checkAnyPeer = save; - }); - - it('should call not call _checkAnyPeer other error', function() { - var save = n._checkAnyPeer; - var spy = n._checkAnyPeer = sinon.spy(); - var otherMessage = 'Could connect to peer xxx'; - var logSpy = console.log = sinon.spy(); - n._handlePeerError({ - message: otherMessage, - }); - console.log = log; - spy.called.should.equal(false); - n.criticalError.should.equal(otherMessage); - logSpy.called.should.equal(true); - n._checkAnyPeer = save; - }); - - }); - - - - describe('#_encode', function() { - - it('should encode data successfully', function() { - var n = new WebRTC(); - var data = new bitcore.Buffer('my data to encode'); - var privkeystr = new bitcore.Buffer('test privkey'); - var privkey = bitcore.util.sha256(privkeystr); - var key = new bitcore.Key(); - key.private = privkey; - key.regenerateSync(); - var encoded = n._encode(key.public, key, data); - should.exist(encoded); - encoded.sig.length.should.not.equal(0); - encoded.pubkey.length.should.not.equal(0); - encoded.encrypted.length.should.not.equal(0); - }); - - }); - - describe('#_decode', function() { - - it('should decode that which was encoded', function() { - var n = new WebRTC(); - var data = new bitcore.Buffer('my data to encrypt'); - var privkeystr = new bitcore.Buffer('test privkey'); - var privkey = bitcore.util.sha256(privkeystr); - var key = new bitcore.Key(); - key.private = privkey; - key.regenerateSync(); - var encoded = n._encode(key.public, key, data); - var decoded = n._decode(key, encoded); - encoded.sig.should.not.equal(0); - decoded.payload.toString().should.equal('my data to encrypt'); - }); - - }); - - describe('#send', function() { - - it('should call _sendToOne for a copayer', function(done) { - var n = new WebRTC(); - n.privkey = bitcore.util.sha256('test'); - - var data = new bitcore.Buffer('my data to send'); - - var privkeystr = new bitcore.Buffer('test privkey'); - var privkey = bitcore.util.sha256(privkeystr); - var key = new bitcore.Key(); - key.private = privkey; - key.regenerateSync(); - - var copayerId = key.public.toString('hex'); - n._sendToOne = function(a1, a2, cb) { - cb(); - }; - var opts = {}; - n.send(copayerId, data, function() { - done(); - }); - - }); - - it('should call _sendToOne with encrypted data for a copayer', function(done) { - var n = new WebRTC(); - n.privkey = bitcore.util.sha256('test'); - - var data = new bitcore.Buffer('my data to send'); - - var privkeystr = new bitcore.Buffer('test privkey'); - var privkey = bitcore.util.sha256(privkeystr); - var key = new bitcore.Key(); - key.private = privkey; - key.regenerateSync(); - - var copayerId = key.public.toString('hex'); - n._sendToOne = function(a1, enc, cb) { - var encPayload = JSON.parse(enc.toString()); - encPayload.sig.length.should.be.greaterThan(0); - cb(); - }; - var opts = {}; - n.send(copayerId, data, function() { - done(); - }); - - }); - - it('should call _sendToOne for a list of copayers', function(done) { - var n = new WebRTC(); - n.privkey = bitcore.util.sha256('test'); - - var data = new bitcore.Buffer('my data to send'); - - var privkeystr = new bitcore.Buffer('test privkey'); - var privkey = bitcore.util.sha256(privkeystr); - var key = new bitcore.Key(); - key.private = privkey; - key.regenerateSync(); - - var copayerIds = [key.public.toString('hex')]; - n._sendToOne = function(a1, a2, cb) { - cb(); - }; - var opts = {}; - n.send(copayerIds, data, function() { - done(); - }); - - }); - }); - - describe('#_onData', function() { - var privkey1 = bitcore.util.sha256('test privkey 1'); - var privkey2 = bitcore.util.sha256('test privkey 2'); - var privkey3 = bitcore.util.sha256('test privkey 2'); - - var key1 = new bitcore.Key(); - key1.private = privkey1; - key1.regenerateSync(); - - var key2 = new bitcore.Key(); - key2.private = privkey2; - key2.regenerateSync(); - - var key3 = new bitcore.Key(); - key3.private = privkey3; - key3.regenerateSync(); - - it('should not reject data sent from a peer with hijacked pubkey', function() { - var n = new WebRTC(); - n.privkey = key2.private.toString('hex'); - - var message = { - type: 'hello', - copayerId: key1.public.toString('hex') - }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var encoded = n._encode(key2.public, key1, messagebuf); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); - - n._deletePeer = sinon.spy(); - - n._onData(encodeduint, isInbound, peerId); - n._deletePeer.calledOnce.should.equal(false); - }); - - it('should reject data sent from a peer with hijacked pubkey', function() { - var n = new WebRTC(); - n.privkey = key2.private.toString('hex'); - - var message = { - type: 'hello', - copayerId: key3.public.toString('hex') //MITM pubkey 3 - }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var encoded = n._encode(key2.public, key1, messagebuf); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); - - n._deletePeer = sinon.spy(); - - n._onData(encodeduint, isInbound, peerId); - n._deletePeer.calledOnce.should.equal(true); - n._deletePeer.getCall(0).args[0].should.equal(peerId); - n._deletePeer.getCall(0).args[1].should.equal('incorrect pubkey for peerId'); - }); - - it('should not reject data sent from a peer with no previously set nonce but who is setting one now', function() { - var n = new WebRTC(); - n.privkey = key2.private.toString('hex'); - //n.networkNonces = {}; - //n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('0000000000000001', 'hex'); //previously used nonce - - var message = { - type: 'hello', - copayerId: key1.public.toString('hex') - }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var opts = {nonce: new Buffer('0000000000000001', 'hex')}; //message send with new nonce - var encoded = n._encode(key2.public, key1, messagebuf, opts); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); - - n._deletePeer = sinon.spy(); - - n._onData(encodeduint, isInbound, peerId); - n._deletePeer.calledOnce.should.equal(false); - n.getHexNonces()[(new bitcore.SIN(key1.public)).toString()].toString('hex').should.equal('0000000000000001'); - }); - - it('should not reject data sent from a peer with a really big new nonce', function() { - var n = new WebRTC(); - n.privkey = key2.private.toString('hex'); - n.networkNonces = {}; - n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000001', 'hex'); //previously used nonce - - var message = { - type: 'hello', - copayerId: key1.public.toString('hex') - }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var opts = {nonce: new Buffer('5000000000000002', 'hex')}; //message send with new nonce - var encoded = n._encode(key2.public, key1, messagebuf, opts); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); - - n._deletePeer = sinon.spy(); - - n._onData(encodeduint, isInbound, peerId); - n._deletePeer.calledOnce.should.equal(false); - }); - - it('should not reject data sent from a peer with a really big new nonce', function() { - var n = new WebRTC(); - n.privkey = key2.private.toString('hex'); - n.networkNonces = {}; - n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000001', 'hex'); //previously used nonce - - var message = { - type: 'hello', - copayerId: key1.public.toString('hex') - }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var opts = {nonce: new Buffer('5000000000000002', 'hex')}; //message send with new nonce - var encoded = n._encode(key2.public, key1, messagebuf, opts); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); - - n._deletePeer = sinon.spy(); - - n._onData(encodeduint, isInbound, peerId); - n._deletePeer.calledOnce.should.equal(false); - }); - - it('should reject data sent from a peer with an outdated nonce', function() { - var n = new WebRTC(); - n.privkey = key2.private.toString('hex'); - n.networkNonces = {}; - n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('0000000000000002', 'hex'); //previously used nonce - - var message = { - type: 'hello', - copayerId: key1.public.toString('hex') - }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var opts = {nonce: new Buffer('0000000000000001', 'hex')}; //message send with old nonce - var encoded = n._encode(key2.public, key1, messagebuf, opts); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); - - n._deletePeer = sinon.spy(); - - n._onData(encodeduint, isInbound, peerId); - n._deletePeer.calledOnce.should.equal(true); - }); - - it('should reject data sent from a peer with a really big outdated nonce', function() { - var n = new WebRTC(); - n.privkey = key2.private.toString('hex'); - n.networkNonces = {}; - n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000002', 'hex'); //previously used nonce - - var message = { - type: 'hello', - copayerId: key1.public.toString('hex') - }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var opts = {nonce: new Buffer('5000000000000001', 'hex')}; //message send with old nonce - var encoded = n._encode(key2.public, key1, messagebuf, opts); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); - - n._deletePeer = sinon.spy(); - - n._onData(encodeduint, isInbound, peerId); - n._deletePeer.calledOnce.should.equal(true); - }); - - }); - - describe('#setHexNonce', function() { - - it('should set a nonce from a hex value', function() { - var hex = '0000000000000000'; - var n = new WebRTC(); - n.setHexNonce(hex); - n.getHexNonce().should.equal(hex); - n.networkNonce.toString('hex').should.equal(hex); - }); - - }); - - describe('#setHexNonces', function() { - - it('should set a nonce from a hex value', function() { - var hex = '0000000000000000'; - var n = new WebRTC(); - n.setHexNonces({fakeid: hex}); - n.getHexNonces().fakeid.should.equal(hex); - }); - - }); - - describe('#getHexNonce', function() { - - it('should get a nonce hex value', function() { - var hex = '0000000000000000'; - var n = new WebRTC(); - n.setHexNonce(hex); - n.getHexNonce().should.equal(hex); - }); - - }); - - describe('#getHexNonces', function() { - - it('should get a nonce from a hex value', function() { - var hex = '0000000000000000'; - var n = new WebRTC(); - n.setHexNonces({fakeid: hex}); - n.getHexNonces().fakeid.should.equal(hex); - }); - - }); - - describe('#iterateNonce', function() { - - it('should set a nonce not already set', function() { - var n = new WebRTC(); - n.iterateNonce(); - n.networkNonce.slice(4, 8).toString('hex').should.equal('00000001'); - n.networkNonce.slice(0, 4).toString('hex').should.not.equal('00000000'); - }); - - it('called twice should increment', function() { - var n = new WebRTC(); - n.iterateNonce(); - n.networkNonce.slice(4, 8).toString('hex').should.equal('00000001'); - n.iterateNonce(); - n.networkNonce.slice(4, 8).toString('hex').should.equal('00000002'); - }); - - it('should set the first byte to the most significant "now" digit', function() { - var n = new WebRTC(); - n.iterateNonce(); - var buf = new Buffer(4); - buf.writeUInt32BE(Math.floor(Date.now()/1000), 0); - n.networkNonce[0].should.equal(buf[0]); - }); - - }); - -}); From 54cc8606b41ee8bd219b35b5b95d6a28c4e7c6a8 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 12:48:49 -0400 Subject: [PATCH 34/75] remove WebRTC 2 --- copay.js | 1 - util/build.js | 3 --- 2 files changed, 4 deletions(-) diff --git a/copay.js b/copay.js index d9c855cce..bc4156068 100644 --- a/copay.js +++ b/copay.js @@ -9,7 +9,6 @@ module.exports.HDParams = require('./js/models/core/HDParams'); // components -var WebRTC = module.exports.WebRTC = require('./js/models/network/WebRTC'); var Insight = module.exports.Insight = require('./js/models/blockchain/Insight'); var StorageLocalEncrypted = module.exports.StorageLocalEncrypted = require('./js/models/storage/LocalEncrypted'); diff --git a/util/build.js b/util/build.js index 1a7f0a9c1..3c1e683d8 100644 --- a/util/build.js +++ b/util/build.js @@ -44,9 +44,6 @@ var createBundle = function(opts) { b.require('./js/models/core/WalletLock', { expose: '../js/models/core/WalletLock' }); - b.require('./js/models/network/WebRTC', { - expose: '../js/models/network/WebRTC' - }); b.require('./js/models/blockchain/Insight', { expose: '../js/models/blockchain/Insight' }); From 0b803738940eb40ec90b045cfce016c180c57d9e Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 12:50:49 -0400 Subject: [PATCH 35/75] fix test 1 --- test/test.Wallet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.Wallet.js b/test/test.Wallet.js index e46c1c3c3..8d90d799b 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -441,7 +441,7 @@ describe('Wallet model', function() { receiveIndex: 2 }] }; - w._handleIndexes('senderID', aiObj, true); + w._onIndexes('senderID', aiObj, true); w.publicKeyRing.getHDParams(0).getReceiveIndex(2); w.publicKeyRing.getHDParams(0).getChangeIndex(3); }); From 73390cebf8349158d60cbe37dd49d54d4ba4b36a Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 12:51:08 -0400 Subject: [PATCH 36/75] fix test 2 --- test/test.Wallet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.Wallet.js b/test/test.Wallet.js index 8d90d799b..e316234ea 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -467,7 +467,7 @@ describe('Wallet model', function() { copayersExtPubKeys: cepk, nicknameFor: {}, }; - w._handlePublicKeyRing('senderID', { + w._onPublicKeyRing('senderID', { publicKeyRing: pkrObj }, true); w.publicKeyRing.getHDParams(0).getReceiveIndex(2); From f5e7886a72d76e732a07e0f47f5b7227cabe28cc Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 12:51:55 -0400 Subject: [PATCH 37/75] fix test 3 --- test/test.Wallet.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/test/test.Wallet.js b/test/test.Wallet.js index e316234ea..65738da9e 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -512,7 +512,7 @@ describe('Wallet model', function() { var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys').returns({ '027445ab3a935dce7aee1dadb0d103ed6147a0f83deb80474a04538b2c5bc4d509': 'pepe' }); - w._handleTxProposal('senderID', txp, true); + w._onTxProposal('senderID', txp, true); Object.keys(w.txProposals.txps).length.should.equal(1); w.getTxProposals().length.should.equal(1); //stub.restore(); @@ -525,7 +525,7 @@ describe('Wallet model', function() { id.should.equal(newId); done(); }); - w._handleConnect(newId); + w._onConnect(newId); }); it('handle disconnections', function(done) { @@ -534,7 +534,7 @@ describe('Wallet model', function() { id.should.equal(newId); done(); }); - w._handleDisconnect(newId); + w._onDisconnect(newId); }); it('should register new copayers correctly', function() { @@ -993,7 +993,7 @@ describe('Wallet model', function() { var senderId = "03baa45498fee1045fa8f91a2913f638dc3979b455498924d3cf1a11303c679cdb"; Object.keys(w.addressBook).length.should.equal(2); - w._handleAddressBook(senderId, data, true); + w._onAddressBook(senderId, data, true); Object.keys(w.addressBook).length.should.equal(3); }); @@ -1252,7 +1252,7 @@ describe('Wallet model', function() { - describe('_handleTxProposal', function() { + describe('_onTxProposal', function() { var testValidate = function(response, result, done) { var w = cachedCreateW(); @@ -1278,7 +1278,7 @@ describe('Wallet model', function() { }; }); - w._handleTxProposal('senderID', txp); + w._onTxProposal('senderID', txp); spy.callCount.should.equal(1); merge.restore(); }; @@ -1299,11 +1299,11 @@ describe('Wallet model', function() { }); - describe('_handleReject', function() { + describe('_onReject', function() { it('should fails if unknown tx', function() { var w = cachedCreateW(); (function() { - w._handleReject(1, { + w._onReject(1, { ntxid: 1 }, 1); }).should.throw('Unknown TXP'); @@ -1316,7 +1316,7 @@ describe('Wallet model', function() { } }; (function() { - w._handleReject('john', { + w._onReject('john', { ntxid: 'qwerty' }, 1); }).should.throw('already signed'); @@ -1337,7 +1337,7 @@ describe('Wallet model', function() { var spy2 = sinon.spy(w, 'emit'); w.txProposals.txps['qwerty'] = new txp(); w.txProposals.txps['qwerty'].ok.should.equal(0); - w._handleReject('john', { + w._onReject('john', { ntxid: 'qwerty' }, 1); w.txProposals.txps['qwerty'].ok.should.equal(1); @@ -1353,11 +1353,11 @@ describe('Wallet model', function() { }); - describe('_handleSeen', function() { + describe('_onSeen', function() { it('should fails if unknown tx', function() { var w = cachedCreateW(); (function() { - w._handleReject(1, { + w._onReject(1, { ntxid: 1 }, 1); }).should.throw('Unknown TXP'); @@ -1378,7 +1378,7 @@ describe('Wallet model', function() { var spy2 = sinon.spy(w, 'emit'); w.txProposals.txps['qwerty'] = new txp(); w.txProposals.txps['qwerty'].ok.should.equal(0); - w._handleSeen('john', { + w._onSeen('john', { ntxid: 'qwerty' }, 1); w.txProposals.txps['qwerty'].ok.should.equal(1); From 8709d91b37f5edaf8ca46690664c924392d8e55c Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 13:12:05 -0400 Subject: [PATCH 38/75] fix test 4 --- test/test.Wallet.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test.Wallet.js b/test/test.Wallet.js index 65738da9e..60667cf53 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -1402,9 +1402,9 @@ describe('Wallet model', function() { it('#disconnect', function() { var w = cachedCreateW(); - var spy1 = sinon.spy(w.network, 'disconnect'); + var spy1 = sinon.spy(w, 'send'); w.disconnect(); - spy1.callCount.should.equal(1); + spy1.calledOnce.should.be.true; }); }); From 850c4c6f703f74b3fcd3ec7e10e537d34adaa8ed Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 13:13:00 -0400 Subject: [PATCH 39/75] fix test 4 --- test/test.Wallet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.Wallet.js b/test/test.Wallet.js index 60667cf53..c23a27294 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -1093,7 +1093,7 @@ describe('Wallet model', function() { it('should throw if network is different', function() { var backup = copayConfig.forceNetwork; copayConfig.forceNetwork = true; - config.networkName = 'livenet'; + config.networkName = 'testnet'; cachedCreateW2.should.throw(Error); copayConfig.forceNetwork = backup; }); From 6fa50f1dc2481300a0308083e8990ed2fe3ce8d8 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 13:19:16 -0400 Subject: [PATCH 40/75] fix test 5 --- test/test.Wallet.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test.Wallet.js b/test/test.Wallet.js index c23a27294..3406cf42c 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -1093,8 +1093,8 @@ describe('Wallet model', function() { it('should throw if network is different', function() { var backup = copayConfig.forceNetwork; copayConfig.forceNetwork = true; - config.networkName = 'testnet'; - cachedCreateW2.should.throw(Error); + config.networkName = 'livenet'; + createW2.should.throw(Error); copayConfig.forceNetwork = backup; }); }); From df3aafe1a9eba09d9ff9a8b30ae0314fc0e28ef3 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 13:21:34 -0400 Subject: [PATCH 41/75] fix test 6 --- js/models/network/Async.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 5da895e08..7b3222b37 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -23,7 +23,6 @@ var preconditions = require('preconditions').singleton(); */ function Network(opts) { - preconditions.checkArgument(opts); var self = this; opts = opts || {}; this.maxPeers = opts.maxPeers || 12; From ed7916f1bee1c29e0f240a68858ea702cf39c9ae Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 13:57:34 -0400 Subject: [PATCH 42/75] fix test 7, removed a test that made no sense --- js/models/network/Async.js | 38 +++++++------- test/test.network.Async.js | 101 ++++++++++++++++--------------------- 2 files changed, 61 insertions(+), 78 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 7b3222b37..29c021cdb 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -119,8 +119,8 @@ Network.prototype._addConnectedCopayer = function(copayerId) { }; Network.prototype.getKey = function() { + preconditions.checkState(this.privkey || this.key); if (!this.key) { - preconditions.checkState(this.privkey); var key = new bitcore.Key(); key.private = new Buffer(this.privkey, 'hex'); key.regenerateSync(); @@ -286,42 +286,40 @@ Network.prototype.peerFromCopayer = function(hex) { }; Network.prototype.start = function(opts, openCallback) { - opts = opts || {}; + preconditions.checkArgument(opts); + preconditions.checkArgument(opts.privkey); + preconditions.checkArgument(opts.copayerId); + preconditions.checkArgument(opts.lastTimestamp); + + preconditions.checkState(this.connectedPeers && this.connectedPeers.length === 0); if (this.started) return openCallback(); - if (!this.privkey) - this.privkey = opts.privkey; - + this.privkey = opts.privkey; + var pubkey = this.getKey().public.toString('hex'); + this.setCopayerId(opts.copayerId); this.maxPeers = opts.maxPeers || this.maxPeers; - if (opts.token) - this.opts.token = opts.token; - - if (!this.copayerId) - this.setCopayerId(opts.copayerId); - - if (this.connectedPeers.length > 0) { - // already connected - return; - } if (this.socket) { this.socket.destroy(); this.socket.removeAllListeners(); } - var hostPort = this.host + ':' + this.port; - this.socket = io.connect(hostPort, { - reconnection: true, - }); + this.socket = this.createSocket(this.host, this.port); this._setupConnectionHandlers(openCallback); - var pubkey = this.getKey().public.toString('hex'); this.socket.emit('subscribe', pubkey); this.socket.emit('sync', opts.lastTimestamp); this.started = true; }; +Network.prototype.createSocket = function(host, port) { + var hostPort = host + ':' + port; + return io.connect(hostPort, { + reconnection: true, + }); +}; + Network.prototype.getOnlinePeerIDs = function() { return this.connectedPeers; }; diff --git a/test/test.network.Async.js b/test/test.network.Async.js index 89fce1cd4..cf73279de 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -6,40 +6,46 @@ var expect = chai.expect; var sinon = sinon || require('sinon'); var bitcore = bitcore || require('bitcore'); var Async = require('../js/models/network/Async'); +var EventEmitter = require('events').EventEmitter; describe('Network / Async', function() { - it('should create an instance', function() { + + var createN = function() { var n = new Async(); + var fakeSocket = new EventEmitter(); + n.createSocket = function() { + return fakeSocket; + }; + var opts = { + copayerId: '03b51d01d798522cf61211b4dfcdd6db219ee33cf166e1cb7f43d836ab00ccddee', + privkey: '31701118abde096d166607115ed00ce74a2231f68f43144406c863f5ebf06c32', + lastTimestamp: 1, + }; + n.start(opts); + return n; + }; + + it('should create an instance', function() { + var n = createN(); should.exist(n); }); - describe('#Async constructor', function() { - - it('should call cleanUp', function() { - var save = Async.prototype.cleanUp; - Async.prototype.cleanUp = sinon.spy(); - var n = new Async(); - n.cleanUp.calledOnce.should.equal(true); - Async.prototype.cleanUp = save; - }); - }); - describe('#cleanUp', function() { it('should not set netKey', function() { - var n = new Async(); + var n = createN(); (n.netKey === undefined).should.equal(true); }); it('should set privkey to null', function() { - var n = new Async(); + var n = createN(); n.cleanUp(); expect(n.privkey).to.equal(null); }); it('should remove handlers', function() { - var n = new Async(); + var n = createN(); var save = Async.prototype.removeAllListeners; var spy = Async.prototype.removeAllListeners = sinon.spy(); n.cleanUp(); @@ -51,41 +57,27 @@ describe('Network / Async', function() { describe('#send', function() { it('should call _sendToOne for a copayer', function(done) { - var n = new Async(); + var n = createN(); n.privkey = bitcore.util.sha256('test'); var data = new bitcore.Buffer('my data to send'); - var privkeystr = new bitcore.Buffer('test privkey'); - var privkey = bitcore.util.sha256(privkeystr); - var key = new bitcore.Key(); - key.private = privkey; - key.regenerateSync(); - - var copayerId = key.public.toString('hex'); - n._sendToOne = function(a1, a2, cb) { + var copayerId = '03b51d01d798522cf61211b4dfcdd6db219ee33cf166e1cb7f43d836abc5c18b23'; + n._sendToOne = function(a, b, cb) { cb(); }; var opts = {}; - n.send(copayerId, data, function() { - done(); - }); + n.send(copayerId, data, done); }); it('should call _sendToOne with encrypted data for a copayer', function(done) { - var n = new Async(); + var n = createN(); n.privkey = bitcore.util.sha256('test'); var data = new bitcore.Buffer('my data to send'); - var privkeystr = new bitcore.Buffer('test privkey'); - var privkey = bitcore.util.sha256(privkeystr); - var key = new bitcore.Key(); - key.private = privkey; - key.regenerateSync(); - - var copayerId = key.public.toString('hex'); + var copayerId = '03b51d01d798522cf61211b4dfcdd6db219ee33cf166e1cb7f43d836abc5c18b23'; n._sendToOne = function(a1, enc, cb) { var encPayload = JSON.parse(enc.toString()); encPayload.sig.length.should.be.greaterThan(0); @@ -99,18 +91,11 @@ describe('Network / Async', function() { }); it('should call _sendToOne for a list of copayers', function(done) { - var n = new Async(); + var n = createN(); n.privkey = bitcore.util.sha256('test'); var data = new bitcore.Buffer('my data to send'); - - var privkeystr = new bitcore.Buffer('test privkey'); - var privkey = bitcore.util.sha256(privkeystr); - var key = new bitcore.Key(); - key.private = privkey; - key.regenerateSync(); - - var copayerIds = [key.public.toString('hex')]; + var copayerIds = ['03b51d01d798522cf61211b4dfcdd6db219ee33cf166e1cb7f43d836abc5c18b23']; n._sendToOne = function(a1, a2, cb) { cb(); }; @@ -140,7 +125,7 @@ describe('Network / Async', function() { key3.regenerateSync(); it('should not reject data sent from a peer with hijacked pubkey', function() { - var n = new Async(); + var n = createN(); n.privkey = key2.private.toString('hex'); var message = { @@ -164,7 +149,7 @@ describe('Network / Async', function() { }); it('should reject data sent from a peer with hijacked pubkey', function() { - var n = new Async(); + var n = createN(); n.privkey = key2.private.toString('hex'); var message = { @@ -190,7 +175,7 @@ describe('Network / Async', function() { }); it('should not reject data sent from a peer with no previously set nonce but who is setting one now', function() { - var n = new Async(); + var n = createN(); n.privkey = key2.private.toString('hex'); //n.networkNonces = {}; //n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('0000000000000001', 'hex'); //previously used nonce @@ -220,7 +205,7 @@ describe('Network / Async', function() { }); it('should not reject data sent from a peer with a really big new nonce', function() { - var n = new Async(); + var n = createN(); n.privkey = key2.private.toString('hex'); n.networkNonces = {}; n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000001', 'hex'); //previously used nonce @@ -249,7 +234,7 @@ describe('Network / Async', function() { }); it('should not reject data sent from a peer with a really big new nonce', function() { - var n = new Async(); + var n = createN(); n.privkey = key2.private.toString('hex'); n.networkNonces = {}; n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000001', 'hex'); //previously used nonce @@ -278,7 +263,7 @@ describe('Network / Async', function() { }); it('should reject data sent from a peer with an outdated nonce', function() { - var n = new Async(); + var n = createN(); n.privkey = key2.private.toString('hex'); n.networkNonces = {}; n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('0000000000000002', 'hex'); //previously used nonce @@ -307,7 +292,7 @@ describe('Network / Async', function() { }); it('should reject data sent from a peer with a really big outdated nonce', function() { - var n = new Async(); + var n = createN(); n.privkey = key2.private.toString('hex'); n.networkNonces = {}; n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000002', 'hex'); //previously used nonce @@ -341,7 +326,7 @@ describe('Network / Async', function() { it('should set a nonce from a hex value', function() { var hex = '0000000000000000'; - var n = new Async(); + var n = createN(); n.setHexNonce(hex); n.getHexNonce().should.equal(hex); n.networkNonce.toString('hex').should.equal(hex); @@ -353,7 +338,7 @@ describe('Network / Async', function() { it('should set a nonce from a hex value', function() { var hex = '0000000000000000'; - var n = new Async(); + var n = createN(); n.setHexNonces({ fakeid: hex }); @@ -366,7 +351,7 @@ describe('Network / Async', function() { it('should get a nonce hex value', function() { var hex = '0000000000000000'; - var n = new Async(); + var n = createN(); n.setHexNonce(hex); n.getHexNonce().should.equal(hex); }); @@ -377,7 +362,7 @@ describe('Network / Async', function() { it('should get a nonce from a hex value', function() { var hex = '0000000000000000'; - var n = new Async(); + var n = createN(); n.setHexNonces({ fakeid: hex }); @@ -389,14 +374,14 @@ describe('Network / Async', function() { describe('#iterateNonce', function() { it('should set a nonce not already set', function() { - var n = new Async(); + var n = createN(); n.iterateNonce(); n.networkNonce.slice(4, 8).toString('hex').should.equal('00000001'); n.networkNonce.slice(0, 4).toString('hex').should.not.equal('00000000'); }); it('called twice should increment', function() { - var n = new Async(); + var n = createN(); n.iterateNonce(); n.networkNonce.slice(4, 8).toString('hex').should.equal('00000001'); n.iterateNonce(); @@ -404,7 +389,7 @@ describe('Network / Async', function() { }); it('should set the first byte to the most significant "now" digit', function() { - var n = new Async(); + var n = createN(); n.iterateNonce(); var buf = new Buffer(4); buf.writeUInt32BE(Math.floor(Date.now() / 1000), 0); From 372d230e179b79f5b3706ca754607862cedcc83b Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 14:22:13 -0400 Subject: [PATCH 43/75] fix test 8 --- js/models/network/Async.js | 48 +++++++++++++++++++++++--------------- test/test.network.Async.js | 9 +++++-- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 29c021cdb..f348f2d7b 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -179,22 +179,28 @@ Network.prototype.iterateNonce = function() { return this.networkNonce; }; -Network.prototype._onMessage = function(enc) { +Network.prototype.decode = function(enc) { + var sender = enc.pubkey; var key = this.getKey(); + var prevnonce = this.networkNonces ? this.networkNonces[sender] : undefined; + var opts = { + prevnonce: prevnonce + }; + var decoded = AuthMessage.decode(key, enc, opts); + + //if no error thrown in the last step, we can set the copayer's nonce + if (!this.networkNonces) + this.networkNonces = {}; + this.networkNonces[sender] = decoded.nonce; + + var payload = decoded.payload; + return payload; +}; + +Network.prototype._onMessage = function(enc) { var sender = enc.pubkey; try { - var prevnonce = this.networkNonces ? this.networkNonces[sender] : undefined; - var opts = { - prevnonce: prevnonce - }; - var decoded = AuthMessage.decode(key, enc, opts); - - //if no error thrown in the last step, we can set the copayer's nonce - if (!this.networkNonces) - this.networkNonces = {}; - this.networkNonces[sender] = decoded.nonce; - - var payload = decoded.payload; + var payload = this.decode(enc); } catch (e) { this._deletePeer(sender); return; @@ -359,18 +365,22 @@ Network.prototype.send = function(copayerIds, payload, cb) { //console.log('sending ' + JSON.stringify(payload)); copayerIds.forEach(function(copayerId) { //console.log('\t to ' + copayerId); - self.iterateNonce(); - var opts = { - nonce: self.networkNonce - }; - var copayerIdBuf = new Buffer(copayerId, 'hex'); - var message = AuthMessage.encode(copayerIdBuf, self.getKey(), payload, opts); + var message = self.encode(copayerId, payload); self.socket.emit('message', message); }); if (typeof cb === 'function') cb(); }; +Network.prototype.encode = function(copayerId, payload) { + this.iterateNonce(); + var opts = { + nonce: this.networkNonce + }; + var copayerIdBuf = new Buffer(copayerId, 'hex'); + var message = AuthMessage.encode(copayerIdBuf, this.getKey(), payload, opts); +}; + Network.prototype.isOnline = function() { return !!this.socket; }; diff --git a/test/test.network.Async.js b/test/test.network.Async.js index cf73279de..f6860d7eb 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -127,6 +127,7 @@ describe('Network / Async', function() { it('should not reject data sent from a peer with hijacked pubkey', function() { var n = createN(); n.privkey = key2.private.toString('hex'); + n.key = null; var message = { type: 'hello', @@ -151,6 +152,7 @@ describe('Network / Async', function() { it('should reject data sent from a peer with hijacked pubkey', function() { var n = createN(); n.privkey = key2.private.toString('hex'); + n.key = null; var message = { type: 'hello', @@ -177,8 +179,7 @@ describe('Network / Async', function() { it('should not reject data sent from a peer with no previously set nonce but who is setting one now', function() { var n = createN(); n.privkey = key2.private.toString('hex'); - //n.networkNonces = {}; - //n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('0000000000000001', 'hex'); //previously used nonce + n.key = null; var message = { type: 'hello', @@ -207,6 +208,7 @@ describe('Network / Async', function() { it('should not reject data sent from a peer with a really big new nonce', function() { var n = createN(); n.privkey = key2.private.toString('hex'); + n.key = null; n.networkNonces = {}; n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000001', 'hex'); //previously used nonce @@ -236,6 +238,7 @@ describe('Network / Async', function() { it('should not reject data sent from a peer with a really big new nonce', function() { var n = createN(); n.privkey = key2.private.toString('hex'); + n.key = false; n.networkNonces = {}; n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000001', 'hex'); //previously used nonce @@ -265,6 +268,7 @@ describe('Network / Async', function() { it('should reject data sent from a peer with an outdated nonce', function() { var n = createN(); n.privkey = key2.private.toString('hex'); + n.key = null; n.networkNonces = {}; n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('0000000000000002', 'hex'); //previously used nonce @@ -294,6 +298,7 @@ describe('Network / Async', function() { it('should reject data sent from a peer with a really big outdated nonce', function() { var n = createN(); n.privkey = key2.private.toString('hex'); + n.key = null; n.networkNonces = {}; n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000002', 'hex'); //previously used nonce From 302bc4bf7e694f4559952afd6c46d6c69b90e9e6 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 15:08:10 -0400 Subject: [PATCH 44/75] fix test 9 --- js/models/network/Async.js | 17 +++++----- test/test.network.Async.js | 69 +++++++++++++++++--------------------- 2 files changed, 38 insertions(+), 48 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index f348f2d7b..1a1fecd49 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -206,24 +206,22 @@ Network.prototype._onMessage = function(enc) { return; } - // TODO - /* - if (!this.copayerForPeer[sender] || (isInbound && !this.isInboundPeerAuth[sender])) { - this._deletePeer(sender); - return; - } - */ - - //console.log('receiving ' + JSON.stringify(payload)); var self = this; switch (payload.type) { case 'hello': + // if we locked allowed copayers, check if it belongs if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) { this._deletePeer(sender); return; } + //ensure claimed public key is actually the public key of the peer + //e.g., their public key should hash to be their peerId + if (enc.pubkey !== this.peerFromCopayer(payload.copayerId)) { + this._deletePeer(enc.pubkey, 'incorrect pubkey for peerId'); + return; + } this._addConnectedCopayer(payload.copayerId); break; default: @@ -379,6 +377,7 @@ Network.prototype.encode = function(copayerId, payload) { }; var copayerIdBuf = new Buffer(copayerId, 'hex'); var message = AuthMessage.encode(copayerIdBuf, this.getKey(), payload, opts); + return message; }; Network.prototype.isOnline = function() { diff --git a/test/test.network.Async.js b/test/test.network.Async.js index f6860d7eb..3680a97f8 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -11,15 +11,17 @@ var EventEmitter = require('events').EventEmitter; describe('Network / Async', function() { - var createN = function() { + var createN = function(pk) { var n = new Async(); - var fakeSocket = new EventEmitter(); + var fakeSocket = {}; + fakeSocket.emit = function() {}; + fakeSocket.on = function() {}; n.createSocket = function() { return fakeSocket; }; var opts = { copayerId: '03b51d01d798522cf61211b4dfcdd6db219ee33cf166e1cb7f43d836ab00ccddee', - privkey: '31701118abde096d166607115ed00ce74a2231f68f43144406c863f5ebf06c32', + privkey: pk || '31701118abde096d166607115ed00ce74a2231f68f43144406c863f5ebf06c32', lastTimestamp: 1, }; n.start(opts); @@ -59,10 +61,11 @@ describe('Network / Async', function() { it('should call _sendToOne for a copayer', function(done) { var n = createN(); n.privkey = bitcore.util.sha256('test'); + n.key = null; var data = new bitcore.Buffer('my data to send'); - var copayerId = '03b51d01d798522cf61211b4dfcdd6db219ee33cf166e1cb7f43d836abc5c18b23'; + var copayerId = '03b51d01d798522cf61211b4dfcdd6d01020304cf166e1cb7f43d836abc5c18b23'; n._sendToOne = function(a, b, cb) { cb(); }; @@ -74,10 +77,11 @@ describe('Network / Async', function() { it('should call _sendToOne with encrypted data for a copayer', function(done) { var n = createN(); n.privkey = bitcore.util.sha256('test'); + n.key = null; var data = new bitcore.Buffer('my data to send'); - var copayerId = '03b51d01d798522cf61211b4dfcdd6db219ee33cf166e1cb7f43d836abc5c18b23'; + var copayerId = '03b51d01d798522cf61001b4dfcdd6db219ee33cf166e1cb7f43d836abc5c18b23'; n._sendToOne = function(a1, enc, cb) { var encPayload = JSON.parse(enc.toString()); encPayload.sig.length.should.be.greaterThan(0); @@ -107,7 +111,7 @@ describe('Network / Async', function() { }); }); - describe('#_onData', function() { + describe('#_onMessage', function() { var privkey1 = bitcore.util.sha256('test privkey 1'); var privkey2 = bitcore.util.sha256('test privkey 2'); var privkey3 = bitcore.util.sha256('test privkey 2'); @@ -115,62 +119,49 @@ describe('Network / Async', function() { var key1 = new bitcore.Key(); key1.private = privkey1; key1.regenerateSync(); + var pk1 = key1.private.toString('hex'); + var cid1 = key1.public.toString('hex'); var key2 = new bitcore.Key(); key2.private = privkey2; key2.regenerateSync(); + var pk2 = key2.private.toString('hex'); + var cid2 = key2.public.toString('hex'); var key3 = new bitcore.Key(); key3.private = privkey3; key3.regenerateSync(); + var pk3 = key3.private.toString('hex'); + var cid3 = key3.public.toString('hex'); it('should not reject data sent from a peer with hijacked pubkey', function() { - var n = createN(); - n.privkey = key2.private.toString('hex'); - n.key = null; + var n = createN(pk2); var message = { type: 'hello', - copayerId: key1.public.toString('hex') + copayerId: cid1 }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var encoded = n._encode(key2.public, key1, messagebuf); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); + var enc = n.encode(cid2, message); n._deletePeer = sinon.spy(); - n._onData(encodeduint, isInbound, peerId); + n._onMessage(enc); n._deletePeer.calledOnce.should.equal(false); }); it('should reject data sent from a peer with hijacked pubkey', function() { - var n = createN(); - n.privkey = key2.private.toString('hex'); - n.key = null; + var n = createN(pk2); var message = { type: 'hello', - copayerId: key3.public.toString('hex') //MITM pubkey 3 + copayerId: cid3 // MITM }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var encoded = n._encode(key2.public, key1, messagebuf); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); + + var enc = n.encode(cid2, message); n._deletePeer = sinon.spy(); - n._onData(encodeduint, isInbound, peerId); + n._onMessage(enc); n._deletePeer.calledOnce.should.equal(true); n._deletePeer.getCall(0).args[0].should.equal(peerId); n._deletePeer.getCall(0).args[1].should.equal('incorrect pubkey for peerId'); @@ -200,7 +191,7 @@ describe('Network / Async', function() { n._deletePeer = sinon.spy(); - n._onData(encodeduint, isInbound, peerId); + n._onMessage(encodeduint, isInbound, peerId); n._deletePeer.calledOnce.should.equal(false); n.getHexNonces()[(new bitcore.SIN(key1.public)).toString()].toString('hex').should.equal('0000000000000001'); }); @@ -231,7 +222,7 @@ describe('Network / Async', function() { n._deletePeer = sinon.spy(); - n._onData(encodeduint, isInbound, peerId); + n._onMessage(encodeduint, isInbound, peerId); n._deletePeer.calledOnce.should.equal(false); }); @@ -261,7 +252,7 @@ describe('Network / Async', function() { n._deletePeer = sinon.spy(); - n._onData(encodeduint, isInbound, peerId); + n._onMessage(encodeduint, isInbound, peerId); n._deletePeer.calledOnce.should.equal(false); }); @@ -291,7 +282,7 @@ describe('Network / Async', function() { n._deletePeer = sinon.spy(); - n._onData(encodeduint, isInbound, peerId); + n._onMessage(encodeduint, isInbound, peerId); n._deletePeer.calledOnce.should.equal(true); }); @@ -321,7 +312,7 @@ describe('Network / Async', function() { n._deletePeer = sinon.spy(); - n._onData(encodeduint, isInbound, peerId); + n._onMessage(encodeduint, isInbound, peerId); n._deletePeer.calledOnce.should.equal(true); }); From fc5c860d491e0297a9e41ae3005555b8acc2462c Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 15:15:06 -0400 Subject: [PATCH 45/75] refactor --- js/models/network/Async.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 1a1fecd49..543372f7e 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -218,7 +218,10 @@ Network.prototype._onMessage = function(enc) { } //ensure claimed public key is actually the public key of the peer //e.g., their public key should hash to be their peerId - if (enc.pubkey !== this.peerFromCopayer(payload.copayerId)) { + if (enc.pubkey !== payload.copayerId) { + console.log(JSON.stringify(enc)); + console.log(JSON.stringify(enc.pubkey)); + console.log(JSON.stringify(payload.copayerId)); this._deletePeer(enc.pubkey, 'incorrect pubkey for peerId'); return; } @@ -346,24 +349,24 @@ Network.prototype.getCopayerIds = function() { }; -Network.prototype.send = function(copayerIds, payload, cb) { +Network.prototype.send = function(dest, payload, cb) { preconditions.checkArgument(payload); var self = this; - if (!copayerIds) { - copayerIds = this.getCopayerIds(); + if (!dest) { + defst = this.getCopayerIds(); payload.isBroadcast = 1; } - if (typeof copayerIds === 'string') - copayerIds = [copayerIds]; + if (typeof dest === 'string') + dest = [dest]; - var l = copayerIds.length; + var l = dest.length; var i = 0; //console.log('sending ' + JSON.stringify(payload)); - copayerIds.forEach(function(copayerId) { - //console.log('\t to ' + copayerId); - var message = self.encode(copayerId, payload); + dest.forEach(function(to) { + //console.log('\t to ' + to); + var message = self.encode(to, payload); self.socket.emit('message', message); }); if (typeof cb === 'function') cb(); From 609d0327cc4f528df429226b0c6a3722d2484d3d Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 15:29:17 -0400 Subject: [PATCH 46/75] refactor into simpler tests --- test/test.network.Async.js | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/test/test.network.Async.js b/test/test.network.Async.js index 3680a97f8..069590168 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -112,27 +112,14 @@ describe('Network / Async', function() { }); describe('#_onMessage', function() { - var privkey1 = bitcore.util.sha256('test privkey 1'); - var privkey2 = bitcore.util.sha256('test privkey 2'); - var privkey3 = bitcore.util.sha256('test privkey 2'); + var pk1 = 'fb23b9074ca5e7163719b86b41c7ce8348cf3d2839bb5f6125ef6efd5d40d7d3'; + var cid1 = '0311a10109320efb3646c832d3e140c6d9c4f69b16e73fc3f0c23b3d014ec77828'; - var key1 = new bitcore.Key(); - key1.private = privkey1; - key1.regenerateSync(); - var pk1 = key1.private.toString('hex'); - var cid1 = key1.public.toString('hex'); + var pk2 = '89073fe4d3fdef2c5f2909bcda92e4470633f08640d1a62acc464327d611577e'; + var cid2 = '03ceefb9dbcf7410411e5c1268d9d8e850ffd3a55da764a8377f3212571a52c01b'; - var key2 = new bitcore.Key(); - key2.private = privkey2; - key2.regenerateSync(); - var pk2 = key2.private.toString('hex'); - var cid2 = key2.public.toString('hex'); - - var key3 = new bitcore.Key(); - key3.private = privkey3; - key3.regenerateSync(); - var pk3 = key3.private.toString('hex'); - var cid3 = key3.public.toString('hex'); + var pk3 = 'a2ae2c7029c6a4136d7fe60c4d078a2e9d5af8a246bf2d5fee3410e273a5d430'; + var cid3 = '034d3dd2054234737c1cff9d973c9c7e0fb5902c8e56c9d57a699b7842cedfe984'; it('should not reject data sent from a peer with hijacked pubkey', function() { var n = createN(pk2); @@ -162,6 +149,7 @@ describe('Network / Async', function() { n._deletePeer = sinon.spy(); n._onMessage(enc); + console.log(n._deletePeer.callCount); n._deletePeer.calledOnce.should.equal(true); n._deletePeer.getCall(0).args[0].should.equal(peerId); n._deletePeer.getCall(0).args[1].should.equal('incorrect pubkey for peerId'); From c4515d644d7798c7cde8842be3501ad415e551d5 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 15:35:14 -0400 Subject: [PATCH 47/75] fix test 10 --- js/models/network/Async.js | 5 +---- test/test.network.Async.js | 13 ++++++------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 543372f7e..b6fb92cfb 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -218,10 +218,7 @@ Network.prototype._onMessage = function(enc) { } //ensure claimed public key is actually the public key of the peer //e.g., their public key should hash to be their peerId - if (enc.pubkey !== payload.copayerId) { - console.log(JSON.stringify(enc)); - console.log(JSON.stringify(enc.pubkey)); - console.log(JSON.stringify(payload.copayerId)); + if (sender !== payload.copayerId) { this._deletePeer(enc.pubkey, 'incorrect pubkey for peerId'); return; } diff --git a/test/test.network.Async.js b/test/test.network.Async.js index 069590168..ead9de985 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -122,18 +122,17 @@ describe('Network / Async', function() { var cid3 = '034d3dd2054234737c1cff9d973c9c7e0fb5902c8e56c9d57a699b7842cedfe984'; it('should not reject data sent from a peer with hijacked pubkey', function() { - var n = createN(pk2); + var n1 = createN(pk1); + var n2 = createN(pk2); + n2._deletePeer = sinon.spy(); var message = { type: 'hello', copayerId: cid1 }; - var enc = n.encode(cid2, message); - - n._deletePeer = sinon.spy(); - - n._onMessage(enc); - n._deletePeer.calledOnce.should.equal(false); + var enc = n1.encode(cid2, message); + n2._onMessage(enc); + n2._deletePeer.calledOnce.should.equal(false); }); it('should reject data sent from a peer with hijacked pubkey', function() { From 5ace0c7e464478437118b21d0cbb32f061b70834 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 15:40:57 -0400 Subject: [PATCH 48/75] fix test 11+12 --- test/test.network.Async.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/test.network.Async.js b/test/test.network.Async.js index ead9de985..cc8b8886f 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -150,14 +150,11 @@ describe('Network / Async', function() { n._onMessage(enc); console.log(n._deletePeer.callCount); n._deletePeer.calledOnce.should.equal(true); - n._deletePeer.getCall(0).args[0].should.equal(peerId); n._deletePeer.getCall(0).args[1].should.equal('incorrect pubkey for peerId'); }); it('should not reject data sent from a peer with no previously set nonce but who is setting one now', function() { - var n = createN(); - n.privkey = key2.private.toString('hex'); - n.key = null; + var n = createN(pk2); var message = { type: 'hello', From 50348a171f1c4a4fca10dc90ea99275e5f68e106 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 15:48:09 -0400 Subject: [PATCH 49/75] fix test 13 --- js/models/network/Async.js | 4 ++-- test/test.network.Async.js | 29 +++++++++-------------------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index b6fb92cfb..b8c5a5cb8 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -370,10 +370,10 @@ Network.prototype.send = function(dest, payload, cb) { }; -Network.prototype.encode = function(copayerId, payload) { +Network.prototype.encode = function(copayerId, payload, nonce) { this.iterateNonce(); var opts = { - nonce: this.networkNonce + nonce: nonce || this.networkNonce }; var copayerIdBuf = new Buffer(copayerId, 'hex'); var message = AuthMessage.encode(copayerIdBuf, this.getKey(), payload, opts); diff --git a/test/test.network.Async.js b/test/test.network.Async.js index cc8b8886f..75a7feeaf 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -154,30 +154,19 @@ describe('Network / Async', function() { }); it('should not reject data sent from a peer with no previously set nonce but who is setting one now', function() { - var n = createN(pk2); + var n1 = createN(pk1); + var n2 = createN(pk2); + n2._deletePeer = sinon.spy(); var message = { type: 'hello', - copayerId: key1.public.toString('hex') + copayerId: cid1 }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var opts = { - nonce: new Buffer('0000000000000001', 'hex') - }; //message send with new nonce - var encoded = n._encode(key2.public, key1, messagebuf, opts); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); - - n._deletePeer = sinon.spy(); - - n._onMessage(encodeduint, isInbound, peerId); - n._deletePeer.calledOnce.should.equal(false); - n.getHexNonces()[(new bitcore.SIN(key1.public)).toString()].toString('hex').should.equal('0000000000000001'); + var nonce = new Buffer('0000000000000001', 'hex'); + var enc = n1.encode(cid2, message, nonce); + n2._onMessage(enc); + n2._deletePeer.calledOnce.should.equal(false); + n2.getHexNonces()[cid1].toString('hex').should.equal('0000000000000001'); }); it('should not reject data sent from a peer with a really big new nonce', function() { From f22c3e3be247ef749c6245b7125ba733c09a4548 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 15:50:42 -0400 Subject: [PATCH 50/75] fix test 13 --- test/test.network.Async.js | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/test/test.network.Async.js b/test/test.network.Async.js index 75a7feeaf..8944536b6 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -142,7 +142,7 @@ describe('Network / Async', function() { type: 'hello', copayerId: cid3 // MITM }; - + var enc = n.encode(cid2, message); n._deletePeer = sinon.spy(); @@ -170,32 +170,21 @@ describe('Network / Async', function() { }); it('should not reject data sent from a peer with a really big new nonce', function() { - var n = createN(); - n.privkey = key2.private.toString('hex'); - n.key = null; - n.networkNonces = {}; - n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000001', 'hex'); //previously used nonce + var n1 = createN(pk1); + var n2 = createN(pk2); + n2._deletePeer = sinon.spy(); var message = { type: 'hello', - copayerId: key1.public.toString('hex') + copayerId: cid1 }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var opts = { - nonce: new Buffer('5000000000000002', 'hex') - }; //message send with new nonce - var encoded = n._encode(key2.public, key1, messagebuf, opts); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); - - n._deletePeer = sinon.spy(); - - n._onMessage(encodeduint, isInbound, peerId); + n2.networkNonces = {}; + n2.networkNonces[cid1] = new Buffer('5000000000000001', 'hex'); //previously used nonce + var nonce = new Buffer('5000000000000002', 'hex') + var enc = n1.encode(cid2, message, nonce); + n2._onMessage(enc); + n2._deletePeer.calledOnce.should.equal(false); + n2.getHexNonces()[cid1].toString('hex').should.equal('0000000000000001'); n._deletePeer.calledOnce.should.equal(false); }); From 3a84bee9bfb182078e432c4aa66128939ab480ff Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 15:51:03 -0400 Subject: [PATCH 51/75] fix test 13 --- test/test.network.Async.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.network.Async.js b/test/test.network.Async.js index 8944536b6..9d8798efd 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -184,7 +184,7 @@ describe('Network / Async', function() { var enc = n1.encode(cid2, message, nonce); n2._onMessage(enc); n2._deletePeer.calledOnce.should.equal(false); - n2.getHexNonces()[cid1].toString('hex').should.equal('0000000000000001'); + n2.getHexNonces()[cid1].toString('hex').should.equal('5000000000000002'); n._deletePeer.calledOnce.should.equal(false); }); From 78f338f4466c4c7a14d42ada2b38d6faf6f119d6 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 15:51:23 -0400 Subject: [PATCH 52/75] fix test 13 --- test/test.network.Async.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.network.Async.js b/test/test.network.Async.js index 9d8798efd..776570ab2 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -185,7 +185,7 @@ describe('Network / Async', function() { n2._onMessage(enc); n2._deletePeer.calledOnce.should.equal(false); n2.getHexNonces()[cid1].toString('hex').should.equal('5000000000000002'); - n._deletePeer.calledOnce.should.equal(false); + n2._deletePeer.calledOnce.should.equal(false); }); it('should not reject data sent from a peer with a really big new nonce', function() { From 1cca496a66f6f0f2193c0fbdaf4dced034535043 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 15:55:16 -0400 Subject: [PATCH 53/75] fix test 14 --- test/test.network.Async.js | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/test/test.network.Async.js b/test/test.network.Async.js index 776570ab2..006029da6 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -188,36 +188,6 @@ describe('Network / Async', function() { n2._deletePeer.calledOnce.should.equal(false); }); - it('should not reject data sent from a peer with a really big new nonce', function() { - var n = createN(); - n.privkey = key2.private.toString('hex'); - n.key = false; - n.networkNonces = {}; - n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000001', 'hex'); //previously used nonce - - var message = { - type: 'hello', - copayerId: key1.public.toString('hex') - }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var opts = { - nonce: new Buffer('5000000000000002', 'hex') - }; //message send with new nonce - var encoded = n._encode(key2.public, key1, messagebuf, opts); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); - - n._deletePeer = sinon.spy(); - - n._onMessage(encodeduint, isInbound, peerId); - n._deletePeer.calledOnce.should.equal(false); - }); - it('should reject data sent from a peer with an outdated nonce', function() { var n = createN(); n.privkey = key2.private.toString('hex'); From 614d8d63adee76bfc49d4e0ea6c7654a0c23b437 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 15:57:20 -0400 Subject: [PATCH 54/75] fix test 15 --- test/test.network.Async.js | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/test/test.network.Async.js b/test/test.network.Async.js index 006029da6..a2f5ac595 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -179,7 +179,7 @@ describe('Network / Async', function() { copayerId: cid1 }; n2.networkNonces = {}; - n2.networkNonces[cid1] = new Buffer('5000000000000001', 'hex'); //previously used nonce + n2.networkNonces[cid1] = new Buffer('5000000000000001', 'hex'); var nonce = new Buffer('5000000000000002', 'hex') var enc = n1.encode(cid2, message, nonce); n2._onMessage(enc); @@ -189,33 +189,20 @@ describe('Network / Async', function() { }); it('should reject data sent from a peer with an outdated nonce', function() { - var n = createN(); - n.privkey = key2.private.toString('hex'); - n.key = null; - n.networkNonces = {}; - n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('0000000000000002', 'hex'); //previously used nonce + var n1 = createN(pk1); + var n2 = createN(pk2); + n2._deletePeer = sinon.spy(); var message = { type: 'hello', - copayerId: key1.public.toString('hex') + copayerId: cid1 }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var opts = { - nonce: new Buffer('0000000000000001', 'hex') - }; //message send with old nonce - var encoded = n._encode(key2.public, key1, messagebuf, opts); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); - - n._deletePeer = sinon.spy(); - - n._onMessage(encodeduint, isInbound, peerId); - n._deletePeer.calledOnce.should.equal(true); + n2.networkNonces = {}; + n2.networkNonces[cid1] = new Buffer('0000000000000002', 'hex'); + var nonce = new Buffer('0000000000000001', 'hex'); + var enc = n1.encode(cid2, message, nonce); + n2._onMessage(enc); + n2._deletePeer.calledOnce.should.equal(true); }); it('should reject data sent from a peer with a really big outdated nonce', function() { From c90566819566fb338b036a06b9247b6597667177 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 15:57:41 -0400 Subject: [PATCH 55/75] fix test 16 --- test/test.network.Async.js | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/test/test.network.Async.js b/test/test.network.Async.js index a2f5ac595..daef5a61a 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -205,36 +205,6 @@ describe('Network / Async', function() { n2._deletePeer.calledOnce.should.equal(true); }); - it('should reject data sent from a peer with a really big outdated nonce', function() { - var n = createN(); - n.privkey = key2.private.toString('hex'); - n.key = null; - n.networkNonces = {}; - n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000002', 'hex'); //previously used nonce - - var message = { - type: 'hello', - copayerId: key1.public.toString('hex') - }; - var messagestr = JSON.stringify(message); - var messagebuf = new Buffer(messagestr); - - var opts = { - nonce: new Buffer('5000000000000001', 'hex') - }; //message send with old nonce - var encoded = n._encode(key2.public, key1, messagebuf, opts); - var encodedstr = JSON.stringify(encoded); - var encodeduint = new Buffer(encodedstr); - - var isInbound = true; - var peerId = new bitcore.SIN(key1.public); - - n._deletePeer = sinon.spy(); - - n._onMessage(encodeduint, isInbound, peerId); - n._deletePeer.calledOnce.should.equal(true); - }); - }); describe('#setHexNonce', function() { From 7bb0e849953dabd6e4a5975437349681888c5d2e Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 16:08:06 -0400 Subject: [PATCH 56/75] remove console log --- copay.js | 1 + test/test.network.Async.js | 4 ++-- test/unit/controllers/controllersSpec.js | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/copay.js b/copay.js index bc4156068..35178e9a3 100644 --- a/copay.js +++ b/copay.js @@ -9,6 +9,7 @@ module.exports.HDParams = require('./js/models/core/HDParams'); // components +var Async = module.exports.Async = require('./js/models/network/Async'); var Insight = module.exports.Insight = require('./js/models/blockchain/Insight'); var StorageLocalEncrypted = module.exports.StorageLocalEncrypted = require('./js/models/storage/LocalEncrypted'); diff --git a/test/test.network.Async.js b/test/test.network.Async.js index daef5a61a..41954ee48 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -5,7 +5,8 @@ var should = chai.should(); var expect = chai.expect; var sinon = sinon || require('sinon'); var bitcore = bitcore || require('bitcore'); -var Async = require('../js/models/network/Async'); +var copay = copay || require('../copay'); +var Async = copay.Async; var EventEmitter = require('events').EventEmitter; describe('Network / Async', function() { @@ -148,7 +149,6 @@ describe('Network / Async', function() { n._deletePeer = sinon.spy(); n._onMessage(enc); - console.log(n._deletePeer.callCount); n._deletePeer.calledOnce.should.equal(true); n._deletePeer.getCall(0).args[1].should.equal('incorrect pubkey for peerId'); }); diff --git a/test/unit/controllers/controllersSpec.js b/test/unit/controllers/controllersSpec.js index 02ae10eb9..94b26c236 100644 --- a/test/unit/controllers/controllersSpec.js +++ b/test/unit/controllers/controllersSpec.js @@ -175,12 +175,12 @@ describe("Unit: Controllers", function() { }); it('should validate address with network', function() { - form.newaddress.$setViewValue('1JqniWpWNA6Yvdivg3y9izLidETnurxRQm'); + form.newaddress.$setViewValue('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy'); expect(form.newaddress.$invalid).to.equal(false); }); it('should not validate address with other network', function() { - form.newaddress.$setViewValue('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy'); + form.newaddress.$setViewValue('1JqniWpWNA6Yvdivg3y9izLidETnurxRQm'); expect(form.newaddress.$invalid).to.equal(true); }); @@ -199,7 +199,7 @@ describe("Unit: Controllers", function() { }); it('should create a transaction proposal with given values', function() { - sendForm.address.$setViewValue('1JqniWpWNA6Yvdivg3y9izLidETnurxRQm'); + sendForm.address.$setViewValue('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy'); sendForm.amount.$setViewValue(1000); var spy = sinon.spy(scope.wallet, 'createTx'); @@ -245,7 +245,7 @@ describe("Unit: Controllers", function() { it('should create and send a transaction proposal', function() { - sendForm.address.$setViewValue('1JqniWpWNA6Yvdivg3y9izLidETnurxRQm'); + sendForm.address.$setViewValue('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy'); sendForm.amount.$setViewValue(1000); scope.wallet.totalCopayers = scope.wallet.requiredCopayers = 1; var spy = sinon.spy(scope.wallet, 'createTx'); @@ -322,7 +322,7 @@ describe("Unit: Controllers", function() { it('should return networkName', function() { $httpBackend.flush(); // need flush var networkName = scope.networkName; - expect(networkName).equal('livenet'); + expect(networkName).equal('testnet'); }); }); From f10a58ed72806b51525260697eff2cc8b61444b8 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 17:27:59 -0400 Subject: [PATCH 57/75] remove compulsory lastTimestamp --- js/models/network/Async.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index b8c5a5cb8..2fe077f4d 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -293,7 +293,6 @@ Network.prototype.start = function(opts, openCallback) { preconditions.checkArgument(opts); preconditions.checkArgument(opts.privkey); preconditions.checkArgument(opts.copayerId); - preconditions.checkArgument(opts.lastTimestamp); preconditions.checkState(this.connectedPeers && this.connectedPeers.length === 0); From 043fb16d64af644b4314f340efdf1743b3f28e4c Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 17:31:40 -0400 Subject: [PATCH 58/75] fix more tests --- js/models/network/Async.js | 2 +- test/test.network.Async.js | 14 +++----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 2fe077f4d..36b0e7437 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -350,7 +350,7 @@ Network.prototype.send = function(dest, payload, cb) { var self = this; if (!dest) { - defst = this.getCopayerIds(); + dest = this.getCopayerIds(); payload.isBroadcast = 1; } diff --git a/test/test.network.Async.js b/test/test.network.Async.js index 41954ee48..e4feb2877 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -60,10 +60,7 @@ describe('Network / Async', function() { describe('#send', function() { it('should call _sendToOne for a copayer', function(done) { - var n = createN(); - n.privkey = bitcore.util.sha256('test'); - n.key = null; - + var n = createN('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'); var data = new bitcore.Buffer('my data to send'); var copayerId = '03b51d01d798522cf61211b4dfcdd6d01020304cf166e1cb7f43d836abc5c18b23'; @@ -76,10 +73,7 @@ describe('Network / Async', function() { }); it('should call _sendToOne with encrypted data for a copayer', function(done) { - var n = createN(); - n.privkey = bitcore.util.sha256('test'); - n.key = null; - + var n = createN('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'); var data = new bitcore.Buffer('my data to send'); var copayerId = '03b51d01d798522cf61001b4dfcdd6db219ee33cf166e1cb7f43d836abc5c18b23'; @@ -96,9 +90,7 @@ describe('Network / Async', function() { }); it('should call _sendToOne for a list of copayers', function(done) { - var n = createN(); - n.privkey = bitcore.util.sha256('test'); - + var n = createN('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'); var data = new bitcore.Buffer('my data to send'); var copayerIds = ['03b51d01d798522cf61211b4dfcdd6db219ee33cf166e1cb7f43d836abc5c18b23']; n._sendToOne = function(a1, a2, cb) { From 0d837faaecb2877e14509a2258dcfcbce84a08aa Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 17:32:28 -0400 Subject: [PATCH 59/75] fix more tests --- test/test.network.Async.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/test.network.Async.js b/test/test.network.Async.js index e4feb2877..1bdf2cbd8 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -59,9 +59,12 @@ describe('Network / Async', function() { describe('#send', function() { + it('should be able to broadcast', function(done) { + var n = createN('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'); + }); it('should call _sendToOne for a copayer', function(done) { var n = createN('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'); - var data = new bitcore.Buffer('my data to send'); + var data = 'my data to send'; var copayerId = '03b51d01d798522cf61211b4dfcdd6d01020304cf166e1cb7f43d836abc5c18b23'; n._sendToOne = function(a, b, cb) { From 774400d7a7e67323153bc8f92d9c8c6ffc704f85 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 19 Aug 2014 17:34:30 -0400 Subject: [PATCH 60/75] add a broadcast test --- test/test.network.Async.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/test.network.Async.js b/test/test.network.Async.js index 1bdf2cbd8..dd037dfb6 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -59,8 +59,11 @@ describe('Network / Async', function() { describe('#send', function() { - it('should be able to broadcast', function(done) { + it('should be able to broadcast', function() { var n = createN('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'); + var spy = sinon.spy(); + n.send(null, 'hello', spy); + spy.calledOnce.should.be.true; }); it('should call _sendToOne for a copayer', function(done) { var n = createN('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'); From f06874fc0fc0e126d54826d0deedb5cc8fd55f6c Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 21 Aug 2014 16:40:38 -0400 Subject: [PATCH 61/75] improve insight error message --- js/models/blockchain/Insight.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/models/blockchain/Insight.js b/js/models/blockchain/Insight.js index b0a0b7654..610be2ebe 100644 --- a/js/models/blockchain/Insight.js +++ b/js/models/blockchain/Insight.js @@ -256,7 +256,7 @@ Insight.prototype._requestBrowser = function(options, callback) { errTxt = 'CRITICAL: Wrong response from insight' + e2; } } else if (request.status >= 400 && request.status < 499) { - errTxt = 'CRITICAL: Bad request to insight. Probably wrong transaction to broadcast?.'; + errTxt = 'CRITICAL: Bad request to insight: '+request.status; } else { errTxt = 'Error code: ' + request.status + ' - Status: ' + request.statusText + ' - Description: ' + request.responseText; setTimeout(function() { From 0aa63be74bf48d8f0aa472839a20cb7fcea63ebc Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 21 Aug 2014 17:59:25 -0400 Subject: [PATCH 62/75] remove old Message class --- js/models/core/Message.js | 148 ----------------------------------- test/test.Message.js | 159 -------------------------------------- 2 files changed, 307 deletions(-) delete mode 100644 js/models/core/Message.js delete mode 100644 test/test.Message.js diff --git a/js/models/core/Message.js b/js/models/core/Message.js deleted file mode 100644 index ad6324440..000000000 --- a/js/models/core/Message.js +++ /dev/null @@ -1,148 +0,0 @@ -'use strict'; - -var bitcore = require('bitcore'); - -/* Encrypted, authenticated messages to be shared between copayers */ -var Message = function() { -}; - -Message.encode = function(topubkey, fromkey, payload, opts) { - var version1 = new Buffer([1]); //peers will reject messges containing not-understood version1 - //i.e., increment version1 to prevent communications with old clients - var version2 = new Buffer([0]); //peers will not reject messages containing not-understood version2 - //i.e., increment version2 to allow communication with old clients, but signal new clients - var nonce; - if (opts && opts.nonce && Buffer.isBuffer(opts.nonce) && opts.nonce.length == 8) { - nonce = opts.nonce; - } else { - nonce = new Buffer(8); - nonce.fill(0); //nonce is a big endian 8 byte number - } - - var toencrypt = Buffer.concat([version1, version2, nonce, payload]); - var toencrypthexbuf = new Buffer(toencrypt.toString('hex')); //due to bug in sjcl/bitcore, must use hex string - var encrypted = Message._encrypt(topubkey, toencrypthexbuf); - var sig = Message._sign(fromkey, encrypted); - var encoded = { - pubkey: fromkey.public.toString('hex'), - sig: sig.toString('hex'), - encrypted: encrypted.toString('hex') - }; - return encoded; -}; - -Message.decode = function(key, encoded, opts) { - var prevnonce; - if (opts && opts.prevnonce && Buffer.isBuffer(opts.prevnonce) && opts.prevnonce.length == 8) { - prevnonce = opts.prevnonce; - } else { - prevnonce = new Buffer(8); - prevnonce.fill(0); //nonce is a big endian 8 byte number - } - - try { - var frompubkey = new Buffer(encoded.pubkey, 'hex'); - } catch (e) { - throw new Error('Error decoding public key: ' + e); - } - - try { - var sig = new Buffer(encoded.sig, 'hex'); - var encrypted = new Buffer(encoded.encrypted, 'hex'); - } catch (e) { - throw new Error('Error decoding data: ' + e); - } - - try { - var v = Message._verify(frompubkey, sig, encrypted); - } catch (e) { - throw new Error('Error verifying signature: ' + e); - } - - if (!v) { - throw new Error('Invalid signature'); - } - - try { - var decryptedhexbuf = Message._decrypt(key.private, encrypted); - var decrypted = new Buffer(decryptedhexbuf.toString(), 'hex'); //workaround for bug in bitcore/sjcl - } catch (e) { - throw new Error('Cannot decrypt data: ' + e); - } - - try { - var version1 = decrypted[0]; - var version2 = decrypted[1]; - var nonce = decrypted.slice(2, 10); - var payload = decrypted.slice(10); - } catch (e) { - throw new Error('Cannot parse decrypted data: ' + e); - } - - if (payload.length === 0) { - throw new Error('No data present'); - } - - if (version1 !== 1) { - throw new Error('Invalid version number'); - } - - if (version2 !== 0) { - //put special version2 handling code here, if ever needed - } - - if (!Message._noncegt(nonce, prevnonce) && prevnonce.toString('hex') !== '0000000000000000') { - throw new Error('Nonce not equal to zero and not greater than the previous nonce'); - } - - var decoded = { - version1: version1, - version2: version2, - nonce: nonce, - payload: payload - }; - - return decoded; -}; - -//return true if nonce > prevnonce; false otherwise -Message._noncegt = function(nonce, prevnonce) { - var noncep1 = nonce.slice(0, 4).readUInt32BE(0); - var prevnoncep1 = prevnonce.slice(0, 4).readUInt32BE(0); - - if (noncep1 > prevnoncep1) - return true; - - if (noncep1 < prevnoncep1) - return false; - - var noncep2 = nonce.slice(4, 8).readUInt32BE(0); - var prevnoncep2 = prevnonce.slice(4, 8).readUInt32BE(0); - - if (noncep2 > prevnoncep2) - return true; - - return false; -}; - -Message._encrypt = function(topubkey, payload, r, iv) { - var encrypted = bitcore.ECIES.encrypt(topubkey, payload, r, iv); - return encrypted; -}; - -Message._decrypt = function(privkey, encrypted) { - var decrypted = bitcore.ECIES.decrypt(privkey, encrypted); - return decrypted; -}; - -Message._sign = function(key, payload) { - var sig = bitcore.Message.sign(payload, key); - return sig; -}; - -Message._verify = function(pubkey, signature, payload) { - var v = bitcore.Message.verifyWithPubKey(pubkey, payload, signature); - return v; -}; - -module.exports = Message; diff --git a/test/test.Message.js b/test/test.Message.js deleted file mode 100644 index 9bad687d1..000000000 --- a/test/test.Message.js +++ /dev/null @@ -1,159 +0,0 @@ -'use strict'; - -var chai = chai || require('chai'); -var should = chai.should(); -var sinon = require('sinon'); -var Message = require('../js/models/core/Message'); -var bitcore = bitcore || require('bitcore'); -var Buffer = bitcore.Buffer; - -describe('Message model', function() { - var key = new bitcore.Key(); - key.private = bitcore.util.sha256(new Buffer('test')); - key.regenerateSync(); - - var key2 = new bitcore.Key(); - key2.private = bitcore.util.sha256(new Buffer('test 2')); - key2.regenerateSync(); - - describe('#encode', function() { - - it('should encode a message', function() { - var message = new Buffer('message'); - var encoded = Message.encode(key2.public, key, message); - should.exist(encoded.pubkey); - should.exist(encoded.sig); - should.exist(encoded.encrypted); - }); - - }); - - describe('#decode', function() { - - it('should decode an encoded message', function() { - var message = new Buffer('message'); - var messagehex = message.toString('hex'); - var encoded = Message.encode(key2.public, key, message); - - var decoded = Message.decode(key2, encoded); - var payload = decoded.payload; - payload.toString('hex').should.equal(messagehex); - }); - - it('should decode an encoded message with proper prevnonce', function() { - var message = new Buffer('message'); - var messagehex = message.toString('hex'); - var nonce = new Buffer([0, 0, 0, 0, 0, 0, 0, 2]); - var opts = {nonce: nonce}; - var encoded = Message.encode(key2.public, key, message, opts); - - var prevnonce = new Buffer([0, 0, 0, 0, 0, 0, 0, 1]); - opts = {prevnonce: prevnonce}; - var decoded = Message.decode(key2, encoded, opts); - var payload = decoded.payload; - payload.toString('hex').should.equal(messagehex); - }); - - it('should decode an encoded message with proper prevnonce - for first part', function() { - var message = new Buffer('message'); - var messagehex = message.toString('hex'); - var nonce = new Buffer([0, 0, 0, 2, 0, 0, 0, 0]); - var opts = {nonce: nonce}; - var encoded = Message.encode(key2.public, key, message, opts); - - var prevnonce = new Buffer([0, 0, 0, 1, 0, 0, 0, 0]); - opts = {prevnonce: prevnonce}; - var decoded = Message.decode(key2, encoded, opts); - var payload = decoded.payload; - payload.toString('hex').should.equal(messagehex); - }); - - it('should fail if prevnonce is too high', function() { - var message = new Buffer('message'); - var messagehex = message.toString('hex'); - var nonce = new Buffer([0, 0, 0, 0, 0, 0, 0, 1]); - var opts = {nonce: nonce}; - var encoded = Message.encode(key2.public, key, message, opts); - - var prevnonce = new Buffer([0, 0, 0, 0, 0, 0, 0, 1]); - opts = {prevnonce: prevnonce}; - (function() {Message.decode(key2, encoded, opts)}).should.throw('Nonce not equal to zero and not greater than the previous nonce'); - }); - - it('should fail if prevnonce is too high - for first part', function() { - var message = new Buffer('message'); - var messagehex = message.toString('hex'); - var nonce = new Buffer([0, 0, 0, 1, 0, 0, 0, 0]); - var opts = {nonce: nonce}; - var encoded = Message.encode(key2.public, key, message, opts); - - var prevnonce = new Buffer([0, 0, 0, 1, 0, 0, 0, 0]); - opts = {prevnonce: prevnonce}; - (function() {Message.decode(key2, encoded, opts)}).should.throw('Nonce not equal to zero and not greater than the previous nonce'); - }); - - it('should fail if the version number is incorrect', function() { - var payload = new Buffer('message'); - var fromkey = key; - var topubkey = key2.public; - var version1 = new Buffer([2]); - var version2 = new Buffer([0]); - var nonce = new Buffer([0, 0, 0, 0, 0, 0, 0, 0]); - var toencrypt = Buffer.concat([version1, version2, nonce, payload]); - var toencrypt_workaround = new Buffer(toencrypt.toString('hex')); - var encrypted = Message._encrypt(topubkey, toencrypt_workaround); - var sig = Message._sign(fromkey, encrypted); - var encoded = { - pubkey: fromkey.public.toString('hex'), - sig: sig.toString('hex'), - encrypted: encrypted.toString('hex') - }; - - (function() {Message.decode(key2, encoded);}).should.throw('Invalid version number'); - }); - - }); - - describe('#_encrypt', function() { - - it('should encrypt data', function() { - var payload = new Buffer('payload'); - var encrypted = Message._encrypt(key.public, payload); - encrypted.length.should.equal(129); - }); - - }); - - describe('#_decrypt', function() { - var payload = new Buffer('payload'); - var payloadhex = payload.toString('hex'); - - it('should decrypt encrypted data', function() { - var encrypted = Message._encrypt(key.public, payload); - var decrypted = Message._decrypt(key.private, encrypted); - decrypted.toString('hex').should.equal(payloadhex); - }); - - }); - - describe('#_sign', function() { - - it('should sign data', function() { - var payload = new Buffer('payload'); - var sig = Message._sign(key, payload); - sig.length.should.be.greaterThan(60); - }); - - }); - - describe('#_verify', function() { - var payload = new Buffer('payload'); - var sig = Message._sign(key, payload); - - it('should verify signed data', function() { - Message._verify(key.public, sig, payload).should.equal(true); - }); - - }); - -}); From 04080c6ac68ffc8d9ddef96405876ac7210ed738 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 21 Aug 2014 18:02:03 -0400 Subject: [PATCH 63/75] remove old Message class from build --- util/build.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/util/build.js b/util/build.js index 3c1e683d8..5495a04a2 100644 --- a/util/build.js +++ b/util/build.js @@ -76,9 +76,6 @@ var createBundle = function(opts) { 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' }); From 4fff3a9d4d7fb1bb78638eb5330e05febad82d8f Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Fri, 22 Aug 2014 11:51:40 -0400 Subject: [PATCH 64/75] close socket on disconnect --- js/models/core/Wallet.js | 3 +-- js/models/network/Async.js | 23 ++++------------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index a9c9584af..1b809ec73 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -1753,9 +1753,8 @@ Wallet.prototype.disconnect = function() { self.send(null, { type: 'disconnect', walletId: this.id, - }, function() { - self.network.cleanUp(); }); + self.network.cleanUp(); }; Wallet.prototype.getNetwork = function() { diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 36b0e7437..a8aaf1fa1 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -46,25 +46,15 @@ Network.prototype.cleanUp = function() { this.connections = {}; this.criticalErr = ''; this.removeAllListeners(); + if (this.socket) { + this.socket.disconnect(); + this.socket = null; + } }; Network.parent = EventEmitter; // Array helpers -Network._arrayDiff = function(a, b) { - var seen = []; - var diff = []; - - for (var i = 0; i < b.length; i++) - seen[b[i]] = true; - - for (var j = 0; j < a.length; j++) - if (!seen[a[j]]) - diff.push(a[j]); - - return diff; -}; - Network._inArray = function(el, array) { return array.indexOf(el) > -1; }; @@ -303,11 +293,6 @@ Network.prototype.start = function(opts, openCallback) { this.setCopayerId(opts.copayerId); this.maxPeers = opts.maxPeers || this.maxPeers; - if (this.socket) { - this.socket.destroy(); - this.socket.removeAllListeners(); - } - this.socket = this.createSocket(this.host, this.port); this._setupConnectionHandlers(openCallback); this.socket.emit('subscribe', pubkey); From 81a20cb1dc1033ca71560d7ac105c68ddc2c3918 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Fri, 22 Aug 2014 13:13:04 -0400 Subject: [PATCH 65/75] make it work with reconnections --- js/models/network/Async.js | 4 +- js/services/controllerUtils.js | 698 +++++++++++++++++---------------- 2 files changed, 354 insertions(+), 348 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index a8aaf1fa1..1d0d391fe 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -45,7 +45,6 @@ Network.prototype.cleanUp = function() { this.copayerForPeer = {}; this.connections = {}; this.criticalErr = ''; - this.removeAllListeners(); if (this.socket) { this.socket.disconnect(); this.socket = null; @@ -224,6 +223,7 @@ Network.prototype._setupConnectionHandlers = function(cb) { var self = this; self.socket.on('connect', function() { + alert('socket connected!'); self.socket.on('disconnect', function() { self.cleanUp(); }); @@ -298,6 +298,7 @@ Network.prototype.start = function(opts, openCallback) { this.socket.emit('subscribe', pubkey); this.socket.emit('sync', opts.lastTimestamp); this.started = true; + alert('started = true'); }; @@ -305,6 +306,7 @@ Network.prototype.createSocket = function(host, port) { var hostPort = host + ':' + port; return io.connect(hostPort, { reconnection: true, + 'force new connection': true }); }; diff --git a/js/services/controllerUtils.js b/js/services/controllerUtils.js index 48ab8049f..943b415a3 100644 --- a/js/services/controllerUtils.js +++ b/js/services/controllerUtils.js @@ -2,377 +2,381 @@ var bitcore = require('bitcore'); angular.module('copayApp.services') -.factory('controllerUtils', function($rootScope, $sce, $location, notification, $timeout, Socket, video, uriHandler) { - var root = {}; - root.getVideoMutedStatus = function(copayer) { - if (!$rootScope.videoInfo) return; + .factory('controllerUtils', function($rootScope, $sce, $location, notification, $timeout, Socket, video, uriHandler) { + var root = {}; + root.getVideoMutedStatus = function(copayer) { + if (!$rootScope.videoInfo) return; - var vi = $rootScope.videoInfo[copayer] - if (!vi) { - return; - } - return vi.muted; - }; - - root.redirIfLogged = function() { - if ($rootScope.wallet) { - $rootScope.wallet.path('receive'); - } - }; - - root.logout = function() { - if ($rootScope.wallet) - $rootScope.wallet.disconnect(); - - Socket.removeAllListeners(); - - $rootScope.wallet = null; - delete $rootScope['wallet']; - - video.close(); - // Clear rootScope - for (var i in $rootScope) { - if (i.charAt(0) != '$') { - delete $rootScope[i]; - } - } - - $location.path('/'); - }; - - root.onError = function(scope) { - if (scope) scope.loading = false; - root.logout(); - } - - root.onErrorDigest = function(scope, msg) { - root.onError(scope); - if (msg) { - notification.error('Error', msg); - } - $rootScope.$digest(); - }; - - root.installStartupHandlers = function(wallet, $scope) { - wallet.on('connectionError', function() { - var message = "Looks like you are already connected to this wallet, please logout and try importing it again."; - notification.error('PeerJS Error', message); - root.onErrorDigest($scope); - }); - wallet.on('ready', function() { - $scope.loading = false; - }); - }; - - root.setupRootVariables = function() { - uriHandler.register(); - $rootScope.unitName = config.unitName; - $rootScope.txAlertCount = 0; - $rootScope.insightError = 0; - $rootScope.isCollapsed = true; - $rootScope.$watch('txAlertCount', function(txAlertCount) { - if (txAlertCount && txAlertCount > 0) { - - notification.info('New Transaction', ($rootScope.txAlertCount == 1) ? 'You have a pending transaction proposal' : 'You have ' + $rootScope.txAlertCount + ' pending transaction proposals', txAlertCount); - } - }); - - - $rootScope.$watch('receivedFund', function(receivedFund) { - if (receivedFund) { - var currentAddr; - for (var i = 0; i < $rootScope.addrInfos.length; i++) { - var addrinfo = $rootScope.addrInfos[i]; - if (addrinfo.address.toString() == receivedFund[1] && !addrinfo.isChange) { - currentAddr = addrinfo.address.toString(); - break; - } - } - if (currentAddr) { - //var beep = new Audio('sound/transaction.mp3'); - notification.funds('Received fund', currentAddr, receivedFund); - //beep.play(); - } - } - }); - - }; - - - root.startNetwork = function(w, $scope) { - Socket.removeAllListeners(); - - root.setupRootVariables(); - root.installStartupHandlers(w, $scope); - root.setSocketHandlers(); - - var handlePeerVideo = function(err, peerID, url) { - if (err) { - delete $rootScope.videoInfo[peerID]; + var vi = $rootScope.videoInfo[copayer] + if (!vi) { return; } - $rootScope.videoInfo[peerID] = { - url: encodeURI(url), - muted: peerID === w.network.peerId - }; + return vi.muted; + }; + + root.redirIfLogged = function() { + if ($rootScope.wallet) { + $rootScope.wallet.path('receive'); + } + }; + + root.logout = function() { + if ($rootScope.wallet) + $rootScope.wallet.disconnect(); + + Socket.removeAllListeners(); + + $rootScope.wallet = null; + delete $rootScope['wallet']; + + video.close(); + // Clear rootScope + for (var i in $rootScope) { + if (i.charAt(0) != '$') { + delete $rootScope[i]; + } + } + + $location.path('/'); + }; + + root.onError = function(scope) { + if (scope) scope.loading = false; + root.logout(); + } + + root.onErrorDigest = function(scope, msg) { + root.onError(scope); + if (msg) { + notification.error('Error', msg); + } $rootScope.$digest(); }; - notification.enableHtml5Mode(); // for chrome: if support, enable it + root.installStartupHandlers = function(wallet, $scope) { + wallet.on('connectionError', function() { + var message = "Looks like you are already connected to this wallet, please logout and try importing it again."; + notification.error('PeerJS Error', message); + root.onErrorDigest($scope); + }); + wallet.on('ready', function() { + $scope.loading = false; + }); + }; - w.on('corrupt', function(peerId) { - notification.error('Error', 'Received corrupt message from ' + peerId); - }); - w.on('ready', function(myPeerID) { - $rootScope.wallet = w; - if ($rootScope.pendingPayment) { - $location.path('send'); - } else { - $location.path('receive'); - } - if (!config.disableVideo) - video.setOwnPeer(myPeerID, w, handlePeerVideo); - }); + root.setupRootVariables = function() { + uriHandler.register(); + $rootScope.unitName = config.unitName; + $rootScope.txAlertCount = 0; + $rootScope.insightError = 0; + $rootScope.isCollapsed = true; + $rootScope.$watch('txAlertCount', function(txAlertCount) { + if (txAlertCount && txAlertCount > 0) { - w.on('publicKeyRingUpdated', function(dontDigest) { - root.setSocketHandlers(); - if (!dontDigest) { - $rootScope.$digest(); - } - }); - w.on('txProposalsUpdated', function(dontDigest) { - root.updateTxs(); - // give sometime to the tx to propagate. - $timeout(function() { - root.updateBalance(function() { - if (!dontDigest) { - $rootScope.$digest(); + notification.info('New Transaction', ($rootScope.txAlertCount == 1) ? 'You have a pending transaction proposal' : 'You have ' + $rootScope.txAlertCount + ' pending transaction proposals', txAlertCount); + } + }); + + + $rootScope.$watch('receivedFund', function(receivedFund) { + if (receivedFund) { + var currentAddr; + for (var i = 0; i < $rootScope.addrInfos.length; i++) { + var addrinfo = $rootScope.addrInfos[i]; + if (addrinfo.address.toString() == receivedFund[1] && !addrinfo.isChange) { + currentAddr = addrinfo.address.toString(); + break; + } } - }); - }, 3000); - }); - w.on('txProposalEvent', function(e) { - var user = w.publicKeyRing.nicknameForCopayer(e.cId); - switch (e.type) { - case 'signed': - notification.info('Transaction Update', 'A transaction was signed by ' + user); - break; - case 'rejected': - notification.info('Transaction Update', 'A transaction was rejected by ' + user); - break; - case 'corrupt': - notification.error('Transaction Error', 'Received corrupt transaction from '+user); - break; - } - }); - w.on('addressBookUpdated', function(dontDigest) { - if (!dontDigest) { + if (currentAddr) { + //var beep = new Audio('sound/transaction.mp3'); + notification.funds('Received fund', currentAddr, receivedFund); + //beep.play(); + } + } + }); + + }; + + + root.startNetwork = function(w, $scope) { + Socket.removeAllListeners(); + + root.setupRootVariables(); + root.installStartupHandlers(w, $scope); + root.setSocketHandlers(); + + var handlePeerVideo = function(err, peerID, url) { + if (err) { + delete $rootScope.videoInfo[peerID]; + return; + } + $rootScope.videoInfo[peerID] = { + url: encodeURI(url), + muted: peerID === w.network.peerId + }; $rootScope.$digest(); - } - }); - w.on('connectionError', function(msg) { - root.onErrorDigest(null, msg); - }); - w.on('connect', function(peerID) { - if (peerID && !config.disableVideo) { - video.callPeer(peerID, handlePeerVideo); - } - $rootScope.$digest(); - }); - w.on('disconnect', function(peerID) { - $rootScope.$digest(); - }); - w.on('close', root.onErrorDigest); - w.on('locked', root.onErrorDigest.bind(this)); - w.netStart(); - }; + }; - root.updateAddressList = function() { - var w = $rootScope.wallet; - if (w && w.isReady()) - $rootScope.addrInfos = w.getAddressesInfo(); - }; + notification.enableHtml5Mode(); // for chrome: if support, enable it - root.updateBalance = function(cb) { - var w = $rootScope.wallet; - if (!w) return root.onErrorDigest(); - if (!w.isReady()) return; + w.on('corrupt', function(peerId) { + notification.error('Error', 'Received corrupt message from ' + peerId); + }); + w.on('ready', function(myPeerID) { + alert('wallet ready!'); + $rootScope.wallet = w; + if ($rootScope.pendingPayment) { + $location.path('send'); + } else { + $location.path('receive'); + } + if (!config.disableVideo) + video.setOwnPeer(myPeerID, w, handlePeerVideo); + }); - $rootScope.balanceByAddr = {}; - $rootScope.updatingBalance = true; + w.on('publicKeyRingUpdated', function(dontDigest) { + root.setSocketHandlers(); + if (!dontDigest) { + $rootScope.$digest(); + } + }); + w.on('txProposalsUpdated', function(dontDigest) { + root.updateTxs(); + // give sometime to the tx to propagate. + $timeout(function() { + root.updateBalance(function() { + if (!dontDigest) { + $rootScope.$digest(); + } + }); + }, 3000); + }); + w.on('txProposalEvent', function(e) { + var user = w.publicKeyRing.nicknameForCopayer(e.cId); + switch (e.type) { + case 'signed': + notification.info('Transaction Update', 'A transaction was signed by ' + user); + break; + case 'rejected': + notification.info('Transaction Update', 'A transaction was rejected by ' + user); + break; + case 'corrupt': + notification.error('Transaction Error', 'Received corrupt transaction from ' + user); + break; + } + }); + w.on('addressBookUpdated', function(dontDigest) { + if (!dontDigest) { + $rootScope.$digest(); + } + }); + w.on('connectionError', function(msg) { + root.onErrorDigest(null, msg); + }); + w.on('connect', function(peerID) { + if (peerID && !config.disableVideo) { + video.callPeer(peerID, handlePeerVideo); + } + $rootScope.$digest(); + }); + w.on('disconnect', function(peerID) { + $rootScope.$digest(); + }); + w.on('close', root.onErrorDigest); + w.on('locked', root.onErrorDigest.bind(this)); + w.netStart(); + }; - w.getBalance(function(err, balanceSat, balanceByAddrSat, safeBalanceSat) { - if (err) { - console.error('Error: ' + err.message); //TODO - root._setCommError(); - return null; - } else { - root._clearCommError(); - } + root.updateAddressList = function() { + var w = $rootScope.wallet; + if (w && w.isReady()) + $rootScope.addrInfos = w.getAddressesInfo(); + }; + + root.updateBalance = function(cb) { + var w = $rootScope.wallet; + if (!w) return root.onErrorDigest(); + if (!w.isReady()) return; + + $rootScope.balanceByAddr = {}; + $rootScope.updatingBalance = true; + + w.getBalance(function(err, balanceSat, balanceByAddrSat, safeBalanceSat) { + if (err) { + console.error('Error: ' + err.message); //TODO + root._setCommError(); + return null; + } else { + root._clearCommError(); + } + + var satToUnit = 1 / config.unitToSatoshi; + var COIN = bitcore.util.COIN; + + $rootScope.totalBalance = balanceSat * satToUnit; + $rootScope.totalBalanceBTC = (balanceSat / COIN); + $rootScope.availableBalance = safeBalanceSat * satToUnit; + $rootScope.availableBalanceBTC = (safeBalanceSat / COIN); + + $rootScope.lockedBalance = (balanceSat - safeBalanceSat) * satToUnit; + $rootScope.lockedBalanceBTC = (balanceSat - safeBalanceSat) / COIN; + + var balanceByAddr = {}; + for (var ii in balanceByAddrSat) { + balanceByAddr[ii] = balanceByAddrSat[ii] * satToUnit; + } + $rootScope.balanceByAddr = balanceByAddr; + root.updateAddressList(); + $rootScope.updatingBalance = false; + return cb ? cb() : null; + }); + }; + + root.updateTxs = function(opts) { + var w = $rootScope.wallet; + if (!w) return; + opts = opts || $rootScope.txsOpts || {}; var satToUnit = 1 / config.unitToSatoshi; - var COIN = bitcore.util.COIN; + var myCopayerId = w.getMyCopayerId(); + var pendingForUs = 0; + var inT = w.getTxProposals().sort(function(t1, t2) { + return t2.createdTs - t1.createdTs + }); + var txs = []; - $rootScope.totalBalance = balanceSat * satToUnit; - $rootScope.totalBalanceBTC = (balanceSat / COIN); - $rootScope.availableBalance = safeBalanceSat * satToUnit; - $rootScope.availableBalanceBTC = (safeBalanceSat / COIN); + inT.forEach(function(i, index) { + if (opts.skip && (index < opts.skip[0] || index >= opts.skip[1])) { + return txs.push(null); + } - $rootScope.lockedBalance = (balanceSat - safeBalanceSat) * satToUnit; - $rootScope.lockedBalanceBTC = (balanceSat - safeBalanceSat) / COIN; + if (myCopayerId != i.creator && !i.finallyRejected && !i.sentTs && !i.rejectedByUs && !i.signedByUs) { + pendingForUs++; + } + if (!i.finallyRejected && !i.sentTs) { + i.isPending = 1; + } - var balanceByAddr = {}; - for (var ii in balanceByAddrSat) { - balanceByAddr[ii] = balanceByAddrSat[ii] * satToUnit; + if (!!opts.pending == !!i.isPending) { + var tx = i.builder.build(); + var outs = []; + tx.outs.forEach(function(o) { + var addr = bitcore.Address.fromScriptPubKey(o.getScript(), config.networkName)[0].toString(); + if (!w.addressIsOwn(addr, { + excludeMain: true + })) { + outs.push({ + address: addr, + value: bitcore.util.valueToBigInt(o.getValue()) * satToUnit, + }); + } + }); + // extra fields + i.outs = outs; + i.fee = i.builder.feeSat * satToUnit; + i.missingSignatures = tx.countInputMissingSignatures(0); + i.actionList = getActionList(i.peerActions); + txs.push(i); + } + }); + + $rootScope.txs = txs; + $rootScope.txsOpts = opts; + if ($rootScope.pendingTxCount < pendingForUs) { + $rootScope.txAlertCount = pendingForUs; } - $rootScope.balanceByAddr = balanceByAddr; + $rootScope.pendingTxCount = pendingForUs; + }; + + function getActionList(actions) { + var peers = Object.keys(actions).map(function(i) { + return { + cId: i, + actions: actions[i] + } + }); + + return peers.sort(function(a, b) { + return !!b.actions.create - !!a.actions.create; + }); + } + + var connectionLost = false; + $rootScope.$watch('insightError', function(status) { + if (!status) return; + + // Reconnected + if (status === -1) { + if (!connectionLost) return; // Skip on first reconnect + connectionLost = false; + notification.success('Networking restored', 'Connection to Insight re-established'); + return; + } + + // Retry + if (status == 1) return; // Skip the first try + connectionLost = true; + notification.error('Networking problem', 'Connection to Insight lost, reconnecting (attempt number ' + (status - 1) + ')'); + }); + + root._setCommError = function(e) { + if ($rootScope.insightError < 0) + $rootScope.insightError = 0; + $rootScope.insightError++; + }; + + root._clearCommError = function(e) { + if ($rootScope.insightError > 0) + $rootScope.insightError = -1; + else + $rootScope.insightError = 0; + }; + + root.setSocketHandlers = function() { root.updateAddressList(); - $rootScope.updatingBalance = false; - return cb ? cb() : null; - }); - }; - - root.updateTxs = function(opts) { - var w = $rootScope.wallet; - if (!w) return; - opts = opts || $rootScope.txsOpts || {}; - - var satToUnit = 1 / config.unitToSatoshi; - var myCopayerId = w.getMyCopayerId(); - var pendingForUs = 0; - var inT = w.getTxProposals().sort(function(t1, t2) { - return t2.createdTs - t1.createdTs - }); - var txs = []; - - inT.forEach(function(i, index) { - if (opts.skip && (index < opts.skip[0] || index >= opts.skip[1])) { - return txs.push(null); + if (!Socket.sysEventsSet) { + Socket.sysOn('error', root._setCommError); + Socket.sysOn('reconnect_error', root._setCommError); + Socket.sysOn('reconnect_failed', root._setCommError); + Socket.sysOn('connect', root._clearCommError); + Socket.sysOn('reconnect', root._clearCommError); + Socket.sysEventsSet = true; } + if (!$rootScope.wallet) return; - if (myCopayerId != i.creator && !i.finallyRejected && !i.sentTs && !i.rejectedByUs && !i.signedByUs) { - pendingForUs++; - } - if (!i.finallyRejected && !i.sentTs) { - i.isPending = 1; - } + var currentAddrs = Socket.getListeners(); + var allAddrs = $rootScope.addrInfos; - if (!!opts.pending == !!i.isPending) { - var tx = i.builder.build(); - var outs = []; - tx.outs.forEach(function(o) { - var addr = bitcore.Address.fromScriptPubKey(o.getScript(), config.networkName)[0].toString(); - if (!w.addressIsOwn(addr, { - excludeMain: true - })) { - outs.push({ - address: addr, - value: bitcore.util.valueToBigInt(o.getValue()) * satToUnit, - }); - } + var newAddrs = []; + for (var i in allAddrs) { + var a = allAddrs[i]; + if (!currentAddrs[a.addressStr]) + newAddrs.push(a); + } + for (var i = 0; i < newAddrs.length; i++) { + Socket.emit('subscribe', newAddrs[i].addressStr); + } + newAddrs.forEach(function(a) { + Socket.on(a.addressStr, function(txid) { + + if (!a.isChange) + notification.funds('Funds received!', a.addressStr); + + root.updateBalance(function() { + $rootScope.$digest(); + }); + }); + }); + + if (!$rootScope.wallet.spendUnconfirmed && !Socket.isListeningBlocks()) { + Socket.emit('subscribe', 'inv'); + Socket.on('block', function(block) { + root.updateBalance(function() { + $rootScope.$digest(); + }); }); - // extra fields - i.outs = outs; - i.fee = i.builder.feeSat * satToUnit; - i.missingSignatures = tx.countInputMissingSignatures(0); - i.actionList = getActionList(i.peerActions); - txs.push(i); } - }); - - $rootScope.txs = txs; - $rootScope.txsOpts = opts; - if ($rootScope.pendingTxCount < pendingForUs) { - $rootScope.txAlertCount = pendingForUs; - } - $rootScope.pendingTxCount = pendingForUs; - }; - - function getActionList(actions) { - var peers = Object.keys(actions).map(function(i) { - return {cId: i, actions: actions[i] } - }); - - return peers.sort(function(a, b) { - return !!b.actions.create - !!a.actions.create; - }); - } - - var connectionLost = false; - $rootScope.$watch('insightError', function(status) { - if (!status) return; - - // Reconnected - if (status === -1) { - if (!connectionLost) return; // Skip on first reconnect - connectionLost = false; - notification.success('Networking restored', 'Connection to Insight re-established'); - return; - } - - // Retry - if (status == 1) return; // Skip the first try - connectionLost = true; - notification.error('Networking problem', 'Connection to Insight lost, reconnecting (attempt number ' + (status-1) + ')'); + }; + return root; }); - - root._setCommError = function(e) { - if ($rootScope.insightError < 0) - $rootScope.insightError = 0; - $rootScope.insightError++; - }; - - root._clearCommError = function(e) { - if ($rootScope.insightError > 0) - $rootScope.insightError = -1; - else - $rootScope.insightError = 0; - }; - - root.setSocketHandlers = function() { - root.updateAddressList(); - if (!Socket.sysEventsSet) { - Socket.sysOn('error', root._setCommError); - Socket.sysOn('reconnect_error', root._setCommError); - Socket.sysOn('reconnect_failed', root._setCommError); - Socket.sysOn('connect', root._clearCommError); - Socket.sysOn('reconnect', root._clearCommError); - Socket.sysEventsSet = true; - } - if (!$rootScope.wallet) return; - - var currentAddrs = Socket.getListeners(); - var allAddrs = $rootScope.addrInfos; - - var newAddrs = []; - for (var i in allAddrs) { - var a = allAddrs[i]; - if (!currentAddrs[a.addressStr]) - newAddrs.push(a); - } - for (var i = 0; i < newAddrs.length; i++) { - Socket.emit('subscribe', newAddrs[i].addressStr); - } - newAddrs.forEach(function(a) { - Socket.on(a.addressStr, function(txid) { - - if (!a.isChange) - notification.funds('Funds received!', a.addressStr); - - root.updateBalance(function() { - $rootScope.$digest(); - }); - }); - }); - - if (!$rootScope.wallet.spendUnconfirmed && !Socket.isListeningBlocks()) { - Socket.emit('subscribe', 'inv'); - Socket.on('block', function(block) { - root.updateBalance(function() { - $rootScope.$digest(); - }); - }); - } - }; - return root; -}); From c6e151db99e001a372d80888088c03c486a40d9b Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Fri, 22 Aug 2014 13:16:53 -0400 Subject: [PATCH 66/75] remove alerts --- js/models/network/Async.js | 2 -- js/services/controllerUtils.js | 1 - 2 files changed, 3 deletions(-) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 1d0d391fe..7d3f89242 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -223,7 +223,6 @@ Network.prototype._setupConnectionHandlers = function(cb) { var self = this; self.socket.on('connect', function() { - alert('socket connected!'); self.socket.on('disconnect', function() { self.cleanUp(); }); @@ -298,7 +297,6 @@ Network.prototype.start = function(opts, openCallback) { this.socket.emit('subscribe', pubkey); this.socket.emit('sync', opts.lastTimestamp); this.started = true; - alert('started = true'); }; diff --git a/js/services/controllerUtils.js b/js/services/controllerUtils.js index 943b415a3..197b53d11 100644 --- a/js/services/controllerUtils.js +++ b/js/services/controllerUtils.js @@ -124,7 +124,6 @@ angular.module('copayApp.services') notification.error('Error', 'Received corrupt message from ' + peerId); }); w.on('ready', function(myPeerID) { - alert('wallet ready!'); $rootScope.wallet = w; if ($rootScope.pendingPayment) { $location.path('send'); From 0f67d3e6bd9392dbe2aa6d22ba57ecc8101a5c47 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Fri, 22 Aug 2014 13:24:42 -0400 Subject: [PATCH 67/75] add some parenthesis --- js/models/core/Wallet.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 1b809ec73..788741ac3 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -554,16 +554,17 @@ Wallet.fromObj = function(o, storage, network, blockchain) { opts.addressBook = o.addressBook; - if (o.privateKey) + if (o.privateKey) { opts.privateKey = PrivateKey.fromObj(o.privateKey); - else + } else { opts.privateKey = new PrivateKey({ networkName: opts.networkName }); + } - if (o.publicKeyRing) + if (o.publicKeyRing) { opts.publicKeyRing = PublicKeyRing.fromObj(o.publicKeyRing); - else { + } else { opts.publicKeyRing = new PublicKeyRing({ networkName: opts.networkName, requiredCopayers: opts.requiredCopayers, @@ -575,13 +576,14 @@ Wallet.fromObj = function(o, storage, network, blockchain) { ); } - if (o.txProposals) + if (o.txProposals) { opts.txProposals = TxProposals.fromObj(o.txProposals, Wallet.builderOpts); - else + } else { opts.txProposals = new TxProposals({ networkName: this.networkName, }); - + } + opts.lastTimestamp = o.lastTimestamp; opts.storage = storage; From 0d225248859f5b3adfb0ad9e3371f4b45fa37313 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Fri, 22 Aug 2014 13:27:09 -0400 Subject: [PATCH 68/75] fix test after rebase --- test/mocks/FakeNetwork.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/test/mocks/FakeNetwork.js b/test/mocks/FakeNetwork.js index 4368e8de5..d1b8fee6c 100644 --- a/test/mocks/FakeNetwork.js +++ b/test/mocks/FakeNetwork.js @@ -6,7 +6,6 @@ function Network(opts) {} util.inherits(Network, EventEmitter); Network.prototype.start = function(opts, cb) { - // start! :D this.peer = { options: { token: "asd" @@ -15,18 +14,12 @@ Network.prototype.start = function(opts, cb) { if (cb) cb(); }; -Network.prototype.send = function(peerIds, data, cb) { - // send! c: -}; +Network.prototype.send = function(peerIds, data, cb) {}; -Network.prototype.connectTo = function(peerId) { - // connect C: -}; +Network.prototype.connectTo = function(peerId) {}; -Network.prototype.disconnect = function(cb) { - // disconect :c -}; +Network.prototype.disconnect = function(cb) {}; Network.prototype.lockIncommingConnections = function() { @@ -43,7 +36,7 @@ Network.prototype.peerFromCopayer = function(copayerId) { //hex version of one's own nonce Network.prototype.setHexNonce = function(networkNonce) { - if (networkNonce && networkNonce.length === 16) + if (networkNonce && networkNonce.length === 16) this.networkNonce = new Buffer(networkNonce, 'hex'); else this.iterateNonce(); @@ -84,7 +77,7 @@ Network.prototype.iterateNonce = function() { //the second 4 bytes is just an iterated "sub" nonce //the whole thing is interpreted as one big endian number var noncep1 = this.networkNonce.slice(0, 4); - noncep1.writeUInt32BE(Math.floor(Date.now()/1000), 0); + noncep1.writeUInt32BE(Math.floor(Date.now() / 1000), 0); var noncep2uint = this.networkNonce.slice(4, 8).readUInt32BE(0); var noncep2 = this.networkNonce.slice(4, 8); noncep2.writeUInt32BE(noncep2uint + 1, 0); @@ -92,4 +85,9 @@ Network.prototype.iterateNonce = function() { }; +Network.prototype.cleanUp = function() { + return; +}; + + module.exports = Network; From e00997bad887507845a3da898b6c353b96c9b341 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Fri, 22 Aug 2014 13:32:34 -0400 Subject: [PATCH 69/75] fix test after rebase 2 --- js/models/network/Async.js | 1 + test/test.blockchain.Insight.js | 1 + test/test.network.Async.js | 1 + 3 files changed, 3 insertions(+) diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 7d3f89242..55fb8d368 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -45,6 +45,7 @@ Network.prototype.cleanUp = function() { this.copayerForPeer = {}; this.connections = {}; this.criticalErr = ''; + this.removeAllListeners(); if (this.socket) { this.socket.disconnect(); this.socket = null; diff --git a/test/test.blockchain.Insight.js b/test/test.blockchain.Insight.js index e80d628f8..9eb9af6f1 100644 --- a/test/test.blockchain.Insight.js +++ b/test/test.blockchain.Insight.js @@ -9,6 +9,7 @@ try { } catch (e) { var copay = require('../copay'); //node } +var Buffer = bitcore.Buffer; var Insight = copay.Insight || require('../js/models/blockchain/Insight'); var ID = '933bf321393459b7'; diff --git a/test/test.network.Async.js b/test/test.network.Async.js index dd037dfb6..4d46dabb3 100644 --- a/test/test.network.Async.js +++ b/test/test.network.Async.js @@ -17,6 +17,7 @@ describe('Network / Async', function() { var fakeSocket = {}; fakeSocket.emit = function() {}; fakeSocket.on = function() {}; + fakeSocket.disconnect = function() {}; n.createSocket = function() { return fakeSocket; }; From 1f0215b6e16294072d5aaf51e76048239418c067 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Fri, 22 Aug 2014 13:33:59 -0400 Subject: [PATCH 70/75] fix test after rebase 3 --- test/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/test/index.html b/test/index.html index 3b99beef9..e5aa76a6c 100644 --- a/test/index.html +++ b/test/index.html @@ -15,7 +15,6 @@ - From c07055b0123d90514dd592c511fd53e0abfec7b8 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 25 Aug 2014 13:49:26 -0300 Subject: [PATCH 71/75] fix new tests from rebase --- test/unit/controllers/controllersSpec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/controllers/controllersSpec.js b/test/unit/controllers/controllersSpec.js index 94b26c236..c056246c8 100644 --- a/test/unit/controllers/controllersSpec.js +++ b/test/unit/controllers/controllersSpec.js @@ -210,7 +210,7 @@ describe("Unit: Controllers", function() { sinon.assert.callCount(spy, 1); sinon.assert.callCount(spy2, 0); sinon.assert.callCount(scope.loadTxs, 1); - spy.getCall(0).args[0].should.equal('1JqniWpWNA6Yvdivg3y9izLidETnurxRQm'); + spy.getCall(0).args[0].should.equal('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy'); spy.getCall(0).args[1].should.equal(1000 * config.unitToSatoshi); (typeof spy.getCall(0).args[2]).should.equal('undefined'); }); @@ -219,7 +219,7 @@ describe("Unit: Controllers", function() { it('should handle big values in 100 BTC', function() { var old = config.unitToSatoshi; config.unitToSatoshi = 100000000;; - sendForm.address.$setViewValue('1JqniWpWNA6Yvdivg3y9izLidETnurxRQm'); + sendForm.address.$setViewValue('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy'); sendForm.amount.$setViewValue(100); var spy = sinon.spy(scope.wallet, 'createTx'); scope.loadTxs = sinon.spy(); @@ -232,7 +232,7 @@ describe("Unit: Controllers", function() { it('should handle big values in 5000 BTC', function() { var old = config.unitToSatoshi; config.unitToSatoshi = 100000000;; - sendForm.address.$setViewValue('1JqniWpWNA6Yvdivg3y9izLidETnurxRQm'); + sendForm.address.$setViewValue('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy'); sendForm.amount.$setViewValue(5000); var spy = sinon.spy(scope.wallet, 'createTx'); scope.loadTxs = sinon.spy(); From 342a69d7379044f53227e854bd600aab8a336e8c Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 25 Aug 2014 18:26:26 -0300 Subject: [PATCH 72/75] make it work with ssl insight --- config.js | 5 +++-- js/controllers/settings.js | 7 +++---- js/models/network/Async.js | 10 ++++++---- views/settings.html | 16 ---------------- 4 files changed, 12 insertions(+), 26 deletions(-) diff --git a/config.js b/config.js index 73293528c..5c658ea68 100644 --- a/config.js +++ b/config.js @@ -17,8 +17,9 @@ var defaultConfig = { // network layer config network: { - host: 'localhost', - port: 3001 + host: 'test-insight.bitpay.com', + port: 443, + schema: 'https' }, // wallet default config diff --git a/js/controllers/settings.js b/js/controllers/settings.js index 6ff26a035..c8761aa17 100644 --- a/js/controllers/settings.js +++ b/js/controllers/settings.js @@ -52,10 +52,9 @@ angular.module('copayApp.controllers').controller('SettingsController', function $scope.save = function() { var network = config.network; - network.key = $scope.networkKey; - network.host = $scope.networkHost; - network.port = $scope.networkPort; - network.secure = $scope.networkSecure; + network.host = $scope.insightHost; + network.port = $scope.insightPort; + network.schema = $scope.insightSecure ? 'https' : 'http'; localStorage.setItem('config', JSON.stringify({ networkName: $scope.networkName, diff --git a/js/models/network/Async.js b/js/models/network/Async.js index 55fb8d368..72ef40ace 100644 --- a/js/models/network/Async.js +++ b/js/models/network/Async.js @@ -28,6 +28,7 @@ function Network(opts) { this.maxPeers = opts.maxPeers || 12; this.host = opts.host || 'localhost'; this.port = opts.port || 3001; + this.schema = opts.schema || 'https'; this.cleanUp(); } @@ -293,7 +294,7 @@ Network.prototype.start = function(opts, openCallback) { this.setCopayerId(opts.copayerId); this.maxPeers = opts.maxPeers || this.maxPeers; - this.socket = this.createSocket(this.host, this.port); + this.socket = this.createSocket(); this._setupConnectionHandlers(openCallback); this.socket.emit('subscribe', pubkey); this.socket.emit('sync', opts.lastTimestamp); @@ -301,11 +302,12 @@ Network.prototype.start = function(opts, openCallback) { }; -Network.prototype.createSocket = function(host, port) { - var hostPort = host + ':' + port; +Network.prototype.createSocket = function() { + var hostPort = this.schema + '://' + this.host + ':' + this.port; return io.connect(hostPort, { reconnection: true, - 'force new connection': true + 'force new connection': true, + 'secure': this.schema === 'https', }); }; diff --git a/views/settings.html b/views/settings.html index 47f92935a..2b231322b 100644 --- a/views/settings.html +++ b/views/settings.html @@ -47,22 +47,6 @@ -
- PeerJS server - - - - - - - - - -

- PeerJS Server is open-source software. You can run your own instance, or use PeerJS Server cloud. Check PeerJS Server -

-
-
« Back