diff --git a/index.html b/index.html index 4acac0961..31992f889 100644 --- a/index.html +++ b/index.html @@ -85,7 +85,7 @@ Share this secret with your other copayers for them to join your wallet
- {{$root.wallet.getMyCopayerId()}} + {{$root.wallet.getSecret()}}
diff --git a/js/controllers/signin.js b/js/controllers/signin.js index f1e8b2fe4..052179478 100644 --- a/js/controllers/signin.js +++ b/js/controllers/signin.js @@ -18,24 +18,26 @@ angular.module('copay.signin').controller('SigninController', }; $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; - walletFactory.network.on('joinError', function() { - controllerUtils.onErrorDigest($scope); + walletFactory.network.on('badSecret', function() { }); - walletFactory.joinCreateSession(secret, function(w) { - if (w) { - controllerUtils.startNetwork(w); - } - else { - $scope.loading = false; - controllerUtils.onErrorDigest(); + walletFactory.joinCreateSession(secret, function(err,w) { + $scope.loading = false; +console.log('[signin.js.27:err:]',err,w); //TODO + + if (err || !w) { + if (err === 'joinError') + $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); }); }; }); diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 02646d3c9..1a9898993 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -9,6 +9,8 @@ var Builder = bitcore.TransactionBuilder; var http = require('http'); var EventEmitter = imports.EventEmitter || require('events').EventEmitter; var copay = copay || require('../../../copay'); +var SecureRandom = bitcore.SecureRandom; +var Base58Check = bitcore.Base58.base58Check; function Wallet(opts) { var self = this; @@ -26,6 +28,8 @@ function Wallet(opts) { this.id = opts.id || Wallet.getRandomId(); this.name = opts.name; + this.netKey = opts.netKey || SecureRandom.getRandomBuffer(8).toString('base64'); + this.verbose = opts.verbose; this.publicKeyRing.walletId = this.id; this.txProposals.walletId = this.id; @@ -124,6 +128,7 @@ Wallet.prototype._optsToObj = function() { requiredCopayers: this.requiredCopayers, totalCopayers: this.totalCopayers, name: this.name, + netKey: this.netKey, }; return obj; @@ -139,6 +144,26 @@ Wallet.prototype.getMyCopayerId = function() { 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() { this.network.lockIncommingConnections(this.publicKeyRing.getAllCopayerIds()); }; @@ -162,6 +187,7 @@ Wallet.prototype.netStart = function() { var startOpts = { copayerId: myId, maxPeers: self.totalCopayers, + netKey: this.netKey, }; if (this.publicKeyRing.isComplete()) { diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index a8dd80f84..cb6974120 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -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 s; + try { + s=Wallet.decodeSecret(secret); + } catch (e) { + return cb('badSecret'); + } + //Create our PrivateK var privateKey = new PrivateKey({ networkName: this.networkName }); this.log('\t### PrivateKey Initialized'); var opts = { copayerId: privateKey.getId(), + netKey: s.netKey, }; self.network.cleanUp(); self.network.start(opts, function() { - self.network.connectTo(copayerId); + self.network.connectTo(s.pubKey); self.network.on('onlyYou', function(sender, data) { - return cb(); + return cb('joinError'); }); self.network.on('data', function(sender, data) { if (data.type ==='walletId') { data.opts.privateKey = privateKey; var w = self.open(data.walletId, data.opts); - w.firstCopayerId = copayerId; - return cb(w); + w.firstCopayerId = s.pubKey; + return cb(null, w); } }); }); diff --git a/js/models/network/WebRTC.js b/js/models/network/WebRTC.js index f45eaa1f4..d45b5aae6 100644 --- a/js/models/network/WebRTC.js +++ b/js/models/network/WebRTC.js @@ -3,7 +3,6 @@ var imports = require('soop').imports(); var EventEmitter= imports.EventEmitter || require('events').EventEmitter; var bitcore = require('bitcore'); var util = bitcore.util; -var Key = bitcore.Key; /* * Emits * 'networkChange' @@ -18,12 +17,11 @@ var Key = bitcore.Key; */ function Network(opts) { - var self = this; + var self = this; opts = opts || {}; this.apiKey = opts.apiKey || 'lwjd5qra8257b9'; this.debug = opts.debug || 3; this.maxPeers = opts.maxPeers || 10; - this.opts = { key: opts.key }; this.sjclParams = opts.sjclParams || { salt: 'f28bfb49ef70573c', iter:500, @@ -31,8 +29,10 @@ function Network(opts) { ts:parseInt(64), }; + // 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]; }); this.cleanUp(); @@ -44,6 +44,7 @@ Network.prototype.cleanUp = function() { this.started = false; this.connectedPeers = []; this.peerId = null; + this.netKey = null; this.copayerId = null; this.signingKey = null; this.allowedCopayerIds=null; @@ -338,6 +339,7 @@ Network.prototype.start = function(opts, openCallback) { if (this.started) return openCallback(); + this.netKey = opts.netKey; this.maxPeers = opts.maxPeers || this.maxPeers; if (!this.copayerId) @@ -363,22 +365,10 @@ Network.prototype.getPeer = function() { return this.peer; }; - -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); +Network.prototype._encrypt = function(payloadStr) { var plainText = sjcl.codec.utf8String.toBits(payloadStr); - var p = this.sjclParams; // auth strength - ct = sjcl.encrypt(key, plainText, p);//,p, rp); + var p = this.sjclParams; + ct = sjcl.encrypt(this.netKey, plainText, p);//,p, rp); var c = JSON.parse(ct); var toSend = { iv: c.iv, @@ -394,8 +384,7 @@ Network.prototype._decrypt = function(encStr) { i[k] = this.sjclParams[k]; } var str= JSON.stringify(i); - var key= this._keyForCopayerId(this.copayerId); - var pt = sjcl.decrypt(key, str); + var pt = sjcl.decrypt(this.netKey, str); return pt; }; @@ -404,7 +393,7 @@ Network.prototype._sendToOne = function(copayerId, payloadStr, sig, cb) { if (peerId !== this.peerId) { var dataConn = this.connections[peerId]; if (dataConn) { - dataConn.send(this._encryptFor(copayerId, payloadStr)); + dataConn.send(this._encrypt(payloadStr)); } else { console.log('[WebRTC.js.255] WARN: NO CONNECTION TO:', peerId); //TODO diff --git a/js/services/controllerUtils.js b/js/services/controllerUtils.js index bfdc3909e..2690e2cbc 100644 --- a/js/services/controllerUtils.js +++ b/js/services/controllerUtils.js @@ -29,11 +29,6 @@ angular.module('copay.controllerUtils') root.onError = function(scope) { if (scope) scope.loading = false; - $rootScope.flashMessage = { - type: 'error', - message: 'Could not connect to peer: ' + - scope - }; root.logout(); } diff --git a/js/services/video.js b/js/services/video.js index 367296934..3902a04bc 100644 --- a/js/services/video.js +++ b/js/services/video.js @@ -7,7 +7,7 @@ var Video = function() { this.mediaConnections = {}; this.localStream = null; - this.onlineSound = new Audio('../../sound/online.wav'); + this.onlineSound = new Audio('sound/online.wav'); }; Video.prototype.setOwnPeer = function(peer, wallet, cb) { @@ -72,11 +72,13 @@ Video.prototype._addCall = function(mediaConnection, cb) { } Video.prototype.close = function() { - this.localStream.stop(); - this.localStream.mozSrcObject = null; - this.localStream.src = ""; - this.localStream.src = null; - this.localStream = null; + if (this.localStream){ + this.localStream.stop(); + this.localStream.mozSrcObject = null; + this.localStream.src = ""; + this.localStream.src = null; + this.localStream = null; + } for (var i = 0; this.mediaConnections.length; i++) { this.mediaConnections[i].close(); } diff --git a/test/test.Wallet.js b/test/test.Wallet.js index bc34c0690..2d6fbfef1 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -31,9 +31,10 @@ describe('Wallet model', function() { (function(){new Wallet(config)}).should.throw(); }); - var createW = function () { + var createW = function (netKey) { var c = JSON.parse(JSON.stringify(config)); - + + if (netKey) c.netKey = netKey; c.privateKey = new copay.PrivateKey({ networkName: c.networkName }); c.publicKeyRing = new copay.PublicKeyRing({ @@ -66,6 +67,9 @@ describe('Wallet model', function() { should.exist(w.publicKeyRing); should.exist(w.privateKey); 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 () { @@ -88,7 +92,8 @@ describe('Wallet model', function() { ]; var createW2 = function (privateKeys) { - var w = createW(); + var netKey = 'T0FbU2JLby0='; + var w = createW(netKey); should.exist(w); var pkr = w.publicKeyRing; @@ -188,4 +193,21 @@ describe('Wallet model', function() { 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(); + }); });