copay/test/Identity.js

531 lines
15 KiB
JavaScript
Raw Normal View History

'use strict';
var _ = require('underscore');
var chai = chai || require('chai');
var should = chai.should();
2014-10-01 06:33:06 -07:00
var FakeBlockchain = requireMock('FakeBlockchain');
var FakeStorage = function FakeStorage() {};
2014-10-01 06:33:06 -07:00
var Identity = copay.Identity;
var Passphrase = copay.Passphrase;
var mockLocalStorage = requireMock('FakeLocalStorage');
var mockSessionStorage = requireMock('FakeLocalStorage');
var PERSISTED_PROPERTIES = (copay.Wallet || require('../js/models/Wallet')).PERSISTED_PROPERTIES;
function assertObjectEqual(a, b) {
PERSISTED_PROPERTIES.forEach(function(k) {
if (a[k] && b[k]) {
_.omit(a[k], 'name').should.be.deep.equal(b[k], k + ' differs');
}
})
}
describe('Identity model', function() {
2014-09-28 14:38:06 -07:00
var iden, storage, wallet, profile;
2014-09-30 11:28:02 -07:00
beforeEach(function(done) {
2014-09-28 14:38:06 -07:00
storage = sinon.stub();
storage.getItem = sinon.stub();
2014-10-14 05:58:12 -07:00
storage.savePassphrase = sinon.spy();
storage.restorePassphrase = sinon.spy();
2014-10-01 04:35:17 -07:00
storage.setPassword = sinon.spy();
storage.hasPassphrase = sinon.stub().returns(true);
2014-09-28 14:38:06 -07:00
storage.getSessionId = sinon.spy();
storage.setFromObj = sinon.spy();
storage.deletePrefix = sinon.stub().yields(null);
2014-09-28 14:38:06 -07:00
Identity._newStorage = sinon.stub().returns(storage);
2014-09-27 14:53:34 -07:00
2014-09-28 14:38:06 -07:00
wallet = sinon.stub();
wallet.store = sinon.stub().yields(null);
2014-10-10 08:02:46 -07:00
wallet.netStart = sinon.stub();
2014-09-29 15:58:00 -07:00
wallet.getId = sinon.stub().returns('wid:123');
2014-09-28 14:38:06 -07:00
Identity._newWallet = sinon.stub().returns(wallet);
2014-09-28 14:38:06 -07:00
profile = sinon.stub();
2014-09-29 02:31:04 -07:00
profile.addWallet = sinon.stub().yields(null);;
profile.deleteWallet = sinon.stub().yields(null);;
2014-09-29 15:58:00 -07:00
profile.listWallets = sinon.stub().returns([]);
profile.setLastOpenedTs = sinon.stub().yields(null);;
2014-09-28 17:22:53 -07:00
profile.store = sinon.stub().yields(null);;
profile.getName = sinon.stub().returns('profile name');;
Identity._createProfile = sinon.stub().callsArgWith(3, null, profile);
2014-09-28 17:22:53 -07:00
Identity.create(email, password, config, function(err, i) {
2014-09-30 11:28:02 -07:00
iden = i;
done();
});
});
afterEach(function() {
2014-09-28 16:50:37 -07:00
iden = storage = wallet = profile = undefined;
});
2014-09-28 14:38:06 -07:00
var email = '[email protected]';
var password = 'password';
var config = {
walletDefaults: {
requiredCopayers: 3,
totalCopayers: 5,
spendUnconfirmed: 1,
reconnectDelay: 100,
},
blockchain: {
host: 'test.insight.is',
port: 80,
schema: 'https'
},
networkName: 'testnet',
passphrase: {
iterations: 100,
storageSalt: 'mjuBtGybi/4=',
},
// network layer config
network: {
testnet: {
url: 'https://test-insight.bitpay.com:443'
},
livenet: {
url: 'https://insight.bitpay.com:443'
},
},
2014-09-28 14:38:06 -07:00
version: '0.0.1',
};
2014-09-28 16:50:37 -07:00
describe('#constructors', function() {
2014-09-28 14:38:06 -07:00
describe('#new', function() {
it('should create an identity', function() {
var iden = new Identity(email, password, config);
should.exist(iden);
iden.walletDefaults.should.deep.equal(config.walletDefaults);
2014-09-28 14:38:06 -07:00
});
});
describe('#create', function(done) {
it('should call .store', function(done) {
Identity.create(email, password, config, function(err, iden) {
2014-09-30 11:28:02 -07:00
2014-09-28 14:38:06 -07:00
should.not.exist(err);
2014-09-29 02:31:04 -07:00
should.exist(iden.profile.addWallet);
2014-09-30 11:28:02 -07:00
Identity._createProfile.getCall(0).args[0].should.deep.equal(email);
Identity._createProfile.getCall(0).args[1].should.deep.equal(password);
2014-09-28 14:38:06 -07:00
done();
});
});
});
describe('#open', function(done) {
beforeEach(function() {
2014-10-14 05:58:12 -07:00
storage.getFirst = sinon.stub().yields(null, 'wallet1234');
profile.listWallets = sinon.stub().returns([{
id: 'walletid'
}]);
profile.getLastFocusedWallet = sinon.stub().returns(null);
2014-10-01 04:35:17 -07:00
Identity._openProfile = sinon.stub().callsArgWith(3, null, profile);
Identity._walletRead = sinon.stub().callsArgWith(2, null, wallet);
});
2014-10-01 04:35:17 -07:00
it('should call ._openProfile', function(done) {
Identity.open(email, password, config, function(err, iden, w) {
Identity._openProfile.calledOnce.should.equal(true);
2014-09-28 14:38:06 -07:00
should.not.exist(err);
2014-10-01 04:35:17 -07:00
iden.profile.should.equal(profile);
2014-09-28 14:38:06 -07:00
done();
});
});
it('should return last focused wallet', function(done) {
var wallets = [{
id: 'wallet1',
store: sinon.stub().yields(null),
netStart: sinon.stub(),
}, {
id: 'wallet2',
store: sinon.stub().yields(null),
netStart: sinon.stub(),
}, {
id: 'wallet3',
store: sinon.stub().yields(null),
netStart: sinon.stub(),
}];
profile.listWallets = sinon.stub().returns(wallets);
profile.getLastFocusedWallet = sinon.stub().returns(wallets[1]);
Identity._walletRead = sinon.stub();
Identity._walletRead.onCall(0).callsArgWith(2, null, wallets[0]);
Identity._walletRead.onCall(1).callsArgWith(2, null, wallets[1]);
Identity._walletRead.onCall(2).callsArgWith(2, null, wallets[2]);
Identity.open(email, password, config, function(err, iden, w) {
w.id.should.equal('wallet2');
done();
});
});
});
});
2014-09-28 16:50:37 -07:00
describe('#store', function() {
it('should call .store from profile and no wallets', function(done) {
profile.store = sinon.stub().yields(null);
iden.wallets = [];
iden.store({}, function(err) {
should.not.exist(err);
profile.store.calledOnce.should.equal(true);
done();
});
});
it('should call .store from profile and wallets (2)', function(done) {
iden.profile.store = sinon.stub().yields(null);
2014-10-01 04:35:17 -07:00
iden.openWallets = [{
2014-09-28 16:50:37 -07:00
store: sinon.stub().yields(null)
}, {
store: sinon.stub().yields(null)
}];
iden.store({}, function(err) {
should.not.exist(err);
iden.profile.store.calledOnce.should.equal(true);
2014-10-01 04:35:17 -07:00
iden.openWallets[0].store.calledOnce.should.equal(true);
iden.openWallets[1].store.calledOnce.should.equal(true);
2014-09-28 16:50:37 -07:00
done();
});
});
});
2014-09-28 17:22:53 -07:00
describe('#createWallet', function() {
it('should create wallet', function(done) {
iden.createWallet(null, function(err, w) {
should.exist(w);
should.not.exist(err);
done();
});
});
2014-09-29 02:31:04 -07:00
it('should add wallet to profile', function(done) {
iden.createWallet(null, function(err, w) {
profile.addWallet.getCall(0).args[0].should.contain('wid:123');
2014-09-29 02:31:04 -07:00
done();
});
});
2014-09-28 17:22:53 -07:00
it('should be able to create wallets with given pk', function(done) {
var priv = 'tprv8ZgxMBicQKsPdEqHcA7RjJTayxA3gSSqeRTttS1JjVbgmNDZdSk9EHZK5pc52GY5xFmwcakmUeKWUDzGoMLGAhrfr5b3MovMUZUTPqisL2m';
iden.createWallet({
privateKeyHex: priv,
}, function(err, w) {
2014-09-30 12:04:17 -07:00
Identity._newWallet.getCall(1).args[0].privateKey.toObj().extendedPrivateKeyString.should.equal(priv);
2014-09-28 17:22:53 -07:00
should.not.exist(err);
done();
});
});
it('should be able to create wallets with random pk', function(done) {
iden.createWallet(null, function(err, w1) {
iden.createWallet(null, function(err, w2) {
2014-09-29 15:58:00 -07:00
Identity._newWallet.getCall(0).args[0].privateKey.toObj().extendedPrivateKeyString.should.not.equal(
Identity._newWallet.getCall(1).args[0].privateKey.toObj().extendedPrivateKeyString
2014-09-28 17:22:53 -07:00
);
done();
});
});
});
});
describe('#deleteWallet', function() {
it('should call profile and wallet', function(done) {
iden.createWallet(null, function(err, w) {
iden.deleteWallet(w.id, function(err) {
should.not.exist(err);
done();
});
});
});
});
2014-09-29 15:58:00 -07:00
describe('#openWallet', function() {
2014-09-29 12:55:45 -07:00
beforeEach(function() {
iden.migrateWallet = sinon.stub().yields(null);
2014-10-01 04:35:17 -07:00
storage.setPassword = sinon.spy();
2014-10-14 05:58:12 -07:00
storage.getFirst = sinon.stub().yields(null, 'wallet1234');
2014-09-29 15:58:00 -07:00
var wallet = sinon.stub();
2014-10-14 11:39:07 -07:00
wallet.netStart = sinon.stub();
2014-09-29 15:58:00 -07:00
wallet.store = sinon.stub().yields(null);
2014-10-10 08:02:46 -07:00
Identity._walletRead = sinon.stub().callsArgWith(2, null, wallet);
2014-09-29 12:55:45 -07:00
});
it('should return wallet and call .store & .migrateWallet', function(done) {
2014-09-29 12:55:45 -07:00
iden.openWallet('dummy', function(err, w) {
2014-09-29 15:58:00 -07:00
should.not.exist(err);
w.store.calledOnce.should.equal(true);
2014-10-01 04:35:17 -07:00
// iden.migrateWallet.calledOnce.should.equal(true);
2014-09-29 12:55:45 -07:00
done();
});
});
2014-09-29 15:58:00 -07:00
});
2014-09-29 12:55:45 -07:00
2014-09-29 15:58:00 -07:00
describe('#importWallet', function() {
2014-09-29 12:55:45 -07:00
2014-09-29 15:58:00 -07:00
beforeEach(function() {
2014-09-29 12:55:45 -07:00
iden.migrateWallet = sinon.stub().yields(null);
2014-10-14 05:58:12 -07:00
storage.getFirst = sinon.stub().yields(null, 'wallet1234');
2014-09-29 12:55:45 -07:00
});
it('should create wallet from encrypted object', function(done) {
iden.storage.setPassphrase = sinon.spy();
iden.storage.decrypt = sinon.stub().withArgs('base64').returns({
networkName: 'testnet'
});
wallet.getId = sinon.stub().returns('ID123');
Identity._walletFromObj = sinon.stub().returns(wallet);
Identity._walletRead = sinon.stub().yields(null, wallet);
2014-09-29 12:55:45 -07:00
2014-09-29 15:58:00 -07:00
iden.importWallet("encrypted object", "xxx", [], function(err) {
iden.openWallet('ID123', function(err, w) {
2014-09-29 12:55:45 -07:00
should.not.exist(err);
2014-09-29 15:58:00 -07:00
should.exist(w);
done();
2014-09-29 12:55:45 -07:00
});
});
});
});
2014-09-29 15:58:00 -07:00
describe('#listWallets', function() {
it('should return empty array if no wallets', function() {
iden.listWallets();
iden.profile.listWallets.calledOnce.should.equal(true);
});
});
2014-09-29 15:58:00 -07:00
describe('#deleteWallet', function() {
Identity._walletDelete = sinon.stub().callsArgWith(2, null);
it('should call Profile deleteWallet', function(done) {
iden.profile.deleteWallet = sinon.stub().yields(null);
iden.deleteWallet('xxx', function() {
iden.profile.deleteWallet.getCall(0).args[0].should.equal('xxx');
done();
});
});
});
2014-10-15 12:24:21 -07:00
2014-10-21 05:57:54 -07:00
describe('#export', function() {
2014-10-15 12:24:21 -07:00
beforeEach(function() {
var ws = [];
_.each([0, 1, 2, 3, 4], function(i) {
var w = sinon.stub();
2014-10-21 05:57:54 -07:00
w.export = sinon.stub().returns('enc' + i);
2014-10-15 12:24:21 -07:00
w.getId = sinon.stub().returns('wid' + i);
ws.push(w);
});
iden.openWallets = ws;
2014-10-21 05:57:54 -07:00
iden.profile.export = sinon.stub().returns('penc');
2014-10-15 12:24:21 -07:00
iden.storage.iterations = 13;
});
it('should create an encrypted object', function() {
2014-10-21 05:57:54 -07:00
var ret = JSON.parse(iden.export());
2014-10-15 12:24:21 -07:00
ret.iterations.should.equal(13);
2014-10-21 05:57:54 -07:00
ret.profile.should.equal('penc');
2014-10-15 12:24:21 -07:00
_.each([0, 1, 2, 3, 4], function(i) {
ret.wallets['wid' + i].should.equal('enc' + i);
});
});
});
2014-10-21 05:57:54 -07:00
describe.only('#import', function() {
beforeEach(function() {
var ws = [];
_.each([0, 1, 2, 3, 4], function(i) {
var w = sinon.stub();
w.export = sinon.stub().returns('enc' + i);
w.getId = sinon.stub().returns('wid' + i);
ws.push(w);
});
iden.openWallets = ws;
iden.profile.export = sinon.stub().returns('penc');
iden.storage.iterations = 13;
iden.storage.decrypt = sinon.stub().returns({
email: '[email protected]',
hash: 'hash1234'
});
});
it('should create an encrypted object', function(done) {
Identity.import(JSON.stringify({
iterations: 10
}), '1234', config, function(err, ret) {
should.not.exist(err);
should.exist(ret);
done();
});
});
});
2014-09-27 14:56:25 -07:00
describe('#joinWallet', function() {
var opts = {
secret: '8WtTuiFTkhP5ao7AF2QErSwV39Cbur6pdMebKzQXFqL59RscXM',
nickname: 'test',
2014-10-01 04:35:17 -07:00
password: 'pass'
};
it('should yield bad network error', function(done) {
2014-10-07 14:33:55 -07:00
var net = sinon.stub();
net.greet = sinon.stub();
2014-09-27 14:53:34 -07:00
net.cleanUp = sinon.stub();
net.start = sinon.stub().yields(null);
net.on = sinon.stub();
net.on.withArgs('data').yields('senderId', {
type: 'walletId',
networkName: 'aWeirdNetworkName',
opts: {},
});
Identity._newAsync = function() {
return net;
};
2014-10-07 14:33:55 -07:00
opts.privHex = undefined;
2014-09-28 14:38:06 -07:00
iden.joinWallet(opts, function(err, w) {
err.should.equal('badNetwork');
done();
});
});
it('should yield to join error', function(done) {
opts.privHex = undefined;
2014-10-07 14:33:55 -07:00
var net = sinon.stub();
net.greet = sinon.stub();
2014-09-27 14:53:34 -07:00
net.cleanUp = sinon.stub();
net.start = sinon.stub().yields(null);
2014-09-28 14:38:06 -07:00
net.on = sinon.stub();
net.on.withArgs('serverError').yields(null);
net.on.withArgs('data').yields('senderId', {
type: 'walletId',
2014-09-28 14:38:06 -07:00
networkName: iden.networkName,
});
Identity._newAsync = function() {
return net;
};
2014-10-07 14:33:55 -07:00
2014-09-28 14:38:06 -07:00
iden.joinWallet(opts, function(err, w) {
err.should.equal('joinError');
done();
});
});
it('should call network.start / create', function(done) {
opts.privHex = undefined;
2014-10-07 14:33:55 -07:00
var net = sinon.stub();
net.cleanUp = sinon.spy();
net.greet = sinon.spy();
net.start = sinon.stub().yields(null);
net.on = sinon.stub();
net.on.withArgs('connected').yields(null);
net.on.withArgs('data').yields('senderId', {
type: 'walletId',
networkName: 'testnet',
opts: {},
});
Identity._newAsync = function() {
return net;
};
var w = sinon.stub();
w.sendWalletReady = sinon.spy();
2014-09-28 14:38:06 -07:00
iden.createWallet = sinon.stub().yields(null, w);
iden.joinWallet(opts, function(err, w) {
net.start.calledOnce.should.equal(true);
2014-09-28 14:38:06 -07:00
iden.createWallet.calledOnce.should.equal(true);
iden.createWallet.calledOnce.should.equal(true);
w.sendWalletReady.calledOnce.should.equal(true);
w.sendWalletReady.getCall(0).args[0].should.equal('03ddbc4711534bc62ccf576ab05f2a0afd11f9e2f4016781f3f5a88de9543a229a');
done();
});
});
it('should return walletFull', function(done) {
opts.privHex = undefined;
2014-10-07 14:33:55 -07:00
var net = sinon.stub();
net.cleanUp = sinon.spy();
net.greet = sinon.spy();
net.start = sinon.stub().yields(null);
net.on = sinon.stub();
net.on.withArgs('connected').yields(null);
net.on.withArgs('data').yields('senderId', {
type: 'walletId',
networkName: 'testnet',
opts: {},
});
Identity._newAsync = function() {
return net;
};
2014-09-28 14:38:06 -07:00
iden.createWallet = sinon.stub().yields(null, null);
iden.joinWallet(opts, function(err, w) {
err.should.equal('walletFull');
done();
});
});
it('should accept a priv key a input', function() {
opts.privHex = 'tprv8ZgxMBicQKsPf7MCvCjnhnr4uiR2Z2gyNC27vgd9KUu98F9mM1tbaRrWMyddVju36GxLbeyntuSadBAttriwGGMWUkRgVmUUCg5nFioGZsd';
2014-10-07 14:33:55 -07:00
var net = sinon.stub();
Identity._newAsync = function() {
return net;
};
2014-10-07 14:33:55 -07:00
net.on = sinon.stub();
net.cleanUp = sinon.spy();
net.start = sinon.spy();
2014-09-28 14:38:06 -07:00
iden.joinWallet(opts, function(err, w) {
net.start.getCall(0).args[0].privkey.should.equal('ddc2fa8c583a73c4b2a24630ec7c283df4e7c230a02c4e48bc36ec61687afd7d');
});
});
it('should call network.start with private key', function() {
opts.privHex = undefined;
2014-10-07 14:33:55 -07:00
var net = sinon.stub();
net.cleanUp = sinon.spy();
2014-10-07 14:33:55 -07:00
net.on = sinon.stub();
net.start = sinon.spy();
Identity._newAsync = function() {
return net;
};
2014-09-28 14:38:06 -07:00
iden.joinWallet(opts, function(err, w) {
net.start.getCall(0).args[0].privkey.length.should.equal(64); //privkey is hex of private key buffer
});
});
});
2014-09-30 04:16:58 -07:00
});