mirror of https://github.com/BTCPrivate/copay.git
550 lines
15 KiB
JavaScript
550 lines
15 KiB
JavaScript
'use strict';
|
|
|
|
var Async = copay.Async;
|
|
var EventEmitter = require('events').EventEmitter;
|
|
|
|
describe('Network / Async', function() {
|
|
|
|
|
|
var createN = function(pk) {
|
|
var n = new Async({
|
|
url: 'http://insight.example.com:1234'
|
|
});
|
|
var fakeSocket = {};
|
|
fakeSocket.emit = function() {};
|
|
fakeSocket.on = function() {};
|
|
fakeSocket.disconnect = function() {};
|
|
fakeSocket.removeAllListeners = function() {};
|
|
n.createSocket = function() {
|
|
return fakeSocket;
|
|
};
|
|
var opts = {
|
|
copayerId: '03b51d01d798522cf61211b4dfcdd6db219ee33cf166e1cb7f43d836ab00ccddee',
|
|
privkey: pk || '31701118abde096d166607115ed00ce74a2231f68f43144406c863f5ebf06c32',
|
|
lastTimestamp: 1,
|
|
};
|
|
n.secretNumber = 'mySecret';
|
|
n.start(opts);
|
|
return n;
|
|
};
|
|
|
|
|
|
it('should create an instance', function() {
|
|
var n = createN();
|
|
should.exist(n);
|
|
});
|
|
|
|
describe('#cleanUp', function() {
|
|
|
|
it('should not set netKey', function() {
|
|
var n = createN();
|
|
(n.netKey === undefined).should.equal(true);
|
|
});
|
|
|
|
it('should set privkey to null', function() {
|
|
var n = createN();
|
|
n.cleanUp();
|
|
expect(n.privkey).to.equal(null);
|
|
});
|
|
|
|
it('should remove handlers', function() {
|
|
var n = createN();
|
|
var save = Async.prototype.removeAllListeners;
|
|
var spy = Async.prototype.removeAllListeners = sinon.spy();
|
|
n.cleanUp();
|
|
spy.calledOnce.should.equal(true);
|
|
Async.prototype.removeAllListeners = save;
|
|
});
|
|
});
|
|
|
|
describe('#send', function() {
|
|
|
|
it('should be able to broadcast', function() {
|
|
var n = createN('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08');
|
|
var spy = sinon.spy();
|
|
var dummy = {
|
|
dummy: true
|
|
};
|
|
n.send(null, dummy, spy);
|
|
spy.calledOnce.should.be.true;
|
|
});
|
|
it('should call _sendToOne for a copayer', function(done) {
|
|
var n = createN('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08');
|
|
var data = 'my data to send';
|
|
|
|
var copayerId = '03b51d01d798522cf61211b4dfcdd6d01020304cf166e1cb7f43d836abc5c18b23';
|
|
n._sendToOne = function(a, b, cb) {
|
|
cb();
|
|
};
|
|
var opts = {};
|
|
n.send(copayerId, data, done);
|
|
|
|
});
|
|
|
|
it('should call _sendToOne with encrypted data for a copayer', function(done) {
|
|
var n = createN('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08');
|
|
var data = new bitcore.Buffer('my data to send');
|
|
|
|
var copayerId = '03b51d01d798522cf61001b4dfcdd6db219ee33cf166e1cb7f43d836abc5c18b23';
|
|
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 = createN('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08');
|
|
var data = new bitcore.Buffer('my data to send');
|
|
var copayerIds = ['03b51d01d798522cf61211b4dfcdd6db219ee33cf166e1cb7f43d836abc5c18b23'];
|
|
n._sendToOne = function(a1, a2, cb) {
|
|
cb();
|
|
};
|
|
var opts = {};
|
|
n.send(copayerIds, data, function() {
|
|
done();
|
|
});
|
|
|
|
});
|
|
});
|
|
|
|
describe('#_onMessage', function() {
|
|
var pk1 = 'fb23b9074ca5e7163719b86b41c7ce8348cf3d2839bb5f6125ef6efd5d40d7d3';
|
|
var cid1 = '0311a10109320efb3646c832d3e140c6d9c4f69b16e73fc3f0c23b3d014ec77828';
|
|
|
|
var pk2 = '89073fe4d3fdef2c5f2909bcda92e4470633f08640d1a62acc464327d611577e';
|
|
var cid2 = '03ceefb9dbcf7410411e5c1268d9d8e850ffd3a55da764a8377f3212571a52c01b';
|
|
|
|
var pk3 = 'a2ae2c7029c6a4136d7fe60c4d078a2e9d5af8a246bf2d5fee3410e273a5d430';
|
|
var cid3 = '034d3dd2054234737c1cff9d973c9c7e0fb5902c8e56c9d57a699b7842cedfe984';
|
|
|
|
it('should not reject data sent from a peer with hijacked pubkey', function() {
|
|
var n1 = createN(pk1);
|
|
var n2 = createN(pk2);
|
|
n2._deletePeer = sinon.spy();
|
|
|
|
var message = {
|
|
type: 'hello',
|
|
copayerId: cid1,
|
|
secretNumber: 'mySecret'
|
|
};
|
|
var enc = n1.encode(cid2, message);
|
|
n2._onMessage(enc);
|
|
n2._deletePeer.calledOnce.should.equal(false);
|
|
});
|
|
|
|
it('should ignore messages', function() {
|
|
var n1 = createN(pk1);
|
|
var n2 = createN(pk2);
|
|
n2._deletePeer = sinon.spy();
|
|
|
|
var message = {
|
|
type: 'hello',
|
|
copayerId: cid1,
|
|
secretNumber: 'mySecret',
|
|
ts: 1
|
|
};
|
|
var enc = n1.encode(cid2, message);
|
|
|
|
enc.ts = 1;
|
|
n2.ignoreMessageFromTs = 1;
|
|
n2._onMessage(enc);
|
|
n2._deletePeer.calledOnce.should.equal(false);
|
|
});
|
|
|
|
|
|
it('should delete peer if copayer does not belong', function() {
|
|
var n1 = createN(pk1);
|
|
var n2 = createN(pk2);
|
|
n2.lockIncommingConnections([cid3]);
|
|
n2._deletePeer = sinon.spy();
|
|
|
|
var message = {
|
|
type: 'hello',
|
|
copayerId: cid1,
|
|
secretNumber: 'mySecret',
|
|
};
|
|
var enc = n1.encode(cid2, message);
|
|
|
|
n2._onMessage(enc);
|
|
n2._deletePeer.calledOnce.should.equal(true);
|
|
});
|
|
|
|
it('should emit data', function() {
|
|
var n1 = createN(pk1);
|
|
var n2 = createN(pk2);
|
|
n2.emit = sinon.spy();
|
|
|
|
var message = {
|
|
type: 'helloxxx',
|
|
copayerId: cid1,
|
|
secretNumber: 'mySecret',
|
|
};
|
|
var enc = n1.encode(cid2, message);
|
|
|
|
n2._onMessage(enc);
|
|
n2.emit.calledOnce.should.equal(true);
|
|
});
|
|
|
|
it('should reject data sent from a peer with hijacked pubkey', function() {
|
|
var n = createN(pk2);
|
|
|
|
var message = {
|
|
type: 'hello',
|
|
copayerId: cid3, // MITM
|
|
secretNumber: 'mySecret'
|
|
};
|
|
|
|
var enc = n.encode(cid2, message);
|
|
|
|
n._deletePeer = sinon.spy();
|
|
|
|
n._onMessage(enc);
|
|
n._deletePeer.calledOnce.should.equal(true);
|
|
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 n1 = createN(pk1);
|
|
var n2 = createN(pk2);
|
|
n2._deletePeer = sinon.spy();
|
|
|
|
var message = {
|
|
type: 'hello',
|
|
copayerId: cid1,
|
|
secretNumber: 'mySecret'
|
|
};
|
|
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() {
|
|
var n1 = createN(pk1);
|
|
var n2 = createN(pk2);
|
|
n2._deletePeer = sinon.spy();
|
|
|
|
var message = {
|
|
type: 'hello',
|
|
copayerId: cid1,
|
|
secretNumber: 'mySecret'
|
|
};
|
|
n2.networkNonces = {};
|
|
n2.networkNonces[cid1] = new Buffer('5000000000000001', 'hex');
|
|
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('5000000000000002');
|
|
n2._deletePeer.calledOnce.should.equal(false);
|
|
});
|
|
|
|
it('should reject data sent from a peer with an outdated nonce', function() {
|
|
var n1 = createN(pk1);
|
|
var n2 = createN(pk2);
|
|
n2._deletePeer = sinon.spy();
|
|
|
|
var message = {
|
|
type: 'hello',
|
|
copayerId: cid1,
|
|
secretNumber: 'mySecret'
|
|
};
|
|
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 accept join with a correct secret number', function() {
|
|
var n1 = createN(pk1);
|
|
var n2 = createN(pk2);
|
|
n2._deletePeer = sinon.spy();
|
|
|
|
var message = {
|
|
type: 'hello',
|
|
copayerId: cid1,
|
|
secretNumber: 'mySecret'
|
|
};
|
|
|
|
var enc = n1.encode(cid2, message);
|
|
n2._onMessage(enc);
|
|
n2._deletePeer.calledOnce.should.equal(false);
|
|
|
|
});
|
|
|
|
it('should reject join with a incorrect secret number', function() {
|
|
var n1 = createN(pk1);
|
|
var n2 = createN(pk2);
|
|
n2._deletePeer = sinon.spy();
|
|
|
|
var message = {
|
|
type: 'hello',
|
|
copayerId: cid1,
|
|
secretNumber: 'otherSecret'
|
|
};
|
|
|
|
var enc = n1.encode(cid2, message);
|
|
n2._onMessage(enc);
|
|
n2._deletePeer.calledOnce.should.equal(true);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
describe('#setHexNonce', function() {
|
|
|
|
it('should set a nonce from a hex value', function() {
|
|
var hex = '0000000000000000';
|
|
var n = createN();
|
|
n.setHexNonce(hex);
|
|
n.getHexNonce().should.equal(hex);
|
|
n.networkNonce.toString('hex').should.equal(hex);
|
|
});
|
|
|
|
it('should return an error', function() {
|
|
var hex = '0000';
|
|
var n = createN();
|
|
(function() {
|
|
n.setHexNonce(hex);
|
|
}).should.throw('incorrect length');
|
|
});
|
|
|
|
it('should iterateNonce', function() {
|
|
var n = createN();
|
|
n.iterateNonce = sinon.spy();
|
|
n.setHexNonce();
|
|
n.iterateNonce.callCount.should.be.equal(1);
|
|
n.setHexNonce(null);
|
|
n.iterateNonce.callCount.should.be.equal(2);
|
|
n.setHexNonce(undefined);
|
|
n.iterateNonce.callCount.should.be.equal(3);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
describe('#setHexNonces', function() {
|
|
|
|
it('should set a nonce from a hex value', function() {
|
|
var hex = '0000000000000000';
|
|
var n = createN();
|
|
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 = createN();
|
|
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 = createN();
|
|
n.setHexNonces({
|
|
fakeid: hex
|
|
});
|
|
n.getHexNonces().fakeid.should.equal(hex);
|
|
});
|
|
|
|
});
|
|
|
|
describe('#iterateNonce', function() {
|
|
|
|
it('should set a nonce not already set', function() {
|
|
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 = createN();
|
|
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 = createN();
|
|
n.iterateNonce();
|
|
var buf = new Buffer(4);
|
|
buf.writeUInt32BE(Math.floor(Date.now() / 1000), 0);
|
|
n.networkNonce[0].should.equal(buf[0]);
|
|
});
|
|
|
|
});
|
|
|
|
describe('#_arrayRemove', function() {
|
|
it('should remove an element from an array', function() {
|
|
var array = ['1', '2', '3', '4'];
|
|
array = Async._arrayRemove('2', array);
|
|
array.length.should.be.equal(3);
|
|
array.indexOf('2').should.be.equal(-1);
|
|
array = Async._arrayRemove('5', array);
|
|
array.length.should.be.equal(3);
|
|
});
|
|
});
|
|
|
|
describe('#getOnlinePeerIDs', function() {
|
|
it('should get peer ids that are online', function() {
|
|
var n = createN();
|
|
n.getOnlinePeerIDs().length.should.be.equal(0);
|
|
n._addCopayer('ab0001');
|
|
n.getOnlinePeerIDs().length.should.be.equal(1);
|
|
n._addCopayer('ab0001');
|
|
n.getOnlinePeerIDs().length.should.be.equal(1);
|
|
n._addCopayer('ab0002');
|
|
n.getOnlinePeerIDs().length.should.be.equal(2);
|
|
});
|
|
});
|
|
|
|
describe('#connectedCopayers', function() {
|
|
it('should get peer ids that are online', function() {
|
|
var n = createN();
|
|
n.connectedCopayers().length.should.be.equal(0);
|
|
n._addCopayer('ab0001');
|
|
n.connectedCopayers().length.should.be.equal(1);
|
|
n._addCopayer('ab0001');
|
|
n.connectedCopayers().length.should.be.equal(1);
|
|
n._addCopayer('ab0002');
|
|
n.connectedCopayers().length.should.be.equal(2);
|
|
});
|
|
});
|
|
|
|
describe('#_deletePeer', function() {
|
|
it('should delete a Peer', function() {
|
|
var n = createN();
|
|
n._addCopayer('ab0001');
|
|
n.connectedPeers.length.should.be.equal(1);
|
|
var peerId = n.connectedPeers[0];
|
|
n._deletePeer(peerId);
|
|
n.connectedPeers.length.should.be.equal(0);
|
|
});
|
|
});
|
|
|
|
describe('#getCopayerIds', function() {
|
|
it('should return the copayer ids', function() {
|
|
var n = createN();
|
|
n.getCopayerIds().length.should.be.equal(1);
|
|
});
|
|
|
|
it('should return the allowed copayer ids', function() {
|
|
var n = createN();
|
|
var lockIds = ['abc001', 'abc002'];
|
|
n.lockIncommingConnections(lockIds);
|
|
n.getCopayerIds().length.should.be.equal(2);
|
|
});
|
|
});
|
|
|
|
describe('#isOnline', function() {
|
|
it('should return if is online', function() {
|
|
var n = createN();
|
|
n.isOnline().should.be.true;
|
|
n.cleanUp();
|
|
n.isOnline().should.be.false;
|
|
});
|
|
});
|
|
|
|
describe('#greet', function() {
|
|
it('should greet ', function() {
|
|
var n = createN();
|
|
n.greet('03b51d01d798522cf61211b4dfcdd6db219ee33cf166e1cb7f43d836ab00ccddee', 'mySecret');
|
|
});
|
|
});
|
|
|
|
describe('#setCopayers', function() {
|
|
it('should setCopayers ', function() {
|
|
var n = createN();
|
|
n.connectedPeers.length.should.be.equal(0);
|
|
var cids = ['abc001', 'abc002'];
|
|
n.setCopayers(cids);
|
|
n.connectedPeers.length.should.be.equal(2);
|
|
});
|
|
});
|
|
|
|
|
|
describe('#lockIncommingConnections', function() {
|
|
it('should lock Incomming Connections ', function() {
|
|
var n = createN();
|
|
var cids = ['abc001', 'abc002', 'abc003'];
|
|
n.setCopayers(cids);
|
|
|
|
var lockIds = ['abc001', 'abc002'];
|
|
n.lockIncommingConnections(lockIds);
|
|
Object.keys(n.allowedCopayerIds).length.should.be.equal(2);
|
|
});
|
|
});
|
|
|
|
describe('#getKey', function() {
|
|
it('should return the key or generate a new one ', function() {
|
|
var n = createN();
|
|
n.key = null;
|
|
var k1 = n.getKey();
|
|
k1.should.not.be.undefined;
|
|
var k2 = n.getKey();
|
|
k2.should.not.be.undefined;
|
|
k1.should.be.equal(k2);
|
|
});
|
|
});
|
|
|
|
describe('#_onError', function() {
|
|
it('should set criticalError ', function() {
|
|
var n = createN();
|
|
expect(n.criticalError).to.be.undefined;
|
|
var myError = {
|
|
message: 'Some error'
|
|
};
|
|
n._onError(myError);
|
|
n.criticalError.should.be.equal('Some error');
|
|
});
|
|
});
|
|
|
|
describe('#_setInboundPeerAuth', function() {
|
|
it('should set isInboundPeerAuth ', function() {
|
|
var n = createN();
|
|
expect(n.isInboundPeerAuth['1']).to.be.undefined;
|
|
|
|
n._setInboundPeerAuth('1');
|
|
n.isInboundPeerAuth['1'].should.be.true;
|
|
});
|
|
});
|
|
|
|
describe('#start', function() {
|
|
it('should not start ', function(done) {
|
|
var n = createN();
|
|
var opts = {
|
|
privkey: 'fb23b9074ca5e7163719b86b41c7ce8348cf3d2839bb5f6125ef6efd5d40d7d3',
|
|
copayerId: '0311a10109320efb3646c832d3e140c6d9c4f69b16e73fc3f0c23b3d014ec77828'
|
|
};
|
|
n.started = 1;
|
|
|
|
n.start(opts, function() {
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
});
|