Skip to content
This repository has been archived by the owner on Apr 3, 2019. It is now read-only.

Commit

Permalink
Merge pull request #34 from isocolsky/fix/various
Browse files Browse the repository at this point in the history
Fix/various
  • Loading branch information
isocolsky committed Mar 17, 2015
2 parents 8f92f9f + 6a3a504 commit e9a9491
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 104 deletions.
63 changes: 15 additions & 48 deletions lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ var Verifier = require('./verifier');
var ServerCompromisedError = require('./servercompromisederror');
var ClientError = require('./clienterror');

var BASE_URL = 'http://localhost:3001/copay/api';
var WALLET_ENCRYPTION_OPTS = {
iter: 5000
};
var BASE_URL = 'http://localhost:3001/bws/api';

/**
* @desc ClientAPI constructor.
Expand Down Expand Up @@ -162,7 +159,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) {
Expand All @@ -183,10 +179,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;
}

Expand All @@ -196,52 +188,25 @@ 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);
// TODO: complete missing fields that live on the server only such as: walletId, walletName, copayerName
credentials = Credentials.importCompressed(str);
// HACK: simulate incomplete credentials
delete credentials.m;
} else {
credentials = Credentials.fromObj(JSON.parse(input));
credentials = Credentials.fromObj(JSON.parse(str));
}
} catch (ex) {
throw new Error('Error importing from source');
}
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
Expand Down Expand Up @@ -365,26 +330,27 @@ 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('Wallet Incomplete');
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'));
Expand All @@ -403,6 +369,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);
});
};
Expand All @@ -422,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');
Expand Down Expand Up @@ -512,7 +480,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;
Expand Down Expand Up @@ -694,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'));
Expand Down
21 changes: 3 additions & 18 deletions lib/clienterror.js
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand Down
61 changes: 26 additions & 35 deletions test/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -256,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) {
Expand Down Expand Up @@ -967,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;
Expand All @@ -980,36 +998,12 @@ 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);
});
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'
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() {
Expand All @@ -1026,8 +1020,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() {});
});
});

Expand All @@ -1045,7 +1037,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);
Expand Down

0 comments on commit e9a9491

Please sign in to comment.