From 48b5a21c2d2de953f687c667b6ee8cdf5857a21c Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 16 Mar 2015 14:52:16 -0300 Subject: [PATCH 1/9] replace copay with bws in base url --- lib/api.js | 3 ++- test/client.js | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/api.js b/lib/api.js index c61aca0c..b9dcb187 100644 --- a/lib/api.js +++ b/lib/api.js @@ -17,7 +17,8 @@ var Verifier = require('./verifier'); var ServerCompromisedError = require('./servercompromisederror'); var ClientError = require('./clienterror'); -var BASE_URL = 'http://localhost:3001/copay/api'; +var BASE_URL = 'http://localhost:3001/bws/api'; + var WALLET_ENCRYPTION_OPTS = { iter: 5000 }; diff --git a/test/client.js b/test/client.js index a5f14b96..de6ec440 100644 --- a/test/client.js +++ b/test/client.js @@ -15,7 +15,6 @@ var Bitcore = WalletUtils.Bitcore; var BWS = require('bitcore-wallet-service'); var Client = require('../lib'); -console.log('[client.js.18:BWS:]', BWS); //TODO var ExpressApp = BWS.ExpressApp; var Storage = BWS.Storage; var TestData = require('./testdata'); From e9d97bc8b8e9edca4288a98ef7a85bf81ec89a83 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 16 Mar 2015 15:11:46 -0300 Subject: [PATCH 2/9] remove unused code --- lib/api.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/api.js b/lib/api.js index b9dcb187..bbd31bd9 100644 --- a/lib/api.js +++ b/lib/api.js @@ -513,7 +513,6 @@ API.prototype.recreateWallet = function(cb) { var walletId = body.walletId; - var secret = WalletUtils.toSecret(walletId, walletPrivKey, self.credentials.network); var i = 1; async.each(self.credentials.publicKeyRing, function(item, next) { var copayerName; From bf3bb544fb206049a469b56ce6af596ff11e2b08 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 16 Mar 2015 15:12:37 -0300 Subject: [PATCH 3/9] remove #toString & #fromString --- lib/api.js | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/lib/api.js b/lib/api.js index bbd31bd9..1609de5b 100644 --- a/lib/api.js +++ b/lib/api.js @@ -226,23 +226,6 @@ API.prototype.import = function(str, opts) { this.credentials = credentials; }; -/** - * Return a serialized object with credentials - */ -API.prototype.toString = function() { - $.checkState(this.credentials); - return this.credentials.toObject(); -}; - -/** - * Get credentials from an object - * - * @param {Object} str - */ -API.prototype.fromString = function(str) { - this.credentials = Credentials.fromObject(str); -}; - /** * Do an HTTP request * @private From bbb05c8a5509342a898644159c419a52721a9836 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 16 Mar 2015 15:14:45 -0300 Subject: [PATCH 4/9] remove encryption from #export/#import --- lib/api.js | 20 ++------------------ test/client.js | 30 ------------------------------ 2 files changed, 2 insertions(+), 48 deletions(-) diff --git a/lib/api.js b/lib/api.js index 1609de5b..fd3ff2d0 100644 --- a/lib/api.js +++ b/lib/api.js @@ -163,7 +163,6 @@ API.prototype.seedFromExtendedPrivateKey = function(xPrivKey) { * * @param {Object} opts * @param {Boolean} opts.compressed - * @param {String} opts.password * @param {Boolean} opts.noSign */ API.prototype.export = function(opts) { @@ -184,10 +183,6 @@ API.prototype.export = function(opts) { output = JSON.stringify(cred.toObj()); } - if (opts.password) { - output = sjcl.encrypt(opts.password, output, WALLET_ENCRYPTION_OPTS); - } - return output; } @@ -197,28 +192,17 @@ API.prototype.export = function(opts) { * * @param {Object} opts * @param {Boolean} opts.compressed - * @param {String} opts.password */ API.prototype.import = function(str, opts) { opts = opts || {}; - var input = str; - if (opts.password) { - try { - input = sjcl.decrypt(opts.password, input); - } catch (ex) { - throw ex; - throw new Error('Incorrect password'); - } - } - var credentials; try { if (opts.compressed) { - credentials = Credentials.importCompressed(input); + credentials = Credentials.importCompressed(str); // TODO: complete missing fields that live on the server only such as: walletId, walletName, copayerName } else { - credentials = Credentials.fromObj(JSON.parse(input)); + credentials = Credentials.fromObj(JSON.parse(str)); } } catch (ex) { throw new Error('Error importing from source'); diff --git a/test/client.js b/test/client.js index de6ec440..dfbbef39 100644 --- a/test/client.js +++ b/test/client.js @@ -983,34 +983,6 @@ describe('client API ', function() { importedClient.credentials.walletName.should.equal(walletName); importedClient.credentials.copayerName.should.equal(copayerName); }); - it('should export & import encrypted', function() { - var xPrivKey = clients[0].credentials.xPrivKey; - should.exist(xPrivKey); - - var exported = clients[0].export({ - password: '123' - }); - exported.should.not.contain(xPrivKey); - - importedClient = helpers.newClient(app); - importedClient.import(exported, { - password: '123' - }); - should.exist(importedClient.credentials.xPrivKey); - importedClient.credentials.xPrivKey.should.equal(xPrivKey); - }); - it('should export & import compressed & encrypted', function() { - var exported = clients[0].export({ - compressed: true, - password: '123' - }); - - importedClient = helpers.newClient(app); - importedClient.import(exported, { - compressed: true, - password: '123' - }); - }); it('should export without signing rights', function() { clients[0].canSign().should.be.true; var exported = clients[0].export({ @@ -1025,8 +997,6 @@ describe('client API ', function() { describe('Fail', function() { it.skip('should fail to export compressed & import uncompressed', function() {}); it.skip('should fail to export uncompressed & import compressed', function() {}); - it.skip('should fail to export unencrypted & import with password', function() {}); - it.skip('should fail to export encrypted & import with incorrect password', function() {}); }); }); From 1d178a3936993e29978fb93e922913a0323f0a96 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 16 Mar 2015 15:16:15 -0300 Subject: [PATCH 5/9] wrap errors in Error class --- lib/api.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/api.js b/lib/api.js index fd3ff2d0..564e85ae 100644 --- a/lib/api.js +++ b/lib/api.js @@ -350,7 +350,7 @@ API.prototype.openWallet = function(cb) { if (err) return cb(err); var wallet = ret.wallet; - if (wallet.status != 'complete') return cb('Wallet Incomplete'); + if (wallet.status != 'complete') return cb(new Error('Wallet Incomplete')); if (!!self.credentials.walletPrivKey) { if (!Verifier.checkCopayers(self.credentials, wallet.copayers)) { @@ -390,7 +390,7 @@ API.prototype.createWallet = function(walletName, copayerName, m, n, network, cb var self = this; network = network || 'livenet'; - if (!_.contains(['testnet', 'livenet'], network)) return cb('Invalid network'); + if (!_.contains(['testnet', 'livenet'], network)) return cb(new Error('Invalid network')); if (!self.credentials) { log.info('Generating new keys'); @@ -661,7 +661,7 @@ API.prototype.getSignatures = function(txp, cb) { var self = this; if (!self.canSign()) - return cb('You do not have the required keys to sign transactions'); + return cb(new Error('You do not have the required keys to sign transactions')); if (!Verifier.checkTxProposal(self.credentials, txp)) { return cb(new ServerCompromisedError('Transaction proposal is invalid')); From 9e6125aa2fb2016ec6cce301aebdfb61085bc339 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 16 Mar 2015 16:06:08 -0300 Subject: [PATCH 6/9] #openWallet fires event when wallet is complete --- lib/api.js | 11 +++++++---- test/client.js | 20 +++++++++++++++++++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/api.js b/lib/api.js index 564e85ae..fe0bb546 100644 --- a/lib/api.js +++ b/lib/api.js @@ -333,24 +333,25 @@ API.prototype.canSign = function() { return this.credentials && this.credentials.canSign(); }; + /** * Open a wallet and try to complete the public key ring. * - * @param {Callback} cb - * @returns {Callback} cb - Returns an error and a flag indicating that the wallet has just been completed and needs to be persisted + * @param {Callback} cb - The callback that handles the response. It returns a flag indicating that the wallet is complete. + * @fires API#walletCompleted */ API.prototype.openWallet = function(cb) { $.checkState(this.credentials); var self = this; - if (self.credentials.isComplete()) return cb(null, false); + if (self.credentials.isComplete()) return cb(null, true); self._doGetRequest('/v1/wallets/', function(err, ret) { if (err) return cb(err); var wallet = ret.wallet; - if (wallet.status != 'complete') return cb(new Error('Wallet Incomplete')); + if (wallet.status != 'complete') return cb(null, false); if (!!self.credentials.walletPrivKey) { if (!Verifier.checkCopayers(self.credentials, wallet.copayers)) { @@ -371,6 +372,8 @@ API.prototype.openWallet = function(cb) { self.credentials.addWalletInfo(wallet.id, wallet.name, wallet.m, wallet.n, null, me.name); } + self.emit('walletCompleted', wallet); + return cb(null, true); }); }; diff --git a/test/client.js b/test/client.js index dfbbef39..ad6b9e35 100644 --- a/test/client.js +++ b/test/client.js @@ -255,6 +255,25 @@ describe('client API ', function() { }) }); }); + it('should fire event when wallet is complete', function(done) { + var checks = 0; + clients[0].on('walletCompleted', function(wallet) { + wallet.name.should.equal('wallet name'); + wallet.status.should.equal('complete'); + if (++checks == 2) done(); + }); + clients[0].createWallet('wallet name', 'creator', 2, 2, 'testnet', function(err, secret) { + should.not.exist(err); + clients[1].joinWallet(secret, 'guest', function(err) { + should.not.exist(err); + clients[0].openWallet(function(err, isComplete) { + should.not.exist(err); + isComplete.should.be.true; + if (++checks == 2) done(); + }); + }); + }); + }); it('should not allow to join a full wallet ', function(done) { helpers.createAndJoinWallet(clients, 2, 2, function(w) { @@ -1014,7 +1033,6 @@ describe('client API ', function() { var recoveryClient = helpers.newClient(app); recoveryClient.seedFromExtendedPrivateKey(xpriv); recoveryClient.openWallet(function(err) { - console.log(err); should.not.exist(err); recoveryClient.credentials.walletName.should.equal(walletName); recoveryClient.credentials.copayerName.should.equal(copayerName); From 3bde97890ace103f9d57d3a7dd4bcc21464bf091 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 16 Mar 2015 17:06:46 -0300 Subject: [PATCH 7/9] upgrade version --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index f1826148..4576b7a9 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "bitcore-wallet-client", "description": "Client for bitcore-wallet-service", "author": "BitPay Inc", - "version": "0.0.6", + "version": "0.0.7", "keywords": [ "bitcoin", "copay", @@ -21,7 +21,7 @@ }, "dependencies": { "async": "^0.9.0", - "bitcore-wallet-utils": "^0.0.4", + "bitcore-wallet-utils": "^0.0.5", "browserify": "^9.0.3", "coveralls": "^2.11.2", "lodash": "^3.3.1", @@ -31,7 +31,7 @@ "uglify": "^0.1.1" }, "devDependencies": { - "bitcore-wallet-service": "^0.0.7", + "bitcore-wallet-service": "^0.0.8", "chai": "^1.9.1", "leveldown": "^0.10.0", "levelup": "^0.19.0", From 849a4fb05204822a9f944f818eda64bdd927d94a Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 16 Mar 2015 18:01:46 -0300 Subject: [PATCH 8/9] fix import/export compressed --- lib/api.js | 9 +++------ test/client.js | 12 ++++++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/api.js b/lib/api.js index fe0bb546..13978a3d 100644 --- a/lib/api.js +++ b/lib/api.js @@ -19,10 +19,6 @@ var ClientError = require('./clienterror'); var BASE_URL = 'http://localhost:3001/bws/api'; -var WALLET_ENCRYPTION_OPTS = { - iter: 5000 -}; - /** * @desc ClientAPI constructor. * @@ -200,7 +196,8 @@ API.prototype.import = function(str, opts) { try { if (opts.compressed) { credentials = Credentials.importCompressed(str); - // TODO: complete missing fields that live on the server only such as: walletId, walletName, copayerName + // HACK: simulate incomplete credentials + delete credentials.m; } else { credentials = Credentials.fromObj(JSON.parse(str)); } @@ -353,7 +350,7 @@ API.prototype.openWallet = function(cb) { if (wallet.status != 'complete') return cb(null, false); - if (!!self.credentials.walletPrivKey) { + if (self.credentials.walletPrivKey) { if (!Verifier.checkCopayers(self.credentials, wallet.copayers)) { return cb(new ServerCompromisedError( 'Copayers in the wallet could not be verified to have known the wallet secret')); diff --git a/test/client.js b/test/client.js index ad6b9e35..d0bf8eba 100644 --- a/test/client.js +++ b/test/client.js @@ -985,7 +985,7 @@ describe('client API ', function() { importedClient = helpers.newClient(app); importedClient.import(exported); }); - it.skip('should export & import compressed', function() { + it('should export & import compressed', function(done) { var walletId = clients[0].credentials.walletId; var walletName = clients[0].credentials.walletName; var copayerName = clients[0].credentials.copayerName; @@ -998,9 +998,13 @@ describe('client API ', function() { importedClient.import(exported, { compressed: true }); - importedClient.credentials.walletId.should.equal(walletId); - importedClient.credentials.walletName.should.equal(walletName); - importedClient.credentials.copayerName.should.equal(copayerName); + importedClient.openWallet(function(err) { + should.not.exist(err); + importedClient.credentials.walletId.should.equal(walletId); + importedClient.credentials.walletName.should.equal(walletName); + importedClient.credentials.copayerName.should.equal(copayerName); + done(); + }); }); it('should export without signing rights', function() { clients[0].canSign().should.be.true; From 6a3a504377481fbbec4381516a830643a8e0429c Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 16 Mar 2015 18:02:03 -0300 Subject: [PATCH 9/9] simplify ClientError class --- lib/clienterror.js | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/lib/clienterror.js b/lib/clienterror.js index f0f40156..d6cad1a0 100644 --- a/lib/clienterror.js +++ b/lib/clienterror.js @@ -1,21 +1,6 @@ -function ClientError() { - var args = Array.prototype.slice.call(arguments); - - switch (args.length) { - case 0: - this.code = 'BADREQUEST'; - this.message = 'Bad request'; - break; - case 1: - this.code = 'BADREQUEST'; - this.message = args[0]; - break; - default: - case 2: - this.code = args[0]; - this.message = args[1]; - break; - } +function ClientError(code, message) { + this.code = code; + this.message = message; }; ClientError.prototype.toString = function() {