mirror of
https://github.com/moparisthebest/mail
synced 2024-11-22 17:02:17 -05:00
[WO-643] Refactor initialization workflow
* Move initialization pre-flight checks to app-controller * Refresh cached public keys for user during incomplete setups * Reorder redirect checks in login ctrl from most specific (pubkey + privkey) to most generic (no keys) * Add overridePermission flag to KeychainDAO.refreshKeyForUserId to refresh w/o asking for user permission
This commit is contained in:
parent
4722af1457
commit
7959be55a7
@ -7,8 +7,9 @@
|
|||||||
var axe = require('axe-logger'),
|
var axe = require('axe-logger'),
|
||||||
Auth = require('./bo/auth'),
|
Auth = require('./bo/auth'),
|
||||||
PGP = require('./crypto/pgp'),
|
PGP = require('./crypto/pgp'),
|
||||||
PgpMailer = require('pgpmailer'),
|
|
||||||
OAuth = require('./util/oauth'),
|
OAuth = require('./util/oauth'),
|
||||||
|
PgpMailer = require('pgpmailer'),
|
||||||
|
util = require('crypto-lib').util,
|
||||||
PgpBuilder = require('pgpbuilder'),
|
PgpBuilder = require('pgpbuilder'),
|
||||||
OutboxBO = require('./bo/outbox'),
|
OutboxBO = require('./bo/outbox'),
|
||||||
mailreader = require('mailreader'),
|
mailreader = require('mailreader'),
|
||||||
@ -121,29 +122,9 @@ ctrl.checkForUpdate = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instanciate the mail email data access object and its dependencies. Login to imap on init.
|
* Fire up the database, retrieve the available keys for the user and initialize the email data access object
|
||||||
*/
|
*/
|
||||||
ctrl.init = function(options, callback) {
|
ctrl.init = function(options, callback) {
|
||||||
// init user's local database
|
|
||||||
ctrl._userStorage.init(options.emailAddress, function(err) {
|
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Migrate the databases if necessary
|
|
||||||
ctrl._updateHandler.update(onUpdate);
|
|
||||||
});
|
|
||||||
|
|
||||||
function onUpdate(err) {
|
|
||||||
if (err) {
|
|
||||||
callback({
|
|
||||||
errMsg: 'Update failed, please reinstall the app.',
|
|
||||||
err: err
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// account information for the email dao
|
// account information for the email dao
|
||||||
var account = {
|
var account = {
|
||||||
realname: options.realname,
|
realname: options.realname,
|
||||||
@ -151,16 +132,70 @@ ctrl.init = function(options, callback) {
|
|||||||
asymKeySize: config.asymKeySize
|
asymKeySize: config.asymKeySize
|
||||||
};
|
};
|
||||||
|
|
||||||
// init email dao
|
// Pre-Flight check: don't even start to initialize stuff if the email address is not valid
|
||||||
ctrl._emailDao.init({
|
if (!util.validateEmailAddress(options.emailAddress)) {
|
||||||
account: account
|
return callback(new Error('The user email address is invalid!'));
|
||||||
}, function(err, keypair) {
|
}
|
||||||
|
|
||||||
|
prepareDatabase();
|
||||||
|
|
||||||
|
// Pre-Flight check: initialize and prepare user's local database
|
||||||
|
function prepareDatabase() {
|
||||||
|
ctrl._userStorage.init(options.emailAddress, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate the databases if necessary
|
||||||
|
ctrl._updateHandler.update(function(err) {
|
||||||
|
if (err) {
|
||||||
|
return callback(new Error('Updating the internal database failed. Please reinstall the app! Reason: ' + err.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareKeys();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieve keypair fom devicestorage/cloud, refresh public key if signup was incomplete before
|
||||||
|
function prepareKeys() {
|
||||||
|
ctrl._keychain.getUserKeyPair(options.emailAddress, function(err, keys) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is either a first start on a new device, OR a subsequent start without completing the signup,
|
||||||
|
// since we can't differenciate those cases here, do a public key refresh because it might be outdated
|
||||||
|
if (keys && keys.publicKey && !keys.privateKey) {
|
||||||
|
ctrl._keychain.refreshKeyForUserId({
|
||||||
|
userId: options.emailAddress,
|
||||||
|
overridePermission: true
|
||||||
|
}, function(err, publicKey) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
initEmailDao({
|
||||||
|
publicKey: publicKey
|
||||||
|
});
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(null, keypair);
|
// either signup was complete or no pubkey is available, so we're good here.
|
||||||
|
initEmailDao(keys);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initEmailDao(keys) {
|
||||||
|
ctrl._emailDao.init({
|
||||||
|
account: account
|
||||||
|
}, function(err) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, keys);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -49,12 +49,26 @@ var LoginCtrl = function($scope, $location) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function redirect(availableKeys) {
|
function redirect(availableKeys) {
|
||||||
// redirect if needed
|
if (availableKeys && availableKeys.publicKey && availableKeys.privateKey) {
|
||||||
if (typeof availableKeys === 'undefined') {
|
// public and private key available, try empty passphrase
|
||||||
// no public key available, start onboarding process
|
appController._emailDao.unlock({
|
||||||
goTo('/login-initial');
|
keypair: availableKeys,
|
||||||
|
passphrase: undefined
|
||||||
|
}, function(err) {
|
||||||
|
if (err) {
|
||||||
|
goTo('/login-existing');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (availableKeys && !availableKeys.privateKey) {
|
appController._auth.storeCredentials(function(err) {
|
||||||
|
if (err) {
|
||||||
|
return $scope.onError(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
goTo('/desktop');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (availableKeys && availableKeys.publicKey && !availableKeys.privateKey) {
|
||||||
// check if private key is synced
|
// check if private key is synced
|
||||||
appController._keychain.requestPrivateKeyDownload({
|
appController._keychain.requestPrivateKeyDownload({
|
||||||
userId: availableKeys.publicKey.userId,
|
userId: availableKeys.publicKey.userId,
|
||||||
@ -74,26 +88,9 @@ var LoginCtrl = function($scope, $location) {
|
|||||||
// no private key, import key file
|
// no private key, import key file
|
||||||
goTo('/login-new-device');
|
goTo('/login-new-device');
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// public and private key available, try empty passphrase
|
// no public key available, start onboarding process
|
||||||
appController._emailDao.unlock({
|
goTo('/login-initial');
|
||||||
keypair: availableKeys,
|
|
||||||
passphrase: undefined
|
|
||||||
}, function(err) {
|
|
||||||
if (err) {
|
|
||||||
goTo('/login-existing');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
appController._auth.storeCredentials(function(err) {
|
|
||||||
if (err) {
|
|
||||||
return $scope.onError(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
goTo('/desktop');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,9 @@ var MailListCtrl = function($scope, $routeParams) {
|
|||||||
}
|
}
|
||||||
firstSelect = false;
|
firstSelect = false;
|
||||||
|
|
||||||
keychainDao.refreshKeyForUserId(email.from[0].address, onKeyRefreshed);
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: email.from[0].address
|
||||||
|
}, onKeyRefreshed);
|
||||||
|
|
||||||
function onKeyRefreshed(err) {
|
function onKeyRefreshed(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -229,7 +229,9 @@ var WriteCtrl = function($scope, $filter, $q) {
|
|||||||
if (keychainDao) {
|
if (keychainDao) {
|
||||||
// check if to address is contained in known public keys
|
// check if to address is contained in known public keys
|
||||||
// when we write an email, we always need to work with the latest keys available
|
// when we write an email, we always need to work with the latest keys available
|
||||||
keychainDao.refreshKeyForUserId(recipient.address, function(err, key) {
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: recipient.address
|
||||||
|
}, function(err, key) {
|
||||||
if (err) {
|
if (err) {
|
||||||
$scope.onError(err);
|
$scope.onError(err);
|
||||||
return;
|
return;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var util = require('crypto-lib').util,
|
var config = require('../app-config').config,
|
||||||
config = require('../app-config').config,
|
|
||||||
str = require('../app-config').string;
|
str = require('../app-config').string;
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -65,60 +64,21 @@ var EmailDAO = function(keychain, pgp, devicestorage, pgpbuilder, mailreader) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the email dao:
|
* Initializes the email dao:
|
||||||
* - validates the email address
|
* - assigns _account
|
||||||
* - retrieves the user's key pair (if available)
|
|
||||||
* - initializes _account.folders with the content from memory
|
* - initializes _account.folders with the content from memory
|
||||||
*
|
*
|
||||||
* @param {Object} options.account The account
|
|
||||||
* @param {String} options.account.emailAddress The user's id
|
* @param {String} options.account.emailAddress The user's id
|
||||||
|
* @param {String} options.account.realname The user's id
|
||||||
* @param {Function} callback(error, keypair) Invoked with the keypair or error information when the email dao is initialized
|
* @param {Function} callback(error, keypair) Invoked with the keypair or error information when the email dao is initialized
|
||||||
*/
|
*/
|
||||||
EmailDAO.prototype.init = function(options, callback) {
|
EmailDAO.prototype.init = function(options, callback) {
|
||||||
var self = this,
|
this._account = options.account;
|
||||||
keypair;
|
this._account.busy = 0; // > 0 triggers the spinner
|
||||||
|
this._account.online = false;
|
||||||
|
this._account.loggingIn = false;
|
||||||
|
|
||||||
self._account = options.account;
|
// init folders from memory
|
||||||
self._account.busy = 0; // triggers the spinner
|
this._initFoldersFromDisk(callback);
|
||||||
self._account.online = false;
|
|
||||||
self._account.loggingIn = false;
|
|
||||||
|
|
||||||
// validate email address
|
|
||||||
var emailAddress = self._account.emailAddress;
|
|
||||||
if (!util.validateEmailAddress(emailAddress)) {
|
|
||||||
callback({
|
|
||||||
errMsg: 'The user email address must be specified!'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// init keychain and then crypto module
|
|
||||||
initKeychain();
|
|
||||||
|
|
||||||
function initKeychain() {
|
|
||||||
// call getUserKeyPair to read/sync keypair with devicestorage/cloud
|
|
||||||
self._keychain.getUserKeyPair(emailAddress, function(err, storedKeypair) {
|
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
keypair = storedKeypair;
|
|
||||||
initFolders();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function initFolders() {
|
|
||||||
// try init folders from memory, since imap client not initiated yet
|
|
||||||
self._initFoldersFromDisk(function(err) {
|
|
||||||
// dont handle offline case this time
|
|
||||||
if (err && err.code !== 42) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(null, keypair);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,11 +81,14 @@ KeychainDAO.prototype.getPublicKeys = function(ids, callback) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for public key updates of a given user id
|
* Checks for public key updates of a given user id
|
||||||
* @param {String} userId The user id (email address) for which to check the key
|
* @param {String} options.userId The user id (email address) for which to check the key
|
||||||
|
* @param {String} options.overridePermission (optional) Indicates if the update should happen automatically (true) or with the user being queried (false). Defaults to false
|
||||||
* @param {Function} callback(error, key) Invoked when the key has been updated or an error occurred
|
* @param {Function} callback(error, key) Invoked when the key has been updated or an error occurred
|
||||||
*/
|
*/
|
||||||
KeychainDAO.prototype.refreshKeyForUserId = function(userId, callback) {
|
KeychainDAO.prototype.refreshKeyForUserId = function(options, callback) {
|
||||||
var self = this;
|
var self = this,
|
||||||
|
userId = options.userId,
|
||||||
|
overridePermission = options.overridePermission;
|
||||||
|
|
||||||
// get the public key corresponding to the userId
|
// get the public key corresponding to the userId
|
||||||
self.getReceiverPublicKey(userId, function(err, localKey) {
|
self.getReceiverPublicKey(userId, function(err, localKey) {
|
||||||
@ -146,10 +149,18 @@ KeychainDAO.prototype.refreshKeyForUserId = function(userId, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// the public key has changed, we need to ask for permission to update the key
|
// the public key has changed, we need to ask for permission to update the key
|
||||||
|
if (overridePermission) {
|
||||||
|
// don't query the user, update the public key right away
|
||||||
|
onPermissionReceived(true);
|
||||||
|
} else {
|
||||||
|
// query the user if the public key should be updated
|
||||||
self.requestPermissionForKeyUpdate({
|
self.requestPermissionForKeyUpdate({
|
||||||
userId: userId,
|
userId: userId,
|
||||||
newKey: newKey
|
newKey: newKey
|
||||||
}, function(granted) {
|
}, onPermissionReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPermissionReceived(granted) {
|
||||||
if (!granted) {
|
if (!granted) {
|
||||||
// permission was not given to update the key, so don't overwrite the old one!
|
// permission was not given to update the key, so don't overwrite the old one!
|
||||||
callback(null, localKey);
|
callback(null, localKey);
|
||||||
@ -169,8 +180,7 @@ KeychainDAO.prototype.refreshKeyForUserId = function(userId, callback) {
|
|||||||
callback(err, err ? undefined : newKey);
|
callback(err, err ? undefined : newKey);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -5,10 +5,12 @@ var controller = require('../../src/js/app-controller'),
|
|||||||
OutboxBO = require('../../src/js/bo/outbox'),
|
OutboxBO = require('../../src/js/bo/outbox'),
|
||||||
DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao'),
|
DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao'),
|
||||||
UpdateHandler = require('../../src/js/util/update/update-handler'),
|
UpdateHandler = require('../../src/js/util/update/update-handler'),
|
||||||
|
KeychainDAO = require('../../src/js/dao/keychain-dao'),
|
||||||
|
config = require('../../src/js/app-config').config,
|
||||||
Auth = require('../../src/js/bo/auth');
|
Auth = require('../../src/js/bo/auth');
|
||||||
|
|
||||||
describe('App Controller unit tests', function() {
|
describe('App Controller unit tests', function() {
|
||||||
var emailDaoStub, outboxStub, updateHandlerStub, appConfigStoreStub, devicestorageStub, isOnlineStub, authStub;
|
var emailDaoStub, outboxStub, updateHandlerStub, appConfigStoreStub, devicestorageStub, isOnlineStub, authStub, keychainStub;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
controller._emailDao = emailDaoStub = sinon.createStubInstance(EmailDAO);
|
controller._emailDao = emailDaoStub = sinon.createStubInstance(EmailDAO);
|
||||||
@ -17,6 +19,7 @@ describe('App Controller unit tests', function() {
|
|||||||
controller._userStorage = devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
|
controller._userStorage = devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
|
||||||
controller._updateHandler = updateHandlerStub = sinon.createStubInstance(UpdateHandler);
|
controller._updateHandler = updateHandlerStub = sinon.createStubInstance(UpdateHandler);
|
||||||
controller._auth = authStub = sinon.createStubInstance(Auth);
|
controller._auth = authStub = sinon.createStubInstance(Auth);
|
||||||
|
controller._keychain = keychainStub = sinon.createStubInstance(KeychainDAO);
|
||||||
|
|
||||||
isOnlineStub = sinon.stub(controller, 'isOnline');
|
isOnlineStub = sinon.stub(controller, 'isOnline');
|
||||||
});
|
});
|
||||||
@ -133,10 +136,13 @@ describe('App Controller unit tests', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('init', function() {
|
describe('init', function() {
|
||||||
var onConnectStub, emailAddress;
|
var onConnectStub, emailAddress, keysWithPubKey;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
emailAddress = 'alice@bob.com';
|
emailAddress = 'alice@bob.com';
|
||||||
|
keysWithPubKey = {
|
||||||
|
publicKey: {}
|
||||||
|
};
|
||||||
|
|
||||||
// onConnect
|
// onConnect
|
||||||
onConnectStub = sinon.stub(controller, 'onConnect');
|
onConnectStub = sinon.stub(controller, 'onConnect');
|
||||||
@ -146,10 +152,22 @@ describe('App Controller unit tests', function() {
|
|||||||
onConnectStub.restore();
|
onConnectStub.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail due to error in storage initialization', function(done) {
|
it('should fail due to malformed email address', function(done) {
|
||||||
devicestorageStub.init.withArgs(undefined).yields({});
|
controller.init({
|
||||||
|
emailAddress: 'ishallfail'
|
||||||
|
}, function(err, keypair) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
expect(keypair).to.not.exist;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
controller.init({}, function(err, keypair) {
|
it('should fail due to error in storage initialization', function(done) {
|
||||||
|
devicestorageStub.init.withArgs(emailAddress).yields(new Error());
|
||||||
|
|
||||||
|
controller.init({
|
||||||
|
emailAddress: emailAddress
|
||||||
|
}, function(err, keypair) {
|
||||||
expect(err).to.exist;
|
expect(err).to.exist;
|
||||||
expect(keypair).to.not.exist;
|
expect(keypair).to.not.exist;
|
||||||
expect(devicestorageStub.init.calledOnce).to.be.true;
|
expect(devicestorageStub.init.calledOnce).to.be.true;
|
||||||
@ -160,7 +178,7 @@ describe('App Controller unit tests', function() {
|
|||||||
|
|
||||||
it('should fail due to error in update handler', function(done) {
|
it('should fail due to error in update handler', function(done) {
|
||||||
devicestorageStub.init.yields();
|
devicestorageStub.init.yields();
|
||||||
updateHandlerStub.update.yields({});
|
updateHandlerStub.update.yields(new Error());
|
||||||
|
|
||||||
controller.init({
|
controller.init({
|
||||||
emailAddress: emailAddress
|
emailAddress: emailAddress
|
||||||
@ -173,10 +191,48 @@ describe('App Controller unit tests', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should fail due to error in getUserKeyPair', function(done) {
|
||||||
|
devicestorageStub.init.yields();
|
||||||
|
updateHandlerStub.update.yields();
|
||||||
|
keychainStub.getUserKeyPair.yields(new Error());
|
||||||
|
|
||||||
|
controller.init({
|
||||||
|
emailAddress: emailAddress
|
||||||
|
}, function(err, keypair) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
expect(keypair).to.not.exist;
|
||||||
|
expect(updateHandlerStub.update.calledOnce).to.be.true;
|
||||||
|
expect(devicestorageStub.init.calledOnce).to.be.true;
|
||||||
|
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail due to error in refreshKeyForUserId', function(done) {
|
||||||
|
devicestorageStub.init.yields();
|
||||||
|
updateHandlerStub.update.yields();
|
||||||
|
keychainStub.getUserKeyPair.yields(null, keysWithPubKey);
|
||||||
|
keychainStub.refreshKeyForUserId.yields(new Error());
|
||||||
|
|
||||||
|
controller.init({
|
||||||
|
emailAddress: emailAddress
|
||||||
|
}, function(err, keypair) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
expect(keypair).to.not.exist;
|
||||||
|
expect(updateHandlerStub.update.calledOnce).to.be.true;
|
||||||
|
expect(devicestorageStub.init.calledOnce).to.be.true;
|
||||||
|
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
||||||
|
expect(keychainStub.refreshKeyForUserId.calledOnce).to.be.true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should fail due to error in emailDao.init', function(done) {
|
it('should fail due to error in emailDao.init', function(done) {
|
||||||
devicestorageStub.init.yields();
|
devicestorageStub.init.yields();
|
||||||
updateHandlerStub.update.yields();
|
updateHandlerStub.update.yields();
|
||||||
emailDaoStub.init.yields({});
|
keychainStub.getUserKeyPair.yields(null, keysWithPubKey);
|
||||||
|
keychainStub.refreshKeyForUserId.yields();
|
||||||
|
emailDaoStub.init.yields(new Error());
|
||||||
|
|
||||||
controller.init({
|
controller.init({
|
||||||
emailAddress: emailAddress
|
emailAddress: emailAddress
|
||||||
@ -184,25 +240,41 @@ describe('App Controller unit tests', function() {
|
|||||||
expect(err).to.exist;
|
expect(err).to.exist;
|
||||||
expect(keypair).to.not.exist;
|
expect(keypair).to.not.exist;
|
||||||
expect(updateHandlerStub.update.calledOnce).to.be.true;
|
expect(updateHandlerStub.update.calledOnce).to.be.true;
|
||||||
expect(emailDaoStub.init.calledOnce).to.be.true;
|
|
||||||
expect(devicestorageStub.init.calledOnce).to.be.true;
|
expect(devicestorageStub.init.calledOnce).to.be.true;
|
||||||
|
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
||||||
|
expect(keychainStub.refreshKeyForUserId.calledOnce).to.be.true;
|
||||||
|
expect(emailDaoStub.init.calledOnce).to.be.true;
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work and return a keypair', function(done) {
|
it('should work and not return a keypair', function(done) {
|
||||||
devicestorageStub.init.withArgs(emailAddress).yields();
|
devicestorageStub.init.withArgs(emailAddress).yields();
|
||||||
emailDaoStub.init.yields(null, {});
|
|
||||||
updateHandlerStub.update.yields();
|
updateHandlerStub.update.yields();
|
||||||
|
keychainStub.getUserKeyPair.withArgs(emailAddress).yields(null, keysWithPubKey);
|
||||||
|
keychainStub.refreshKeyForUserId.withArgs({
|
||||||
|
userId: emailAddress,
|
||||||
|
overridePermission: true
|
||||||
|
}).yields();
|
||||||
|
emailDaoStub.init.withArgs({
|
||||||
|
account: {
|
||||||
|
realname: undefined,
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
asymKeySize: config.asymKeySize
|
||||||
|
}
|
||||||
|
}).yields();
|
||||||
|
|
||||||
controller.init({
|
controller.init({
|
||||||
emailAddress: emailAddress
|
emailAddress: emailAddress
|
||||||
}, function(err, keypair) {
|
}, function(err, keypair) {
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
expect(keypair).to.exist;
|
expect(keypair.publicKey).to.not.exist;
|
||||||
expect(updateHandlerStub.update.calledOnce).to.be.true;
|
expect(updateHandlerStub.update.calledOnce).to.be.true;
|
||||||
expect(emailDaoStub.init.calledOnce).to.be.true;
|
|
||||||
expect(devicestorageStub.init.calledOnce).to.be.true;
|
expect(devicestorageStub.init.calledOnce).to.be.true;
|
||||||
|
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
||||||
|
expect(keychainStub.refreshKeyForUserId.calledOnce).to.be.true;
|
||||||
|
expect(emailDaoStub.init.calledOnce).to.be.true;
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -148,36 +148,18 @@ describe('Email DAO unit tests', function() {
|
|||||||
initFoldersStub = sinon.stub(dao, '_initFoldersFromDisk');
|
initFoldersStub = sinon.stub(dao, '_initFoldersFromDisk');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should initialize folders and return keypair', function(done) {
|
it('should initialize folders', function(done) {
|
||||||
keychainStub.getUserKeyPair.withArgs(emailAddress).yieldsAsync(null, mockKeyPair);
|
|
||||||
initFoldersStub.yieldsAsync();
|
initFoldersStub.yieldsAsync();
|
||||||
|
|
||||||
dao.init({
|
dao.init({
|
||||||
account: account
|
account: account
|
||||||
}, function(err, keypair) {
|
}, function(err) {
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
expect(keypair).to.exist;
|
|
||||||
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
|
||||||
expect(initFoldersStub.calledOnce).to.be.true;
|
expect(initFoldersStub.calledOnce).to.be.true;
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail when keychain errors', function(done) {
|
|
||||||
keychainStub.getUserKeyPair.yieldsAsync({});
|
|
||||||
|
|
||||||
dao.init({
|
|
||||||
account: account
|
|
||||||
}, function(err, keypair) {
|
|
||||||
expect(err).to.exist;
|
|
||||||
expect(keypair).to.not.exist;
|
|
||||||
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
|
||||||
expect(initFoldersStub.called).to.be.false;
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#unlock', function() {
|
describe('#unlock', function() {
|
||||||
|
@ -85,7 +85,9 @@ describe('Keychain DAO unit tests', function() {
|
|||||||
it('should not find a key', function(done) {
|
it('should not find a key', function(done) {
|
||||||
getPubKeyStub.yields();
|
getPubKeyStub.yields();
|
||||||
|
|
||||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: testUser
|
||||||
|
}, function(err, key) {
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
expect(key).to.not.exist;
|
expect(key).to.not.exist;
|
||||||
|
|
||||||
@ -97,7 +99,9 @@ describe('Keychain DAO unit tests', function() {
|
|||||||
getPubKeyStub.yields(null, oldKey);
|
getPubKeyStub.yields(null, oldKey);
|
||||||
pubkeyDaoStub.get.withArgs(oldKey._id).yields(null, oldKey);
|
pubkeyDaoStub.get.withArgs(oldKey._id).yields(null, oldKey);
|
||||||
|
|
||||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: testUser
|
||||||
|
}, function(err, key) {
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
expect(key).to.to.equal(oldKey);
|
expect(key).to.to.equal(oldKey);
|
||||||
|
|
||||||
@ -121,7 +125,33 @@ describe('Keychain DAO unit tests', function() {
|
|||||||
lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields();
|
lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields();
|
||||||
lawnchairDaoStub.persist.withArgs('publickey_' + newKey._id, newKey).yields();
|
lawnchairDaoStub.persist.withArgs('publickey_' + newKey._id, newKey).yields();
|
||||||
|
|
||||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: testUser
|
||||||
|
}, function(err, key) {
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
expect(key).to.equal(newKey);
|
||||||
|
|
||||||
|
expect(getPubKeyStub.calledOnce).to.be.true;
|
||||||
|
expect(pubkeyDaoStub.get.calledOnce).to.be.true;
|
||||||
|
expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true;
|
||||||
|
expect(lawnchairDaoStub.remove.calledOnce).to.be.true;
|
||||||
|
expect(lawnchairDaoStub.persist.calledOnce).to.be.true;
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update key without approval', function(done) {
|
||||||
|
getPubKeyStub.yields(null, oldKey);
|
||||||
|
pubkeyDaoStub.get.withArgs(oldKey._id).yields();
|
||||||
|
pubkeyDaoStub.getByUserId.withArgs(testUser).yields(null, newKey);
|
||||||
|
lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields();
|
||||||
|
lawnchairDaoStub.persist.withArgs('publickey_' + newKey._id, newKey).yields();
|
||||||
|
|
||||||
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: testUser,
|
||||||
|
overridePermission: true
|
||||||
|
}, function(err, key) {
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
expect(key).to.equal(newKey);
|
expect(key).to.equal(newKey);
|
||||||
|
|
||||||
@ -146,7 +176,9 @@ describe('Keychain DAO unit tests', function() {
|
|||||||
};
|
};
|
||||||
lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields();
|
lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields();
|
||||||
|
|
||||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: testUser
|
||||||
|
}, function(err, key) {
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
expect(key).to.not.exist;
|
expect(key).to.not.exist;
|
||||||
|
|
||||||
@ -167,7 +199,9 @@ describe('Keychain DAO unit tests', function() {
|
|||||||
code: 42
|
code: 42
|
||||||
});
|
});
|
||||||
|
|
||||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: testUser
|
||||||
|
}, function(err, key) {
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
expect(key).to.to.equal(oldKey);
|
expect(key).to.to.equal(oldKey);
|
||||||
|
|
||||||
@ -191,7 +225,9 @@ describe('Keychain DAO unit tests', function() {
|
|||||||
cb(false);
|
cb(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: testUser
|
||||||
|
}, function(err, key) {
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
expect(key).to.equal(oldKey);
|
expect(key).to.equal(oldKey);
|
||||||
|
|
||||||
@ -208,7 +244,9 @@ describe('Keychain DAO unit tests', function() {
|
|||||||
it('should not remove manually imported key', function(done) {
|
it('should not remove manually imported key', function(done) {
|
||||||
getPubKeyStub.yields(null, importedKey);
|
getPubKeyStub.yields(null, importedKey);
|
||||||
|
|
||||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: testUser
|
||||||
|
}, function(err, key) {
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
expect(key).to.equal(importedKey);
|
expect(key).to.equal(importedKey);
|
||||||
|
|
||||||
@ -225,7 +263,9 @@ describe('Keychain DAO unit tests', function() {
|
|||||||
code: 42
|
code: 42
|
||||||
});
|
});
|
||||||
|
|
||||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: testUser
|
||||||
|
}, function(err, key) {
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
expect(key).to.to.equal(oldKey);
|
expect(key).to.to.equal(oldKey);
|
||||||
|
|
||||||
@ -251,7 +291,9 @@ describe('Keychain DAO unit tests', function() {
|
|||||||
lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields();
|
lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields();
|
||||||
lawnchairDaoStub.persist.yields({});
|
lawnchairDaoStub.persist.yields({});
|
||||||
|
|
||||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: testUser
|
||||||
|
}, function(err, key) {
|
||||||
expect(err).to.exist;
|
expect(err).to.exist;
|
||||||
expect(key).to.not.exist;
|
expect(key).to.not.exist;
|
||||||
|
|
||||||
@ -275,7 +317,9 @@ describe('Keychain DAO unit tests', function() {
|
|||||||
};
|
};
|
||||||
lawnchairDaoStub.remove.yields({});
|
lawnchairDaoStub.remove.yields({});
|
||||||
|
|
||||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: testUser
|
||||||
|
}, function(err, key) {
|
||||||
expect(err).to.exist;
|
expect(err).to.exist;
|
||||||
expect(key).to.not.exist;
|
expect(key).to.not.exist;
|
||||||
|
|
||||||
@ -301,7 +345,9 @@ describe('Keychain DAO unit tests', function() {
|
|||||||
lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields();
|
lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields();
|
||||||
lawnchairDaoStub.persist.yields({});
|
lawnchairDaoStub.persist.yields({});
|
||||||
|
|
||||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: testUser
|
||||||
|
}, function(err, key) {
|
||||||
expect(err).to.exist;
|
expect(err).to.exist;
|
||||||
expect(key).to.not.exist;
|
expect(key).to.not.exist;
|
||||||
|
|
||||||
@ -319,7 +365,9 @@ describe('Keychain DAO unit tests', function() {
|
|||||||
getPubKeyStub.yields(null, oldKey);
|
getPubKeyStub.yields(null, oldKey);
|
||||||
pubkeyDaoStub.get.withArgs(oldKey._id).yields({});
|
pubkeyDaoStub.get.withArgs(oldKey._id).yields({});
|
||||||
|
|
||||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
keychainDao.refreshKeyForUserId({
|
||||||
|
userId: testUser
|
||||||
|
}, function(err, key) {
|
||||||
expect(err).to.exist;
|
expect(err).to.exist;
|
||||||
expect(key).to.not.exist;
|
expect(key).to.not.exist;
|
||||||
|
|
||||||
|
@ -364,7 +364,9 @@ describe('Mail List controller unit test', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields();
|
keychainMock.refreshKeyForUserId.withArgs({
|
||||||
|
userId: mail.from[0].address
|
||||||
|
}).yields();
|
||||||
|
|
||||||
scope.select(mail);
|
scope.select(mail);
|
||||||
|
|
||||||
@ -397,7 +399,7 @@ describe('Mail List controller unit test', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields();
|
keychainMock.refreshKeyForUserId.withArgs({userId: mail.from[0].address}).yields();
|
||||||
|
|
||||||
scope.select(mail);
|
scope.select(mail);
|
||||||
|
|
||||||
|
@ -192,7 +192,9 @@ describe('Write controller unit test', function() {
|
|||||||
address: 'asds@example.com'
|
address: 'asds@example.com'
|
||||||
};
|
};
|
||||||
|
|
||||||
keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields({
|
keychainMock.refreshKeyForUserId.withArgs({
|
||||||
|
userId: recipient.address
|
||||||
|
}).yields({
|
||||||
errMsg: '404 not found yadda yadda'
|
errMsg: '404 not found yadda yadda'
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -212,7 +214,9 @@ describe('Write controller unit test', function() {
|
|||||||
address: 'asdf@example.com'
|
address: 'asdf@example.com'
|
||||||
};
|
};
|
||||||
|
|
||||||
keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields(null, {
|
keychainMock.refreshKeyForUserId.withArgs({
|
||||||
|
userId: recipient.address
|
||||||
|
}).yields(null, {
|
||||||
userId: 'asdf@example.com'
|
userId: 'asdf@example.com'
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -240,7 +244,9 @@ describe('Write controller unit test', function() {
|
|||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields(null, key);
|
keychainMock.refreshKeyForUserId.withArgs({
|
||||||
|
userId: recipient.address
|
||||||
|
}).yields(null, key);
|
||||||
|
|
||||||
scope.$digest = function() {
|
scope.$digest = function() {
|
||||||
expect(recipient.key).to.deep.equal(key);
|
expect(recipient.key).to.deep.equal(key);
|
||||||
|
Loading…
Reference in New Issue
Block a user