mirror of https://github.com/BTCPrivate/copay.git
peer authentication
This commit is contained in:
parent
08fa60d41c
commit
6ace16e20d
12
index.html
12
index.html
|
@ -129,7 +129,7 @@
|
||||||
<div class="large-6 columns">
|
<div class="large-6 columns">
|
||||||
<h3>Join a Wallet in Creation</h3>
|
<h3>Join a Wallet in Creation</h3>
|
||||||
<input type="text" class="form-control" placeholder="Paste wallet secret here"
|
<input type="text" class="form-control" placeholder="Paste wallet secret here"
|
||||||
ng-model="connectionId" required ng-minlength="32" ng-maxlength="32" autofocus>
|
ng-model="connectionId" required autofocus>
|
||||||
</div>
|
</div>
|
||||||
<div class="large-3 columns">
|
<div class="large-3 columns">
|
||||||
<button class="button primary expand round"
|
<button class="button primary expand round"
|
||||||
|
@ -202,8 +202,8 @@
|
||||||
|
|
||||||
<ul class="no-bullet">
|
<ul class="no-bullet">
|
||||||
<li class="panel" ng-repeat="copayer in $root.wallet.network.connectedCopayers()">
|
<li class="panel" ng-repeat="copayer in $root.wallet.network.connectedCopayers()">
|
||||||
<span ng-if="copayer === $root.wallet.getMyCopayerId()"> You ({{copayer}})</span>
|
<span ng-if="copayer === $root.wallet.getMyCopayerId()"> You </span>
|
||||||
<span ng-if="copayer !== $root.wallet.getMyCopayerId()">{{copayer}}</span>
|
{{copayer}}
|
||||||
<span>
|
<span>
|
||||||
<i class="fi-check size-16 panel-sign right p5h br100"></i>
|
<i class="fi-check size-16 panel-sign right p5h br100"></i>
|
||||||
</span>
|
</span>
|
||||||
|
@ -279,9 +279,8 @@
|
||||||
<tr ng-repeat="(peer, actions) in tx.peerActions">
|
<tr ng-repeat="(peer, actions) in tx.peerActions">
|
||||||
<td colspan="3">
|
<td colspan="3">
|
||||||
<div class="panel status">
|
<div class="panel status">
|
||||||
<span ng-if="peer == $root.wallet.network.peerId"> You
|
<span ng-if="peer === $root.wallet.getMyCopayerId()"> You</span>
|
||||||
</span>
|
{{peer}}
|
||||||
<span ng-if="peer != $root.wallet.network.peerId"> {{peer}}</span>
|
|
||||||
|
|
||||||
<span ng-repeat="(action, ts) in actions">
|
<span ng-repeat="(action, ts) in actions">
|
||||||
<span ng-if="action == 'create'" title="{{ts | date:'medium'}}" class="fi-page-add size-18 right m10h"></span>
|
<span ng-if="action == 'create'" title="{{ts | date:'medium'}}" class="fi-page-add size-18 right m10h"></span>
|
||||||
|
@ -492,6 +491,7 @@
|
||||||
<script src="lib/peerjs/peer.js"></script>
|
<script src="lib/peerjs/peer.js"></script>
|
||||||
<script src="lib/bitcore.js"></script>
|
<script src="lib/bitcore.js"></script>
|
||||||
<script src="lib/crypto-js/rollups/aes.js"></script>
|
<script src="lib/crypto-js/rollups/aes.js"></script>
|
||||||
|
<script src="lib/crypto-js/rollups/hmac-sha256.js"></script>
|
||||||
<script src="lib/file-saver/FileSaver.js"></script>
|
<script src="lib/file-saver/FileSaver.js"></script>
|
||||||
<script src="lib/socket.io.js"></script>
|
<script src="lib/socket.io.js"></script>
|
||||||
<script src="js/copayBundle.js"></script>
|
<script src="js/copayBundle.js"></script>
|
||||||
|
|
|
@ -60,7 +60,7 @@ angular.module('copay.transactions').controller('TransactionsController',
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var p = w.txProposals.getTxProposal(ntxid);
|
var p = w.txProposals.getTxProposal(ntxid);
|
||||||
if (p.txp.builder.isFullySigned()) {
|
if (p.builder.isFullySigned()) {
|
||||||
$scope.send(ntxid);
|
$scope.send(ntxid);
|
||||||
_updateTxs();
|
_updateTxs();
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
|
|
|
@ -18,13 +18,22 @@ function PrivateKey(opts) {
|
||||||
this.privateKeyCache = opts.privateKeyCache || {};
|
this.privateKeyCache = opts.privateKeyCache || {};
|
||||||
};
|
};
|
||||||
|
|
||||||
PrivateKey.prototype.getId = function(prefix) {
|
PrivateKey.prototype.getId = function() {
|
||||||
var buf = this.bip.extendedPublicKey;
|
if (!this.id) {
|
||||||
if (prefix) {
|
var path = PublicKeyRing.SIGNING_BRANCH;
|
||||||
buf = Buffer.concat([prefix, buf]);
|
var bip32 = this.bip.derive(path);
|
||||||
|
this.id= bip32.eckey.public.toString('hex');
|
||||||
}
|
}
|
||||||
var hash = util.sha256(buf).toString('hex');
|
return this.id;
|
||||||
return hash.substring(0, hash.length/2);
|
};
|
||||||
|
|
||||||
|
PrivateKey.prototype.getSigningKey = function() {
|
||||||
|
if (!this.sid) {
|
||||||
|
var path = PublicKeyRing.SIGNING_BRANCH;
|
||||||
|
var bip32 = this.bip.derive(path);
|
||||||
|
this.sid= bip32.eckey.private.toString('hex');
|
||||||
|
}
|
||||||
|
return this.sid;
|
||||||
};
|
};
|
||||||
|
|
||||||
PrivateKey.fromObj = function(obj) {
|
PrivateKey.fromObj = function(obj) {
|
||||||
|
|
|
@ -44,9 +44,12 @@ function PublicKeyRing(opts) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PublicKeyRing.Branch = function (index, isChange) {
|
PublicKeyRing.Branch = function (index, isChange) {
|
||||||
return 'm/'+(isChange?1:0)+'/'+index;
|
// first 0 is for future use: could be copayerId.
|
||||||
|
return 'm/0/'+(isChange?1:0)+'/'+index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PublicKeyRing.SIGNING_BRANCH = 'm/100/0/0';
|
||||||
|
|
||||||
PublicKeyRing.fromObj = function (data) {
|
PublicKeyRing.fromObj = function (data) {
|
||||||
if (data instanceof PublicKeyRing) {
|
if (data instanceof PublicKeyRing) {
|
||||||
throw new Error('bad data format: Did you use .toObj()?');
|
throw new Error('bad data format: Did you use .toObj()?');
|
||||||
|
@ -77,17 +80,20 @@ PublicKeyRing.prototype.serialize = function () {
|
||||||
return JSON.stringify(this.toObj());
|
return JSON.stringify(this.toObj());
|
||||||
};
|
};
|
||||||
|
|
||||||
PublicKeyRing.prototype.getCopayerId = function(i, prefix) {
|
PublicKeyRing.prototype.getCopayerId = function(i) {
|
||||||
var buf = this.copayersBIP32[i].extendedPublicKey;
|
this.copayerIds = this.copayerIds || [];
|
||||||
if (prefix) {
|
|
||||||
buf = Buffer.concat([prefix, buf]);
|
if (!this.copayerIds[i]) {
|
||||||
|
var path = PublicKeyRing.SIGNING_BRANCH;
|
||||||
|
var bip32 = this.copayersBIP32[i].derive(path);
|
||||||
|
this.copayerIds[i]= bip32.eckey.public.toString('hex');
|
||||||
}
|
}
|
||||||
var hash = util.sha256(buf).toString('hex');
|
|
||||||
return hash.substring(0, hash.length/2);
|
return this.copayerIds[i];
|
||||||
};
|
};
|
||||||
|
|
||||||
PublicKeyRing.prototype.myCopayerId = function(i, prefix) {
|
PublicKeyRing.prototype.myCopayerId = function(i) {
|
||||||
return this.getCopayerId(0,prefix);
|
return this.getCopayerId(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
PublicKeyRing.prototype.registeredCopayers = function () {
|
PublicKeyRing.prototype.registeredCopayers = function () {
|
||||||
|
|
|
@ -169,9 +169,10 @@ Wallet.prototype.netStart = function() {
|
||||||
|
|
||||||
var myId = self.getMyCopayerId();
|
var myId = self.getMyCopayerId();
|
||||||
var startOpts = {
|
var startOpts = {
|
||||||
copayerId: myId
|
copayerId: myId,
|
||||||
|
signingKeyHex: self.privateKey.getSigningKey(),
|
||||||
};
|
};
|
||||||
net.start(function() {
|
net.start(startOpts, function() {
|
||||||
self.emit('created');
|
self.emit('created');
|
||||||
for (var i=0; i<self.publicKeyRing.registeredCopayers(); i++) {
|
for (var i=0; i<self.publicKeyRing.registeredCopayers(); i++) {
|
||||||
var otherId = self.getCopayerId(i);
|
var otherId = self.getCopayerId(i);
|
||||||
|
@ -184,7 +185,7 @@ Wallet.prototype.netStart = function() {
|
||||||
}
|
}
|
||||||
self.emit('refresh');
|
self.emit('refresh');
|
||||||
}
|
}
|
||||||
}, startOpts);
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.store = function(isSync) {
|
Wallet.prototype.store = function(isSync) {
|
||||||
|
|
|
@ -146,8 +146,8 @@ WalletFactory.prototype.joinCreateSession = function(copayerId, cb) {
|
||||||
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());
|
self.network.setCopayerId(privateKey.getId());
|
||||||
|
self.network.setSigningKey(privateKey.getSigningKey());
|
||||||
self.network.start(function() {
|
self.network.start({}, function() {
|
||||||
self.network.connectTo(copayerId);
|
self.network.connectTo(copayerId);
|
||||||
self.network.on('data', function(sender, data) {
|
self.network.on('data', function(sender, data) {
|
||||||
if (data.type ==='walletId') {
|
if (data.type ==='walletId') {
|
||||||
|
|
|
@ -3,6 +3,7 @@ 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
|
||||||
|
@ -102,10 +103,10 @@ console.log('[WebRTC.js.99:arrayDiff:]',arrayDiff); //TODO
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Network.prototype._sendCopayerId = function(copayerId) {
|
Network.prototype._sendHello = function(copayerId) {
|
||||||
console.log('#### SENDING COPAYERID TO TO ', copayerId);
|
console.log('#### SENDING HELLO TO ', copayerId);
|
||||||
this.send(copayerId, {
|
this.send(copayerId, {
|
||||||
type: 'copayerId',
|
type: 'hello',
|
||||||
copayerId: this.copayerId,
|
copayerId: this.copayerId,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -133,26 +134,32 @@ Network.prototype._addCopayer = function(copayerId, isInbound) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Network.prototype._onData = function(data, isInbound, peerId) {
|
Network.prototype._onData = function(data, isInbound, peerId) {
|
||||||
var obj;
|
var sig, payload;
|
||||||
try {
|
try {
|
||||||
obj = JSON.parse(data);
|
var dataObj = JSON.parse(data);
|
||||||
|
sig = dataObj.sig;
|
||||||
|
payload= dataObj.payload;
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('### ERROR ON DATA: "%s" ', data, isInbound, e);
|
console.log('### ERROR ON DATA: "%s" ', data, isInbound, e);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
console.log('### RECEIVED TYPE: %s FROM %s', obj.data.type, obj.sender, obj.data);
|
|
||||||
|
console.log('### RECEIVED INBOUND?:%s TYPE: %s FROM %s: sig:%s',
|
||||||
|
isInbound, payload.type, peerId, sig, payload);
|
||||||
var self=this;
|
var self=this;
|
||||||
|
|
||||||
if(obj.data.type === 'copayerId') {
|
// TODO _func
|
||||||
if (this.peerFromCopayer(obj.data.copayerId) === peerId) {
|
if(payload.type === 'hello') {
|
||||||
console.log('#### Peer sent the right copayerId. Setting it up.'); //TODO
|
var thisSig = this._sign(payload, this.copayerId);
|
||||||
this._addCopayer(obj.data.copayerId, isInbound);
|
if (thisSig !== sig) {
|
||||||
this._notifyNetworkChange( isInbound ? obj.data.copayerId : null);
|
console.log('#### Peer sent WRONG hello. Closing connection.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('#### Peer sent signed hello. Setting it up.'); //TODO
|
||||||
|
this._addCopayer(payload.copayerId, isInbound);
|
||||||
|
this._notifyNetworkChange( isInbound ? payload.copayerId : null);
|
||||||
this.emit('open');
|
this.emit('open');
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log('### RECEIVED WRONG COPAYER ID FROM:', peerId); //TODO
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,17 +168,29 @@ Network.prototype._onData = function(data, isInbound, peerId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(obj.data.type) {
|
// check sig
|
||||||
|
if (this.copayerForPeer[peerId]) {
|
||||||
|
var copayerIdBuf = new Buffer(this.copayerForPeer[peerId],'hex');
|
||||||
|
if (!bitcore.Message.verifyWithPubKey( copayerIdBuf, JSON.stringify(payload),
|
||||||
|
new Buffer(sig,'hex'))) {
|
||||||
|
|
||||||
|
console.log('[WebRTC.js.152] SIGNATURE VERIFICATION FAILED!!'); //TODO
|
||||||
|
// TODO close connection
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(payload.type) {
|
||||||
case 'copayers':
|
case 'copayers':
|
||||||
this._addCopayer(this.copayerForPeer[peerId], false);
|
this._addCopayer(this.copayerForPeer[peerId], false);
|
||||||
this._connectToCopayers(obj.data.copayers);
|
this._connectToCopayers(payload.copayers);
|
||||||
this._notifyNetworkChange();
|
this._notifyNetworkChange();
|
||||||
break;
|
break;
|
||||||
case 'disconnect':
|
case 'disconnect':
|
||||||
this._onClose(obj.sender);
|
this._onClose(peerId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.emit('data', self.copayerForPeer[obj.sender], obj.data, isInbound);
|
this.emit('data', self.copayerForPeer[peerId], payload, isInbound);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -193,12 +212,12 @@ Network.prototype._setupConnectionHandlers = function(dataConn, isInbound) {
|
||||||
|
|
||||||
self.connections[dataConn.peer] = dataConn;
|
self.connections[dataConn.peer] = dataConn;
|
||||||
|
|
||||||
console.log('### DATA CONNECTION READY: ADDING PEER: %s (inbound: %s)',
|
console.log('### DATA CONNECTION READY: %s (inbound: %s) AUTHENTICATING...',
|
||||||
dataConn.peer, isInbound);
|
dataConn.peer, isInbound);
|
||||||
|
|
||||||
// The outbount send its copayerID
|
// The connection peer send hello (with signature)
|
||||||
if(!isInbound)
|
if(!isInbound)
|
||||||
self._sendCopayerId(self.copayerForPeer[dataConn.peer]);
|
self._sendHello(self.copayerForPeer[dataConn.peer]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -272,24 +291,39 @@ Network.prototype.setCopayerId = function(copayerId) {
|
||||||
if (this.started) {
|
if (this.started) {
|
||||||
throw new Error ('network already started: can not change peerId')
|
throw new Error ('network already started: can not change peerId')
|
||||||
}
|
}
|
||||||
|
console.log('[WebRTC.js.295] SETING COPAYER ID:' + copayerId); //TODO
|
||||||
this.copayerId = copayerId;
|
this.copayerId = copayerId;
|
||||||
|
this.copayerIdBuf = new Buffer(copayerId,'hex');
|
||||||
this.peerId = this.peerFromCopayer(this.copayerId);
|
this.peerId = this.peerFromCopayer(this.copayerId);
|
||||||
this._addCopayerMap(this.peerId,copayerId);
|
this._addCopayerMap(this.peerId,copayerId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Network.prototype.setSigningKey = function(keyHex) {
|
||||||
|
if (this.started || this.signingKey) {
|
||||||
|
throw new Error ('network already started or key assigned: can not change key')
|
||||||
|
}
|
||||||
|
var k = new Key();
|
||||||
|
k.private = new Buffer(keyHex,'hex');
|
||||||
|
k.regenerateSync();
|
||||||
|
this.signingKey = k;
|
||||||
|
};
|
||||||
|
|
||||||
Network.prototype.peerFromCopayer = function(hex) {
|
Network.prototype.peerFromCopayer = function(hex) {
|
||||||
return util.sha256(new Buffer(hex,'hex')).toString('hex');
|
return util.sha256(new Buffer(hex,'hex')).toString('hex');
|
||||||
};
|
};
|
||||||
|
|
||||||
Network.prototype.start = function(openCallback, opts) {
|
Network.prototype.start = function(opts, openCallback) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
var self = this;
|
var self = this;
|
||||||
if (this.started) return openCallback();
|
if (this.started) return openCallback();
|
||||||
|
|
||||||
opts.connectedPeers = opts.connectedPeers || [];
|
opts.connectedPeers = opts.connectedPeers || [];
|
||||||
|
|
||||||
|
if (!this.copayerId)
|
||||||
|
this.setCopayerId(opts.copayerId);
|
||||||
|
if (!this.signingKey)
|
||||||
|
this.setSigningKey(opts.signingKeyHex);
|
||||||
|
|
||||||
this.setCopayerId(this.copayerId || opts.copayerId);
|
|
||||||
this.peer = new Peer(this.peerId, this.opts);
|
this.peer = new Peer(this.peerId, this.opts);
|
||||||
this._setupPeerHandlers(openCallback);
|
this._setupPeerHandlers(openCallback);
|
||||||
for (var i = 0; i<opts.connectedPeers.length; i++) {
|
for (var i = 0; i<opts.connectedPeers.length; i++) {
|
||||||
|
@ -300,15 +334,39 @@ Network.prototype.start = function(openCallback, opts) {
|
||||||
console.log('[WebRTC.js.237] started TRUE'); //TODO
|
console.log('[WebRTC.js.237] started TRUE'); //TODO
|
||||||
};
|
};
|
||||||
|
|
||||||
Network.prototype._sendToOne = function(copayerId, data, cb) {
|
|
||||||
|
|
||||||
|
Network.prototype._sign = function(payload, copayerId) {
|
||||||
|
var ret='';
|
||||||
|
var str = JSON.stringify(payload);
|
||||||
|
if (payload.type ==='hello') {
|
||||||
|
console.log('[WebRTC.js.331] SIGNING WITH HMAC:', copayerId); //TODO
|
||||||
|
ret = CryptoJS.enc.Base64.stringify(
|
||||||
|
CryptoJS.HmacSHA256(
|
||||||
|
str,
|
||||||
|
copayerId
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!this.signingKey)
|
||||||
|
throw new Error ('no key to sign messages :(');
|
||||||
|
|
||||||
|
console.log('[WebRTC.js.341] SIGNING WITH ECDSA'); //TODO
|
||||||
|
ret = bitcore.Message.sign(
|
||||||
|
str,
|
||||||
|
this.signingKey
|
||||||
|
).toString('hex');
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
Network.prototype._sendToOne = function(copayerId, payload, 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({
|
||||||
sender: this.peerId,
|
sig: this._sign(payload, copayerId),
|
||||||
data: data
|
payload: payload
|
||||||
});
|
});
|
||||||
dataConn.send(str);
|
dataConn.send(str);
|
||||||
}
|
}
|
||||||
|
@ -319,24 +377,24 @@ console.log('[WebRTC.js.255] WARN: NO CONNECTION TO:', peerId); //TODO
|
||||||
if (typeof cb === 'function') cb();
|
if (typeof cb === 'function') cb();
|
||||||
};
|
};
|
||||||
|
|
||||||
Network.prototype.send = function(copayerIds, data, cb) {
|
Network.prototype.send = function(copayerIds, payload, cb) {
|
||||||
var self=this;
|
var self=this;
|
||||||
if (!copayerIds) {
|
if (!copayerIds) {
|
||||||
copayerIds = this.connectedCopayers();
|
copayerIds = this.connectedCopayers();
|
||||||
data.isBroadcast = 1;
|
payload.isBroadcast = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
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, data, function () {
|
self._sendToOne(copayerId, payload, 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, data, cb);
|
self._sendToOne(copayerIds, payload, cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
Network.prototype.connectTo = function(copayerId) {
|
Network.prototype.connectTo = function(copayerId) {
|
||||||
|
|
|
@ -70,7 +70,7 @@ describe('PrivateKey model', function() {
|
||||||
it('should calculate .id', function () {
|
it('should calculate .id', function () {
|
||||||
var w1 = new PrivateKey(config);
|
var w1 = new PrivateKey(config);
|
||||||
should.exist(w1.getId());
|
should.exist(w1.getId());
|
||||||
w1.getId().length.should.equal(32);
|
w1.getId().length.should.equal(66);
|
||||||
});
|
});
|
||||||
it('fromObj toObj roundtrip', function () {
|
it('fromObj toObj roundtrip', function () {
|
||||||
var w1 = new PrivateKey(config);
|
var w1 = new PrivateKey(config);
|
||||||
|
|
|
@ -228,7 +228,7 @@ describe('PublicKeyRing model', function() {
|
||||||
networkName: 'livenet',
|
networkName: 'livenet',
|
||||||
});
|
});
|
||||||
wx.addCopayer();
|
wx.addCopayer();
|
||||||
(function() { w.merge(wx, true);}).should.throw();
|
(function() { w.merge(wx);}).should.throw();
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue