Browse Source

test regaining access to wallet with only xPrivKey

activeAddress
Ivan Socolsky 10 years ago
parent
commit
f486ecacd3
  1. 22
      lib/client/api.js
  2. 4
      lib/client/credentials.js
  3. 1
      lib/client/verifier.js
  4. 207
      test/integration/client.js

22
lib/client/api.js

@ -92,7 +92,7 @@ function API(opts) {
util.inherits(API, events.EventEmitter);
API.prototype.seedFromExtendedPrivateKey = function(xPrivKey) {
this.credentials = Credentials.seedFromExtendedPrivateKey(xPrivKey);
this.credentials = Credentials.fromExtendedPrivateKey(xPrivKey);
};
API.prototype.seedFromAirGapped = function(seed) {
@ -254,15 +254,25 @@ 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('Wallet Incomplete');
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'));
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'));
}
} else {
log.warn('Could not perform verification of other copayers in the wallet');
}
self.credentials.addPublicKeyRing(_.pluck(wallet.copayers, 'xPubKey'));
if (!self.credentials.hasWalletInfo()) {
var me = _.find(wallet.copayers, {
id: self.credentials.copayerId
});
self.credentials.addWalletInfo(wallet.id, wallet.name, wallet.m, wallet.n, null, me.name);
}
return cb(null, true);
});
};

4
lib/client/credentials.js

@ -105,6 +105,10 @@ Credentials.prototype.addWalletInfo = function(walletId, walletName, m, n, walle
}
};
Credentials.prototype.hasWalletInfo = function() {
return !!this.walletId;
};
Credentials.prototype.addPublicKeyRing = function(publicKeyRing) {
this.publicKeyRing = _.clone(publicKeyRing);
};

1
lib/client/verifier.js

@ -18,6 +18,7 @@ Verifier.checkAddress = function(credentials, address) {
};
Verifier.checkCopayers = function(credentials, copayers) {
$.checkState(credentials.walletPrivKey);
var walletPubKey = Bitcore.PrivateKey.fromString(credentials.walletPrivKey).toPublicKey().toString();
if (copayers.length != credentials.n) {

207
test/integration/client.js

@ -1,6 +1,7 @@
'use strict';
var _ = require('lodash');
var $ = require('preconditions').singleton();
var chai = require('chai');
var sinon = require('sinon');
var should = chai.should();
@ -20,6 +21,7 @@ var TestData = require('../testdata');
var helpers = {};
helpers.getRequest = function(app) {
$.checkArgument(app);
return function(args, cb) {
var req = request(app);
var r = req[args.method](args.relUrl);
@ -38,6 +40,13 @@ helpers.getRequest = function(app) {
};
};
helpers.newClient = function(app) {
$.checkArgument(app);
return new Client({
request: helpers.getRequest(app),
});
};
helpers.createAndJoinWallet = function(clients, m, n, cb) {
clients[0].createWallet('wallet name', 'creator', m, n, 'testnet',
function(err, secret) {
@ -148,9 +157,7 @@ describe('client API ', function() {
});
// Generates 5 clients
clients = _.map(_.range(5), function(i) {
return new Client({
request: helpers.getRequest(app),
});
return helpers.newClient(app);
});
blockExplorerMock.reset();
});
@ -179,10 +186,8 @@ describe('client API ', function() {
});
var s2 = sinon.stub();
s2.load = sinon.stub().yields(null);
var client = new Client({
storage: s2,
});
client.request = helpers.getRequest(app);
var client = helpers.newClient(app);
client.storage = s2;
client.createWallet('1', '2', 1, 1, 'testnet',
function(err) {
err.code.should.equal('ERROR');
@ -206,10 +211,8 @@ describe('client API ', function() {
});
var s2 = sinon.stub();
s2.load = sinon.stub().yields(null);
var client = new Client({
storage: s2,
});
client.request = helpers.getRequest(app);
var client = helpers.newClient(app);
client.storage = s2;
client.createWallet('1', '2', 1, 1, 'testnet',
function(err) {
err.code.should.equal('ERROR');
@ -865,92 +868,120 @@ describe('client API ', function() {
it.skip('should get paginated transaction history', function(done) {});
});
describe('Export & Import', function() {
var address, importedClient;
beforeEach(function(done) {
importedClient = null;
helpers.createAndJoinWallet(clients, 1, 1, function() {
clients[0].createAddress(function(err, addr) {
should.not.exist(err);
should.exist(addr.address);
address = addr.address;
done();
describe('Mobility, backup & recovery', function() {
describe('Export & Import', function() {
describe('Success', function() {
var address, importedClient;
beforeEach(function(done) {
importedClient = null;
helpers.createAndJoinWallet(clients, 1, 1, function() {
clients[0].createAddress(function(err, addr) {
should.not.exist(err);
should.exist(addr.address);
address = addr.address;
done();
});
});
});
afterEach(function(done) {
importedClient.getMainAddresses({}, function(err, list) {
should.not.exist(err);
should.exist(list);
list.length.should.equal(1);
list[0].address.should.equal(address);
done();
});
});
});
});
afterEach(function(done) {
importedClient.getMainAddresses({}, function(err, list) {
should.not.exist(err);
should.exist(list);
list.length.should.equal(1);
list[0].address.should.equal(address);
done();
});
});
it('should export & import', function() {
var exported = clients[0].export();
it('should export & import', function() {
var exported = clients[0].export();
importedClient = new Client({
request: helpers.getRequest(app),
});
importedClient.import(exported);
});
it.skip('should export & import compressed', function() {
var walletId = clients[0].credentials.walletId;
var walletName = clients[0].credentials.walletName;
var copayerName = clients[0].credentials.copayerName;
importedClient = helpers.newClient(app);
importedClient.import(exported);
});
it.skip('should export & import compressed', function() {
var walletId = clients[0].credentials.walletId;
var walletName = clients[0].credentials.walletName;
var copayerName = clients[0].credentials.copayerName;
var exported = clients[0].export({
compressed: true
});
var exported = clients[0].export({
compressed: true
});
importedClient = new Client({
request: helpers.getRequest(app),
});
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);
importedClient = helpers.newClient(app);
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);
var exported = clients[0].export({
password: '123'
});
exported.should.not.contain(xPrivKey);
importedClient = new Client({
request: helpers.getRequest(app),
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.import(exported, {
password: '123'
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() {});
});
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 = new Client({
request: helpers.getRequest(app),
});
importedClient.import(exported, {
compressed: true,
password: '123'
describe('Recovery', function() {
it('should be able to regain access to a 1-1 wallet with just the xPriv', function(done) {
helpers.createAndJoinWallet(clients, 1, 1, function() {
var xpriv = clients[0].credentials.xPrivKey;
var walletName = clients[0].credentials.walletName;
var copayerName = clients[0].credentials.copayerName;
clients[0].createAddress(function(err, addr) {
should.not.exist(err);
should.exist(addr);
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);
recoveryClient.getMainAddresses({}, function(err, list) {
should.not.exist(err);
should.exist(list);
list[0].address.should.equal(addr.address);
done();
});
});
});
});
});
});
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() {});
});
describe('Air gapped related flows', function() {
@ -960,9 +991,7 @@ describe('client API ', function() {
});
var seed = airgapped.getSeed();
var proxy = new Client({
request: helpers.getRequest(app),
});
var proxy = helpers.newClient(app);
proxy.seedFromAirGapped(seed);
should.not.exist(proxy.credentials.xPrivKey);
proxy.createWallet('wallet name', 'creator', 1, 1, 'testnet', function(err) {
@ -981,9 +1010,7 @@ describe('client API ', function() {
});
var seed = airgapped.getSeed();
var proxy = new Client({
request: helpers.getRequest(app),
});
var proxy = helpers.newClient(app);
proxy.seedFromAirGapped(seed);
async.waterfall([

Loading…
Cancel
Save