add tests to server internals

This commit is contained in:
Matias Alejo Garcia 2015-02-22 03:46:47 -03:00
parent 8d382c1e88
commit fa3355ef99
7 changed files with 166 additions and 189 deletions

View File

@ -7,8 +7,8 @@ var utils = require('./cli-utils');
program = utils.configureCommander(program);
program
.option('-i, --input [filename]', 'input file')
.option('-o, --output [filename]', 'output file')
.option('-i, --input [filename]', 'use input file instead of server\'s')
.option('-o, --output [filename]', 'write tx to output file')
.parse(process.argv);
var args = program.args;

View File

@ -178,7 +178,7 @@ API.prototype._doRequest = function(method, url, args, data, cb) {
return cb(_parseError(body));
}
return cb(null, body);
return cb(null, body, res.header);
});
};
@ -490,8 +490,15 @@ API.prototype.import = function(str, cb) {
API.prototype.parseTxProposals = function(txps, cb) {
var self = this;
this._loadAndCheck(function(err, data) {
this._load(function(err, data) {
if (err) return cb(err);
if (data.n > 1) {
var pkrComplete = data.publicKeyRing && data.m && data.publicKeyRing.length === data.n;
if (!pkrComplete) {
return cb('Wallet Incomplete');
}
}
_processTxps(txps, data.sharedEncryptingKey);

View File

@ -14,6 +14,13 @@ log.level = 'debug';
var ExpressApp = function() {};
/**
* start
*
* @param opts.WalletService options for WalletService class
* @param opts.basePath
* @param opts.disableLogs
*/
ExpressApp.start = function(opts) {
opts = opts || {};
@ -28,7 +35,7 @@ ExpressApp.start = function(opts) {
});
var allowCORS = function(req, res, next) {
if ('OPTIONS' == req.method) {
res.send(200);
res.sendStatus(200);
res.end();
return;
}
@ -42,7 +49,12 @@ ExpressApp.start = function(opts) {
limit: POST_LIMIT
}));
app.use(require('morgan')('dev'));
if (!opts.disableLogs) {
// TODO access.log
//var accessLogStream = fs.createWriteStream(__dirname + '/access.log', {flags: 'a'})
//app.use(morgan('combined', {stream: accessLogStream}))
app.use(require('morgan')('dev'));
}
var router = express.Router();
@ -51,7 +63,9 @@ ExpressApp.start = function(opts) {
if (err instanceof WalletService.ClientError) {
var status = (err.code == 'NOTAUTHORIZED') ? 401 : 400;
log.error('Err: ' + status + ':' + req.url + ' :' + err.code + ':' + err.message);
if (!opts.disableLogs)
log.error('Err: ' + status + ':' + req.url + ' :' + err.code + ':' + err.message);
res.status(status).json({
code: err.code,
error: err.message,
@ -64,7 +78,9 @@ ExpressApp.start = function(opts) {
}
var m = message || err.toString();
log.error('Error: ' + req.url + ' :' + code + ':' + m);
if (!opts.disableLogs)
log.error('Err: ' + req.url + ' :' + code + ':' + m);
res.status(code || 500).json({
error: m,
}).end();
@ -106,7 +122,6 @@ ExpressApp.start = function(opts) {
var server = WalletService.getInstance();
server.createWallet(req.body, function(err, walletId) {
if (err) return returnError(err, res, req);
res.json({
walletId: walletId,
});
@ -255,7 +270,7 @@ ExpressApp.start = function(opts) {
res.end();
});
});
app.use(opts.base_path || '/copay/api', router);
app.use(opts.basePath || '/copay/api', router);
return app;
};

View File

@ -432,28 +432,22 @@ WalletService.prototype.getBalance = function(opts, cb) {
WalletService.prototype._selectUtxos = function(txp, utxos) {
console.log('[server.js.434:utxos:]',utxos); //TODO
var i = 0;
var total = 0;
var selected = [];
var inputs = _.sortBy(utxos, 'amount');
console.log('[server.js.438:inputs:]',inputs); //TODO
while (i < inputs.length) {
selected.push(inputs[i]);
total += inputs[i].satoshis;
console.log('[server.js.443]'); //TODO
if (total >= txp.amount + Bitcore.Transaction.FEE_PER_KB) {
try {
// Check if there are enough fees
txp.inputs = selected;
console.log('[server.js.449]'); //TODO
var raw = txp.getRawTx();
return;
} catch (ex) {
console.log('[server.js.453:ex:]',ex); //TODO
if (ex.name != 'bitcore.ErrorTransactionFeeError') {
throw ex.message;
}
@ -504,7 +498,6 @@ WalletService.prototype.createTx = function(opts, cb) {
return cb(new ClientError('DUSTAMOUNT', 'Amount below dust threshold'));
self._getUtxos(function(err, utxos) {
console.log('[server.js.506:utxos:]',utxos); //TODO
if (err) return cb(err);
var changeAddress = wallet.createAddress(true);
@ -536,7 +529,6 @@ console.log('[server.js.523:ex:]',ex); //TODO
txp.inputPaths = _.pluck(txp.inputs, 'path');
console.log('[server.js.530]'); //TODO
self.storage.storeAddressAndWallet(wallet, changeAddress, function(err) {
if (err) return cb(err);

View File

@ -11,7 +11,6 @@ var request = require('supertest');
var Client = require('../../lib/client');
var API = Client.API;
var Bitcore = require('bitcore');
var TestData = require('./clienttestdata');
var WalletUtils = require('../../lib/walletutils');
var ExpressApp = require('../../lib/expressapp');
var Storage = require('../../lib/storage');
@ -138,7 +137,8 @@ describe('client API ', function() {
WalletService: {
storage: storage,
blockExplorer: blockExplorerMock,
}
},
disableLogs: true,
});
// Generates 5 clients
_.each(_.range(5), function(i) {
@ -157,6 +157,70 @@ describe('client API ', function() {
blockExplorerMock.reset();
});
describe('Server internals', function() {
it('should allow cors', function(done) {
clients[0]._doRequest('options', '/', null, {}, function(err, x, headers) {
headers['access-control-allow-origin'].should.equal('*');
should.exist(headers['access-control-allow-methods']);
should.exist(headers['access-control-allow-headers']);
done();
});
});
it('should handle critical errors', function(done) {
var s = sinon.stub();
s.storeWallet = sinon.stub().yields('bigerror');
s.fetchWallet = sinon.stub().yields(null);
app = ExpressApp.start({
WalletService: {
storage: s,
blockExplorer: blockExplorerMock,
},
disableLogs: true,
});
var s2 = sinon.stub();
s2.load = sinon.stub().yields(null);
var client = new Client({
storage: s2,
});
client.request = helpers.getRequest(app);
client.createWallet('1', '2', 1, 1, 'testnet',
function(err) {
err.code.should.equal('ERROR');
done();
});
});
it('should handle critical errors (Case2)', function(done) {
var s = sinon.stub();
s.storeWallet = sinon.stub().yields({
code: 501,
message: 'wow'
});
s.fetchWallet = sinon.stub().yields(null);
app = ExpressApp.start({
WalletService: {
storage: s,
blockExplorer: blockExplorerMock,
},
disableLogs: true,
});
var s2 = sinon.stub();
s2.load = sinon.stub().yields(null);
var client = new Client({
storage: s2,
});
client.request = helpers.getRequest(app);
client.createWallet('1', '2', 1, 1, 'testnet',
function(err) {
err.code.should.equal('ERROR');
done();
});
});
});
describe('Wallet Creation', function() {
it('should check balance in a 1-1 ', function(done) {
helpers.createAndJoinWallet(clients, 1, 1, function(err) {
@ -362,6 +426,70 @@ describe('client API ', function() {
});
});
});
it('should be able get Tx proposals from a file', function(done) {
helpers.createAndJoinWallet(clients, 1, 2, function(err, w) {
should.not.exist(err);
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
blockExplorerMock.setUtxo(x0, 1, 1);
var opts = {
amount: 10000000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hello 1-1',
};
clients[1].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
clients[1].getTxProposals({
getRawTxps: true
}, function(err, txs, rawTxps) {
should.not.exist(err);
clients[0].parseTxProposals(rawTxps, function(err, txs2) {
should.not.exist(err);
txs[0].should.deep.equal(txs2[0]);
done();
});
});
});
});
});
});
it('should detect fakes from Tx proposals file', function(done) {
helpers.createAndJoinWallet(clients, 1, 2, function(err, w) {
should.not.exist(err);
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
blockExplorerMock.setUtxo(x0, 1, 1);
var opts = {
amount: 10000000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hello 1-1',
};
clients[1].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
clients[1].getTxProposals({
getRawTxps: true
}, function(err, txs, rawTxps) {
should.not.exist(err);
//Tamper
rawTxps[0].amount++;
clients[0].parseTxProposals(rawTxps, function(err, txs2) {
err.code.should.equal('SERVERCOMPROMISED');
done();
});
});
});
});
});
});
});
describe('Address Creation', function() {

View File

@ -1,168 +0,0 @@
var storage = {
wallet11: {
"m": 1,
"n": 1,
"walletPrivKey": "{\"bn\":\"6b862ffbfc90a37a2fedbbcfea91c6a4e49f49b6aaa322b6e16c46bfdbe71a38\",\"compressed\":true,\"network\":\"livenet\"}",
"network": "testnet",
"xPrivKey": "tprv8ZgxMBicQKsPeisyNJteQXZnb7CnhYc4TVAyxxicXuxMjK1rmaqVq1xnXtbSTPxUKKL9h5xJhUvw1AKfDD3i98A82eJWSYRWYjmPksewFKR",
"copayerId": "a84daa08-17b5-45ad-84cd-e275f3b07123",
"signingPrivKey": "42798f82c4ed9ace4d66335165071edf180e70bc0fc08dacb3e35185a2141d5b",
"publicKeyRing": ["tpubD6NzVbkrYhZ4YBumFxZEowDuA8iirsny2nmmFUkuxBkkZoGdPyf61Waei3tDYvVa1yqW82Xhmmd6oiibeDyM1MS3zTiky7Yg75UEV9oQhFJ"]
},
incompleteWallet22: {
"m": 2,
"n": 2,
"walletPrivKey": "L2Fu6TM1AqSNBaQcjgjvYjGf3EzS3MVSTwEeTw3bvy52x7ZkffWj",
"network": "testnet",
"secret": "b6f57154-0df8-4845-a61d-47ecd648c2d4:eab5a55d9214845ee8d13ea1033e42ec8d7f780ae6e521d830252a80433e91a5:T",
"xPrivKey": "tprv8ZgxMBicQKsPfFVXegcKyJjy2Y5DSrHNrtGBHG1f9pPX75QQdHwHGjWUtR7cCUXV7QcCCDon4cieHWTYscy8M7oXwF3qd3ssfBiV9M68bPB",
"copayerId": "3fc03e7a-6ebc-409b-a4b7-45b14d5a8199",
"signingPrivKey": "0d3c796fb12e387c4b5a5c566312b2b22fa0553ca041d859e3f0987215ca3a4f",
"publicKeyRing": []
},
complete22: {
"xPrivKey": "xprv9s21ZrQH143K3nwnRt6W25h7smm4k4nbuN4QKnNkTMDHFcB11wJXYF78TpwQ3xKjik9M66nRd9WUiHB5C8XgoWSbpMRMc2AxpcUNUsi4thi",
"m": 2,
"n": 2,
"publicKeyRing": ["xpub661MyMwAqRbcGzNFbVQLh6CV6ukHuhBn4Bf4CGrQ6pFfNNdJ3pxrEVDtFHGsTzyz6Py23FhP8GWAqew3PsvnstEs2iayH1PK5Mx1bSVSEAG", "xpub661MyMwAqRbcGH2FXudWPDdrRobZ9XWTGaz18AnN1gkG8QW9ZUcn63RcK5qJJ5DXYXeAWBNqprdvvg8VHA5twmBHCUc6gWygXkwmU1Dohwh"],
"copayerId": "c6ef9ad6de90b16174a0c0bdc430238ef6c04cb12e3bafa7c46e5acfb2b9d0b9",
"signingPrivKey": "KyhU3befBaePqHuPQNNyY1XFUgnArR3GUKZpZwV5vS7u1pcR3uzB",
"sharedEncryptingKey": "ezDRS2NRchMJLf1IWtjL5A==",
"network": "livenet"
},
complete11: {
"copayerId": "56cb00afd85f4f37fa900ac4e367676f2eb6189a773633eb9f119eb21a22ba44",
"xPrivKey": "tprv8ZgxMBicQKsPdjYWSKKh8SuMZAQ6K3J6v5H3A8ZVyyvXk4h1xft3qeRTmCZbxQB77n3ndfF6G4AevqgpiAVuCmZqYURH3wzSQviTvP1nkYN",
"publicKeyRing": ["tpubD6NzVbkrYhZ4XCaJKxzHXrZU8Bv2UNV1VNspSeboQFivaYwnb4he293KwLPxnNNSBEj3RAE5EEaHqPWatzexGd613hGMLLQz5BEgjtpgWnZ"],
"network": "testnet",
"m": 1,
"n": 1,
"signingPrivKey": "KxyNf4A1Td61GMrnC6LNQYsfE9zKvgsFmmgkPYrPoJHva4j9YSL1",
"walletPrivKey": "L4JHs2ZggZkEuRLffH2WVe337nwZWMxytxViLLGyAfGREk6bUCXo",
"sharedEncryptingKey": "ezDRS2NRchMJLf1IWtjL5A=="
},
};
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',
publicKeyRing: ['tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
'tpubD6NzVbkrYhZ4WSuBBLyubi8DHMipbFQcZoLJHjb21gEtznCEJMJhwkvaSshHVLtq8C1uNMKD4GtADVYY6WZt1cyT218JUm3PiNKYVkMATWV'
],
addressIndex: 0,
copayers: [{
xPubKey: 'tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
xPubKeySignature: '3045022100ef86122060bbb7681db05486f8b1ee1579c5800e8da78182a87384f05542a4cc0220215ce7ef8c484b64178779414efdf2b7033d25ed752eebf4eb3241f9fa8e6b67',
}, {
xPubKey: 'tpubD6NzVbkrYhZ4WSuBBLyubi8DHMipbFQcZoLJHjb21gEtznCEJMJhwkvaSshHVLtq8C1uNMKD4GtADVYY6WZt1cyT218JUm3PiNKYVkMATWV',
xPubKeySignature: '3044022025c93b418ebdbb66a0f2b21af709420e8ae769bf054f29aaa252cb5417c46a2302205e0c8b931324736b7eea4971a48039614e19abe26e13ab0ef1547aef92b55aab',
}],
pubKey: ' { "x": "b2903ab878ed1316f82b859e9807e23bab3d579175563e1068d2ed9c9e37873c", "y": "5f30165915557394223a58329c1527dfa0f34f483d8aed02e0638f9124dbddef", "compressed": true }',
network: 'testnet',
}
},
incompleteWallet: {
wallet: {
m: 2,
n: 2,
status: 'pending',
publicKeyRing: ['tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
'tpubD6NzVbkrYhZ4WSuBBLyubi8DHMipbFQcZoLJHjb21gEtznCEJMJhwkvaSshHVLtq8C1uNMKD4GtADVYY6WZt1cyT218JUm3PiNKYVkMATWV'
],
addressIndex: 0,
copayers: [{
xPubKey: 'tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
xPubKeySignature: '3045022100ef86122060bbb7681db05486f8b1ee1579c5800e8da78182a87384f05542a4cc0220215ce7ef8c484b64178779414efdf2b7033d25ed752eebf4eb3241f9fa8e6b67',
}],
pubKey: ' { "x": "b2903ab878ed1316f82b859e9807e23bab3d579175563e1068d2ed9c9e37873c", "y": "5f30165915557394223a58329c1527dfa0f34f483d8aed02e0638f9124dbddef", "compressed": true }',
network: 'testnet',
}
},
corruptWallet22: {
wallet: {
m: 2,
n: 2,
status: 'complete',
publicKeyRing: ['tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
'tpubD6NzVbkrYhZ4WSuBBLyubi8DHMipbFQcZoLJHjb21gEtznCEJMJhwkvaSshHVLtq8C1uNMKD4GtADVYY6WZt1cyT218JUm3PiNKYVkMATWV'
],
copayers: [{
xPubKey: 'tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
xPubKeySignature: '3045022100ef86122060bbb7681db05486f8b1ee1579c5800e8da78182a87384f05542a4cc0220215ce7ef8c484b64178779414efdf2b7033d25ed752eebf4eb3241f9fa8e6b67',
}, {
xPubKey: 'tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
xPubKeySignature: 'bababa',
}],
}
},
corruptWallet222: {
wallet: {
m: 2,
n: 2,
status: 'complete',
publicKeyRing: ['tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
'tpubD6NzVbkrYhZ4WSuBBLyubi8DHMipbFQcZoLJHjb21gEtznCEJMJhwkvaSshHVLtq8C1uNMKD4GtADVYY6WZt1cyT218JUm3PiNKYVkMATWV'
],
copayers: [{
xPubKey: 'tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
}, ],
}
},
pendingTxs: [{
version: '1.0.0',
createdOn: 1424287779,
id: '01424287779165d80a7123-f5c4-4144-ac1b-663220c01c55',
creatorId: '02da4d1bd797b41a5565fe54f22583051bd3c29dbbc86eedadb6af6e9200af1048',
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
amount: 10000,
message: '{"iv":"vDH4J15lBiokSP+iUS4ofA==","v":1,"iter":1,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","ct":"X/vPh+vh/Qv8IRSx"}',
changeAddress: '2Mu4nmHhBWFk766M4yXJi2oyi59HZLKHWqn',
inputs: [{
address: '2MvBhgsQX6EusXvNGdcjM5dschDkaos1uuk',
txid: '006a2915d8f1811620f8b83357869a94c53714f90ce4be4a5ca0d5305a21400d',
vout: 0,
scriptPubKey: 'a914203dd60a7659995a6e3bba7caac3c2d684c836ce87',
amount: 0.1,
path: 'm/2147483647/0/0',
publicKeys: ['0371629fe3547002723ef57ad4dae0d97653cf89b0a570637cffca2f23982f0f92']
}],
requiredSignatures: 1,
requiredRejections: 1,
status: 'pending',
inputPaths: ['m/2147483647/0/0'],
actions: {},
creatorName: 'ematiu'
}],
};
module.exports.serverResponse = serverResponse;
module.exports.storage = storage;

View File

@ -100,13 +100,15 @@ helpers.stubUtxos = function(server, wallet, amounts, cb) {
var utxos = _.map(amounts, function(amount, i) {
var address = addresses[i % addresses.length];
return {
var obj = {
txid: helpers.randomTXID(),
vout: Math.floor((Math.random() * 10) + 1),
satoshis: helpers.toSatoshi(amount).toString(),
scriptPubKey: address.getScriptPubKey(wallet.m).toBuffer().toString('hex'),
address: address.address,
};
obj.toObject = function() {return obj;};
return obj;
});
blockExplorer.getUnspentUtxos = sinon.stub().callsArgWith(1, null, utxos);
@ -191,6 +193,7 @@ describe('Copay server', function() {
helpers.offset = 0;
});
describe('#getInstanceWithAuth', function() {
beforeEach(function() {});