mirror of https://github.com/BTCPrivate/copay.git
add random key for network encryption
This commit is contained in:
parent
add1b084cc
commit
2dc59de87e
|
@ -85,7 +85,7 @@
|
||||||
Share this secret with your other copayers for them to join your wallet <br>
|
Share this secret with your other copayers for them to join your wallet <br>
|
||||||
</div>
|
</div>
|
||||||
<div class="size-24">
|
<div class="size-24">
|
||||||
<b>{{$root.wallet.getMyCopayerId()}}</b>
|
<b>{{$root.wallet.getSecret()}}</b>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -18,24 +18,26 @@ angular.module('copay.signin').controller('SigninController',
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.join = function(secret) {
|
$scope.join = function(secret) {
|
||||||
if (!secret || secret.length !==66 || !secret.match(/^[0-9a-f]*$/) ) {
|
|
||||||
$rootScope.flashMessage = { message: 'Bad secret secret string', type: 'error'};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$scope.loading = true;
|
$scope.loading = true;
|
||||||
|
|
||||||
walletFactory.network.on('joinError', function() {
|
walletFactory.network.on('badSecret', function() {
|
||||||
controllerUtils.onErrorDigest($scope);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
walletFactory.joinCreateSession(secret, function(w) {
|
walletFactory.joinCreateSession(secret, function(err,w) {
|
||||||
if (w) {
|
$scope.loading = false;
|
||||||
controllerUtils.startNetwork(w);
|
console.log('[signin.js.27:err:]',err,w); //TODO
|
||||||
}
|
|
||||||
else {
|
if (err || !w) {
|
||||||
$scope.loading = false;
|
if (err === 'joinError')
|
||||||
controllerUtils.onErrorDigest();
|
$rootScope.flashMessage = { message: 'Can not find peer'};
|
||||||
|
else if (err === 'badSecret')
|
||||||
|
$rootScope.flashMessage = { message: 'Bad secret secret string', type: 'error'};
|
||||||
|
else
|
||||||
|
$rootScope.flashMessage = { message: 'Unknown error', type: 'error'};
|
||||||
|
controllerUtils.onErrorDigest();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
controllerUtils.startNetwork(w);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,6 +9,8 @@ var Builder = bitcore.TransactionBuilder;
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
var EventEmitter = imports.EventEmitter || require('events').EventEmitter;
|
var EventEmitter = imports.EventEmitter || require('events').EventEmitter;
|
||||||
var copay = copay || require('../../../copay');
|
var copay = copay || require('../../../copay');
|
||||||
|
var SecureRandom = bitcore.SecureRandom;
|
||||||
|
var Base58Check = bitcore.Base58.base58Check;
|
||||||
|
|
||||||
function Wallet(opts) {
|
function Wallet(opts) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -26,6 +28,8 @@ function Wallet(opts) {
|
||||||
|
|
||||||
this.id = opts.id || Wallet.getRandomId();
|
this.id = opts.id || Wallet.getRandomId();
|
||||||
this.name = opts.name;
|
this.name = opts.name;
|
||||||
|
this.netKey = opts.netKey || SecureRandom.getRandomBuffer(8).toString('base64');
|
||||||
|
|
||||||
this.verbose = opts.verbose;
|
this.verbose = opts.verbose;
|
||||||
this.publicKeyRing.walletId = this.id;
|
this.publicKeyRing.walletId = this.id;
|
||||||
this.txProposals.walletId = this.id;
|
this.txProposals.walletId = this.id;
|
||||||
|
@ -124,6 +128,7 @@ Wallet.prototype._optsToObj = function() {
|
||||||
requiredCopayers: this.requiredCopayers,
|
requiredCopayers: this.requiredCopayers,
|
||||||
totalCopayers: this.totalCopayers,
|
totalCopayers: this.totalCopayers,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
|
netKey: this.netKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
@ -139,6 +144,26 @@ Wallet.prototype.getMyCopayerId = function() {
|
||||||
return this.getCopayerId(0);
|
return this.getCopayerId(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Wallet.prototype.getSecret = function() {
|
||||||
|
var i = new Buffer(this.getMyCopayerId(),'hex');
|
||||||
|
var k = new Buffer(this.netKey,'base64');
|
||||||
|
var b = Buffer.concat([i,k]);
|
||||||
|
var str = Base58Check.encode(b);
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Wallet.decodeSecret = function(secretB) {
|
||||||
|
var secret = Base58Check.decode(secretB);
|
||||||
|
var netKeyBuf = secret.slice(-8);
|
||||||
|
var pubKeyBuf = secret.slice(0,33);
|
||||||
|
return {
|
||||||
|
pubKey: pubKeyBuf.toString('hex'),
|
||||||
|
netKey: netKeyBuf.toString('base64'),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Wallet.prototype._lockIncomming = function() {
|
Wallet.prototype._lockIncomming = function() {
|
||||||
this.network.lockIncommingConnections(this.publicKeyRing.getAllCopayerIds());
|
this.network.lockIncommingConnections(this.publicKeyRing.getAllCopayerIds());
|
||||||
};
|
};
|
||||||
|
@ -162,6 +187,7 @@ Wallet.prototype.netStart = function() {
|
||||||
var startOpts = {
|
var startOpts = {
|
||||||
copayerId: myId,
|
copayerId: myId,
|
||||||
maxPeers: self.totalCopayers,
|
maxPeers: self.totalCopayers,
|
||||||
|
netKey: this.netKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.publicKeyRing.isComplete()) {
|
if (this.publicKeyRing.isComplete()) {
|
||||||
|
|
|
@ -149,27 +149,35 @@ WalletFactory.prototype.remove = function(walletId) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
WalletFactory.prototype.joinCreateSession = function(copayerId, cb) {
|
WalletFactory.prototype.joinCreateSession = function(secret, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
var s;
|
||||||
|
try {
|
||||||
|
s=Wallet.decodeSecret(secret);
|
||||||
|
} catch (e) {
|
||||||
|
return cb('badSecret');
|
||||||
|
}
|
||||||
|
|
||||||
//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');
|
||||||
var opts = {
|
var opts = {
|
||||||
copayerId: privateKey.getId(),
|
copayerId: privateKey.getId(),
|
||||||
|
netKey: s.netKey,
|
||||||
};
|
};
|
||||||
self.network.cleanUp();
|
self.network.cleanUp();
|
||||||
self.network.start(opts, function() {
|
self.network.start(opts, function() {
|
||||||
self.network.connectTo(copayerId);
|
self.network.connectTo(s.pubKey);
|
||||||
self.network.on('onlyYou', function(sender, data) {
|
self.network.on('onlyYou', function(sender, data) {
|
||||||
return cb();
|
return cb('joinError');
|
||||||
});
|
});
|
||||||
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;
|
||||||
var w = self.open(data.walletId, data.opts);
|
var w = self.open(data.walletId, data.opts);
|
||||||
w.firstCopayerId = copayerId;
|
w.firstCopayerId = s.pubKey;
|
||||||
return cb(w);
|
return cb(null, w);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,6 @@ var imports = require('soop').imports();
|
||||||
var EventEmitter= imports.EventEmitter || require('events').EventEmitter;
|
var EventEmitter= imports.EventEmitter || require('events').EventEmitter;
|
||||||
var bitcore = require('bitcore');
|
var bitcore = require('bitcore');
|
||||||
var util = bitcore.util;
|
var util = bitcore.util;
|
||||||
var Key = bitcore.Key;
|
|
||||||
/*
|
/*
|
||||||
* Emits
|
* Emits
|
||||||
* 'networkChange'
|
* 'networkChange'
|
||||||
|
@ -18,12 +17,11 @@ var Key = bitcore.Key;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Network(opts) {
|
function Network(opts) {
|
||||||
var self = this;
|
var self = this;
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
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.sjclParams = opts.sjclParams || {
|
this.sjclParams = opts.sjclParams || {
|
||||||
salt: 'f28bfb49ef70573c',
|
salt: 'f28bfb49ef70573c',
|
||||||
iter:500,
|
iter:500,
|
||||||
|
@ -31,8 +29,10 @@ function Network(opts) {
|
||||||
ts:parseInt(64),
|
ts:parseInt(64),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// For using your own peerJs server
|
// For using your own peerJs server
|
||||||
['port', 'host', 'path', 'debug'].forEach(function(k) {
|
self.opts = {};
|
||||||
|
['port', 'host', 'path', 'debug', 'key'].forEach(function(k) {
|
||||||
if (opts[k]) self.opts[k] = opts[k];
|
if (opts[k]) self.opts[k] = opts[k];
|
||||||
});
|
});
|
||||||
this.cleanUp();
|
this.cleanUp();
|
||||||
|
@ -44,6 +44,7 @@ Network.prototype.cleanUp = function() {
|
||||||
this.started = false;
|
this.started = false;
|
||||||
this.connectedPeers = [];
|
this.connectedPeers = [];
|
||||||
this.peerId = null;
|
this.peerId = null;
|
||||||
|
this.netKey = null;
|
||||||
this.copayerId = null;
|
this.copayerId = null;
|
||||||
this.signingKey = null;
|
this.signingKey = null;
|
||||||
this.allowedCopayerIds=null;
|
this.allowedCopayerIds=null;
|
||||||
|
@ -338,6 +339,7 @@ Network.prototype.start = function(opts, openCallback) {
|
||||||
|
|
||||||
if (this.started) return openCallback();
|
if (this.started) return openCallback();
|
||||||
|
|
||||||
|
this.netKey = opts.netKey;
|
||||||
this.maxPeers = opts.maxPeers || this.maxPeers;
|
this.maxPeers = opts.maxPeers || this.maxPeers;
|
||||||
|
|
||||||
if (!this.copayerId)
|
if (!this.copayerId)
|
||||||
|
@ -363,22 +365,10 @@ Network.prototype.getPeer = function() {
|
||||||
return this.peer;
|
return this.peer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Network.prototype._encrypt = function(payloadStr) {
|
||||||
Network.prototype._keyForCopayerId = function(copayerId) {
|
|
||||||
var key=this.keyCache[copayerId];
|
|
||||||
if (key) return key;
|
|
||||||
|
|
||||||
var cBuf = new Buffer(copayerId,'hex');
|
|
||||||
var key = bitcore.util.sha256(cBuf).toString('base64');
|
|
||||||
this.keyCache[copayerId] = key;
|
|
||||||
return key;
|
|
||||||
};
|
|
||||||
|
|
||||||
Network.prototype._encryptFor = function(copayerId, payloadStr) {
|
|
||||||
var key = this._keyForCopayerId(copayerId);
|
|
||||||
var plainText = sjcl.codec.utf8String.toBits(payloadStr);
|
var plainText = sjcl.codec.utf8String.toBits(payloadStr);
|
||||||
var p = this.sjclParams; // auth strength
|
var p = this.sjclParams;
|
||||||
ct = sjcl.encrypt(key, plainText, p);//,p, rp);
|
ct = sjcl.encrypt(this.netKey, plainText, p);//,p, rp);
|
||||||
var c = JSON.parse(ct);
|
var c = JSON.parse(ct);
|
||||||
var toSend = {
|
var toSend = {
|
||||||
iv: c.iv,
|
iv: c.iv,
|
||||||
|
@ -394,8 +384,7 @@ Network.prototype._decrypt = function(encStr) {
|
||||||
i[k] = this.sjclParams[k];
|
i[k] = this.sjclParams[k];
|
||||||
}
|
}
|
||||||
var str= JSON.stringify(i);
|
var str= JSON.stringify(i);
|
||||||
var key= this._keyForCopayerId(this.copayerId);
|
var pt = sjcl.decrypt(this.netKey, str);
|
||||||
var pt = sjcl.decrypt(key, str);
|
|
||||||
return pt;
|
return pt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -404,7 +393,7 @@ Network.prototype._sendToOne = function(copayerId, payloadStr, sig, cb) {
|
||||||
if (peerId !== this.peerId) {
|
if (peerId !== this.peerId) {
|
||||||
var dataConn = this.connections[peerId];
|
var dataConn = this.connections[peerId];
|
||||||
if (dataConn) {
|
if (dataConn) {
|
||||||
dataConn.send(this._encryptFor(copayerId, payloadStr));
|
dataConn.send(this._encrypt(payloadStr));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log('[WebRTC.js.255] WARN: NO CONNECTION TO:', peerId); //TODO
|
console.log('[WebRTC.js.255] WARN: NO CONNECTION TO:', peerId); //TODO
|
||||||
|
|
|
@ -29,11 +29,6 @@ angular.module('copay.controllerUtils')
|
||||||
|
|
||||||
root.onError = function(scope) {
|
root.onError = function(scope) {
|
||||||
if (scope) scope.loading = false;
|
if (scope) scope.loading = false;
|
||||||
$rootScope.flashMessage = {
|
|
||||||
type: 'error',
|
|
||||||
message: 'Could not connect to peer: ' +
|
|
||||||
scope
|
|
||||||
};
|
|
||||||
root.logout();
|
root.logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ var Video = function() {
|
||||||
|
|
||||||
this.mediaConnections = {};
|
this.mediaConnections = {};
|
||||||
this.localStream = null;
|
this.localStream = null;
|
||||||
this.onlineSound = new Audio('../../sound/online.wav');
|
this.onlineSound = new Audio('sound/online.wav');
|
||||||
};
|
};
|
||||||
|
|
||||||
Video.prototype.setOwnPeer = function(peer, wallet, cb) {
|
Video.prototype.setOwnPeer = function(peer, wallet, cb) {
|
||||||
|
@ -72,11 +72,13 @@ Video.prototype._addCall = function(mediaConnection, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Video.prototype.close = function() {
|
Video.prototype.close = function() {
|
||||||
this.localStream.stop();
|
if (this.localStream){
|
||||||
this.localStream.mozSrcObject = null;
|
this.localStream.stop();
|
||||||
this.localStream.src = "";
|
this.localStream.mozSrcObject = null;
|
||||||
this.localStream.src = null;
|
this.localStream.src = "";
|
||||||
this.localStream = null;
|
this.localStream.src = null;
|
||||||
|
this.localStream = null;
|
||||||
|
}
|
||||||
for (var i = 0; this.mediaConnections.length; i++) {
|
for (var i = 0; this.mediaConnections.length; i++) {
|
||||||
this.mediaConnections[i].close();
|
this.mediaConnections[i].close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,10 @@ describe('Wallet model', function() {
|
||||||
(function(){new Wallet(config)}).should.throw();
|
(function(){new Wallet(config)}).should.throw();
|
||||||
});
|
});
|
||||||
|
|
||||||
var createW = function () {
|
var createW = function (netKey) {
|
||||||
var c = JSON.parse(JSON.stringify(config));
|
var c = JSON.parse(JSON.stringify(config));
|
||||||
|
|
||||||
|
if (netKey) c.netKey = netKey;
|
||||||
c.privateKey = new copay.PrivateKey({ networkName: c.networkName });
|
c.privateKey = new copay.PrivateKey({ networkName: c.networkName });
|
||||||
|
|
||||||
c.publicKeyRing = new copay.PublicKeyRing({
|
c.publicKeyRing = new copay.PublicKeyRing({
|
||||||
|
@ -66,6 +67,9 @@ describe('Wallet model', function() {
|
||||||
should.exist(w.publicKeyRing);
|
should.exist(w.publicKeyRing);
|
||||||
should.exist(w.privateKey);
|
should.exist(w.privateKey);
|
||||||
should.exist(w.txProposals);
|
should.exist(w.txProposals);
|
||||||
|
should.exist(w.netKey);
|
||||||
|
var b = new Buffer(w.netKey,'base64');
|
||||||
|
b.toString('hex').length.should.equal(16);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should provide some basic features', function () {
|
it('should provide some basic features', function () {
|
||||||
|
@ -88,7 +92,8 @@ describe('Wallet model', function() {
|
||||||
];
|
];
|
||||||
|
|
||||||
var createW2 = function (privateKeys) {
|
var createW2 = function (privateKeys) {
|
||||||
var w = createW();
|
var netKey = 'T0FbU2JLby0=';
|
||||||
|
var w = createW(netKey);
|
||||||
should.exist(w);
|
should.exist(w);
|
||||||
|
|
||||||
var pkr = w.publicKeyRing;
|
var pkr = w.publicKeyRing;
|
||||||
|
@ -188,4 +193,21 @@ describe('Wallet model', function() {
|
||||||
should.exist(w2.privateKey.toObj);
|
should.exist(w2.privateKey.toObj);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('#getSecret decodeSecret', function () {
|
||||||
|
var w = createW2();
|
||||||
|
var id = w.getMyCopayerId();
|
||||||
|
var nk = w.netKey;
|
||||||
|
|
||||||
|
var sb= w.getSecret();
|
||||||
|
should.exist(sb);
|
||||||
|
var s = Wallet.decodeSecret(sb);
|
||||||
|
s.pubKey.should.equal(id);
|
||||||
|
s.netKey.should.equal(nk);
|
||||||
|
|
||||||
|
});
|
||||||
|
it('decodeSecret check', function () {
|
||||||
|
(function(){Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoKM');}).should.not.throw();
|
||||||
|
(function(){Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoK');}).should.throw();
|
||||||
|
(function(){Wallet.decodeSecret('12345');}).should.throw();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue