From f439f23b61c0e2c6b11a6f4ea94d6600b2edde99 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Sat, 14 Feb 2015 12:54:00 -0300 Subject: [PATCH 1/4] add rm --- app.js | 12 +++++++++- bit-wallet/bit | 5 +++-- bit-wallet/bit-reject | 6 ++--- bit-wallet/bit-rm | 52 +++++++++++++++++++++++++++++++++++++++++++ lib/client/API.js | 25 +++++++++++++++++++++ 5 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 bit-wallet/bit-rm diff --git a/app.js b/app.js index 7cd3ccb..ceb23df 100644 --- a/app.js +++ b/app.js @@ -207,7 +207,17 @@ router.post('/v1/txproposals/:id/signatures/', function(req, res) { router.post('/v1/txproposals/:id/rejections', function(req, res) { getServerWithAuth(req, res, function(server) { req.body.txProposalId = req.params['id']; - server.signTx(req.body, function(err, txp) { + server.rejectTx(req.body, function(err, txp) { + if (err) return returnError(err, res, req); + res.end(); + }); + }); +}); + +router.delete('/v1/txproposals/:id/', function(req, res) { + getServerWithAuth(req, res, function(server) { + req.body.txProposalId = req.params['id']; + server.removePendingTx(req.body, function(err, txp) { if (err) return returnError(err, res, req); res.end(); }); diff --git a/bit-wallet/bit b/bit-wallet/bit index 06930e3..cffe423 100755 --- a/bit-wallet/bit +++ b/bit-wallet/bit @@ -11,8 +11,9 @@ program .command('addresses', 'list addresses') .command('balance', 'wallet balance') .command('send
', 'send bitcoins') - .command('sign ', 'sign a Transaction Proposal') - .command('reject ', 'reject a Transaction Proposal') + .command('sign ', 'sign a transaction proposal') + .command('reject [reason]', 'reject a transaction proposal') + .command('rm ', 'remove a transaction proposal') .parse(process.argv); diff --git a/bit-wallet/bit-reject b/bit-wallet/bit-reject index b4bb33f..4e2f127 100644 --- a/bit-wallet/bit-reject +++ b/bit-wallet/bit-reject @@ -9,14 +9,14 @@ program .version('0.0.1') .option('-c,--config [file]', 'Wallet config filename') .option('-v,--verbose', 'be verbose') - .usage('[options] ') + .usage('[options] [reason]') .parse(process.argv); var args = program.args; if (!args[0]) program.help(); - var txpid = args[0]; +var reason = args[1] || ''; var cli = new Client({ filename: program.config @@ -41,7 +41,7 @@ cli.getTxProposals({}, function(err, x) { }).join(' '));; var txp = txps[0]; - cli.rejectTxProposal(txp, function(err, x) { + cli.rejectTxProposal(txp, reason, function(err, x) { common.die(err); if (program.verbose) diff --git a/bit-wallet/bit-rm b/bit-wallet/bit-rm new file mode 100644 index 0000000..9a864e8 --- /dev/null +++ b/bit-wallet/bit-rm @@ -0,0 +1,52 @@ +#!/usr/bin/env node + +var _ = require('lodash'); +var program = require('commander'); +var ClientLib = require('../lib/clientlib.js'); +var common = require('./common'); + +program + .version('0.0.1') + .option('-c,--config [file]', 'Wallet config filename') + .option('-v,--verbose', 'be verbose') + .usage('[options] ') + .parse(process.argv); + +var args = program.args; +if (!args[0]) + program.help(); + +var txpid = args[0]; + +var cli = new ClientLib({ + filename: program.config +}); + +cli.txProposals({}, function(err, x) { + common.die(err); + + if (program.verbose) + console.log('* Raw Server Response:\n', x); //TODO + + var txps = _.filter(x, function(x) { + return _.endsWith(common.shortID(x.id), txpid); + }); + + if (!txps.length) + common.die('Could not find TX Proposal:' + txpid); + + if (txps.length > 1) + common.die('More than one TX Proposals match:' + txpid + ' : ' + _.map(txps, function(x) { + return x.id; + }).join(' '));; + + var txp = txps[0]; + cli.rm(txp, function(err, x) { + common.die(err); + + if (program.verbose) + console.log('* Raw Server Response:\n', x); //TODO + + console.log('Transaction rejected.'); + }); +}); diff --git a/lib/client/API.js b/lib/client/API.js index 615c58c..8f1ca41 100644 --- a/lib/client/API.js +++ b/lib/client/API.js @@ -359,4 +359,29 @@ API.prototype.rejectTxProposal = function(txp, reason, cb) { this._doPostRequest(url, args, data, cb); }; +ClientLib.prototype.rm = function(txp, cb) { + var self = this; + var data = this._loadAndCheck(); + + var url = '/v1/txproposals/' + txp.id; + var reqSignature = _signRequest(url, {}, data.signingPrivKey); + + request({ + headers: { + 'x-identity': data.copayerId, + 'x-signature': reqSignature, + }, + method: 'delete', + url: _getUrl(url), + json: true, + }, function(err, res, body) { + if (err) return cb(err); + if (res.statusCode != 200) { + _parseError(body); + return cb('Request error'); + } + return cb(null, body); + }); +}; + module.exports = API; From eca7d55afbfe6044605f6d67a7ef43098124e264 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Sun, 15 Feb 2015 12:46:38 -0300 Subject: [PATCH 2/4] update rm --- bit-wallet/bit-rm | 8 ++++---- cli.js | 30 ------------------------------ lib/client/API.js | 20 ++------------------ 3 files changed, 6 insertions(+), 52 deletions(-) delete mode 100644 cli.js diff --git a/bit-wallet/bit-rm b/bit-wallet/bit-rm index 9a864e8..960821c 100644 --- a/bit-wallet/bit-rm +++ b/bit-wallet/bit-rm @@ -2,7 +2,7 @@ var _ = require('lodash'); var program = require('commander'); -var ClientLib = require('../lib/clientlib.js'); +var Client = require('../lib/client'); var common = require('./common'); program @@ -18,11 +18,11 @@ if (!args[0]) var txpid = args[0]; -var cli = new ClientLib({ +var cli = new Client({ filename: program.config }); -cli.txProposals({}, function(err, x) { +cli.getTxProposals({}, function(err, x) { common.die(err); if (program.verbose) @@ -41,7 +41,7 @@ cli.txProposals({}, function(err, x) { }).join(' '));; var txp = txps[0]; - cli.rm(txp, function(err, x) { + cli.removeTxProposal(txp, function(err, x) { common.die(err); if (program.verbose) diff --git a/cli.js b/cli.js deleted file mode 100644 index 3e1e0b3..0000000 --- a/cli.js +++ /dev/null @@ -1,30 +0,0 @@ -var _ = require('lodash'); -var async = require('async'); -var log = require('npmlog'); -var fs = require('fs'); - -var CliLib = require('./lib/clilib'); - -try { - fs.unlinkSync('copay.dat'); -} catch (e) {} - -var cli = new CliLib({ - filename: 'copay.dat' -}); - -cli.createWallet('my wallet', 'me', 1, 1, 'testnet', function(err, secret) { - if (err) { - console.log(err); - process.exit(); - } - - cli.status(function(err, status) { - if (err) { - console.log(err); - process.exit(); - } - - console.log(status); - }) -}); diff --git a/lib/client/API.js b/lib/client/API.js index 8f1ca41..1bae91c 100644 --- a/lib/client/API.js +++ b/lib/client/API.js @@ -359,29 +359,13 @@ API.prototype.rejectTxProposal = function(txp, reason, cb) { this._doPostRequest(url, args, data, cb); }; -ClientLib.prototype.rm = function(txp, cb) { +ClientLib.prototype.removeTxProposal = function(txp, cb) { var self = this; var data = this._loadAndCheck(); var url = '/v1/txproposals/' + txp.id; - var reqSignature = _signRequest(url, {}, data.signingPrivKey); - request({ - headers: { - 'x-identity': data.copayerId, - 'x-signature': reqSignature, - }, - method: 'delete', - url: _getUrl(url), - json: true, - }, function(err, res, body) { - if (err) return cb(err); - if (res.statusCode != 200) { - _parseError(body); - return cb('Request error'); - } - return cb(null, body); - }); + this._doRequest('delete', url, {}, data, cb); }; module.exports = API; From 5d6c89599ac803cd0b1616f76aafd28b36376466 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Sun, 15 Feb 2015 13:03:48 -0300 Subject: [PATCH 3/4] bug fixes --- app.js | 2 +- bit-wallet/bit-reject | 21 +++++---------------- bit-wallet/bit-rm | 24 +++++------------------- bit-wallet/bit-sign | 21 +++++---------------- bit-wallet/common.js | 26 +++++++++++++++++++++++--- lib/client/API.js | 4 ++-- lib/server.js | 8 ++++---- 7 files changed, 45 insertions(+), 61 deletions(-) diff --git a/app.js b/app.js index ceb23df..99eba80 100644 --- a/app.js +++ b/app.js @@ -217,7 +217,7 @@ router.post('/v1/txproposals/:id/rejections', function(req, res) { router.delete('/v1/txproposals/:id/', function(req, res) { getServerWithAuth(req, res, function(server) { req.body.txProposalId = req.params['id']; - server.removePendingTx(req.body, function(err, txp) { + server.removePendingTx(req.body, function(err) { if (err) return returnError(err, res, req); res.end(); }); diff --git a/bit-wallet/bit-reject b/bit-wallet/bit-reject index 4e2f127..a2d7a9e 100644 --- a/bit-wallet/bit-reject +++ b/bit-wallet/bit-reject @@ -22,30 +22,19 @@ var cli = new Client({ filename: program.config }); -cli.getTxProposals({}, function(err, x) { +cli.getTxProposals({}, function(err, txps) { common.die(err); if (program.verbose) - console.log('* Raw Server Response:\n', x); //TODO + console.log('* Raw Server Response:\n', txps); //TODO - var txps = _.filter(x, function(x) { - return _.endsWith(common.shortID(x.id), txpid); - }); + var txp = common.findOneTxProposal(txps, txpid); - if (!txps.length) - common.die('Could not find TX Proposal:' + txpid); - - if (txps.length > 1) - common.die('More than one TX Proposals match:' + txpid + ' : ' + _.map(txps, function(x) { - return x.id; - }).join(' '));; - - var txp = txps[0]; - cli.rejectTxProposal(txp, reason, function(err, x) { + cli.rejectTxProposal(txp, reason, function(err, tx) { common.die(err); if (program.verbose) - console.log('* Raw Server Response:\n', x); //TODO + console.log('* Raw Server Response:\n', tx); //TODO console.log('Transaction rejected.'); }); diff --git a/bit-wallet/bit-rm b/bit-wallet/bit-rm index 960821c..45902eb 100644 --- a/bit-wallet/bit-rm +++ b/bit-wallet/bit-rm @@ -22,31 +22,17 @@ var cli = new Client({ filename: program.config }); -cli.getTxProposals({}, function(err, x) { +cli.getTxProposals({}, function(err, txps) { common.die(err); if (program.verbose) - console.log('* Raw Server Response:\n', x); //TODO + console.log('* Raw Server Response:\n', txps); //TODO - var txps = _.filter(x, function(x) { - return _.endsWith(common.shortID(x.id), txpid); - }); + var txp = common.findOneTxProposal(txps, txpid); - if (!txps.length) - common.die('Could not find TX Proposal:' + txpid); - - if (txps.length > 1) - common.die('More than one TX Proposals match:' + txpid + ' : ' + _.map(txps, function(x) { - return x.id; - }).join(' '));; - - var txp = txps[0]; - cli.removeTxProposal(txp, function(err, x) { + cli.removeTxProposal(txp, function(err) { common.die(err); - if (program.verbose) - console.log('* Raw Server Response:\n', x); //TODO - - console.log('Transaction rejected.'); + console.log('Transaction removed.'); }); }); diff --git a/bit-wallet/bit-sign b/bit-wallet/bit-sign index 68289a6..f4d8348 100755 --- a/bit-wallet/bit-sign +++ b/bit-wallet/bit-sign @@ -22,30 +22,19 @@ var cli = new ClientLib({ filename: program.config }); -cli.getTxProposals({}, function(err, x) { +cli.getTxProposals({}, function(err, txps) { common.die(err); if (program.verbose) - console.log('* Raw Server Response:\n', x); //TODO + console.log('* Raw Server Response:\n', txps); //TODO - var txps = _.filter(x, function(x) { - return _.endsWith(common.shortID(x.id), txpid); - }); + var txp = common.findOneTxProposal(txps, txpid); - if (!txps.length) - common.die('Could not find TX Proposal:' + txpid); - - if (txps.length > 1) - common.die('More than one TX Proposals match:' + txpid + ' : ' + _.map(txps, function(x) { - return x.id; - }).join(' '));; - - var txp = txps[0]; - cli.signTxProposal(txp, function(err, x) { + cli.signTxProposal(txp, function(err, tx) { common.die(err); if (program.verbose) - console.log('* Raw Server Response:\n', x); //TODO + console.log('* Raw Server Response:\n', tx); //TODO console.log('Transaction signed.'); }); diff --git a/bit-wallet/common.js b/bit-wallet/common.js index 5fe7337..8671e0d 100644 --- a/bit-wallet/common.js +++ b/bit-wallet/common.js @@ -1,3 +1,7 @@ +'use strict'; + +var _ = require('lodash'); + var common = function() {}; @@ -9,14 +13,14 @@ var die = common.die = function(err) { }; common.parseMN = function(MN) { - if (!MN) + if (!MN) die('No m-n parameter'); var mn = MN.split('-'); - var m = parseInt(mn[0]); + var m = parseInt(mn[0]); var n = parseInt(mn[1]); - if (!m || ! n) { + if (!m || !n) { die('Bad m-n parameter'); } @@ -28,4 +32,20 @@ common.shortID = function(id) { return id.substr(id.length - 4); }; +common.findOneTxProposal = function(txps, id) { + var matches = _.filter(txps, function(tx) { + return _.endsWith(common.shortID(tx.id), id); + }); + + if (!matches.length) + common.die('Could not find TX Proposal:' + id); + + if (matches.length > 1) + common.die('More than one TX Proposals match:' + id + ' : ' + _.map(matches, function(tx) { + return tx.id; + }).join(' '));; + + return matches[0]; +}; + module.exports = common; diff --git a/lib/client/API.js b/lib/client/API.js index 1bae91c..df263c2 100644 --- a/lib/client/API.js +++ b/lib/client/API.js @@ -84,7 +84,7 @@ API.prototype._loadAndCheck = function() { return data; }; -ClientLib.prototype._doRequest = function(method, url, args, data, cb) { +API.prototype._doRequest = function(method, url, args, data, cb) { var reqSignature = _signRequest(method, url, args, data.signingPrivKey); var absUrl = _getUrl(url); request({ @@ -359,7 +359,7 @@ API.prototype.rejectTxProposal = function(txp, reason, cb) { this._doPostRequest(url, args, data, cb); }; -ClientLib.prototype.removeTxProposal = function(txp, cb) { +API.prototype.removeTxProposal = function(txp, cb) { var self = this; var data = this._loadAndCheck(); diff --git a/lib/server.js b/lib/server.js index d186758..21b4d7f 100644 --- a/lib/server.js +++ b/lib/server.js @@ -547,19 +547,19 @@ CopayServer.prototype.removeWallet = function(opts, cb) { * removePendingTx * * @param opts - * @param {string} opts.id - The tx id. + * @param {string} opts.txProposalId - The tx id. * @return {undefined} */ CopayServer.prototype.removePendingTx = function(opts, cb) { var self = this; - if (!Utils.checkRequired(opts, ['id'])) + if (!Utils.checkRequired(opts, ['txProposalId'])) return cb(new ClientError('Required argument missing')); Utils.runLocked(self.walletId, cb, function(cb) { self.getTx({ - id: opts.id + id: opts.txProposalId, }, function(err, txp) { if (err) return cb(err); @@ -576,7 +576,7 @@ CopayServer.prototype.removePendingTx = function(opts, cb) { return cb(new ClientError('Cannot remove a proposal signed/rejected by other copayers')); self._notify('transactionProposalRemoved'); - self.storage.removeTx(self.walletId, opts.id, cb); + self.storage.removeTx(self.walletId, txp.id, cb); }); }); }; From eba565661cd332abb4ed279945153ba8d63fcbe3 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Sun, 15 Feb 2015 13:08:34 -0300 Subject: [PATCH 4/4] fix integration tests --- test/integration.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/integration.js b/test/integration.js index e80218c..1faf0c1 100644 --- a/test/integration.js +++ b/test/integration.js @@ -1499,7 +1499,7 @@ describe('Copay server', function() { it('should allow creator to remove an unsigned TX', function(done) { server.removePendingTx({ - id: txp.id + txProposalId: txp.id }, function(err) { should.not.exist(err); server.getPendingTxs({}, function(err, txs) { @@ -1516,7 +1516,7 @@ describe('Copay server', function() { signatures: signatures, }, function(err) { server.removePendingTx({ - id: txp.id + txProposalId: txp.id }, function(err) { should.not.exist(err); server.getPendingTxs({}, function(err, txs) { @@ -1530,7 +1530,7 @@ describe('Copay server', function() { it('should not allow non-creator copayer to remove an unsigned TX ', function(done) { helpers.getAuthServer(wallet.copayers[1].id, function(server2) { server2.removePendingTx({ - id: txp.id + txProposalId: txp.id }, function(err) { err.message.should.contain('creators'); server2.getPendingTxs({}, function(err, txs) { @@ -1550,7 +1550,7 @@ describe('Copay server', function() { }, function(err) { should.not.exist(err); server.removePendingTx({ - id: txp.id + txProposalId: txp.id }, function(err) { err.message.should.contain('other copayers'); done();