Merge pull request #1275 from matiaspando/feature/secret

Added secret number feature
This commit is contained in:
Yemel Jardi 2014-09-04 09:48:18 -03:00
commit bd5b7a22b0
6 changed files with 90 additions and 14 deletions

View File

@ -43,6 +43,7 @@ function Wallet(opts) {
' and tried to create a Wallet with network ' + this.getNetworkName()); ' and tried to create a Wallet with network ' + this.getNetworkName());
this.id = opts.id || Wallet.getRandomId(); this.id = opts.id || Wallet.getRandomId();
this.secretNumber = opts.secretNumber || Wallet.getRandomNumber();
this.lock = new WalletLock(this.storage, this.id, opts.lockTimeOutMin); this.lock = new WalletLock(this.storage, this.id, opts.lockTimeOutMin);
this.name = opts.name; this.name = opts.name;
@ -50,6 +51,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; this.network.maxPeers = this.totalCopayers;
this.network.secretNumber = this.secretNumber;
this.registeredPeerIds = []; this.registeredPeerIds = [];
this.addressBook = opts.addressBook || {}; this.addressBook = opts.addressBook || {};
this.publicKey = this.privateKey.publicHex; this.publicKey = this.privateKey.publicHex;
@ -78,6 +80,11 @@ Wallet.getRandomId = function() {
return r; return r;
}; };
Wallet.getRandomNumber = function() {
var r = bitcore.SecureRandom.getPseudoRandomBuffer(5).toString('hex');
return r;
};
Wallet.prototype.seedCopayer = function(pubKey) { Wallet.prototype.seedCopayer = function(pubKey) {
this.seededCopayerId = pubKey; this.seededCopayerId = pubKey;
}; };
@ -408,18 +415,28 @@ Wallet.prototype.getMyCopayerIdPriv = function() {
return this.privateKey.getIdPriv(); //copayer idpriv is hex of a private key return this.privateKey.getIdPriv(); //copayer idpriv is hex of a private key
}; };
Wallet.prototype.getSecretNumber = function() {
if (this.secretNumber) return this.secretNumber;
this.secretNumber = Wallet.getRandomNumber();
return this.secretNumber;
};
Wallet.prototype.getSecret = function() { Wallet.prototype.getSecret = function() {
var pubkeybuf = new Buffer(this.getMyCopayerId(), 'hex'); var buf = new Buffer(this.getMyCopayerId() + this.getSecretNumber(), 'hex');
var str = Base58Check.encode(pubkeybuf); var str = Base58Check.encode(buf);
return str; return str;
}; };
Wallet.decodeSecret = function(secretB) { Wallet.decodeSecret = function(secretB) {
var secret = Base58Check.decode(secretB); var secret = Base58Check.decode(secretB);
var pubKeyBuf = secret.slice(0, 33); var pubKeyBuf = secret.slice(0, 33);
var secretNumber = secret.slice(33, 38);
return { return {
pubKey: pubKeyBuf.toString('hex') pubKey: pubKeyBuf.toString('hex'),
secretNumber : secretNumber.toString('hex')
} }
}; };
@ -445,6 +462,7 @@ Wallet.prototype.netStart = function(callback) {
privkey: myIdPriv, privkey: myIdPriv,
maxPeers: self.totalCopayers, maxPeers: self.totalCopayers,
lastTimestamp: this.lastTimestamp, lastTimestamp: this.lastTimestamp,
secretNumber: self.secretNumber,
}; };
if (this.publicKeyRing.isComplete()) { if (this.publicKeyRing.isComplete()) {

View File

@ -233,7 +233,8 @@ WalletFactory.prototype.joinCreateSession = function(secret, nickname, passphras
var opts = { var opts = {
copayerId: privateKey.getId(), copayerId: privateKey.getId(),
privkey: privateKey.getIdPriv(), privkey: privateKey.getIdPriv(),
key: privateKey.getIdKey() key: privateKey.getIdKey(),
secretNumber : s.secretNumber,
}; };
self.network.cleanUp(); self.network.cleanUp();
@ -248,7 +249,7 @@ WalletFactory.prototype.joinCreateSession = function(secret, nickname, passphras
}); });
self.network.start(opts, function() { self.network.start(opts, function() {
self.network.greet(s.pubKey); self.network.greet(s.pubKey,opts.secretNumber);
self.network.on('data', function(sender, data) { self.network.on('data', function(sender, data) {
if (data.type === 'walletId') { if (data.type === 'walletId') {
if (data.networkName !== self.networkName) { if (data.networkName !== self.networkName) {

View File

@ -17,6 +17,7 @@ function Network(opts) {
this.host = opts.host || 'localhost'; this.host = opts.host || 'localhost';
this.port = opts.port || 3001; this.port = opts.port || 3001;
this.schema = opts.schema || 'https'; this.schema = opts.schema || 'https';
this.secretNumber = opts.secretNumber;
this.cleanUp(); this.cleanUp();
} }
@ -73,11 +74,12 @@ Network.prototype.connectedCopayers = function() {
return ret; return ret;
}; };
Network.prototype._sendHello = function(copayerId) { Network.prototype._sendHello = function(copayerId,secretNumber) {
this.send(copayerId, { this.send(copayerId, {
type: 'hello', type: 'hello',
copayerId: this.copayerId, copayerId: this.copayerId,
secretNumber : secretNumber
}); });
}; };
@ -193,6 +195,12 @@ Network.prototype._onMessage = function(enc) {
var self = this; var self = this;
switch (payload.type) { switch (payload.type) {
case 'hello': case 'hello':
if (typeof payload.secretNumber === 'undefined' || payload.secretNumber !== this.secretNumber)
{
this._deletePeer(enc.pubkey, 'incorrect secret number');
return;
}
// if we locked allowed copayers, check if it belongs // if we locked allowed copayers, check if it belongs
if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) { if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) {
this._deletePeer(sender); this._deletePeer(sender);
@ -240,8 +248,8 @@ Network.prototype._onError = function(err) {
this.criticalError = err.message; this.criticalError = err.message;
}; };
Network.prototype.greet = function(copayerId) { Network.prototype.greet = function(copayerId,secretNumber) {
this._sendHello(copayerId); this._sendHello(copayerId,secretNumber);
var peerId = this.peerFromCopayer(copayerId); var peerId = this.peerFromCopayer(copayerId);
this._addCopayerMap(peerId, copayerId); this._addCopayerMap(peerId, copayerId);
}; };
@ -350,6 +358,7 @@ Network.prototype.send = function(dest, payload, cb) {
if (to == this.copayerId) if (to == this.copayerId)
continue; continue;
log.debug('SEND to: ' + to, this.copayerId, payload); log.debug('SEND to: ' + to, this.copayerId, payload);
var message = this.encode(to, payload); var message = this.encode(to, payload);
this.socket.emit('message', message); this.socket.emit('message', message);
} }

View File

@ -337,22 +337,29 @@ describe('Wallet model', function() {
it('#getSecret decodeSecret', function() { it('#getSecret decodeSecret', function() {
var w = cachedCreateW2(); var w = cachedCreateW2();
var id = w.getMyCopayerId(); var id = w.getMyCopayerId();
var secretNumber = w.getSecretNumber();
var sb = w.getSecret(); var sb = w.getSecret();
should.exist(sb); should.exist(sb);
var s = Wallet.decodeSecret(sb); var s = Wallet.decodeSecret(sb);
s.pubKey.should.equal(id); s.pubKey.should.equal(id);
s.secretNumber.should.equal(secretNumber);
}); });
it('decodeSecret check', function() { it('decodeSecret check', function() {
(function() { (function() {
Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoKM'); Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoKM');
}).should.not. }).should.not.
throw(); throw();
(function() { (function() {
Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoK'); Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoK');
}).should. }).should.
throw(); throw();
(function() { (function() {
Wallet.decodeSecret('12345'); Wallet.decodeSecret('12345');
}).should. }).should.

View File

@ -27,10 +27,12 @@ describe('Network / Async', function() {
privkey: pk || '31701118abde096d166607115ed00ce74a2231f68f43144406c863f5ebf06c32', privkey: pk || '31701118abde096d166607115ed00ce74a2231f68f43144406c863f5ebf06c32',
lastTimestamp: 1, lastTimestamp: 1,
}; };
n.secretNumber = 'mySecret';
n.start(opts); n.start(opts);
return n; return n;
}; };
it('should create an instance', function() { it('should create an instance', function() {
var n = createN(); var n = createN();
should.exist(n); should.exist(n);
@ -129,7 +131,8 @@ describe('Network / Async', function() {
var message = { var message = {
type: 'hello', type: 'hello',
copayerId: cid1 copayerId: cid1,
secretNumber : 'mySecret'
}; };
var enc = n1.encode(cid2, message); var enc = n1.encode(cid2, message);
n2._onMessage(enc); n2._onMessage(enc);
@ -141,7 +144,8 @@ describe('Network / Async', function() {
var message = { var message = {
type: 'hello', type: 'hello',
copayerId: cid3 // MITM copayerId: cid3, // MITM
secretNumber : 'mySecret'
}; };
var enc = n.encode(cid2, message); var enc = n.encode(cid2, message);
@ -160,7 +164,8 @@ describe('Network / Async', function() {
var message = { var message = {
type: 'hello', type: 'hello',
copayerId: cid1 copayerId: cid1,
secretNumber : 'mySecret'
}; };
var nonce = new Buffer('0000000000000001', 'hex'); var nonce = new Buffer('0000000000000001', 'hex');
var enc = n1.encode(cid2, message, nonce); var enc = n1.encode(cid2, message, nonce);
@ -176,7 +181,8 @@ describe('Network / Async', function() {
var message = { var message = {
type: 'hello', type: 'hello',
copayerId: cid1 copayerId: cid1,
secretNumber : 'mySecret'
}; };
n2.networkNonces = {}; n2.networkNonces = {};
n2.networkNonces[cid1] = new Buffer('5000000000000001', 'hex'); n2.networkNonces[cid1] = new Buffer('5000000000000001', 'hex');
@ -195,7 +201,8 @@ describe('Network / Async', function() {
var message = { var message = {
type: 'hello', type: 'hello',
copayerId: cid1 copayerId: cid1,
secretNumber : 'mySecret'
}; };
n2.networkNonces = {}; n2.networkNonces = {};
n2.networkNonces[cid1] = new Buffer('0000000000000002', 'hex'); n2.networkNonces[cid1] = new Buffer('0000000000000002', 'hex');
@ -205,6 +212,40 @@ describe('Network / Async', function() {
n2._deletePeer.calledOnce.should.equal(true); 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() { describe('#setHexNonce', function() {

View File

@ -12,7 +12,7 @@
<h1 class="text-primary line-sidebar-b">Waiting copayers</h1> <h1 class="text-primary line-sidebar-b">Waiting copayers</h1>
<h3>Share this secret with your other copayers</h3> <h3>Share this secret with your other copayers</h3>
<div class="panel"> <div class="panel">
<qrcode size="250" data="{{$root.wallet.getSecret()}}"></qrcode> <qrcode size="350" data="{{$root.wallet.getSecret()}}"></qrcode>
<div class="secret text-gray size-14"> <div class="secret text-gray size-14">
{{$root.wallet.getSecret()}} {{$root.wallet.getSecret()}}
<span class="btn-copy" clip-copy="$root.wallet.getSecret()"></span> <span class="btn-copy" clip-copy="$root.wallet.getSecret()"></span>