add nonce support to WebRTC and Wallet
Each person keeps track of their own nonce, and the nonces of the other copayers. The nonce is iterated for each message. If a person ever doesn't iterate their nonce, that message is discarded by the copayers. The nonces are saved as networkNonce (your nonce) and networkNonces (the nonces of your copayers) in the wallet file. In order to support restoring old wallets, the first four bytes of the 8 byte nonce are actually the current time in seconds. Thus you can restore an old wallet, because certainly at least one second has passed since your last message. Only if you try to restore an old wallet within 1 second from the time of your last message will you have a problem (or if your system clock is grossly inaccurate).
This commit is contained in:
parent
a1155c2798
commit
88ab38eb00
6 changed files with 370 additions and 23 deletions
|
|
@ -50,6 +50,11 @@ function Wallet(opts) {
|
||||||
this.registeredPeerIds = [];
|
this.registeredPeerIds = [];
|
||||||
this.addressBook = opts.addressBook || {};
|
this.addressBook = opts.addressBook || {};
|
||||||
this.publicKey = this.privateKey.publicHex;
|
this.publicKey = this.privateKey.publicHex;
|
||||||
|
|
||||||
|
//network nonces are 8 byte buffers, representing a big endian number
|
||||||
|
//one nonce for oneself, and then one nonce for each copayer
|
||||||
|
this.network.setHexNonce(opts.networkNonce);
|
||||||
|
this.network.setHexNonces(opts.networkNonces);
|
||||||
}
|
}
|
||||||
|
|
||||||
Wallet.parent = EventEmitter;
|
Wallet.parent = EventEmitter;
|
||||||
|
|
@ -343,8 +348,14 @@ Wallet.prototype.store = function() {
|
||||||
|
|
||||||
Wallet.prototype.toObj = function() {
|
Wallet.prototype.toObj = function() {
|
||||||
var optsObj = this._optsToObj();
|
var optsObj = this._optsToObj();
|
||||||
|
|
||||||
|
var networkNonce = this.network.getHexNonce();
|
||||||
|
var networkNonces = this.network.getHexNonces();
|
||||||
|
|
||||||
var walletObj = {
|
var walletObj = {
|
||||||
opts: optsObj,
|
opts: optsObj,
|
||||||
|
networkNonce: networkNonce, //yours
|
||||||
|
networkNonces: networkNonces, //copayers
|
||||||
publicKeyRing: this.publicKeyRing.toObj(),
|
publicKeyRing: this.publicKeyRing.toObj(),
|
||||||
txProposals: this.txProposals.toObj(),
|
txProposals: this.txProposals.toObj(),
|
||||||
privateKey: this.privateKey ? this.privateKey.toObj() : undefined,
|
privateKey: this.privateKey ? this.privateKey.toObj() : undefined,
|
||||||
|
|
@ -374,6 +385,10 @@ Wallet.prototype.toEncryptedObj = function() {
|
||||||
return this.storage.export(walletObj);
|
return this.storage.export(walletObj);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Wallet.prototype.send = function(recipients, obj) {
|
||||||
|
this.network.send(recipients, obj);
|
||||||
|
};
|
||||||
|
|
||||||
Wallet.prototype.sendAllTxProposals = function(recipients) {
|
Wallet.prototype.sendAllTxProposals = function(recipients) {
|
||||||
var ntxids = this.txProposals.getNtxids();
|
var ntxids = this.txProposals.getNtxids();
|
||||||
for (var i in ntxids) {
|
for (var i in ntxids) {
|
||||||
|
|
@ -386,7 +401,7 @@ Wallet.prototype.sendTxProposal = function(ntxid, recipients) {
|
||||||
preconditions.checkArgument(ntxid);
|
preconditions.checkArgument(ntxid);
|
||||||
preconditions.checkState(this.txProposals.txps[ntxid]);
|
preconditions.checkState(this.txProposals.txps[ntxid]);
|
||||||
this.log('### SENDING txProposal ' + ntxid + ' TO:', recipients || 'All', this.txProposals);
|
this.log('### SENDING txProposal ' + ntxid + ' TO:', recipients || 'All', this.txProposals);
|
||||||
this.network.send(recipients, {
|
this.send(recipients, {
|
||||||
type: 'txProposal',
|
type: 'txProposal',
|
||||||
txProposal: this.txProposals.txps[ntxid].toObj(),
|
txProposal: this.txProposals.txps[ntxid].toObj(),
|
||||||
walletId: this.id,
|
walletId: this.id,
|
||||||
|
|
@ -396,7 +411,7 @@ Wallet.prototype.sendTxProposal = function(ntxid, recipients) {
|
||||||
Wallet.prototype.sendWalletReady = function(recipients) {
|
Wallet.prototype.sendWalletReady = function(recipients) {
|
||||||
this.log('### SENDING WalletReady TO:', recipients);
|
this.log('### SENDING WalletReady TO:', recipients);
|
||||||
|
|
||||||
this.network.send(recipients, {
|
this.send(recipients, {
|
||||||
type: 'walletReady',
|
type: 'walletReady',
|
||||||
walletId: this.id,
|
walletId: this.id,
|
||||||
});
|
});
|
||||||
|
|
@ -405,7 +420,7 @@ Wallet.prototype.sendWalletReady = function(recipients) {
|
||||||
Wallet.prototype.sendWalletId = function(recipients) {
|
Wallet.prototype.sendWalletId = function(recipients) {
|
||||||
this.log('### SENDING walletId TO:', recipients || 'All', this.id);
|
this.log('### SENDING walletId TO:', recipients || 'All', this.id);
|
||||||
|
|
||||||
this.network.send(recipients, {
|
this.send(recipients, {
|
||||||
type: 'walletId',
|
type: 'walletId',
|
||||||
walletId: this.id,
|
walletId: this.id,
|
||||||
opts: this._optsToObj(),
|
opts: this._optsToObj(),
|
||||||
|
|
@ -419,7 +434,7 @@ Wallet.prototype.sendPublicKeyRing = function(recipients) {
|
||||||
var publicKeyRing = this.publicKeyRing.toObj();
|
var publicKeyRing = this.publicKeyRing.toObj();
|
||||||
delete publicKeyRing.publicKeysCache; // exclude publicKeysCache from network obj
|
delete publicKeyRing.publicKeysCache; // exclude publicKeysCache from network obj
|
||||||
|
|
||||||
this.network.send(recipients, {
|
this.send(recipients, {
|
||||||
type: 'publicKeyRing',
|
type: 'publicKeyRing',
|
||||||
publicKeyRing: publicKeyRing,
|
publicKeyRing: publicKeyRing,
|
||||||
walletId: this.id,
|
walletId: this.id,
|
||||||
|
|
@ -429,7 +444,7 @@ Wallet.prototype.sendIndexes = function(recipients) {
|
||||||
var indexes = AddressIndex.serialize(this.publicKeyRing.indexes);
|
var indexes = AddressIndex.serialize(this.publicKeyRing.indexes);
|
||||||
this.log('### INDEXES TO:', recipients || 'All', indexes);
|
this.log('### INDEXES TO:', recipients || 'All', indexes);
|
||||||
|
|
||||||
this.network.send(recipients, {
|
this.send(recipients, {
|
||||||
type: 'indexes',
|
type: 'indexes',
|
||||||
indexes: indexes,
|
indexes: indexes,
|
||||||
walletId: this.id,
|
walletId: this.id,
|
||||||
|
|
@ -438,7 +453,7 @@ Wallet.prototype.sendIndexes = function(recipients) {
|
||||||
|
|
||||||
Wallet.prototype.sendAddressBook = function(recipients) {
|
Wallet.prototype.sendAddressBook = function(recipients) {
|
||||||
this.log('### SENDING addressBook TO:', recipients || 'All', this.addressBook);
|
this.log('### SENDING addressBook TO:', recipients || 'All', this.addressBook);
|
||||||
this.network.send(recipients, {
|
this.send(recipients, {
|
||||||
type: 'addressbook',
|
type: 'addressbook',
|
||||||
addressBook: this.addressBook,
|
addressBook: this.addressBook,
|
||||||
walletId: this.id,
|
walletId: this.id,
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,57 @@ Network.prototype.getKey = function() {
|
||||||
return this.key;
|
return this.key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//hex version of one's own nonce
|
||||||
|
Network.prototype.setHexNonce = function(networkNonce) {
|
||||||
|
if (networkNonce) {
|
||||||
|
if (networkNonce.length !== 16)
|
||||||
|
throw new Error('incorrect length of hex nonce');
|
||||||
|
this.networkNonce = new Buffer(networkNonce, 'hex');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this.iterateNonce();
|
||||||
|
};
|
||||||
|
|
||||||
|
//hex version of copayers' nonces
|
||||||
|
Network.prototype.setHexNonces = function(networkNonces) {
|
||||||
|
for (var i in networkNonces) {
|
||||||
|
if (!this.networkNonces)
|
||||||
|
this.networkNonces = {};
|
||||||
|
if (networkNonces[i].length === 16)
|
||||||
|
this.networkNonces[i] = new Buffer(networkNonces[i], 'hex');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//for oneself
|
||||||
|
Network.prototype.getHexNonce = function() {
|
||||||
|
return this.networkNonce.toString('hex');
|
||||||
|
};
|
||||||
|
|
||||||
|
//for copayers
|
||||||
|
Network.prototype.getHexNonces = function() {
|
||||||
|
var networkNoncesHex = [];
|
||||||
|
for (var i in this.networkNonces) {
|
||||||
|
networkNoncesHex[i] = this.networkNonces[i].toString('hex');
|
||||||
|
}
|
||||||
|
return networkNoncesHex;
|
||||||
|
};
|
||||||
|
|
||||||
|
Network.prototype.iterateNonce = function() {
|
||||||
|
if (!this.networkNonce || this.networkNonce.length !== 8) {
|
||||||
|
this.networkNonce = new Buffer(8);
|
||||||
|
this.networkNonce.fill(0);
|
||||||
|
}
|
||||||
|
//the first 4 bytes of a nonce is a unix timestamp in seconds
|
||||||
|
//the second 4 bytes is just an iterated "sub" nonce
|
||||||
|
//the whole thing is interpreted as one big endian number
|
||||||
|
var noncep1 = this.networkNonce.slice(0, 4);
|
||||||
|
noncep1.writeUInt32BE(Math.floor(Date.now()/1000), 0);
|
||||||
|
var noncep2uint = this.networkNonce.slice(4, 8).readUInt32BE(0);
|
||||||
|
var noncep2 = this.networkNonce.slice(4, 8);
|
||||||
|
noncep2.writeUInt32BE(noncep2uint + 1, 0);
|
||||||
|
return this.networkNonce;
|
||||||
|
};
|
||||||
|
|
||||||
Network.prototype._onData = function(enc, isInbound, peerId) {
|
Network.prototype._onData = function(enc, isInbound, peerId) {
|
||||||
var encUint8Array = new Uint8Array(enc);
|
var encUint8Array = new Uint8Array(enc);
|
||||||
var encbuf = new Buffer(encUint8Array);
|
var encbuf = new Buffer(encUint8Array);
|
||||||
|
|
@ -173,7 +224,16 @@ Network.prototype._onData = function(enc, isInbound, peerId) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var encoded = JSON.parse(encstr);
|
var encoded = JSON.parse(encstr);
|
||||||
var databuf = this._decode(key, encoded);
|
var prevnonce = this.networkNonces ? this.networkNonces[peerId] : undefined;
|
||||||
|
var opts = {prevnonce: prevnonce};
|
||||||
|
var decoded = this._decode(key, encoded, opts);
|
||||||
|
|
||||||
|
//if no error thrown in the last step, we can set the copayer's nonce
|
||||||
|
if (!this.networkNonces)
|
||||||
|
this.networkNonces = {};
|
||||||
|
this.networkNonces[peerId] = decoded.nonce;
|
||||||
|
|
||||||
|
var databuf = decoded.payload;
|
||||||
var datastr = databuf.toString();
|
var datastr = databuf.toString();
|
||||||
var payload = JSON.parse(datastr);
|
var payload = JSON.parse(datastr);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
@ -384,13 +444,13 @@ Network.prototype._encode = function(topubkey, fromkey, payload, opts) {
|
||||||
|
|
||||||
Network.prototype._decode = function(key, encoded, opts) {
|
Network.prototype._decode = function(key, encoded, opts) {
|
||||||
var decoded = Message.decode(key, encoded, opts);
|
var decoded = Message.decode(key, encoded, opts);
|
||||||
var payload = decoded.payload;
|
return decoded;
|
||||||
return payload;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Network.prototype._sendToOne = function(copayerId, payload, opts, cb) {
|
Network.prototype._sendToOne = function(copayerId, payload, cb) {
|
||||||
if (!Buffer.isBuffer(payload))
|
if (!Buffer.isBuffer(payload))
|
||||||
throw new Error('payload must be a buffer');
|
throw new Error('payload must be a buffer');
|
||||||
|
|
||||||
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];
|
||||||
|
|
@ -401,7 +461,7 @@ Network.prototype._sendToOne = function(copayerId, payload, opts, cb) {
|
||||||
if (typeof cb === 'function') cb();
|
if (typeof cb === 'function') cb();
|
||||||
};
|
};
|
||||||
|
|
||||||
Network.prototype.send = function(copayerIds, payload, opts, cb) {
|
Network.prototype.send = function(copayerIds, payload, cb) {
|
||||||
if (!payload) return cb();
|
if (!payload) return cb();
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
@ -419,10 +479,12 @@ Network.prototype.send = function(copayerIds, payload, opts, cb) {
|
||||||
var l = copayerIds.length;
|
var l = copayerIds.length;
|
||||||
var i = 0;
|
var i = 0;
|
||||||
copayerIds.forEach(function(copayerId) {
|
copayerIds.forEach(function(copayerId) {
|
||||||
|
self.iterateNonce();
|
||||||
|
var opts = {nonce: self.networkNonce};
|
||||||
var copayerIdBuf = new Buffer(copayerId, 'hex');
|
var copayerIdBuf = new Buffer(copayerId, 'hex');
|
||||||
var encPayload = self._encode(copayerIdBuf, self.getKey(), payloadBuf);
|
var encPayload = self._encode(copayerIdBuf, self.getKey(), payloadBuf, opts);
|
||||||
var enc = new Buffer(JSON.stringify(encPayload));
|
var enc = new Buffer(JSON.stringify(encPayload));
|
||||||
self._sendToOne(copayerId, enc, opts, function() {
|
self._sendToOne(copayerId, enc, function() {
|
||||||
if (++i === l && typeof cb === 'function') cb();
|
if (++i === l && typeof cb === 'function') cb();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -41,4 +41,55 @@ Network.prototype.peerFromCopayer = function(copayerId) {
|
||||||
return copayerId;
|
return copayerId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//hex version of one's own nonce
|
||||||
|
Network.prototype.setHexNonce = function(networkNonce) {
|
||||||
|
if (networkNonce && networkNonce.length === 16)
|
||||||
|
this.networkNonce = new Buffer(networkNonce, 'hex');
|
||||||
|
else
|
||||||
|
this.iterateNonce();
|
||||||
|
};
|
||||||
|
|
||||||
|
//hex version of copayers' nonces
|
||||||
|
Network.prototype.setHexNonces = function(networkNonces) {
|
||||||
|
for (var i in networkNonces) {
|
||||||
|
if (!this.networkNonces)
|
||||||
|
this.networkNonces = {};
|
||||||
|
if (networkNonces[i].length === 16)
|
||||||
|
this.networkNonces[i] = new Buffer(networkNonces[i], 'hex');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//for oneself
|
||||||
|
Network.prototype.getHexNonce = function() {
|
||||||
|
return this.networkNonce.toString('hex');
|
||||||
|
};
|
||||||
|
|
||||||
|
//for copayers
|
||||||
|
Network.prototype.getHexNonces = function() {
|
||||||
|
var networkNoncesHex = [];
|
||||||
|
for (var i in this.networkNonces) {
|
||||||
|
networkNoncesHex = this.networkNonces[i].toString('hex');
|
||||||
|
}
|
||||||
|
return networkNoncesHex;
|
||||||
|
};
|
||||||
|
|
||||||
|
Network.prototype.iterateNonce = function() {
|
||||||
|
if (!this.networkNonce || this.networkNonce.length !== 8) {
|
||||||
|
this.networkNonce = new Buffer(8);
|
||||||
|
this.networkNonce.fill(0);
|
||||||
|
this.networkNonce[7] = 1;
|
||||||
|
return this.networkNonce;
|
||||||
|
}
|
||||||
|
//the first 4 bytes of a nonce is a unix timestamp in seconds
|
||||||
|
//the second 4 bytes is just an iterated "sub" nonce
|
||||||
|
//the whole thing is interpreted as one big endian number
|
||||||
|
var noncep1 = this.networkNonce.slice(0, 4);
|
||||||
|
noncep1.writeUInt32BE(Math.floor(Date.now()/1000), 0);
|
||||||
|
var noncep2uint = this.networkNonce.slice(4, 8).readUInt32BE(0);
|
||||||
|
var noncep2 = this.networkNonce.slice(4, 8);
|
||||||
|
noncep2.writeUInt32BE(noncep2uint + 1, 0);
|
||||||
|
return this.networkNonce;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = require('soop')(Network);
|
module.exports = require('soop')(Network);
|
||||||
|
|
|
||||||
|
|
@ -687,6 +687,7 @@ describe('Wallet model', function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should send all TxProposal', function(done) {
|
it('should send all TxProposal', function(done) {
|
||||||
var w = cachedCreateW2();
|
var w = cachedCreateW2();
|
||||||
var utxo = createUTXO(w);
|
var utxo = createUTXO(w);
|
||||||
|
|
@ -700,6 +701,16 @@ describe('Wallet model', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#send', function() {
|
||||||
|
it('should call this.network.send', function () {
|
||||||
|
var w = cachedCreateW2();
|
||||||
|
var save = w.network.send;
|
||||||
|
w.network.send = sinon.spy();
|
||||||
|
w.send();
|
||||||
|
w.network.send.calledOnce.should.equal(true);
|
||||||
|
w.network.send = save;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('#indexDiscovery', function() {
|
describe('#indexDiscovery', function() {
|
||||||
var ADDRESSES_CHANGE, ADDRESSES_RECEIVE, w;
|
var ADDRESSES_CHANGE, ADDRESSES_RECEIVE, w;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ var FakeBlockchain = require('./mocks/FakeBlockchain');
|
||||||
var FakeStorage = require('./mocks/FakeStorage');
|
var FakeStorage = require('./mocks/FakeStorage');
|
||||||
var WalletFactory = require('../js/models/core/WalletFactory');
|
var WalletFactory = require('../js/models/core/WalletFactory');
|
||||||
|
|
||||||
var o = '{"opts":{"id":"dbfe10c3fae71cea","spendUnconfirmed":1,"requiredCopayers":3,"totalCopayers":5,"version":"0.0.5"},"publicKeyRing":{"walletId":"dbfe10c3fae71cea","networkName":"testnet","requiredCopayers":3,"totalCopayers":5,"indexes":[{"cosigner":2,"changeIndex":0,"receiveIndex":0}],"copayersBackup":[],"copayersExtPubKeys":["tpubD6NzVbkrYhZ4YGK8ZhZ8WVeBXNAAoTYjjpw9twCPiNGrGQYFktP3iVQkKmZNiFnUcAFMJRxJVJF6Nq9MDv2kiRceExJaHFbxUCGUiRhmy97","tpubD6NzVbkrYhZ4YKGDJkzWdQsQV3AcFemaQKiwNhV4RL8FHnBFvinidGdQtP8RKj3h34E65RkdtxjrggZYqsEwJ8RhhN2zz9VrjLnrnwbXYNc","tpubD6NzVbkrYhZ4YkDiewjb32Pp3Sz9WK2jpp37KnL7RCrHAyPpnLfgdfRnTdpn6DTWmPS7niywfgWiT42aJb1J6CjWVNmkgsMCxuw7j9DaGKB","tpubD6NzVbkrYhZ4XEtUAz4UUTWbprewbLTaMhR8NUvSJUEAh4Sidxr6rRPFdqqVRR73btKf13wUjds2i8vVCNo8sbKrAnyoTr3o5Y6QSbboQjk","tpubD6NzVbkrYhZ4Yj9AAt6xUVuGPVd8jXCrEE6V2wp7U3PFh8jYYvVad31b4VUXEYXzSnkco4fktu8r4icBsB2t3pCR3WnhVLedY2hxGcPFLKD"],"nicknameFor":{},"publicKeysCache":{"m/0/1/0":["0314368b8efa07e8c7dad30498d0a7e3aa575db1fef833347c6d381c1a33a17b17","02cfd95f89ab46bd3bd86954dd9f83dbab0cd2e4466dee587e8e4d8d733fc0d748","02568969eb6212fe946450be6c5b3353fc754a40b2cdc4aed501a8976fec371da8","0360f870a088ae0ef1c37035a9b6a462ca8dcdd5da275f4e2dcd19f44b81d3e7e4","0300ad8f1bded838b02e127bb25961fbcee718db2df81f680f889692acdcbdd73d"],"m/0/1/1":["024f97a9adb2fa9306c4e3d9244f5e5355c7e2c6b3dd4122ba804e17dc9729df5d","0214834a5adcbc4ad0f3bbbc1c280b8ac480387fcc9a1fd988c1526ed496d923c4","024e72338bd5e976375d076bd71a9649e9141b4cbfc9e16cb7109b354b3e913a05","0322045ea35c3118aa7ab9f2c9f182b0120956b0aa65cc72b9d093f145327a4b17","030dc2450c72df366c1960739c577a2efd4451070bd78effcb6f71d1bcd7dfc7a8"],"m/0/1/2":["0247de59deb66783b8f9b0c326234a9569d00866c2a73f599e77a4d0cab5cbce8f","0376e49f0ac3647404034aae0dc8dd927c34a634ef24ea36f56a272f75fce9539b","032fbaa2593bd1eea4a46e7ac15f15802cdd1eb65a7d5bc4364ddd9d52f0838234","03a81f2a7e1f7191aa0b0c6e0a4ccefc71edd3564e86014972fe338045f68d5a5a","02eb8a012ea9a709392502cacda6ef5115d6d2319ab470d546d9068ab941621a99"],"m/0/0/0":["036dcbd378b4352120d6b720b6294dd2d0dd02801fcf010bb69dadbec1f3999279","022089eedb85dc45d1efa418e1ea226588deedebc1d85acca15ff72783e33636c0","0388aa5fd432b74c56427396f350d236c3ca8f7b2f62da513ce4c2e6ff04a67e9c","02fc4caa7449db7483d2e1fccdacac6fa2f736278c758af9966402589b5632f13e","02e4a15b885d8b2d586f82fa85d16179644e60a154674bde0ec3004810b1bdab99"],"m/0/0/1":["039afa26b2f341c76c7b3c3d0672438f35ac6ebb67b1ddfefac9cd79b7b24418c1","021acaaf500d431ebc396f50630767b01c91ce98ae48e968775ceaad932b7e3b8e","022a947259c4a9f76d5e95c0849df31d01233df41d0d75d631b89317a48d8cddce","03d38d9f94217da780303d9a8987c86d737ef39683febc0cd6632cddbfa62186fd","0394d2581b307fe2af19721888d922aab58ab198ef88cedf9506177e30d807811e"],"m/0/0/2":["037825ffce15d34f9bd6c02bcda7701826706471a4d6ab5004eb965f98811c2098","023768dd6d3c71b7df5733ccda5b2d8b454d5b4c4179d91a6fda74db8b869a2406","021a79e91f003f308764d43039e9b5d56bc8f33ca2f4d30ec6cc5a37c0d09dc273","02437f1e388b273936319f79a5d22958ef5ebff9c8cd7b6f6f72518445b1e30867","0373b0881cb4fd02baa62589023fdfe9739c6148cf104d907549f2528eb80146f5"]}},"txProposals":{"txps":[],"walletId":"dbfe10c3fae71cea","networkName":"testnet"},"privateKey":{"extendedPrivateKeyString":"tprv8ZgxMBicQKsPeoHLg3tY75z4xLeEe8MqAXLNcRA6J6UTRvHV8VZTXznt9eoTmSk1fwSrwZtMhY3XkNsceJ14h6sCXHSWinRqMSSbY8tfhHi","networkName":"testnet","privateKeyCache":{}},"addressBook":{}}';
|
var o = '{"opts":{"id":"dbfe10c3fae71cea","spendUnconfirmed":1,"requiredCopayers":3,"totalCopayers":5,"version":"0.0.5"},"networkNonce":"0000000000000001","networkNonces":[],"publicKeyRing":{"walletId":"dbfe10c3fae71cea","networkName":"testnet","requiredCopayers":3,"totalCopayers":5,"indexes":[{"cosigner":2,"changeIndex":0,"receiveIndex":0}],"copayersBackup":[],"copayersExtPubKeys":["tpubD6NzVbkrYhZ4YGK8ZhZ8WVeBXNAAoTYjjpw9twCPiNGrGQYFktP3iVQkKmZNiFnUcAFMJRxJVJF6Nq9MDv2kiRceExJaHFbxUCGUiRhmy97","tpubD6NzVbkrYhZ4YKGDJkzWdQsQV3AcFemaQKiwNhV4RL8FHnBFvinidGdQtP8RKj3h34E65RkdtxjrggZYqsEwJ8RhhN2zz9VrjLnrnwbXYNc","tpubD6NzVbkrYhZ4YkDiewjb32Pp3Sz9WK2jpp37KnL7RCrHAyPpnLfgdfRnTdpn6DTWmPS7niywfgWiT42aJb1J6CjWVNmkgsMCxuw7j9DaGKB","tpubD6NzVbkrYhZ4XEtUAz4UUTWbprewbLTaMhR8NUvSJUEAh4Sidxr6rRPFdqqVRR73btKf13wUjds2i8vVCNo8sbKrAnyoTr3o5Y6QSbboQjk","tpubD6NzVbkrYhZ4Yj9AAt6xUVuGPVd8jXCrEE6V2wp7U3PFh8jYYvVad31b4VUXEYXzSnkco4fktu8r4icBsB2t3pCR3WnhVLedY2hxGcPFLKD"],"nicknameFor":{},"publicKeysCache":{"m/0/1/0":["0314368b8efa07e8c7dad30498d0a7e3aa575db1fef833347c6d381c1a33a17b17","02cfd95f89ab46bd3bd86954dd9f83dbab0cd2e4466dee587e8e4d8d733fc0d748","02568969eb6212fe946450be6c5b3353fc754a40b2cdc4aed501a8976fec371da8","0360f870a088ae0ef1c37035a9b6a462ca8dcdd5da275f4e2dcd19f44b81d3e7e4","0300ad8f1bded838b02e127bb25961fbcee718db2df81f680f889692acdcbdd73d"],"m/0/1/1":["024f97a9adb2fa9306c4e3d9244f5e5355c7e2c6b3dd4122ba804e17dc9729df5d","0214834a5adcbc4ad0f3bbbc1c280b8ac480387fcc9a1fd988c1526ed496d923c4","024e72338bd5e976375d076bd71a9649e9141b4cbfc9e16cb7109b354b3e913a05","0322045ea35c3118aa7ab9f2c9f182b0120956b0aa65cc72b9d093f145327a4b17","030dc2450c72df366c1960739c577a2efd4451070bd78effcb6f71d1bcd7dfc7a8"],"m/0/1/2":["0247de59deb66783b8f9b0c326234a9569d00866c2a73f599e77a4d0cab5cbce8f","0376e49f0ac3647404034aae0dc8dd927c34a634ef24ea36f56a272f75fce9539b","032fbaa2593bd1eea4a46e7ac15f15802cdd1eb65a7d5bc4364ddd9d52f0838234","03a81f2a7e1f7191aa0b0c6e0a4ccefc71edd3564e86014972fe338045f68d5a5a","02eb8a012ea9a709392502cacda6ef5115d6d2319ab470d546d9068ab941621a99"],"m/0/0/0":["036dcbd378b4352120d6b720b6294dd2d0dd02801fcf010bb69dadbec1f3999279","022089eedb85dc45d1efa418e1ea226588deedebc1d85acca15ff72783e33636c0","0388aa5fd432b74c56427396f350d236c3ca8f7b2f62da513ce4c2e6ff04a67e9c","02fc4caa7449db7483d2e1fccdacac6fa2f736278c758af9966402589b5632f13e","02e4a15b885d8b2d586f82fa85d16179644e60a154674bde0ec3004810b1bdab99"],"m/0/0/1":["039afa26b2f341c76c7b3c3d0672438f35ac6ebb67b1ddfefac9cd79b7b24418c1","021acaaf500d431ebc396f50630767b01c91ce98ae48e968775ceaad932b7e3b8e","022a947259c4a9f76d5e95c0849df31d01233df41d0d75d631b89317a48d8cddce","03d38d9f94217da780303d9a8987c86d737ef39683febc0cd6632cddbfa62186fd","0394d2581b307fe2af19721888d922aab58ab198ef88cedf9506177e30d807811e"],"m/0/0/2":["037825ffce15d34f9bd6c02bcda7701826706471a4d6ab5004eb965f98811c2098","023768dd6d3c71b7df5733ccda5b2d8b454d5b4c4179d91a6fda74db8b869a2406","021a79e91f003f308764d43039e9b5d56bc8f33ca2f4d30ec6cc5a37c0d09dc273","02437f1e388b273936319f79a5d22958ef5ebff9c8cd7b6f6f72518445b1e30867","0373b0881cb4fd02baa62589023fdfe9739c6148cf104d907549f2528eb80146f5"]}},"txProposals":{"txps":[],"walletId":"dbfe10c3fae71cea","networkName":"testnet"},"privateKey":{"extendedPrivateKeyString":"tprv8ZgxMBicQKsPeoHLg3tY75z4xLeEe8MqAXLNcRA6J6UTRvHV8VZTXznt9eoTmSk1fwSrwZtMhY3XkNsceJ14h6sCXHSWinRqMSSbY8tfhHi","networkName":"testnet","privateKeyCache":{}},"addressBook":{}}';
|
||||||
|
|
||||||
describe('WalletFactory model', function() {
|
describe('WalletFactory model', function() {
|
||||||
var config = {
|
var config = {
|
||||||
|
|
@ -97,8 +97,8 @@ describe('WalletFactory model', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('support old index schema: #fromObj #toObj round trip', function() {
|
it('support old index schema: #fromObj #toObj round trip', function() {
|
||||||
var o = '{"opts":{"id":"dbfe10c3fae71cea","spendUnconfirmed":1,"requiredCopayers":3,"totalCopayers":5,"version":"0.0.5"},"publicKeyRing":{"walletId":"dbfe10c3fae71cea","networkName":"testnet","requiredCopayers":3,"totalCopayers":5,"indexes":{"changeIndex":0,"receiveIndex":0},"copayersBackup":[],"copayersExtPubKeys":["tpubD6NzVbkrYhZ4YGK8ZhZ8WVeBXNAAoTYjjpw9twCPiNGrGQYFktP3iVQkKmZNiFnUcAFMJRxJVJF6Nq9MDv2kiRceExJaHFbxUCGUiRhmy97","tpubD6NzVbkrYhZ4YKGDJkzWdQsQV3AcFemaQKiwNhV4RL8FHnBFvinidGdQtP8RKj3h34E65RkdtxjrggZYqsEwJ8RhhN2zz9VrjLnrnwbXYNc","tpubD6NzVbkrYhZ4YkDiewjb32Pp3Sz9WK2jpp37KnL7RCrHAyPpnLfgdfRnTdpn6DTWmPS7niywfgWiT42aJb1J6CjWVNmkgsMCxuw7j9DaGKB","tpubD6NzVbkrYhZ4XEtUAz4UUTWbprewbLTaMhR8NUvSJUEAh4Sidxr6rRPFdqqVRR73btKf13wUjds2i8vVCNo8sbKrAnyoTr3o5Y6QSbboQjk","tpubD6NzVbkrYhZ4Yj9AAt6xUVuGPVd8jXCrEE6V2wp7U3PFh8jYYvVad31b4VUXEYXzSnkco4fktu8r4icBsB2t3pCR3WnhVLedY2hxGcPFLKD"],"nicknameFor":{},"publicKeysCache":{"m/0/1/0":["0314368b8efa07e8c7dad30498d0a7e3aa575db1fef833347c6d381c1a33a17b17","02cfd95f89ab46bd3bd86954dd9f83dbab0cd2e4466dee587e8e4d8d733fc0d748","02568969eb6212fe946450be6c5b3353fc754a40b2cdc4aed501a8976fec371da8","0360f870a088ae0ef1c37035a9b6a462ca8dcdd5da275f4e2dcd19f44b81d3e7e4","0300ad8f1bded838b02e127bb25961fbcee718db2df81f680f889692acdcbdd73d"],"m/0/1/1":["024f97a9adb2fa9306c4e3d9244f5e5355c7e2c6b3dd4122ba804e17dc9729df5d","0214834a5adcbc4ad0f3bbbc1c280b8ac480387fcc9a1fd988c1526ed496d923c4","024e72338bd5e976375d076bd71a9649e9141b4cbfc9e16cb7109b354b3e913a05","0322045ea35c3118aa7ab9f2c9f182b0120956b0aa65cc72b9d093f145327a4b17","030dc2450c72df366c1960739c577a2efd4451070bd78effcb6f71d1bcd7dfc7a8"],"m/0/1/2":["0247de59deb66783b8f9b0c326234a9569d00866c2a73f599e77a4d0cab5cbce8f","0376e49f0ac3647404034aae0dc8dd927c34a634ef24ea36f56a272f75fce9539b","032fbaa2593bd1eea4a46e7ac15f15802cdd1eb65a7d5bc4364ddd9d52f0838234","03a81f2a7e1f7191aa0b0c6e0a4ccefc71edd3564e86014972fe338045f68d5a5a","02eb8a012ea9a709392502cacda6ef5115d6d2319ab470d546d9068ab941621a99"],"m/0/0/0":["036dcbd378b4352120d6b720b6294dd2d0dd02801fcf010bb69dadbec1f3999279","022089eedb85dc45d1efa418e1ea226588deedebc1d85acca15ff72783e33636c0","0388aa5fd432b74c56427396f350d236c3ca8f7b2f62da513ce4c2e6ff04a67e9c","02fc4caa7449db7483d2e1fccdacac6fa2f736278c758af9966402589b5632f13e","02e4a15b885d8b2d586f82fa85d16179644e60a154674bde0ec3004810b1bdab99"],"m/0/0/1":["039afa26b2f341c76c7b3c3d0672438f35ac6ebb67b1ddfefac9cd79b7b24418c1","021acaaf500d431ebc396f50630767b01c91ce98ae48e968775ceaad932b7e3b8e","022a947259c4a9f76d5e95c0849df31d01233df41d0d75d631b89317a48d8cddce","03d38d9f94217da780303d9a8987c86d737ef39683febc0cd6632cddbfa62186fd","0394d2581b307fe2af19721888d922aab58ab198ef88cedf9506177e30d807811e"],"m/0/0/2":["037825ffce15d34f9bd6c02bcda7701826706471a4d6ab5004eb965f98811c2098","023768dd6d3c71b7df5733ccda5b2d8b454d5b4c4179d91a6fda74db8b869a2406","021a79e91f003f308764d43039e9b5d56bc8f33ca2f4d30ec6cc5a37c0d09dc273","02437f1e388b273936319f79a5d22958ef5ebff9c8cd7b6f6f72518445b1e30867","0373b0881cb4fd02baa62589023fdfe9739c6148cf104d907549f2528eb80146f5"]}},"txProposals":{"txps":[],"walletId":"dbfe10c3fae71cea","networkName":"testnet"},"privateKey":{"extendedPrivateKeyString":"tprv8ZgxMBicQKsPeoHLg3tY75z4xLeEe8MqAXLNcRA6J6UTRvHV8VZTXznt9eoTmSk1fwSrwZtMhY3XkNsceJ14h6sCXHSWinRqMSSbY8tfhHi","networkName":"testnet","privateKeyCache":{}},"addressBook":{}}';
|
var o = '{"opts":{"id":"dbfe10c3fae71cea","spendUnconfirmed":1,"requiredCopayers":3,"totalCopayers":5,"version":"0.0.5"},"networkNonce":"0000000000000001","networkNonces":[],"publicKeyRing":{"walletId":"dbfe10c3fae71cea","networkName":"testnet","requiredCopayers":3,"totalCopayers":5,"indexes":{"changeIndex":0,"receiveIndex":0},"copayersBackup":[],"copayersExtPubKeys":["tpubD6NzVbkrYhZ4YGK8ZhZ8WVeBXNAAoTYjjpw9twCPiNGrGQYFktP3iVQkKmZNiFnUcAFMJRxJVJF6Nq9MDv2kiRceExJaHFbxUCGUiRhmy97","tpubD6NzVbkrYhZ4YKGDJkzWdQsQV3AcFemaQKiwNhV4RL8FHnBFvinidGdQtP8RKj3h34E65RkdtxjrggZYqsEwJ8RhhN2zz9VrjLnrnwbXYNc","tpubD6NzVbkrYhZ4YkDiewjb32Pp3Sz9WK2jpp37KnL7RCrHAyPpnLfgdfRnTdpn6DTWmPS7niywfgWiT42aJb1J6CjWVNmkgsMCxuw7j9DaGKB","tpubD6NzVbkrYhZ4XEtUAz4UUTWbprewbLTaMhR8NUvSJUEAh4Sidxr6rRPFdqqVRR73btKf13wUjds2i8vVCNo8sbKrAnyoTr3o5Y6QSbboQjk","tpubD6NzVbkrYhZ4Yj9AAt6xUVuGPVd8jXCrEE6V2wp7U3PFh8jYYvVad31b4VUXEYXzSnkco4fktu8r4icBsB2t3pCR3WnhVLedY2hxGcPFLKD"],"nicknameFor":{},"publicKeysCache":{"m/0/1/0":["0314368b8efa07e8c7dad30498d0a7e3aa575db1fef833347c6d381c1a33a17b17","02cfd95f89ab46bd3bd86954dd9f83dbab0cd2e4466dee587e8e4d8d733fc0d748","02568969eb6212fe946450be6c5b3353fc754a40b2cdc4aed501a8976fec371da8","0360f870a088ae0ef1c37035a9b6a462ca8dcdd5da275f4e2dcd19f44b81d3e7e4","0300ad8f1bded838b02e127bb25961fbcee718db2df81f680f889692acdcbdd73d"],"m/0/1/1":["024f97a9adb2fa9306c4e3d9244f5e5355c7e2c6b3dd4122ba804e17dc9729df5d","0214834a5adcbc4ad0f3bbbc1c280b8ac480387fcc9a1fd988c1526ed496d923c4","024e72338bd5e976375d076bd71a9649e9141b4cbfc9e16cb7109b354b3e913a05","0322045ea35c3118aa7ab9f2c9f182b0120956b0aa65cc72b9d093f145327a4b17","030dc2450c72df366c1960739c577a2efd4451070bd78effcb6f71d1bcd7dfc7a8"],"m/0/1/2":["0247de59deb66783b8f9b0c326234a9569d00866c2a73f599e77a4d0cab5cbce8f","0376e49f0ac3647404034aae0dc8dd927c34a634ef24ea36f56a272f75fce9539b","032fbaa2593bd1eea4a46e7ac15f15802cdd1eb65a7d5bc4364ddd9d52f0838234","03a81f2a7e1f7191aa0b0c6e0a4ccefc71edd3564e86014972fe338045f68d5a5a","02eb8a012ea9a709392502cacda6ef5115d6d2319ab470d546d9068ab941621a99"],"m/0/0/0":["036dcbd378b4352120d6b720b6294dd2d0dd02801fcf010bb69dadbec1f3999279","022089eedb85dc45d1efa418e1ea226588deedebc1d85acca15ff72783e33636c0","0388aa5fd432b74c56427396f350d236c3ca8f7b2f62da513ce4c2e6ff04a67e9c","02fc4caa7449db7483d2e1fccdacac6fa2f736278c758af9966402589b5632f13e","02e4a15b885d8b2d586f82fa85d16179644e60a154674bde0ec3004810b1bdab99"],"m/0/0/1":["039afa26b2f341c76c7b3c3d0672438f35ac6ebb67b1ddfefac9cd79b7b24418c1","021acaaf500d431ebc396f50630767b01c91ce98ae48e968775ceaad932b7e3b8e","022a947259c4a9f76d5e95c0849df31d01233df41d0d75d631b89317a48d8cddce","03d38d9f94217da780303d9a8987c86d737ef39683febc0cd6632cddbfa62186fd","0394d2581b307fe2af19721888d922aab58ab198ef88cedf9506177e30d807811e"],"m/0/0/2":["037825ffce15d34f9bd6c02bcda7701826706471a4d6ab5004eb965f98811c2098","023768dd6d3c71b7df5733ccda5b2d8b454d5b4c4179d91a6fda74db8b869a2406","021a79e91f003f308764d43039e9b5d56bc8f33ca2f4d30ec6cc5a37c0d09dc273","02437f1e388b273936319f79a5d22958ef5ebff9c8cd7b6f6f72518445b1e30867","0373b0881cb4fd02baa62589023fdfe9739c6148cf104d907549f2528eb80146f5"]}},"txProposals":{"txps":[],"walletId":"dbfe10c3fae71cea","networkName":"testnet"},"privateKey":{"extendedPrivateKeyString":"tprv8ZgxMBicQKsPeoHLg3tY75z4xLeEe8MqAXLNcRA6J6UTRvHV8VZTXznt9eoTmSk1fwSrwZtMhY3XkNsceJ14h6sCXHSWinRqMSSbY8tfhHi","networkName":"testnet","privateKeyCache":{}},"addressBook":{}}';
|
||||||
var o2 = '{"opts":{"id":"dbfe10c3fae71cea","spendUnconfirmed":1,"requiredCopayers":3,"totalCopayers":5,"version":"0.0.5"},"publicKeyRing":{"walletId":"dbfe10c3fae71cea","networkName":"testnet","requiredCopayers":3,"totalCopayers":5,"indexes":[{"cosigner":2147483647,"changeIndex":0,"receiveIndex":0},{"cosigner":0,"changeIndex":0,"receiveIndex":0},{"cosigner":1,"changeIndex":0,"receiveIndex":0},{"cosigner":2,"changeIndex":0,"receiveIndex":0},{"cosigner":3,"changeIndex":0,"receiveIndex":0},{"cosigner":4,"changeIndex":0,"receiveIndex":0}],"copayersBackup":[],"copayersExtPubKeys":["tpubD6NzVbkrYhZ4YGK8ZhZ8WVeBXNAAoTYjjpw9twCPiNGrGQYFktP3iVQkKmZNiFnUcAFMJRxJVJF6Nq9MDv2kiRceExJaHFbxUCGUiRhmy97","tpubD6NzVbkrYhZ4YKGDJkzWdQsQV3AcFemaQKiwNhV4RL8FHnBFvinidGdQtP8RKj3h34E65RkdtxjrggZYqsEwJ8RhhN2zz9VrjLnrnwbXYNc","tpubD6NzVbkrYhZ4YkDiewjb32Pp3Sz9WK2jpp37KnL7RCrHAyPpnLfgdfRnTdpn6DTWmPS7niywfgWiT42aJb1J6CjWVNmkgsMCxuw7j9DaGKB","tpubD6NzVbkrYhZ4XEtUAz4UUTWbprewbLTaMhR8NUvSJUEAh4Sidxr6rRPFdqqVRR73btKf13wUjds2i8vVCNo8sbKrAnyoTr3o5Y6QSbboQjk","tpubD6NzVbkrYhZ4Yj9AAt6xUVuGPVd8jXCrEE6V2wp7U3PFh8jYYvVad31b4VUXEYXzSnkco4fktu8r4icBsB2t3pCR3WnhVLedY2hxGcPFLKD"],"nicknameFor":{},"publicKeysCache":{"m/0/1/0":["0314368b8efa07e8c7dad30498d0a7e3aa575db1fef833347c6d381c1a33a17b17","02cfd95f89ab46bd3bd86954dd9f83dbab0cd2e4466dee587e8e4d8d733fc0d748","02568969eb6212fe946450be6c5b3353fc754a40b2cdc4aed501a8976fec371da8","0360f870a088ae0ef1c37035a9b6a462ca8dcdd5da275f4e2dcd19f44b81d3e7e4","0300ad8f1bded838b02e127bb25961fbcee718db2df81f680f889692acdcbdd73d"],"m/0/1/1":["024f97a9adb2fa9306c4e3d9244f5e5355c7e2c6b3dd4122ba804e17dc9729df5d","0214834a5adcbc4ad0f3bbbc1c280b8ac480387fcc9a1fd988c1526ed496d923c4","024e72338bd5e976375d076bd71a9649e9141b4cbfc9e16cb7109b354b3e913a05","0322045ea35c3118aa7ab9f2c9f182b0120956b0aa65cc72b9d093f145327a4b17","030dc2450c72df366c1960739c577a2efd4451070bd78effcb6f71d1bcd7dfc7a8"],"m/0/1/2":["0247de59deb66783b8f9b0c326234a9569d00866c2a73f599e77a4d0cab5cbce8f","0376e49f0ac3647404034aae0dc8dd927c34a634ef24ea36f56a272f75fce9539b","032fbaa2593bd1eea4a46e7ac15f15802cdd1eb65a7d5bc4364ddd9d52f0838234","03a81f2a7e1f7191aa0b0c6e0a4ccefc71edd3564e86014972fe338045f68d5a5a","02eb8a012ea9a709392502cacda6ef5115d6d2319ab470d546d9068ab941621a99"],"m/0/0/0":["036dcbd378b4352120d6b720b6294dd2d0dd02801fcf010bb69dadbec1f3999279","022089eedb85dc45d1efa418e1ea226588deedebc1d85acca15ff72783e33636c0","0388aa5fd432b74c56427396f350d236c3ca8f7b2f62da513ce4c2e6ff04a67e9c","02fc4caa7449db7483d2e1fccdacac6fa2f736278c758af9966402589b5632f13e","02e4a15b885d8b2d586f82fa85d16179644e60a154674bde0ec3004810b1bdab99"],"m/0/0/1":["039afa26b2f341c76c7b3c3d0672438f35ac6ebb67b1ddfefac9cd79b7b24418c1","021acaaf500d431ebc396f50630767b01c91ce98ae48e968775ceaad932b7e3b8e","022a947259c4a9f76d5e95c0849df31d01233df41d0d75d631b89317a48d8cddce","03d38d9f94217da780303d9a8987c86d737ef39683febc0cd6632cddbfa62186fd","0394d2581b307fe2af19721888d922aab58ab198ef88cedf9506177e30d807811e"],"m/0/0/2":["037825ffce15d34f9bd6c02bcda7701826706471a4d6ab5004eb965f98811c2098","023768dd6d3c71b7df5733ccda5b2d8b454d5b4c4179d91a6fda74db8b869a2406","021a79e91f003f308764d43039e9b5d56bc8f33ca2f4d30ec6cc5a37c0d09dc273","02437f1e388b273936319f79a5d22958ef5ebff9c8cd7b6f6f72518445b1e30867","0373b0881cb4fd02baa62589023fdfe9739c6148cf104d907549f2528eb80146f5"]}},"txProposals":{"txps":[],"walletId":"dbfe10c3fae71cea","networkName":"testnet"},"privateKey":{"extendedPrivateKeyString":"tprv8ZgxMBicQKsPeoHLg3tY75z4xLeEe8MqAXLNcRA6J6UTRvHV8VZTXznt9eoTmSk1fwSrwZtMhY3XkNsceJ14h6sCXHSWinRqMSSbY8tfhHi","networkName":"testnet","privateKeyCache":{}},"addressBook":{}}';
|
var o2 = '{"opts":{"id":"dbfe10c3fae71cea","spendUnconfirmed":1,"requiredCopayers":3,"totalCopayers":5,"version":"0.0.5"},"networkNonce":"0000000000000001","networkNonces":[],"publicKeyRing":{"walletId":"dbfe10c3fae71cea","networkName":"testnet","requiredCopayers":3,"totalCopayers":5,"indexes":[{"cosigner":2147483647,"changeIndex":0,"receiveIndex":0},{"cosigner":0,"changeIndex":0,"receiveIndex":0},{"cosigner":1,"changeIndex":0,"receiveIndex":0},{"cosigner":2,"changeIndex":0,"receiveIndex":0},{"cosigner":3,"changeIndex":0,"receiveIndex":0},{"cosigner":4,"changeIndex":0,"receiveIndex":0}],"copayersBackup":[],"copayersExtPubKeys":["tpubD6NzVbkrYhZ4YGK8ZhZ8WVeBXNAAoTYjjpw9twCPiNGrGQYFktP3iVQkKmZNiFnUcAFMJRxJVJF6Nq9MDv2kiRceExJaHFbxUCGUiRhmy97","tpubD6NzVbkrYhZ4YKGDJkzWdQsQV3AcFemaQKiwNhV4RL8FHnBFvinidGdQtP8RKj3h34E65RkdtxjrggZYqsEwJ8RhhN2zz9VrjLnrnwbXYNc","tpubD6NzVbkrYhZ4YkDiewjb32Pp3Sz9WK2jpp37KnL7RCrHAyPpnLfgdfRnTdpn6DTWmPS7niywfgWiT42aJb1J6CjWVNmkgsMCxuw7j9DaGKB","tpubD6NzVbkrYhZ4XEtUAz4UUTWbprewbLTaMhR8NUvSJUEAh4Sidxr6rRPFdqqVRR73btKf13wUjds2i8vVCNo8sbKrAnyoTr3o5Y6QSbboQjk","tpubD6NzVbkrYhZ4Yj9AAt6xUVuGPVd8jXCrEE6V2wp7U3PFh8jYYvVad31b4VUXEYXzSnkco4fktu8r4icBsB2t3pCR3WnhVLedY2hxGcPFLKD"],"nicknameFor":{},"publicKeysCache":{"m/0/1/0":["0314368b8efa07e8c7dad30498d0a7e3aa575db1fef833347c6d381c1a33a17b17","02cfd95f89ab46bd3bd86954dd9f83dbab0cd2e4466dee587e8e4d8d733fc0d748","02568969eb6212fe946450be6c5b3353fc754a40b2cdc4aed501a8976fec371da8","0360f870a088ae0ef1c37035a9b6a462ca8dcdd5da275f4e2dcd19f44b81d3e7e4","0300ad8f1bded838b02e127bb25961fbcee718db2df81f680f889692acdcbdd73d"],"m/0/1/1":["024f97a9adb2fa9306c4e3d9244f5e5355c7e2c6b3dd4122ba804e17dc9729df5d","0214834a5adcbc4ad0f3bbbc1c280b8ac480387fcc9a1fd988c1526ed496d923c4","024e72338bd5e976375d076bd71a9649e9141b4cbfc9e16cb7109b354b3e913a05","0322045ea35c3118aa7ab9f2c9f182b0120956b0aa65cc72b9d093f145327a4b17","030dc2450c72df366c1960739c577a2efd4451070bd78effcb6f71d1bcd7dfc7a8"],"m/0/1/2":["0247de59deb66783b8f9b0c326234a9569d00866c2a73f599e77a4d0cab5cbce8f","0376e49f0ac3647404034aae0dc8dd927c34a634ef24ea36f56a272f75fce9539b","032fbaa2593bd1eea4a46e7ac15f15802cdd1eb65a7d5bc4364ddd9d52f0838234","03a81f2a7e1f7191aa0b0c6e0a4ccefc71edd3564e86014972fe338045f68d5a5a","02eb8a012ea9a709392502cacda6ef5115d6d2319ab470d546d9068ab941621a99"],"m/0/0/0":["036dcbd378b4352120d6b720b6294dd2d0dd02801fcf010bb69dadbec1f3999279","022089eedb85dc45d1efa418e1ea226588deedebc1d85acca15ff72783e33636c0","0388aa5fd432b74c56427396f350d236c3ca8f7b2f62da513ce4c2e6ff04a67e9c","02fc4caa7449db7483d2e1fccdacac6fa2f736278c758af9966402589b5632f13e","02e4a15b885d8b2d586f82fa85d16179644e60a154674bde0ec3004810b1bdab99"],"m/0/0/1":["039afa26b2f341c76c7b3c3d0672438f35ac6ebb67b1ddfefac9cd79b7b24418c1","021acaaf500d431ebc396f50630767b01c91ce98ae48e968775ceaad932b7e3b8e","022a947259c4a9f76d5e95c0849df31d01233df41d0d75d631b89317a48d8cddce","03d38d9f94217da780303d9a8987c86d737ef39683febc0cd6632cddbfa62186fd","0394d2581b307fe2af19721888d922aab58ab198ef88cedf9506177e30d807811e"],"m/0/0/2":["037825ffce15d34f9bd6c02bcda7701826706471a4d6ab5004eb965f98811c2098","023768dd6d3c71b7df5733ccda5b2d8b454d5b4c4179d91a6fda74db8b869a2406","021a79e91f003f308764d43039e9b5d56bc8f33ca2f4d30ec6cc5a37c0d09dc273","02437f1e388b273936319f79a5d22958ef5ebff9c8cd7b6f6f72518445b1e30867","0373b0881cb4fd02baa62589023fdfe9739c6148cf104d907549f2528eb80146f5"]}},"txProposals":{"txps":[],"walletId":"dbfe10c3fae71cea","networkName":"testnet"},"privateKey":{"extendedPrivateKeyString":"tprv8ZgxMBicQKsPeoHLg3tY75z4xLeEe8MqAXLNcRA6J6UTRvHV8VZTXznt9eoTmSk1fwSrwZtMhY3XkNsceJ14h6sCXHSWinRqMSSbY8tfhHi","networkName":"testnet","privateKeyCache":{}},"addressBook":{}}';
|
||||||
|
|
||||||
var wf = new WalletFactory(config, '0.0.5');
|
var wf = new WalletFactory(config, '0.0.5');
|
||||||
var w = wf.fromObj(JSON.parse(o));
|
var w = wf.fromObj(JSON.parse(o));
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ describe('Network / WebRTC', function() {
|
||||||
var encoded = n._encode(key.public, key, data);
|
var encoded = n._encode(key.public, key, data);
|
||||||
var decoded = n._decode(key, encoded);
|
var decoded = n._decode(key, encoded);
|
||||||
encoded.sig.should.not.equal(0);
|
encoded.sig.should.not.equal(0);
|
||||||
decoded.toString().should.equal('my data to encrypt');
|
decoded.payload.toString().should.equal('my data to encrypt');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
@ -168,11 +168,11 @@ describe('Network / WebRTC', function() {
|
||||||
key.regenerateSync();
|
key.regenerateSync();
|
||||||
|
|
||||||
var copayerId = key.public.toString('hex');
|
var copayerId = key.public.toString('hex');
|
||||||
n._sendToOne = function(a1, a2, a3, cb) {
|
n._sendToOne = function(a1, a2, cb) {
|
||||||
cb();
|
cb();
|
||||||
};
|
};
|
||||||
var opts = {};
|
var opts = {};
|
||||||
n.send(copayerId, data, opts, function() {
|
n.send(copayerId, data, function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -191,13 +191,13 @@ describe('Network / WebRTC', function() {
|
||||||
key.regenerateSync();
|
key.regenerateSync();
|
||||||
|
|
||||||
var copayerId = key.public.toString('hex');
|
var copayerId = key.public.toString('hex');
|
||||||
n._sendToOne = function(a1, enc, opts, cb) {
|
n._sendToOne = function(a1, enc, cb) {
|
||||||
var encPayload = JSON.parse(enc.toString());
|
var encPayload = JSON.parse(enc.toString());
|
||||||
encPayload.sig.length.should.be.greaterThan(0);
|
encPayload.sig.length.should.be.greaterThan(0);
|
||||||
cb();
|
cb();
|
||||||
};
|
};
|
||||||
var opts = {};
|
var opts = {};
|
||||||
n.send(copayerId, data, opts, function() {
|
n.send(copayerId, data, function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -216,11 +216,11 @@ describe('Network / WebRTC', function() {
|
||||||
key.regenerateSync();
|
key.regenerateSync();
|
||||||
|
|
||||||
var copayerIds = [key.public.toString('hex')];
|
var copayerIds = [key.public.toString('hex')];
|
||||||
n._sendToOne = function(a1, a2, a3, cb) {
|
n._sendToOne = function(a1, a2, cb) {
|
||||||
cb();
|
cb();
|
||||||
};
|
};
|
||||||
var opts = {};
|
var opts = {};
|
||||||
n.send(copayerIds, data, opts, function() {
|
n.send(copayerIds, data, function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -294,6 +294,214 @@ describe('Network / WebRTC', function() {
|
||||||
n._deletePeer.getCall(0).args[1].should.equal('incorrect pubkey for peerId');
|
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 n = new WebRTC();
|
||||||
|
n.privkey = key2.private.toString('hex');
|
||||||
|
//n.networkNonces = {};
|
||||||
|
//n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('0000000000000001', 'hex'); //previously used nonce
|
||||||
|
|
||||||
|
var message = {
|
||||||
|
type: 'hello',
|
||||||
|
copayerId: key1.public.toString('hex')
|
||||||
|
};
|
||||||
|
var messagestr = JSON.stringify(message);
|
||||||
|
var messagebuf = new Buffer(messagestr);
|
||||||
|
|
||||||
|
var opts = {nonce: new Buffer('0000000000000001', 'hex')}; //message send with new nonce
|
||||||
|
var encoded = n._encode(key2.public, key1, messagebuf, opts);
|
||||||
|
var encodedstr = JSON.stringify(encoded);
|
||||||
|
var encodeduint = new Buffer(encodedstr);
|
||||||
|
|
||||||
|
var isInbound = true;
|
||||||
|
var peerId = new bitcore.SIN(key1.public);
|
||||||
|
|
||||||
|
n._deletePeer = sinon.spy();
|
||||||
|
|
||||||
|
n._onData(encodeduint, isInbound, peerId);
|
||||||
|
n._deletePeer.calledOnce.should.equal(false);
|
||||||
|
n.getHexNonces()[(new bitcore.SIN(key1.public)).toString()].toString('hex').should.equal('0000000000000001');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not reject data sent from a peer with a really big new nonce', function() {
|
||||||
|
var n = new WebRTC();
|
||||||
|
n.privkey = key2.private.toString('hex');
|
||||||
|
n.networkNonces = {};
|
||||||
|
n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000001', 'hex'); //previously used nonce
|
||||||
|
|
||||||
|
var message = {
|
||||||
|
type: 'hello',
|
||||||
|
copayerId: key1.public.toString('hex')
|
||||||
|
};
|
||||||
|
var messagestr = JSON.stringify(message);
|
||||||
|
var messagebuf = new Buffer(messagestr);
|
||||||
|
|
||||||
|
var opts = {nonce: new Buffer('5000000000000002', 'hex')}; //message send with new nonce
|
||||||
|
var encoded = n._encode(key2.public, key1, messagebuf, opts);
|
||||||
|
var encodedstr = JSON.stringify(encoded);
|
||||||
|
var encodeduint = new Buffer(encodedstr);
|
||||||
|
|
||||||
|
var isInbound = true;
|
||||||
|
var peerId = new bitcore.SIN(key1.public);
|
||||||
|
|
||||||
|
n._deletePeer = sinon.spy();
|
||||||
|
|
||||||
|
n._onData(encodeduint, isInbound, peerId);
|
||||||
|
n._deletePeer.calledOnce.should.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not reject data sent from a peer with a really big new nonce', function() {
|
||||||
|
var n = new WebRTC();
|
||||||
|
n.privkey = key2.private.toString('hex');
|
||||||
|
n.networkNonces = {};
|
||||||
|
n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000001', 'hex'); //previously used nonce
|
||||||
|
|
||||||
|
var message = {
|
||||||
|
type: 'hello',
|
||||||
|
copayerId: key1.public.toString('hex')
|
||||||
|
};
|
||||||
|
var messagestr = JSON.stringify(message);
|
||||||
|
var messagebuf = new Buffer(messagestr);
|
||||||
|
|
||||||
|
var opts = {nonce: new Buffer('5000000000000002', 'hex')}; //message send with new nonce
|
||||||
|
var encoded = n._encode(key2.public, key1, messagebuf, opts);
|
||||||
|
var encodedstr = JSON.stringify(encoded);
|
||||||
|
var encodeduint = new Buffer(encodedstr);
|
||||||
|
|
||||||
|
var isInbound = true;
|
||||||
|
var peerId = new bitcore.SIN(key1.public);
|
||||||
|
|
||||||
|
n._deletePeer = sinon.spy();
|
||||||
|
|
||||||
|
n._onData(encodeduint, isInbound, peerId);
|
||||||
|
n._deletePeer.calledOnce.should.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject data sent from a peer with an outdated nonce', function() {
|
||||||
|
var n = new WebRTC();
|
||||||
|
n.privkey = key2.private.toString('hex');
|
||||||
|
n.networkNonces = {};
|
||||||
|
n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('0000000000000002', 'hex'); //previously used nonce
|
||||||
|
|
||||||
|
var message = {
|
||||||
|
type: 'hello',
|
||||||
|
copayerId: key1.public.toString('hex')
|
||||||
|
};
|
||||||
|
var messagestr = JSON.stringify(message);
|
||||||
|
var messagebuf = new Buffer(messagestr);
|
||||||
|
|
||||||
|
var opts = {nonce: new Buffer('0000000000000001', 'hex')}; //message send with old nonce
|
||||||
|
var encoded = n._encode(key2.public, key1, messagebuf, opts);
|
||||||
|
var encodedstr = JSON.stringify(encoded);
|
||||||
|
var encodeduint = new Buffer(encodedstr);
|
||||||
|
|
||||||
|
var isInbound = true;
|
||||||
|
var peerId = new bitcore.SIN(key1.public);
|
||||||
|
|
||||||
|
n._deletePeer = sinon.spy();
|
||||||
|
|
||||||
|
n._onData(encodeduint, isInbound, peerId);
|
||||||
|
n._deletePeer.calledOnce.should.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject data sent from a peer with a really big outdated nonce', function() {
|
||||||
|
var n = new WebRTC();
|
||||||
|
n.privkey = key2.private.toString('hex');
|
||||||
|
n.networkNonces = {};
|
||||||
|
n.networkNonces[(new bitcore.SIN(key1.public)).toString()] = new Buffer('5000000000000002', 'hex'); //previously used nonce
|
||||||
|
|
||||||
|
var message = {
|
||||||
|
type: 'hello',
|
||||||
|
copayerId: key1.public.toString('hex')
|
||||||
|
};
|
||||||
|
var messagestr = JSON.stringify(message);
|
||||||
|
var messagebuf = new Buffer(messagestr);
|
||||||
|
|
||||||
|
var opts = {nonce: new Buffer('5000000000000001', 'hex')}; //message send with old nonce
|
||||||
|
var encoded = n._encode(key2.public, key1, messagebuf, opts);
|
||||||
|
var encodedstr = JSON.stringify(encoded);
|
||||||
|
var encodeduint = new Buffer(encodedstr);
|
||||||
|
|
||||||
|
var isInbound = true;
|
||||||
|
var peerId = new bitcore.SIN(key1.public);
|
||||||
|
|
||||||
|
n._deletePeer = sinon.spy();
|
||||||
|
|
||||||
|
n._onData(encodeduint, isInbound, peerId);
|
||||||
|
n._deletePeer.calledOnce.should.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#setHexNonce', function() {
|
||||||
|
|
||||||
|
it('should set a nonce from a hex value', function() {
|
||||||
|
var hex = '0000000000000000';
|
||||||
|
var n = new WebRTC();
|
||||||
|
n.setHexNonce(hex);
|
||||||
|
n.getHexNonce().should.equal(hex);
|
||||||
|
n.networkNonce.toString('hex').should.equal(hex);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#setHexNonces', function() {
|
||||||
|
|
||||||
|
it('should set a nonce from a hex value', function() {
|
||||||
|
var hex = '0000000000000000';
|
||||||
|
var n = new WebRTC();
|
||||||
|
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 = new WebRTC();
|
||||||
|
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 = new WebRTC();
|
||||||
|
n.setHexNonces({fakeid: hex});
|
||||||
|
n.getHexNonces().fakeid.should.equal(hex);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#iterateNonce', function() {
|
||||||
|
|
||||||
|
it('should set a nonce not already set', function() {
|
||||||
|
var n = new WebRTC();
|
||||||
|
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 = new WebRTC();
|
||||||
|
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 = new WebRTC();
|
||||||
|
n.iterateNonce();
|
||||||
|
var buf = new Buffer(4);
|
||||||
|
buf.writeUInt32BE(Math.floor(Date.now()/1000), 0);
|
||||||
|
n.networkNonce[0].should.equal(buf[0]);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue