Merge pull request #188 from matiu/feature/peer-checking

Feature/peer checking
This commit is contained in:
Mario Colque 2014-04-25 10:27:06 -03:00
commit 6cb1b5a851
13 changed files with 206 additions and 145 deletions

6
API.js
View File

@ -169,13 +169,13 @@ API.prototype.getCommands = decorate('getCommands', [
['callback', 'function'] ['callback', 'function']
]); ]);
API.prototype._cmd_getWalletIds = function(callback) { API.prototype._cmd_getWallets = function(callback) {
var self = this; var self = this;
return callback(null, self.walletFactory.getWalletIds()); return callback(null, self.walletFactory.getWallets());
}; };
API.prototype.getWalletIds = decorate('getWalletIds', [ API.prototype.getWallets = decorate('getWallets', [
['callback', 'function'] ['callback', 'function']
]); ]);

View File

@ -17,12 +17,12 @@
<a href="#"><img src="./img/logo-negative.svg" alt="Copay" width="130" /></a> <a href="#"><img src="./img/logo-negative.svg" alt="Copay" width="130" /></a>
</figure> </figure>
<div class="text-right" ng-show="$root.wallet"> <div class="text-right" ng-show="$root.wallet">
<div ng-if="$root.wallet.name"> <div>
<h5>Wallet: {{$root.wallet.name}} &lt;{{$root.wallet.id}}&gt;</h5> <h5 >
<p> <span ng-if="!$root.wallet.name && $root.wallet.id">Wallet ID: {{$root.wallet.id}}</span>
</div> <span ng-if="$root.wallet.name">Wallet: {{$root.wallet.name}} &lt;{{$root.wallet.id}}&gt;</span>
<div ng-if="!$root.wallet.name && $root.wallet.id"> [{{$root.wallet.requiredCopayers}}-{{$root.wallet.totalCopayers}}]<br>
<h5 >Wallet ID: {{$root.wallet.id}}</h5> </h5>
</div> </div>
<p> <p>
Balance: {{totalBalance || 0}} <i class="fi-bitcoin"></i><br> Balance: {{totalBalance || 0}} <i class="fi-bitcoin"></i><br>
@ -101,7 +101,7 @@
<script type="text/ng-template" id="signin.html"> <script type="text/ng-template" id="signin.html">
<div class="signin" ng-controller="SigninController"> <div class="signin" ng-controller="SigninController">
<div data-alert class="alert-box info round" ng-show="loading"> <div data-alert class="alert-box info round" ng-show="loading">
Connecting to wallet... Looking for peers...
</div> </div>
<div ng-show="!loading"> <div ng-show="!loading">
<div ng-show="!wallets.length"> <div ng-show="!wallets.length">

View File

@ -34,7 +34,7 @@ angular.module('copay.setup').controller('SetupController',
name: walletName, name: walletName,
}; };
var w = walletFactory.create(opts); var w = walletFactory.create(opts);
controllerUtils.setupUxHandlers(w); controllerUtils.startNetwork(w);
}; };
}); });

View File

@ -14,7 +14,7 @@ angular.module('copay.signin').controller('SigninController',
$scope.open = function(walletId, opts) { $scope.open = function(walletId, opts) {
$scope.loading = true; $scope.loading = true;
var w = walletFactory.open(walletId, opts); var w = walletFactory.open(walletId, opts);
controllerUtils.setupUxHandlers(w); controllerUtils.startNetwork(w);
}; };
$scope.join = function(secret) { $scope.join = function(secret) {
@ -29,8 +29,13 @@ angular.module('copay.signin').controller('SigninController',
}); });
walletFactory.joinCreateSession(secret, function(w) { walletFactory.joinCreateSession(secret, function(w) {
console.log('[signin.js.33] joinCreateSession RETURN', w); //TODO if (w) {
controllerUtils.setupUxHandlers(w); controllerUtils.startNetwork(w);
}
else {
$scope.loading = false;
controllerUtils.onErrorDigest();
}
}); });
}; };
}); });

View File

@ -77,13 +77,15 @@ angular.module('copay.transactions').controller('TransactionsController',
$scope.getTransactions = function() { $scope.getTransactions = function() {
var w =$rootScope.wallet; var w =$rootScope.wallet;
var addresses = w.getAddressesStr(); if (w) {
var addresses = w.getAddressesStr();
if (addresses.length > 0) { if (addresses.length > 0) {
w.blockchain.getTransactions(addresses, function(txs) { w.blockchain.getTransactions(addresses, function(txs) {
$scope.blockchain_txs = txs; $scope.blockchain_txs = txs;
$rootScope.$digest(); $rootScope.$digest();
}); });
}
} }
}; };

View File

@ -92,17 +92,25 @@ PublicKeyRing.prototype.getCopayerId = function(i) {
return this.copayerIds[i]; return this.copayerIds[i];
}; };
PublicKeyRing.prototype.myCopayerId = function(i) {
return this.getCopayerId(0);
};
PublicKeyRing.prototype.registeredCopayers = function () { PublicKeyRing.prototype.registeredCopayers = function () {
return this.copayersBIP32.length; return this.copayersBIP32.length;
}; };
PublicKeyRing.prototype.isComplete = function () { PublicKeyRing.prototype.isComplete = function () {
return this.registeredCopayers() >= this.totalCopayers; return this.registeredCopayers() === this.totalCopayers;
};
PublicKeyRing.prototype.getAllCopayerIds = function() {
var ret = [];
var l = this.registeredCopayers();
for(var i=0; i<l; i++) {
ret.push(this.getCopayerId(i));
}
return ret;
};
PublicKeyRing.prototype.myCopayerId = function(i) {
return this.getCopayerId(0);
}; };
PublicKeyRing.prototype._checkKeys = function() { PublicKeyRing.prototype._checkKeys = function() {

View File

@ -30,6 +30,7 @@ function Wallet(opts) {
this.publicKeyRing.walletId = this.id; this.publicKeyRing.walletId = this.id;
this.txProposals.walletId = this.id; this.txProposals.walletId = this.id;
this.network.maxPeers = this.totalCopayers;
} }
Wallet.parent = EventEmitter; Wallet.parent = EventEmitter;
@ -47,7 +48,6 @@ Wallet.getRandomId = function() {
Wallet.prototype._handlePublicKeyRing = function(senderId, data, isInbound) { Wallet.prototype._handlePublicKeyRing = function(senderId, data, isInbound) {
this.log('RECV PUBLICKEYRING:', data); this.log('RECV PUBLICKEYRING:', data);
var shouldSend = false;
var recipients, pkr = this.publicKeyRing; var recipients, pkr = this.publicKeyRing;
var inPKR = copay.PublicKeyRing.fromObj(data.publicKeyRing); var inPKR = copay.PublicKeyRing.fromObj(data.publicKeyRing);
@ -55,26 +55,18 @@ Wallet.prototype._handlePublicKeyRing = function(senderId, data, isInbound) {
if (hasChanged) { if (hasChanged) {
this.log('### BROADCASTING PKR'); this.log('### BROADCASTING PKR');
recipients = null; recipients = null;
shouldSend = true;
}
// else if (isInbound && !data.isBroadcast) {
// // always replying to connecting peer
// this.log('### REPLYING PKR TO:', senderId);
// recipients = senderId;
// shouldSend = true;
// }
if (shouldSend) {
this.sendPublicKeyRing(recipients); this.sendPublicKeyRing(recipients);
if (this.publicKeyRing.isComplete()) {
this._lockIncomming();
}
} }
this.store(); this.store();
}; };
Wallet.prototype._handleTxProposals = function(senderId, data, isInbound) { Wallet.prototype._handleTxProposals = function(senderId, data, isInbound) {
this.log('RECV TXPROPOSAL:', data); //TODO this.log('RECV TXPROPOSAL:', data);
var shouldSend = false;
var recipients; var recipients;
var inTxp = copay.TxProposals.fromObj(data.txProposals); var inTxp = copay.TxProposals.fromObj(data.txProposals);
var mergeInfo = this.txProposals.merge(inTxp, true); var mergeInfo = this.txProposals.merge(inTxp, true);
@ -82,18 +74,8 @@ Wallet.prototype._handleTxProposals = function(senderId, data, isInbound) {
if (mergeInfo.hasChanged || addSeen) { if (mergeInfo.hasChanged || addSeen) {
this.log('### BROADCASTING txProposals. '); this.log('### BROADCASTING txProposals. ');
recipients = null; recipients = null;
shouldSend = true;
}
// else if (isInbound && !data.isBroadcast) {
// // always replying to connecting peer
// this.log('### REPLYING txProposals TO:', senderId);
// recipients = senderId;
// shouldSend = true;
// }
if (shouldSend)
this.sendTxProposals(recipients); this.sendTxProposals(recipients);
}
this.store(); this.store();
}; };
@ -155,6 +137,10 @@ Wallet.prototype.getMyCopayerId = function() {
return this.getCopayerId(0); return this.getCopayerId(0);
}; };
Wallet.prototype._lockIncomming = function() {
this.network.lockIncommingConnections(this.publicKeyRing.getAllCopayerIds());
};
Wallet.prototype.netStart = function() { Wallet.prototype.netStart = function() {
var self = this; var self = this;
var net = this.network; var net = this.network;
@ -174,8 +160,13 @@ Wallet.prototype.netStart = function() {
var startOpts = { var startOpts = {
copayerId: myId, copayerId: myId,
signingKeyHex: self.privateKey.getSigningKey(), signingKeyHex: self.privateKey.getSigningKey(),
maxPeers: self.totalCopayers,
}; };
if (this.publicKeyRing.isComplete()) {
this._lockIncomming();
}
net.start(startOpts, function() { net.start(startOpts, function() {
self.emit('created', net.getPeer()); self.emit('created', net.getPeer());
var registered = self.getRegisteredPeerIds(); var registered = self.getRegisteredPeerIds();
@ -208,7 +199,6 @@ Wallet.prototype.getRegisteredPeerIds = function() {
}; };
Wallet.prototype.store = function(isSync) { Wallet.prototype.store = function(isSync) {
this.log('[Wallet.js.135:store:]'); //TODO
var wallet = this.toObj(); var wallet = this.toObj();
this.storage.setFromObj(this.id, wallet); this.storage.setFromObj(this.id, wallet);
@ -540,8 +530,7 @@ Wallet.prototype.connectTo = function(peerId) {
}; };
Wallet.prototype.disconnect = function() { Wallet.prototype.disconnect = function() {
this.log('## DISCONNECTING');
console.log('[Wallet.js.524] DISC'); //TODO
this.network.disconnect(); this.network.disconnect();
}; };

View File

@ -149,10 +149,16 @@ WalletFactory.prototype.joinCreateSession = function(copayerId, cb) {
//Create our PrivateK //Create our PrivateK
var privateKey = new PrivateKey({ networkName: this.networkName }); var privateKey = new PrivateKey({ networkName: this.networkName });
this.log('\t### PrivateKey Initialized'); this.log('\t### PrivateKey Initialized');
self.network.setCopayerId(privateKey.getId()); var opts = {
self.network.setSigningKey(privateKey.getSigningKey()); copayerId: privateKey.getId(),
self.network.start({}, function() { signingKeyHex: privateKey.getSigningKey(),
};
self.network.cleanUp();
self.network.start(opts, function() {
self.network.connectTo(copayerId); self.network.connectTo(copayerId);
self.network.on('onlyYou', function(sender, data) {
return cb();
});
self.network.on('data', function(sender, data) { self.network.on('data', function(sender, data) {
if (data.type ==='walletId') { if (data.type ==='walletId') {
data.opts.privateKey = privateKey; data.opts.privateKey = privateKey;

View File

@ -19,27 +19,42 @@ var Key = bitcore.Key;
function Network(opts) { function Network(opts) {
var self = this; var self = this;
opts = opts || {}; opts = opts || {};
this.peerId = opts.peerId; this.apiKey = opts.apiKey || 'lwjd5qra8257b9';
this.apiKey = opts.apiKey || 'lwjd5qra8257b9'; this.debug = opts.debug || 3;
this.debug = opts.debug || 3; this.maxPeers = opts.maxPeers || 10;
this.maxPeers = opts.maxPeers || 10; this.opts = { key: opts.key };
this.opts = {
key: opts.key
};
this.connections = {};
this.copayerForPeer = {};
// For using your own peerJs server // For using your own peerJs server
['port', 'host', 'path', 'debug'].forEach(function(k) { ['port', 'host', 'path', 'debug'].forEach(function(k) {
if (opts[k]) self.opts[k] = opts[k]; if (opts[k]) self.opts[k] = opts[k];
}); });
this.connectedPeers = []; this.cleanUp();
this.started = false;
} }
Network.parent = EventEmitter; Network.parent = EventEmitter;
Network.prototype.cleanUp = function() {
this.started = false;
this.connectedPeers = [];
this.peerId = null;
this.copayerId = null;
this.signingKey = null;
this.allowedCopayerIds=null;
this.authenticatedPeers=[];
this.copayerForPeer={};
this.connections={};
if (this.peer) {
console.log('## DESTROYING PEER INSTANCE'); //TODO
this.peer.disconnect();
this.peer.destroy();
this.peer = null;
}
this.closing = 0;
};
Network.parent=EventEmitter;
// Array helpers // Array helpers
Network._arrayDiff = function(a, b) { Network._arrayDiff = function(a, b) {
var seen = []; var seen = [];
@ -83,9 +98,16 @@ Network.prototype.connectedCopayers = function() {
return ret; return ret;
}; };
Network.prototype._onClose = function(peerId) { Network.prototype._deletePeer = function(peerId) {
if (this.connections[peerId]) {
this.connections[peerId].close();
}
delete this.connections[peerId]; delete this.connections[peerId];
this.connectedPeers = Network._arrayRemove(peerId, this.connectedPeers); this.connectedPeers = Network._arrayRemove(peerId, this.connectedPeers);
};
Network.prototype._onClose = function(peerId) {
this._deletePeer(peerId);
this._notifyNetworkChange(); this._notifyNetworkChange();
}; };
@ -99,7 +121,7 @@ Network.prototype._connectToCopayers = function(copayerIds) {
}; };
Network.prototype._sendHello = function(copayerId) { Network.prototype._sendHello = function(copayerId) {
console.log('#### SENDING HELLO TO ', copayerId); console.log('### SENDING HELLO TO ', copayerId);
this.send(copayerId, { this.send(copayerId, {
type: 'hello', type: 'hello',
copayerId: this.copayerId, copayerId: this.copayerId,
@ -107,7 +129,7 @@ Network.prototype._sendHello = function(copayerId) {
}; };
Network.prototype._sendCopayers = function(copayerIds) { Network.prototype._sendCopayers = function(copayerIds) {
console.log('#### SENDING PEER LIST: ', this.connectedPeers,this.connectedCopayers(), ' TO ', copayerIds?copayerIds: 'ALL'); console.log('### SENDING PEER LIST: ', this.connectedPeers,this.connectedCopayers(), ' TO ', copayerIds?copayerIds: 'ALL');
this.send(copayerIds, { this.send(copayerIds, {
type: 'copayers', type: 'copayers',
copayers: this.connectedCopayers(), copayers: this.connectedCopayers(),
@ -128,6 +150,8 @@ Network.prototype._addCopayer = function(copayerId, isInbound) {
} }
}; };
Network.prototype._onData = function(data, isInbound, peerId) { Network.prototype._onData = function(data, isInbound, peerId) {
var sig, payload; var sig, payload;
try { try {
@ -136,45 +160,53 @@ Network.prototype._onData = function(data, isInbound, peerId) {
payload= dataObj.payload; payload= dataObj.payload;
} catch (e) { } catch (e) {
console.log('### ERROR ON DATA: "%s" ', data, isInbound, e); console.log('### ERROR IN DATA: "%s" ', data, isInbound, e);
this._deletePeer(peerId);
return; return;
}; };
console.log('### RECEIVED INBOUND?:%s TYPE: %s FROM %s: sig:%s', console.log('### RECEIVED INBOUND?:%s TYPE: %s FROM %s',
isInbound, payload.type, peerId, sig, payload); isInbound, payload.type, peerId, payload);
var self=this;
// TODO _func // TODO _func
if(payload.type === 'hello') { if(payload.type === 'hello') {
var thisSig = this._sign(payload, this.copayerId); var thisSig = this._signHMAC(payload, this.copayerId);
if (thisSig !== sig) { if (thisSig !== sig) {
console.log('#### Peer sent WRONG hello. Closing connection.'); console.log('#### Peer sent WRONG hello signature. Closing connection.');
this._deletePeer(peerId);
return; return;
} }
if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) {
console.log('#### Peer is not on the allowedCopayerIds. Closing connection',
this.allowedCopayerIds, payload.copayerId);
this._deletePeer(peerId);
return;
}
console.log('#### Peer sent signed hello. Setting it up.'); //TODO console.log('#### Peer sent signed hello. Setting it up.'); //TODO
this._addCopayer(payload.copayerId, isInbound); this._addCopayer(payload.copayerId, isInbound);
this._setPeerAuthenticated(peerId);
this._notifyNetworkChange( isInbound ? payload.copayerId : null); this._notifyNetworkChange( isInbound ? payload.copayerId : null);
this.emit('open'); this.emit('open');
return; return;
} }
if (!this.copayerForPeer[peerId]) { //copayerForPeer is populated also in 'copayers' message, so we need authenticatedPeer
console.log('### Discarting message from unknow peer: ', peerId); //TODO if (isInbound && (!this.copayerForPeer[peerId] || !this.authenticatedPeers[peerId])) {
console.log('### Closing connection from unknown/unauthenticated peer: ', peerId);
this._deletePeer(peerId);
return; return;
} }
// check sig var copayerIdBuf = new Buffer(this.copayerForPeer[peerId],'hex');
if (this.copayerForPeer[peerId]) { if (!bitcore.Message.verifyWithPubKey( copayerIdBuf, JSON.stringify(payload),
var copayerIdBuf = new Buffer(this.copayerForPeer[peerId],'hex'); new Buffer(sig,'hex'))) {
if (!bitcore.Message.verifyWithPubKey( copayerIdBuf, JSON.stringify(payload), console.log('[WebRTC.js.152] SIGNATURE VERIFICATION FAILED!!'); //TODO
new Buffer(sig,'hex'))) { this._deletePeer(peerId);
return;
console.log('[WebRTC.js.152] SIGNATURE VERIFICATION FAILED!!'); //TODO
// TODO close connection
return;
}
} }
var self=this;
switch(payload.type) { switch(payload.type) {
case 'copayers': case 'copayers':
this._addCopayer(this.copayerForPeer[peerId], false); this._addCopayer(this.copayerForPeer[peerId], false);
@ -192,24 +224,27 @@ Network.prototype._onData = function(data, isInbound, peerId) {
Network.prototype._checkAnyPeer = function() { Network.prototype._checkAnyPeer = function() {
if (!this.connectedPeers.length) { if (!this.connectedPeers.length) {
console.log('EMIT openError: no more peers, not even you!'); console.log('EMIT openError: no more peers, not even you!');
this._cleanUp(); this.cleanUp();
this.emit('openError'); this.emit('openError');
} }
} if (this.connectedPeers.length === 1) {
this.emit('onlyYou');
}
};
Network.prototype._setupConnectionHandlers = function(dataConn, isInbound) { Network.prototype._setupConnectionHandlers = function(dataConn, isInbound) {
var self = this; var self = this;
dataConn.on('open', function() { dataConn.on('open', function() {
if (!Network._inArray(dataConn.peer, self.connectedPeers) if (!Network._inArray(dataConn.peer, self.connectedPeers)
&& ! self.connections[dataConn.peer]) { && !self.connections[dataConn.peer]) {
self.connections[dataConn.peer] = dataConn; self.connections[dataConn.peer] = dataConn;
console.log('### DATA CONNECTION READY: %s (inbound: %s) AUTHENTICATING...', console.log('### DATA CONNECTION READY: %s (inbound: %s) AUTHENTICATING...',
dataConn.peer, isInbound); dataConn.peer, isInbound);
// The connection peer send hello (with signature) // The connecting peer send hello (with signature)
if(!isInbound) if(!isInbound)
self._sendHello(self.copayerForPeer[dataConn.peer]); self._sendHello(self.copayerForPeer[dataConn.peer]);
} }
@ -236,7 +271,6 @@ Network.prototype._setupConnectionHandlers = function(dataConn, isInbound) {
}; };
Network.prototype._notifyNetworkChange = function(newCopayerId) { Network.prototype._notifyNetworkChange = function(newCopayerId) {
console.log('[WebRTC.js.164:_notifyNetworkChange:]', newCopayerId); //TODO
this.emit('networkChange', newCopayerId); this.emit('networkChange', newCopayerId);
}; };
@ -276,11 +310,21 @@ Network.prototype._setupPeerHandlers = function(openCallback) {
Network.prototype._addCopayerMap = function(peerId, copayerId) { Network.prototype._addCopayerMap = function(peerId, copayerId) {
if (!this.copayerForPeer[peerId]) { if (!this.copayerForPeer[peerId]) {
console.log('ADDING COPAYER MAPPING: %s => %s', peerId, copayerId); //TODO if(Object.keys(this.copayerForPeer).length < this.maxPeers) {
this.copayerForPeer[peerId]=copayerId; console.log('Adding peer/copayer', peerId, copayerId); //TODO
this.copayerForPeer[peerId]=copayerId;
}
else {
console.log('### maxPeerLimit of %d reached. Refusing to add more copayers.', this.maxPeers); //TODO
}
} }
}; };
Network.prototype._setPeerAuthenticated = function(peerId) {
this.authenticatedPeers[peerId] = 1;
};
Network.prototype.setCopayerId = function(copayerId) { Network.prototype.setCopayerId = function(copayerId) {
if (this.started) { if (this.started) {
throw new Error('network already started: can not change peerId') throw new Error('network already started: can not change peerId')
@ -303,14 +347,16 @@ Network.prototype.setSigningKey = function(keyHex) {
}; };
Network.prototype.peerFromCopayer = function(hex) { Network.prototype.peerFromCopayer = function(hex) {
return util.sha256(new Buffer(hex,'hex')).toString('hex'); var SIN = bitcore.SIN;
return new SIN(new Buffer(hex,'hex')).toString();
}; };
Network.prototype.start = function(opts, openCallback) { Network.prototype.start = function(opts, openCallback) {
opts = opts || {}; opts = opts || {};
var self = this;
if (this.started) return openCallback(); if (this.started) return openCallback();
opts.connectedPeers = opts.connectedPeers || [];
this.maxPeers = opts.maxPeers || this.maxPeers;
if (!this.copayerId) if (!this.copayerId)
this.setCopayerId(opts.copayerId); this.setCopayerId(opts.copayerId);
@ -320,7 +366,8 @@ Network.prototype.start = function(opts, openCallback) {
console.log('CREATING PEER INSTANCE:', this.peerId); //TODO console.log('CREATING PEER INSTANCE:', this.peerId); //TODO
this.peer = new Peer(this.peerId, this.opts); this.peer = new Peer(this.peerId, this.opts);
this._setupPeerHandlers(openCallback); this._setupPeerHandlers(openCallback);
for (var i = 0; i < opts.connectedPeers.length; i++) { opts.connectedPeers = opts.connectedPeers || [];
for (var i = 0; i<opts.connectedPeers.length; i++) {
var otherPeerId = opts.connectedPeers[i]; var otherPeerId = opts.connectedPeers[i];
this.connectTo(otherPeerId); this.connectTo(otherPeerId);
} }
@ -328,26 +375,28 @@ Network.prototype.start = function(opts, openCallback) {
}; };
Network.prototype._sign = function(payload, copayerId) { Network.prototype._signHMAC = function(payload, copayerId) {
var str = JSON.stringify(payload);
if (payload.type !=='hello')
throw new Error ('HMAC only for hello messages')
return util.sha512hmac(
new Buffer(str),
new Buffer(copayerId,'hex')
).toString('hex');
};
Network.prototype._signECDSA = function(payload) {
var ret=''; var ret='';
var str = JSON.stringify(payload); var str = JSON.stringify(payload);
if (payload.type ==='hello') { if (!this.signingKey)
ret = ( throw new Error ('no key to sign messages :(');
util.sha512hmac(
new Buffer(str), return bitcore.Message.sign(
new Buffer(copayerId,'hex') str,
)).toString('hex'); this.signingKey
} ).toString('hex');
else { };
if (!this.signingKey)
throw new Error ('no key to sign messages :(');
ret = bitcore.Message.sign(
str,
this.signingKey
).toString('hex');
}
return ret;
}
Network.prototype.getOnlinePeerIDs = function() { Network.prototype.getOnlinePeerIDs = function() {
return this.connectedPeers; return this.connectedPeers;
}; };
@ -356,13 +405,13 @@ Network.prototype.getPeer = function() {
return this.peer; return this.peer;
}; };
Network.prototype._sendToOne = function(copayerId, payload, cb) { Network.prototype._sendToOne = function(copayerId, payload, sig, cb) {
var peerId = this.peerFromCopayer(copayerId); var peerId = this.peerFromCopayer(copayerId);
if (peerId !== this.peerId) { if (peerId !== this.peerId) {
var dataConn = this.connections[peerId]; var dataConn = this.connections[peerId];
if (dataConn) { if (dataConn) {
var str = JSON.stringify({ var str = JSON.stringify({
sig: this._sign(payload, copayerId), sig: sig,
payload: payload payload: payload
}); });
dataConn.send(str); dataConn.send(str);
@ -381,17 +430,26 @@ Network.prototype.send = function(copayerIds, payload, cb) {
payload.isBroadcast = 1; payload.isBroadcast = 1;
} }
var sig;
if (payload.type === 'hello') {
var hisId = copayerIds;
sig=this._signHMAC(payload,hisId);
}
else {
sig=this._signECDSA(payload);
}
if (Array.isArray(copayerIds)) { if (Array.isArray(copayerIds)) {
var l = copayerIds.length; var l = copayerIds.length;
var i = 0; var i = 0;
copayerIds.forEach(function(copayerId) { copayerIds.forEach(function(copayerId) {
self._sendToOne(copayerId, payload, function () { self._sendToOne(copayerId, payload, sig, function () {
if (++i === l && typeof cb === 'function') cb(); if (++i === l && typeof cb === 'function') cb();
}); });
}); });
} }
else if (typeof copayerIds === 'string') else if (typeof copayerIds === 'string')
self._sendToOne(copayerIds, payload, cb); self._sendToOne(copayerIds, payload, sig, cb);
}; };
Network.prototype.connectTo = function(copayerId) { Network.prototype.connectTo = function(copayerId) {
@ -399,7 +457,7 @@ Network.prototype.connectTo = function(copayerId) {
var peerId = this.peerFromCopayer(copayerId); var peerId = this.peerFromCopayer(copayerId);
this._addCopayerMap(peerId,copayerId); this._addCopayerMap(peerId,copayerId);
console.log('### STARTING CONNECTION TO:', peerId, copayerId); console.log('### STARTING CONNECTION TO:\n\t'+ peerId+"\n\t"+ copayerId);
var dataConn = this.peer.connect(peerId, { var dataConn = this.peer.connect(peerId, {
serialization: 'none', serialization: 'none',
reliable: true, reliable: true,
@ -408,28 +466,21 @@ Network.prototype.connectTo = function(copayerId) {
self._setupConnectionHandlers(dataConn, false); self._setupConnectionHandlers(dataConn, false);
}; };
Network.prototype._cleanUp = function() { Network.prototype.lockIncommingConnections = function(allowedCopayerIdsArray) {
var self = this; if (!this.allowedCopayerIds)
self.connectedPeers = []; console.log('[webrtc] #### LOCKING INCOMMING CONNECTIONS');
self.started = false;
self.peerId = null; this.allowedCopayerIds={};
self.copayerId = null; for(var i in allowedCopayerIdsArray) {
self.signingKey = null; this.allowedCopayerIds[ allowedCopayerIdsArray[i] ] = 1;
if (self.peer) {
console.log('## DESTROYING PEER INSTANCE'); //TODO
self.peer.disconnect();
self.peer.destroy();
self.peer = null;
} }
self.closing = 0;
}; };
Network.prototype.disconnect = function(cb, forced) { Network.prototype.disconnect = function(cb, forced) {
var self = this; var self = this;
self.closing = 1; self.closing = 1;
self.send(null, { type: 'disconnect' }, function(){ self.send(null, { type: 'disconnect' }, function(){
self._cleanUp(); self.cleanUp();
if (typeof cb === 'function') cb(); if (typeof cb === 'function') cb();
}); });
}; };

View File

@ -34,7 +34,8 @@ angular.module('copay.controllerUtils')
root.onError(scope); root.onError(scope);
$rootScope.$digest(); $rootScope.$digest();
} }
root.setupUxHandlers = function(w) {
root.startNetwork = function(w) {
var handlePeerVideo = function(err, peerID, url) { var handlePeerVideo = function(err, peerID, url) {
if (err) { if (err) {
return; return;
@ -55,7 +56,6 @@ angular.module('copay.controllerUtils')
root.updateBalance(); root.updateBalance();
}); });
w.on('refresh', function() { w.on('refresh', function() {
console.log('[controllerUtils.js] Refreshing'); //TODO
root.updateBalance(); root.updateBalance();
}); });
w.on('openError', root.onErrorDigest); w.on('openError', root.onErrorDigest);

View File

@ -23,7 +23,7 @@ FakeStorage.prototype.clear = function() {
delete this['storage']; delete this['storage'];
} }
FakeStorage.prototype.getWalletIds = function() { FakeStorage.prototype.getWallets = function() {
return []; return [];
}; };

View File

@ -110,10 +110,10 @@ describe('API', function() {
}); });
}); });
describe('#getWalletIds', function() { describe('#getWallets', function() {
it('should get the wallet ids', function(done) { it('should get the wallet ids', function(done) {
var api = new API({Storage: Storage}); var api = new API({Storage: Storage});
api.getWalletIds(function(err, result) { api.getWallets(function(err, result) {
result.length.should.be.greaterThan(-1); result.length.should.be.greaterThan(-1);
done(); done();
}); });

View File

@ -5,7 +5,7 @@ var should = chai.should();
var copay = copay || require('../copay'); var copay = copay || require('../copay');
var Wallet = require('../js/models/core/Wallet'); var Wallet = require('../js/models/core/Wallet');
var Storage= require('./mocks/FakeStorage'); var Storage= require('./mocks/FakeStorage');
var Network= copay.WebRTC; var Network= require('./mocks/FakeNetwork');
var Blockchain= copay.Insight; var Blockchain= copay.Insight;
var addCopayers = function (w) { var addCopayers = function (w) {