diff --git a/index.html b/index.html index c189e16e2..f022894d4 100644 --- a/index.html +++ b/index.html @@ -85,6 +85,14 @@

I am

{{$root.peerId}}

+ + +

Copayers ({{$root.connectedPeers.length}}/5)

Copayers ({{$root.connectedPeers.length}}/5)

@@ -214,11 +222,12 @@ - + + diff --git a/js/config.js b/js/config.js index 3793d88bd..1d866dd7f 100644 --- a/js/config.js +++ b/js/config.js @@ -1,45 +1,5 @@ 'use strict'; -//Setting up route -angular - .module('copay') - .config(function($routeProvider) { - - $routeProvider - .when('/', { - templateUrl: 'signin.html' - }) - .when('/signin', { - templateUrl: 'signin.html' - }) - .when('/home', { - templateUrl: 'home.html' - }) - .when('/join/:id', { - templateUrl: 'join.html' - }) - .when('/peer', { - templateUrl: 'peer.html' - }) - .when('/transactions', { - templateUrl: 'transactions.html' - }) - .when('/send', { - templateUrl: 'send.html' - }) - .when('/backup', { - templateUrl: 'backup.html' - }) - .otherwise({ - templateUrl: '404.html' - }); - }); - -//Setting HTML5 Location Mode -angular - .module('copay') - .config(function($locationProvider) { - $locationProvider - .html5Mode(false); - //.hashPrefix('!'); - }); +var config = { + networkName: 'testnet', +}; diff --git a/js/controllers/signin.js b/js/controllers/signin.js index 9acfe3b70..42b4183a5 100644 --- a/js/controllers/signin.js +++ b/js/controllers/signin.js @@ -19,8 +19,6 @@ angular.module('copay.signin').controller('SigninController', $scope.loading = true; if (cid) { - $rootScope.connectedTo.push(cid); - Network.init(function() { Network.connect(cid, function() { $location.path('peer'); @@ -29,11 +27,9 @@ angular.module('copay.signin').controller('SigninController', } }; - if (peerData && peerData.peerId && peerData.connectedTo.length > 0) { + if (peerData && peerData.peerId && peerData.connectedPeers.length > 0) { $rootScope.peerId = peerData.peerId; - $rootScope.connectedPeers = peerData.connectedPeers; - - $scope.join(peerData.connectedTo[0]); + $scope.join(peerData.connectedPeers); } }); diff --git a/js/init.js b/js/init.js index 4c8f29b30..d9e3481d8 100644 --- a/js/init.js +++ b/js/init.js @@ -1,5 +1,5 @@ 'use strict'; - +var copay = require('copay'); angular.element(document).ready(function() { // Init the app angular.bootstrap(document, ['copay']); diff --git a/js/models/PublicKeyRing.js b/js/models/PublicKeyRing.js index c5b043a77..df6cb2254 100644 --- a/js/models/PublicKeyRing.js +++ b/js/models/PublicKeyRing.js @@ -29,7 +29,7 @@ var CHANGE_BRANCH = 'm/1/'; function PublicKeyRing(opts) { opts = opts || {}; - this.network = opts.network === 'livenet' ? + this.network = opts.networkName === 'livenet' ? bitcore.networks.livenet : bitcore.networks.testnet; this.requiredCopayers = opts.requiredCopayers || 3; @@ -60,7 +60,7 @@ PublicKeyRing.encrypt = function (passphrase, payload) { }; PublicKeyRing.read = function (id, passphrase) { - var encPayload = storage.read(id); + var encPayload = storage.get(id); if (!encPayload) throw new Error('Could not find wallet data'); var data; @@ -74,9 +74,7 @@ PublicKeyRing.read = function (id, passphrase) { if (data.id !== id) throw new Error('Wrong id in data'); - var config = { network: data.networkName === 'livenet' ? - bitcore.networks.livenet : bitcore.networks.testnet - }; + var config = { networkName: data.networkName }; var w = new PublicKeyRing(config); @@ -121,7 +119,7 @@ PublicKeyRing.prototype.store = function (passphrase) { if (!this.id) throw new Error('wallet has no id'); - storage.save(this.id, PublicKeyRing.encrypt(passphrase,this.serialize())); + storage.set(this.id, PublicKeyRing.encrypt(passphrase,this.serialize())); this.dirty = 0; return true; @@ -134,7 +132,7 @@ PublicKeyRing.prototype.registeredCopayers = function () { PublicKeyRing.prototype.haveAllRequiredPubKeys = function () { - return this.registeredCopayers() === this.totalCopayers; + return this.registeredCopayers() >= this.totalCopayers; }; PublicKeyRing.prototype._checkKeys = function() { @@ -236,9 +234,16 @@ PublicKeyRing.prototype.getAddresses = function() { return ret; }; -PublicKeyRing.prototype._checkInPRK = function(inPKR) { - if (this.id !== inPKR.id) +PublicKeyRing.prototype._checkInPRK = function(inPKR, ignoreId) { + + + if (!inPKR.ts) { + throw new Error('inPRK bad format: Did you use .toObj()?'); + } + + if (!ignoreId && this.id !== inPKR.id) { throw new Error('inPRK id mismatch'); + } if (this.network.name !== inPKR.networkName) throw new Error('inPRK network mismatch'); @@ -296,10 +301,10 @@ PublicKeyRing.prototype._mergePubkeys = function(inPKR) { return hasChanged; }; -PublicKeyRing.prototype.merge = function(inPKR) { +PublicKeyRing.prototype.merge = function(inPKR, ignoreId) { var hasChanged = false; - this._checkInPRK(inPKR); + this._checkInPRK(inPKR, ignoreId); if (this._mergeIndexes(inPKR)) hasChanged = true; diff --git a/js/models/Storage.js b/js/models/Storage.js index 34286e9ab..c6036747c 100644 --- a/js/models/Storage.js +++ b/js/models/Storage.js @@ -6,11 +6,11 @@ function Storage() { this.data = {}; } -Storage.prototype.read = function(k) { +Storage.prototype.get = function(k) { return this.data[k]; }; -Storage.prototype.save = function(k,v) { +Storage.prototype.set = function(k,v) { this.data[k]=v; }; diff --git a/js/routes.js b/js/routes.js new file mode 100644 index 000000000..3793d88bd --- /dev/null +++ b/js/routes.js @@ -0,0 +1,45 @@ +'use strict'; + +//Setting up route +angular + .module('copay') + .config(function($routeProvider) { + + $routeProvider + .when('/', { + templateUrl: 'signin.html' + }) + .when('/signin', { + templateUrl: 'signin.html' + }) + .when('/home', { + templateUrl: 'home.html' + }) + .when('/join/:id', { + templateUrl: 'join.html' + }) + .when('/peer', { + templateUrl: 'peer.html' + }) + .when('/transactions', { + templateUrl: 'transactions.html' + }) + .when('/send', { + templateUrl: 'send.html' + }) + .when('/backup', { + templateUrl: 'backup.html' + }) + .otherwise({ + templateUrl: '404.html' + }); + }); + +//Setting HTML5 Location Mode +angular + .module('copay') + .config(function($locationProvider) { + $locationProvider + .html5Mode(false); + //.hashPrefix('!'); + }); diff --git a/js/services/network.js b/js/services/network.js index 9e1031bf3..6cea32267 100644 --- a/js/services/network.js +++ b/js/services/network.js @@ -4,9 +4,7 @@ angular.module('copay.network') .factory('Network', function($rootScope, Storage) { var peer; $rootScope.connectedPeers = []; - $rootScope.connectedTo = []; $rootScope.peerId = null; - $rootScope.publicKeyRing = []; // Array helpers var _arrayDiff = function(a, b) { @@ -42,12 +40,11 @@ angular.module('copay.network') var _saveDataStorage = function() { Storage.save('peerData', { peerId: $rootScope.peerId, - connectedTo: $rootScope.connectedTo, connectedPeers: $rootScope.connectedPeers }); }; - var _sender = function(pid, data, cb) { + var _sendToOne = function(pid, data, cb) { if (pid !== $rootScope.peerId) { var conns = peer.connections[pid]; @@ -67,40 +64,79 @@ angular.module('copay.network') } }; - var _onData = function(data) { + var _onData = function(data, isOutbound) { var obj = JSON.parse(data); - + console.log('### RECEIVED TYPE: %s FROM %s', obj.data.type, obj.sender); switch(obj.data.type) { - case 'connectedPeers': - _connectToPeers(obj.data.peers); - break; - case 'getPeers': - _send(obj.sender, { - type: 'connectToPeers', - peers: $rootScope.connectedPeers - }); + case 'peerList': + if (_connectToPeers(obj.data.peers)) { + //TODO Remove log + console.log('### BROADCASTING PEER LIST'); + _send( $rootScope.connectedPeers, { + type: 'peerList', + peers: $rootScope.connectedPeers, + isBroadcast: 1, + }); + $rootScope.$digest(); + } + else if (!isOutbound && !obj.data.isBroadcast) { + // replying always to connecting peer + console.log('### REPLYING PEERLIST TO:', obj.sender ); + _send( obj.sender, { + type: 'peerList', + peers: $rootScope.connectedPeers + }); + } break; case 'disconnect': _onClose(obj.sender); break; + case 'publicKeyRing': + console.log('### RECEIVED PKR FROM:', obj.sender); + + if ($rootScope.publicKeyRing.merge(obj.data.publicKeyRing, true)) { + //TODO Remove log + console.log('### BROADCASTING PRK'); + _send( $rootScope.connectedPeers, { + type: 'publicKeyRing', + publicKeyRing: $rootScope.publicKeyRing.toObj(), + isBroadcast: 1, + }); + $rootScope.$digest(); + } + else if (!isOutbound && !obj.data.isBroadcast) { + // replying always to connecting peer + console.log('### REPLYING PRK TO:', obj.sender ); + _send( obj.sender, { + type: 'publicKeyRing', + publicKeyRing: $rootScope.publicKeyRing.toObj(), + }); + + } + + //TODO Remove log + console.log('*** PRK:', $rootScope.publicKeyRing.toObj()); + break; } }; var _onClose = function(pid) { $rootScope.connectedPeers = _arrayRemove(pid, $rootScope.connectedPeers); - $rootScope.connectedTo = _arrayRemove(pid, $rootScope.connectedTo); - _saveDataStorage(); $rootScope.$digest(); }; var _connectToPeers = function(peers) { - var arrayDiff = _arrayDiff(peers, $rootScope.connectedTo); - + var ret = false; + var arrayDiff1= _arrayDiff(peers, $rootScope.connectedPeers); + var arrayDiff = _arrayDiff(arrayDiff1, [$rootScope.peerId]); arrayDiff.forEach(function(pid) { - _connect(pid); + console.log('### CONNECTING TO:',pid); + ret = true; + connect(pid); }); + return ret; }; // public methods @@ -110,71 +146,95 @@ angular.module('copay.network') debug: 3 }); + + $rootScope.publicKeyRing = new copay.PublicKeyRing({ + network: config.networkName, + }); + $rootScope.publicKeyRing.addCopayer(); + console.log('### PublicKeyRing Initialized'); + + peer.on('open', function(pid) { + console.log('### PEER OPEN. I AM:' + pid); $rootScope.peerId = pid; - _arrayPushOnce(pid, $rootScope.connectedPeers); _saveDataStorage(); cb(); - $rootScope.$digest(); }); - peer.on('connection', function(conn) { - if (conn.label === 'wallet') { - conn.on('open', function() { - if (!_inArray(conn.peer, $rootScope.connectedTo)) { - var c = peer.connect(conn.peer, { - label: 'wallet', - serialization: 'none', - reliable: false, - metadata: { message: 'hi copayer!' } - }); + peer.on('connection', function(dataConn) { + if (dataConn.label === 'wallet') { + console.log('### NEW INBOUND CONNECTION'); //TODO + dataConn.on('open', function() { + if (!_inArray(dataConn.peer, $rootScope.connectedPeers)) { + console.log('### INBOUND DATA CONNECTION READY TO:' + dataConn.peer); //TODO + _arrayPushOnce(dataConn.peer, $rootScope.connectedPeers); + _saveDataStorage(); - c.on('open', function() { - $rootScope.connectedTo.push(conn.peer); - _arrayPushOnce(conn.peer, $rootScope.connectedPeers); - _saveDataStorage(); - - $rootScope.$digest(); - }); - - c.on('data', _onData); - - c.on('close', function() { - _onClose(c.peer); - }); + $rootScope.$digest(); } }); + + dataConn.on('data', _onData); + dataConn.on('error', function(e) { + console.log('### ## INBOUND DATA ERROR',e ); //TODO + _onClose(dataConn.peer); + }); + dataConn.on('close', function() { + _onClose(dataConn.peer); + }); } }); }; var connect = function(pid, cb) { if (pid !== $rootScope.peerId) { - var c = peer.connect(pid, { + + console.log('### STARTING CONNECT TO:' + pid ); + + var dataConn = peer.connect(pid, { label: 'wallet', serialization: 'none', - reliable: false, + reliable: true, metadata: { message: 'hi copayer!' } }); - c.on('open', function() { - _arrayPushOnce(pid, $rootScope.connectedTo); - _arrayPushOnce(pid, $rootScope.connectedPeers); + dataConn.on('open', function() { - _send(pid, { type: 'getPeers' }); + console.log('### OUTBOUND DATA CONN READY TO:' + pid ); + _arrayPushOnce(pid, $rootScope.connectedPeers); _saveDataStorage(); + console.log('#### SENDING PEER LIST: ' +$rootScope.connectedPeers); + _send(pid, { + type: 'peerList', + peers: $rootScope.connectedPeers + }); + + + console.log('#### SENDING PKR '); + _send(dataConn.peer, { + type: 'publicKeyRing', + publicKeyRing: $rootScope.publicKeyRing.toObj(), + }); + if (typeof cb === 'function') cb(); $rootScope.$digest(); }); - c.on('data', _onData); + dataConn.on('data', function(data) { + _onData(data,true); + }); - c.on('close', function() { - _onClose(c.peer); + dataConn.on('error', function(e) { + console.log('### ## INBOUND DATA ERROR',e ); //TODO + _onClose(dataConn.peer); + }); + + dataConn.on('close', function() { + _onClose(dataConn.peer); }); } }; @@ -182,32 +242,28 @@ angular.module('copay.network') var _send = function(pids, data, cb) { if (Array.isArray(pids)) pids.forEach(function(pid) { - _sender(pid, data, cb); + _sendToOne(pid, data, cb); }); else if (typeof pids === 'string') - _sender(pids, data, cb); + _sendToOne(pids, data, cb); }; var disconnect = function(cb) { + Storage.remove('peerData'); var conns = $rootScope.connectedPeers.length; var i = 1; - _send($rootScope.connectedPeers, { type: 'disconnect' }, function() { i += 1; if (i === conns) { + + $rootScope.connectedPeers = []; + $rootScope.peerId = null; peer.disconnect(); peer.destroy(); - if (typeof cb === 'function') cb(); } }); - - Storage.remove('peerData'); - - $rootScope.connectedPeers = []; - $rootScope.connectedTo = []; - $rootScope.peerId = null; } return { diff --git a/js/services/storage.js b/js/services/storage.js index b036f5aa4..d315ded79 100644 --- a/js/services/storage.js +++ b/js/services/storage.js @@ -7,7 +7,7 @@ angular.module('copay.storage') return JSON.parse(localStorage.getItem(key)); }, - save: function(key, data) { + set: function(key, data) { localStorage.setItem(key, JSON.stringify(data)); }, diff --git a/test/FakeStorage.js b/test/FakeStorage.js index 164b526ba..f12fc6f95 100644 --- a/test/FakeStorage.js +++ b/test/FakeStorage.js @@ -3,11 +3,11 @@ var FakeStorage = function(){ this.storage = {}; }; -FakeStorage.prototype.read = function (id) { +FakeStorage.prototype.set = function (id) { return this.storage[id]; }; -FakeStorage.prototype.save = function(id, payload) { +FakeStorage.prototype.get = function(id, payload) { this.storage[id] = payload; } diff --git a/test/test.publickeyring.js b/test/test.publickeyring.js index 8db683ccd..b78896aeb 100644 --- a/test/test.publickeyring.js +++ b/test/test.publickeyring.js @@ -13,13 +13,13 @@ var aMasterPubKey = 'tprv8ZgxMBicQKsPdSVTiWXEqCCzqRaRr9EAQdn5UVMpT9UHX67Dh1FmzEM var config = { - network:'livenet', + networkName:'livenet', }; -var createW = function (network) { +var createW = function (networkName) { var config = { - network: network || 'livenet', + networkName: networkName || 'livenet', }; var w = new PublicKeyRing(config); @@ -39,7 +39,7 @@ describe('PublicKeyRing model', function() { it('should create an instance (livenet)', function () { var w = new PublicKeyRing({ - network: config.network + networkName: config.networkName }); should.exist(w); w.network.name.should.equal('livenet'); @@ -158,7 +158,7 @@ describe('PublicKeyRing model', function() { w.generateAddress(false); var w2 = new PublicKeyRing({ - network: 'livenet', + networkName: 'livenet', id: w.id, }); w2.merge(w.toObj()).should.equal(true); @@ -182,33 +182,48 @@ describe('PublicKeyRing model', function() { w.generateAddress(false); + + var w2 = new PublicKeyRing({ + networkName: 'livenet', + }); + (function() { w2.merge(w.toObj());}).should.throw(); + (function() { w2.merge(w,true);}).should.throw(); + +console.log('[test.publickeyring.js.190]'); //TODO + w2.merge(w.toObj(),true).should.equal(true); + +console.log('[test.publickeyring.js.193]'); //TODO + + var w3 = new PublicKeyRing({ - network: 'livenet', + networkName: 'livenet', id: w.id, requiredCopayers: 2, }); (function() { w3.merge(w.toObj());}).should.throw(); var w4 = new PublicKeyRing({ - network: 'testnet', + networkName: 'testnet', id: w.id, }); (function() { w4.merge(w.toObj());}).should.throw(); var w5 = new PublicKeyRing({ - network: 'livenet', + networkName: 'livenet', id: w.id, totalCopayers: 4, }); (function() { w5.merge(w.toObj());}).should.throw(); var w6 = new PublicKeyRing({ - network: 'livenet', + networkName: 'livenet', id: w.id, }); (function() { w6.merge(w);}).should.throw(); w.networkName= 'livenet'; (function() { w6.merge(w);}).should.throw(); + + }); @@ -222,7 +237,7 @@ describe('PublicKeyRing model', function() { } var w2 = new PublicKeyRing({ - network: 'livenet', + networkName: 'livenet', id: w.id, }); should.exist(w); @@ -248,7 +263,7 @@ describe('PublicKeyRing model', function() { for(var i=0; i<5; i++) { w.haveAllRequiredPubKeys().should.equal(false); var w2 = new PublicKeyRing({ - network: 'livenet', + networkName: 'livenet', id: w.id, }); w2.addCopayer();