add tests, refactor checks
This commit is contained in:
parent
196ae2a448
commit
03adc38897
|
@ -1,7 +1,14 @@
|
|||
var $ = require('preconditions').singleton();
|
||||
var _ = require('lodash');
|
||||
var log = require('npmlog');
|
||||
|
||||
var Bitcore = require('bitcore');
|
||||
var BitcoinUtils = require('../bitcoinutils')
|
||||
var SignUtils = require('../signutils');
|
||||
|
||||
/*
|
||||
* Checks data given by the server
|
||||
*/
|
||||
|
||||
function Verifier(opts) {};
|
||||
|
||||
|
@ -10,4 +17,43 @@ Verifier.checkAddress = function(data, address) {
|
|||
return (local.address == address.address && JSON.stringify(local.publicKeys) == JSON.stringify(address.publicKeys));
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
|
||||
Verifier.checkCopayers = function(copayers, walletPrivKey, myXPrivKey, n) {
|
||||
|
||||
var walletPubKey = Bitcore.PrivateKey.fromString(walletPrivKey).toPublicKey().toString();
|
||||
|
||||
if (copayers.length != n) {
|
||||
log.error('Missing public keys in server response');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Repeated xpub kes?
|
||||
var uniq = [];
|
||||
var error;
|
||||
_.each(copayers, function(copayer) {
|
||||
if (uniq[copayers.xPubKey]++) {
|
||||
log.error('Repeated public keys in server response');
|
||||
error = true;
|
||||
}
|
||||
|
||||
// Not signed pub keys
|
||||
if (!SignUtils.verify(copayer.xPubKey, copayer.xPubKeySignature, walletPubKey)) {
|
||||
log.error('Invalid signatures in server response');
|
||||
error = true;
|
||||
}
|
||||
});
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
var myXPubKey = new Bitcore.HDPublicKey(myXPrivKey).toString();
|
||||
if (!_.contains(_.pluck(copayers, 'xPubKey'), myXPubKey)) {
|
||||
log.error('Server response does not contains our public keys')
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
module.exports = Verifier;
|
||||
|
|
|
@ -62,55 +62,30 @@ function API(opts) {
|
|||
};
|
||||
|
||||
|
||||
API.prototype._isWalletCorrupt = function(wallet, data) {
|
||||
var pubKey = Bitcore.PrivateKey.fromString(data.walletPrivKey).toPublicKey().toString();
|
||||
var fake = [];
|
||||
|
||||
if (data.n != wallet.copayers.length)
|
||||
return true;
|
||||
|
||||
var uniq = [];
|
||||
_.each(wallet.copayers, function(copayer) {
|
||||
if (uniq[copayer.xPubKey]++)
|
||||
return true;
|
||||
|
||||
if (!SignUtils.verify(copayer.xPubKey, copayer.xPubKeySignature, pubKey)) {
|
||||
fake.push(copayer);
|
||||
}
|
||||
});
|
||||
return fake.length > 0;
|
||||
};
|
||||
|
||||
|
||||
API.prototype._tryToComplete = function(data, cb) {
|
||||
var self = this;
|
||||
|
||||
var url = '/v1/wallets/';
|
||||
self._doGetRequest(url, data, function(err, wallet) {
|
||||
self._doGetRequest(url, data, function(err, ret) {
|
||||
if (err) return cb(err);
|
||||
var wallet = ret.wallet;
|
||||
|
||||
if (wallet.status === 'complete' && !data.verified) {
|
||||
|
||||
if (self._isWalletCorrupt(wallet, data)) {
|
||||
data.verified = 'corrupt';
|
||||
} else {
|
||||
data.verified = 'ok';
|
||||
}
|
||||
self.storage.save(data, function(err) {
|
||||
if (data.verified == 'corrupt') {
|
||||
return cb('Some copayers in the wallet could not be verified to have known the wallet secret');
|
||||
}
|
||||
return cb(err, data);
|
||||
});
|
||||
} else {
|
||||
if (wallet.status != 'complete')
|
||||
return cb('Wallet Incomplete');
|
||||
}
|
||||
|
||||
if (!Verifier.checkCopayers(wallet.copayers, data.walletPrivKey, data.xPrivKey, data.n))
|
||||
return cb('Some copayers in the wallet could not be verified to have known the wallet secret');
|
||||
|
||||
data.publicKeyRing = _.pluck(wallet.copayers, 'xPubKey')
|
||||
|
||||
self.storage.save(data, function(err) {
|
||||
return cb(err, data);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
API.prototype._loadAndCheck = function(cb) {
|
||||
var self = this;
|
||||
|
||||
|
@ -118,9 +93,6 @@ API.prototype._loadAndCheck = function(cb) {
|
|||
if (err || !data) {
|
||||
return cb(err || 'Wallet file not found.');
|
||||
}
|
||||
if (data.verified == 'corrupt') {
|
||||
return cb('The wallet is tagged as corrupt. Some of the copayers cannot be verified to have known the wallet secret.');
|
||||
}
|
||||
if (data.n > 1) {
|
||||
var pkrComplete = data.publicKeyRing && data.m && data.publicKeyRing.length === data.n;
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ describe(' client API ', function() {
|
|||
})
|
||||
|
||||
|
||||
it('should complain wallet is not complete ', function(done) {
|
||||
it('should handle incomple wallets', function(done) {
|
||||
var request = sinon.stub();
|
||||
|
||||
// Wallet request
|
||||
|
@ -64,7 +64,7 @@ describe(' client API ', function() {
|
|||
});
|
||||
})
|
||||
|
||||
it(' should reject wallets with bad signatures', function(done) {
|
||||
it('should reject wallets with bad signatures', function(done) {
|
||||
var request = sinon.stub();
|
||||
// Wallet request
|
||||
request.onCall(0).yields(null, {
|
||||
|
@ -78,7 +78,7 @@ describe(' client API ', function() {
|
|||
done();
|
||||
});
|
||||
})
|
||||
it(' should reject wallets with missing signatures ', function(done) {
|
||||
it('should reject wallets with missing signatures ', function(done) {
|
||||
var request = sinon.stub();
|
||||
// Wallet request
|
||||
request.onCall(0).yields(null, {
|
||||
|
@ -92,6 +92,23 @@ describe(' client API ', function() {
|
|||
done();
|
||||
});
|
||||
})
|
||||
|
||||
it('should reject wallets missing caller"s pubkey', function(done) {
|
||||
var request = sinon.stub();
|
||||
// Wallet request
|
||||
request.onCall(0).yields(null, {
|
||||
statusCode: 200,
|
||||
}, TestData.serverResponse.missingMyPubKey);
|
||||
|
||||
client.request = request;
|
||||
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.incompleteWallet22));
|
||||
client.createAddress(function(err, x) {
|
||||
err.should.contain('verified');
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe(' createAddress ', function() {
|
||||
|
|
|
@ -25,6 +25,27 @@ var storage = {
|
|||
|
||||
var serverResponse = {
|
||||
completeWallet: {
|
||||
wallet: {
|
||||
m: 2,
|
||||
n: 2,
|
||||
status: 'complete',
|
||||
publicKeyRing: ['tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
|
||||
'tpubD6NzVbkrYhZ4WSuBBLyubi8DHMipbFQcZoLJHjb21gEtznCEJMJhwkvaSshHVLtq8C1uNMKD4GtADVYY6WZt1cyT218JUm3PiNKYVkMATWV'
|
||||
],
|
||||
addressIndex: 0,
|
||||
copayers: [{
|
||||
xPubKey: 'tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
|
||||
xPubKeySignature: '3045022100ef86122060bbb7681db05486f8b1ee1579c5800e8da78182a87384f05542a4cc0220215ce7ef8c484b64178779414efdf2b7033d25ed752eebf4eb3241f9fa8e6b67',
|
||||
}, {
|
||||
xPubKey: 'tpubD6NzVbkrYhZ4YiXKYLGvNiQ5bZb9cBUHSBrxZn3xa6BuwZfBFgksTE8M4ZFBLWVJ4PLnAJs2JKhkpJVqsrJEAkGpb62rx62Bk4o4N5Lz8dQ',
|
||||
xPubKeySignature: '3045022100e03b069db333428153c306c9bf66ebc7f25e7d7f3d087e1ca7234fbbb1a47efa02207421fb375d0dd7a7f2116301f2cdf1bce88554a6c88a82d4ec9fb37fb6680ae8',
|
||||
}],
|
||||
pubKey: ' { "x": "b2903ab878ed1316f82b859e9807e23bab3d579175563e1068d2ed9c9e37873c", "y": "5f30165915557394223a58329c1527dfa0f34f483d8aed02e0638f9124dbddef", "compressed": true }',
|
||||
network: 'testnet',
|
||||
}},
|
||||
|
||||
missingMyPubKey: {
|
||||
wallet: {
|
||||
m: 2,
|
||||
n: 2,
|
||||
status: 'complete',
|
||||
|
@ -41,10 +62,11 @@ var serverResponse = {
|
|||
}],
|
||||
pubKey: ' { "x": "b2903ab878ed1316f82b859e9807e23bab3d579175563e1068d2ed9c9e37873c", "y": "5f30165915557394223a58329c1527dfa0f34f483d8aed02e0638f9124dbddef", "compressed": true }',
|
||||
network: 'testnet',
|
||||
},
|
||||
}},
|
||||
|
||||
|
||||
incompleteWallet: {
|
||||
wallet: {
|
||||
m: 2,
|
||||
n: 2,
|
||||
status: 'pending',
|
||||
|
@ -58,9 +80,10 @@ var serverResponse = {
|
|||
}],
|
||||
pubKey: ' { "x": "b2903ab878ed1316f82b859e9807e23bab3d579175563e1068d2ed9c9e37873c", "y": "5f30165915557394223a58329c1527dfa0f34f483d8aed02e0638f9124dbddef", "compressed": true }',
|
||||
network: 'testnet',
|
||||
},
|
||||
}},
|
||||
|
||||
corruptWallet22: {
|
||||
wallet: {
|
||||
m: 2,
|
||||
n: 2,
|
||||
status: 'complete',
|
||||
|
@ -74,8 +97,9 @@ var serverResponse = {
|
|||
xPubKey: 'tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
|
||||
xPubKeySignature: 'bababa',
|
||||
}],
|
||||
},
|
||||
}},
|
||||
corruptWallet222: {
|
||||
wallet: {
|
||||
m: 2,
|
||||
n: 2,
|
||||
status: 'complete',
|
||||
|
@ -85,7 +109,7 @@ var serverResponse = {
|
|||
copayers: [{
|
||||
xPubKey: 'tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
|
||||
}, ],
|
||||
}
|
||||
}},
|
||||
};
|
||||
|
||||
module.exports.serverResponse = serverResponse;
|
||||
|
|
Loading…
Reference in New Issue