mirror of https://github.com/BTCPrivate/copay.git
Merge pull request #188 from matiu/feature/peer-checking
Feature/peer checking
This commit is contained in:
commit
6cb1b5a851
6
API.js
6
API.js
|
@ -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']
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
14
index.html
14
index.html
|
@ -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}} <{{$root.wallet.id}}></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}} <{{$root.wallet.id}}></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">
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -77,6 +77,7 @@ angular.module('copay.transactions').controller('TransactionsController',
|
||||||
|
|
||||||
$scope.getTransactions = function() {
|
$scope.getTransactions = function() {
|
||||||
var w =$rootScope.wallet;
|
var w =$rootScope.wallet;
|
||||||
|
if (w) {
|
||||||
var addresses = w.getAddressesStr();
|
var addresses = w.getAddressesStr();
|
||||||
|
|
||||||
if (addresses.length > 0) {
|
if (addresses.length > 0) {
|
||||||
|
@ -85,6 +86,7 @@ angular.module('copay.transactions').controller('TransactionsController',
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.reject = function (ntxid) {
|
$scope.reject = function (ntxid) {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -20,26 +20,41 @@ 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 = {
|
this.opts = { key: opts.key };
|
||||||
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
|
|
||||||
if (this.copayerForPeer[peerId]) {
|
|
||||||
var copayerIdBuf = new Buffer(this.copayerForPeer[peerId],'hex');
|
var copayerIdBuf = new Buffer(this.copayerForPeer[peerId],'hex');
|
||||||
if (!bitcore.Message.verifyWithPubKey( copayerIdBuf, JSON.stringify(payload),
|
if (!bitcore.Message.verifyWithPubKey( copayerIdBuf, JSON.stringify(payload),
|
||||||
new Buffer(sig,'hex'))) {
|
new Buffer(sig,'hex'))) {
|
||||||
|
|
||||||
console.log('[WebRTC.js.152] SIGNATURE VERIFICATION FAILED!!'); //TODO
|
console.log('[WebRTC.js.152] SIGNATURE VERIFICATION FAILED!!'); //TODO
|
||||||
// TODO close connection
|
this._deletePeer(peerId);
|
||||||
return;
|
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,10 +224,13 @@ 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;
|
||||||
|
@ -209,7 +244,7 @@ Network.prototype._setupConnectionHandlers = function(dataConn, isInbound) {
|
||||||
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,9 +310,19 @@ 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) {
|
||||||
|
console.log('Adding peer/copayer', peerId, copayerId); //TODO
|
||||||
this.copayerForPeer[peerId]=copayerId;
|
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) {
|
||||||
|
@ -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,6 +366,7 @@ 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);
|
||||||
|
opts.connectedPeers = opts.connectedPeers || [];
|
||||||
for (var i = 0; i<opts.connectedPeers.length; i++) {
|
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 ret='';
|
|
||||||
var str = JSON.stringify(payload);
|
var str = JSON.stringify(payload);
|
||||||
if (payload.type ==='hello') {
|
if (payload.type !=='hello')
|
||||||
ret = (
|
throw new Error ('HMAC only for hello messages')
|
||||||
util.sha512hmac(
|
return util.sha512hmac(
|
||||||
new Buffer(str),
|
new Buffer(str),
|
||||||
new Buffer(copayerId,'hex')
|
new Buffer(copayerId,'hex')
|
||||||
)).toString('hex');
|
).toString('hex');
|
||||||
}
|
};
|
||||||
else {
|
|
||||||
|
Network.prototype._signECDSA = function(payload) {
|
||||||
|
var ret='';
|
||||||
|
var str = JSON.stringify(payload);
|
||||||
if (!this.signingKey)
|
if (!this.signingKey)
|
||||||
throw new Error ('no key to sign messages :(');
|
throw new Error ('no key to sign messages :(');
|
||||||
ret = bitcore.Message.sign(
|
|
||||||
|
return bitcore.Message.sign(
|
||||||
str,
|
str,
|
||||||
this.signingKey
|
this.signingKey
|
||||||
).toString('hex');
|
).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;
|
|
||||||
self.copayerId = null;
|
|
||||||
self.signingKey = null;
|
|
||||||
if (self.peer) {
|
|
||||||
console.log('## DESTROYING PEER INSTANCE'); //TODO
|
|
||||||
self.peer.disconnect();
|
|
||||||
self.peer.destroy();
|
|
||||||
self.peer = null;
|
|
||||||
}
|
|
||||||
self.closing = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
this.allowedCopayerIds={};
|
||||||
|
for(var i in allowedCopayerIdsArray) {
|
||||||
|
this.allowedCopayerIds[ allowedCopayerIdsArray[i] ] = 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
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();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -23,7 +23,7 @@ FakeStorage.prototype.clear = function() {
|
||||||
delete this['storage'];
|
delete this['storage'];
|
||||||
}
|
}
|
||||||
|
|
||||||
FakeStorage.prototype.getWalletIds = function() {
|
FakeStorage.prototype.getWallets = function() {
|
||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
});
|
});
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue