diff --git a/lib/client/Verifier.js b/lib/client/Verifier.js index 42ae592..797233e 100644 --- a/lib/client/Verifier.js +++ b/lib/client/Verifier.js @@ -17,9 +17,6 @@ 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(); @@ -56,4 +53,11 @@ Verifier.checkCopayers = function(copayers, walletPrivKey, myXPrivKey, n) { }; +Verifier.checkTxProposal = function(data, txp) { + var header = txp.toAddress + '|' + txp.amount + '|' + (txp.message || ''); + if (!SignUtils.verify(header, txp.proposalSignature, data.signingPubKey)) return false; + + return Verifier.checkAddress(data, txp.changeAddress); +}; + module.exports = Verifier; diff --git a/lib/client/api.js b/lib/client/api.js index 066308d..3f0cd56 100644 --- a/lib/client/api.js +++ b/lib/client/api.js @@ -62,7 +62,6 @@ function API(opts) { }; - API.prototype._tryToComplete = function(data, cb) { var self = this; @@ -329,6 +328,10 @@ API.prototype.signTxProposal = function(txp, cb) { function(err, data) { if (err) return cb(err); + if (!Verifier.checkTxProposal(data, txp)) { + return cb(new ServerCompromisedError('Server sent fake transaction proposal')); + } + //Derive proper key to sign, for each input var privs = [], diff --git a/lib/server.js b/lib/server.js index ac1373d..b15ccf8 100644 --- a/lib/server.js +++ b/lib/server.js @@ -464,7 +464,7 @@ CopayServer.prototype.createTx = function(opts, cb) { if (!wallet.isComplete()) return cb(new ClientError('Wallet is not complete')); var copayer = wallet.getCopayer(self.copayerId); - var msg = opts.toAddress + '|' + opts.amount + '|' + opts.message; + var msg = opts.toAddress + '|' + opts.amount + '|' + (opts.message || ''); if (!self._verifySignature(msg, opts.proposalSignature, copayer.signingPubKey)) return cb(new ClientError('Invalid proposal signature')); diff --git a/test/integration/clientApi.js b/test/integration/clientApi.js index 07f29fd..699a777 100644 --- a/test/integration/clientApi.js +++ b/test/integration/clientApi.js @@ -126,6 +126,46 @@ describe(' client API ', function() { client.request = request; + client.createAddress(function(err, x) { + should.not.exist(err); + x.address.should.equal('2N3fA6wDtnebzywPkGuNK9KkFaEzgbPRRTq'); + done(); + }); + }) + it(' should detect fake addresses ', function(done) { + var response = { + createdOn: 1424105995, + address: '2N3fA6wDtnebzywPkGuNK9KkFaEzgbPRRTq', + path: 'm/2147483647/0/8', + publicKeys: ['03f6a5fe8db51bfbaf26ece22a3e3bc242891a47d3048fc70bc0e8c03a071ad76f'] + }; + var request = sinon.mock().yields(null, { + statusCode: 200 + }, response); + client.request = request; + client.createAddress(function(err, x) { + err.code.should.equal('SERVERCOMPROMISED'); + err.message.should.contain('fake address'); + done(); + }); + }) + }) + + describe(' createAddress ', function() { + it(' should check address ', function(done) { + + var response = { + createdOn: 1424105995, + address: '2N3fA6wDtnebzywPkGuNK9KkFaEzgbPRRTq', + path: 'm/2147483647/0/7', + publicKeys: ['03f6a5fe8db51bfbaf26ece22a3e3bc242891a47d3048fc70bc0e8c03a071ad76f'] + }; + var request = sinon.mock().yields(null, { + statusCode: 200 + }, response); + client.request = request; + + client.createAddress(function(err, x) { should.not.exist(err); x.address.should.equal('2N3fA6wDtnebzywPkGuNK9KkFaEzgbPRRTq'); diff --git a/test/integration/server.js b/test/integration/server.js index 85b6438..ae8ee1c 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -176,7 +176,7 @@ helpers.createProposalOpts = function(toAddress, amount, message, signingKey) { message: message, proposalSignature: null, }; - var msg = opts.toAddress + '|' + opts.amount + '|' + opts.message; + var msg = opts.toAddress + '|' + opts.amount + '|' + (opts.message || ''); try { opts.proposalSignature = SignUtils.sign(msg, signingKey); } catch (ex) {} @@ -706,7 +706,7 @@ describe('Copay server', function() { }); }); - it('should fail to create tx for address invalid address', function(done) { + it('should fail to create tx for invalid address', function(done) { helpers.createUtxos(server, wallet, [100, 200], function(utxos) { helpers.stubBlockExplorer(server, utxos); var txOpts = helpers.createProposalOpts('invalid address', 80, null, TestData.copayers[0].privKey);