mirror of
https://github.com/moparisthebest/mail
synced 2024-12-22 07:18:49 -05:00
[WO-851] Request OAuth token on each connection request
This commit is contained in:
parent
86653e8700
commit
0446f8219b
@ -4,12 +4,9 @@ var ngModule = angular.module('woEmail');
|
||||
ngModule.service('account', Account);
|
||||
module.exports = Account;
|
||||
|
||||
var axe = require('axe-logger'),
|
||||
util = require('crypto-lib').util,
|
||||
PgpMailer = require('pgpmailer'),
|
||||
ImapClient = require('imap-client');
|
||||
var util = require('crypto-lib').util;
|
||||
|
||||
function Account(appConfig, auth, accountStore, email, outbox, keychain, updateHandler, pgpbuilder, dialog) {
|
||||
function Account(appConfig, auth, accountStore, email, outbox, keychain, updateHandler, dialog) {
|
||||
this._appConfig = appConfig;
|
||||
this._auth = auth;
|
||||
this._accountStore = accountStore;
|
||||
@ -17,7 +14,6 @@ function Account(appConfig, auth, accountStore, email, outbox, keychain, updateH
|
||||
this._outbox = outbox;
|
||||
this._keychain = keychain;
|
||||
this._updateHandler = updateHandler;
|
||||
this._pgpbuilder = pgpbuilder;
|
||||
this._dialog = dialog;
|
||||
this._accounts = []; // init accounts list
|
||||
}
|
||||
@ -102,68 +98,16 @@ Account.prototype.init = function(options) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the user agent is online.
|
||||
*/
|
||||
Account.prototype.isOnline = function() {
|
||||
return navigator.onLine;
|
||||
};
|
||||
|
||||
/**
|
||||
* Event that is called when the user agent goes online. This create new instances of the imap-client and pgp-mailer and connects to the mail server.
|
||||
*/
|
||||
Account.prototype.onConnect = function(callback) {
|
||||
var self = this;
|
||||
var config = self._appConfig.config;
|
||||
|
||||
callback = callback || self._dialog.error;
|
||||
|
||||
if (!self.isOnline() || !self._emailDao || !self._emailDao._account) {
|
||||
if (!this._emailDao || !this._emailDao._account) {
|
||||
// prevent connection infinite loop
|
||||
return;
|
||||
}
|
||||
|
||||
// init imap/smtp clients
|
||||
self._auth.getCredentials().then(function(credentials) {
|
||||
// add the maximum update batch size for imap folders to the imap configuration
|
||||
credentials.imap.maxUpdateSize = config.imapUpdateBatchSize;
|
||||
|
||||
// tls socket worker path for multithreaded tls in non-native tls environments
|
||||
credentials.imap.tlsWorkerPath = credentials.smtp.tlsWorkerPath = config.workerPath + '/tcp-socket-tls-worker.min.js';
|
||||
|
||||
var pgpMailer = new PgpMailer(credentials.smtp, self._pgpbuilder);
|
||||
var imapClient = new ImapClient(credentials.imap);
|
||||
imapClient.onError = onConnectionError;
|
||||
pgpMailer.onError = onConnectionError;
|
||||
|
||||
// certificate update handling
|
||||
imapClient.onCert = self._auth.handleCertificateUpdate.bind(self._auth, 'imap', self.onConnect.bind(self), self._dialog.error);
|
||||
pgpMailer.onCert = self._auth.handleCertificateUpdate.bind(self._auth, 'smtp', self.onConnect.bind(self), self._dialog.error);
|
||||
|
||||
// connect to clients
|
||||
return self._emailDao.onConnect({
|
||||
imapClient: imapClient,
|
||||
pgpMailer: pgpMailer,
|
||||
ignoreUploadOnSent: self._emailDao.checkIgnoreUploadOnSent(credentials.imap.host)
|
||||
});
|
||||
}).then(callback).catch(callback);
|
||||
|
||||
function onConnectionError(error) {
|
||||
axe.debug('Connection error. Attempting reconnect in ' + config.reconnectInterval + ' ms. Error: ' + (error.errMsg || error.message) + (error.stack ? ('\n' + error.stack) : ''));
|
||||
|
||||
setTimeout(function() {
|
||||
axe.debug('Reconnecting...');
|
||||
// re-init client modules on error
|
||||
self.onConnect(function(err) {
|
||||
if (err) {
|
||||
axe.error('Reconnect attempt failed! ' + (err.errMsg || err.message) + (err.stack ? ('\n' + err.stack) : ''));
|
||||
return;
|
||||
}
|
||||
|
||||
axe.debug('Reconnect attempt complete.');
|
||||
});
|
||||
}, config.reconnectInterval);
|
||||
}
|
||||
this._emailDao.onConnect().then(callback).catch(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -5,7 +5,10 @@ ngModule.service('email', Email);
|
||||
module.exports = Email;
|
||||
|
||||
var config = require('../app-config').config,
|
||||
str = require('../app-config').string;
|
||||
str = require('../app-config').string,
|
||||
axe = require('axe-logger'),
|
||||
PgpMailer = require('pgpmailer'),
|
||||
ImapClient = require('imap-client');
|
||||
|
||||
//
|
||||
//
|
||||
@ -50,13 +53,15 @@ var MSG_PART_TYPE_HTML = 'html';
|
||||
* @param {Object} pgpbuilder Generates and encrypts MIME and SMTP messages
|
||||
* @param {Object} mailreader Parses MIME messages received from IMAP
|
||||
*/
|
||||
function Email(keychain, pgp, accountStore, pgpbuilder, mailreader, dialog) {
|
||||
function Email(keychain, pgp, accountStore, pgpbuilder, mailreader, dialog, appConfig, auth) {
|
||||
this._keychain = keychain;
|
||||
this._pgp = pgp;
|
||||
this._devicestorage = accountStore;
|
||||
this._pgpbuilder = pgpbuilder;
|
||||
this._mailreader = mailreader;
|
||||
this._dialog = dialog;
|
||||
this._appConfig = appConfig;
|
||||
this._auth = auth;
|
||||
}
|
||||
|
||||
|
||||
@ -896,37 +901,40 @@ Email.prototype.decryptBody = function(options) {
|
||||
* Encrypted (if necessary) and sends a message with a predefined clear text greeting.
|
||||
*
|
||||
* @param {Object} options.email The message to be sent
|
||||
* @param {Object} mailer an instance of the pgpmailer to be used for testing purposes only
|
||||
*/
|
||||
Email.prototype.sendEncrypted = function(options) {
|
||||
Email.prototype.sendEncrypted = function(options, mailer) {
|
||||
// mime encode, sign, encrypt and send email via smtp
|
||||
return this._sendGeneric({
|
||||
encrypt: true,
|
||||
smtpclient: options.smtpclient, // filled solely in the integration test, undefined in normal usage
|
||||
mail: options.email,
|
||||
publicKeysArmored: options.email.publicKeysArmored
|
||||
});
|
||||
}, mailer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a signed message in the plain
|
||||
*
|
||||
* @param {Object} options.email The message to be sent
|
||||
* @param {Object} mailer an instance of the pgpmailer to be used for testing purposes only
|
||||
*/
|
||||
Email.prototype.sendPlaintext = function(options) {
|
||||
Email.prototype.sendPlaintext = function(options, mailer) {
|
||||
// add suffix to plaintext mail
|
||||
options.email.body += str.signature + config.cloudUrl + '/' + this._account.emailAddress;
|
||||
// mime encode, sign and send email via smtp
|
||||
return this._sendGeneric({
|
||||
smtpclient: options.smtpclient, // filled solely in the integration test, undefined in normal usage
|
||||
mail: options.email
|
||||
});
|
||||
}, mailer);
|
||||
};
|
||||
|
||||
/**
|
||||
* This funtion wraps error handling for sending via pgpMailer and uploading to imap.
|
||||
* @param {Object} options.email The message to be sent
|
||||
* @param {Object} mailer an instance of the pgpmailer to be used for testing purposes only
|
||||
*/
|
||||
Email.prototype._sendGeneric = function(options) {
|
||||
Email.prototype._sendGeneric = function(options, mailer) {
|
||||
var self = this;
|
||||
self.busy();
|
||||
return new Promise(function(resolve) {
|
||||
@ -934,8 +942,33 @@ Email.prototype._sendGeneric = function(options) {
|
||||
resolve();
|
||||
|
||||
}).then(function() {
|
||||
return self._mailerSend(options);
|
||||
// get the smtp credentials
|
||||
return self._auth.getCredentials();
|
||||
|
||||
}).then(function(credentials) {
|
||||
// gmail does not require you to upload to the sent items folder after successful sending, whereas most other providers do
|
||||
self.ignoreUploadOnSent = self.checkIgnoreUploadOnSent(credentials.smtp.host);
|
||||
|
||||
// tls socket worker path for multithreaded tls in non-native tls environments
|
||||
credentials.smtp.tlsWorkerPath = config.workerPath + '/tcp-socket-tls-worker.min.js';
|
||||
|
||||
// create a new pgpmailer
|
||||
self._pgpMailer = (mailer || new PgpMailer(credentials.smtp, self._pgpbuilder));
|
||||
|
||||
// certificate update retriggers sending after cert update is persisted
|
||||
self._pgpMailer.onCert = self._auth.handleCertificateUpdate.bind(self._auth, 'smtp', self._sendGeneric.bind(self, options), self._dialog.error);
|
||||
}).then(function() {
|
||||
|
||||
// send the email
|
||||
return new Promise(function(resolve, reject) {
|
||||
self._pgpMailer.send(options, function(err, rfcText) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(rfcText);
|
||||
}
|
||||
});
|
||||
});
|
||||
}).then(function(rfcText) {
|
||||
// try to upload to sent, but we don't actually care if the upload failed or not
|
||||
// this should not negatively impact the process of sending
|
||||
@ -987,29 +1020,45 @@ Email.prototype.encrypt = function(options) {
|
||||
* given instance of the imap client. If the connection attempt was successful, it will
|
||||
* update the locally available folders with the newly received IMAP folder listing.
|
||||
*
|
||||
* @param {Object} options.imapClient The IMAP client used to receive messages
|
||||
* @param {Object} options.pgpMailer The SMTP client used to send messages
|
||||
* @param {Object} imap an instance of the imap-client to be used for testing purposes only
|
||||
*/
|
||||
Email.prototype.onConnect = function(options) {
|
||||
Email.prototype.onConnect = function(imap) {
|
||||
var self = this;
|
||||
|
||||
self._account.loggingIn = true;
|
||||
|
||||
self._imapClient = options.imapClient;
|
||||
self._pgpMailer = options.pgpMailer;
|
||||
// init imap/smtp clients
|
||||
return self._auth.getCredentials().then(function(credentials) {
|
||||
// add the maximum update batch size for imap folders to the imap configuration
|
||||
credentials.imap.maxUpdateSize = config.imapUpdateBatchSize;
|
||||
|
||||
// gmail does not require you to upload to the sent items folder after successful sending, whereas most other providers do
|
||||
self.ignoreUploadOnSent = !!options.ignoreUploadOnSent;
|
||||
// tls socket worker path for multithreaded tls in non-native tls environments
|
||||
credentials.imap.tlsWorkerPath = config.workerPath + '/tcp-socket-tls-worker.min.js';
|
||||
|
||||
return imapLogin().then(function() {
|
||||
self._imapClient = (imap || new ImapClient(credentials.imap));
|
||||
|
||||
self._imapClient.onError = onConnectionError; // connection error handling
|
||||
self._imapClient.onCert = self._auth.handleCertificateUpdate.bind(self._auth, 'imap', self.onConnect.bind(self), self._dialog.error); // certificate update handling
|
||||
self._imapClient.onSyncUpdate = self._onSyncUpdate.bind(self); // attach sync update handler
|
||||
|
||||
}).then(function() {
|
||||
// imap login
|
||||
return new Promise(function(resolve, reject) {
|
||||
self._imapClient.login(function(err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}).then(function() {
|
||||
self._account.loggingIn = false;
|
||||
// init folders
|
||||
return self._initFoldersFromImap();
|
||||
|
||||
}).then(function() {
|
||||
// attach sync update handler
|
||||
self._imapClient.onSyncUpdate = self._onSyncUpdate.bind(self);
|
||||
|
||||
// fill the imap mailboxCache with information we have locally available:
|
||||
// - highest locally available moseq (NB! JavaScript can't handle 64 bit uints, so modseq values are strings)
|
||||
// - list of locally available uids
|
||||
@ -1071,16 +1120,20 @@ Email.prototype.onConnect = function(options) {
|
||||
});
|
||||
});
|
||||
|
||||
function imapLogin() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
self._imapClient.login(function(err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
function onConnectionError(error) {
|
||||
axe.debug('IMAP connection error, disconnected. Reason: ' + error.message + (error.stack ? ('\n' + error.stack) : ''));
|
||||
|
||||
if (!self.isOnline()) {
|
||||
return;
|
||||
}
|
||||
|
||||
axe.debug('Attempting reconnect in ' + config.reconnectInterval / 1000 + ' seconds.');
|
||||
|
||||
setTimeout(function() {
|
||||
axe.debug('Reconnecting the IMAP stack');
|
||||
// re-init client modules on error
|
||||
self.onConnect().catch(self._dialog.error);
|
||||
}, config.reconnectInterval);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1667,24 +1720,6 @@ Email.prototype._parse = function(options) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Send email via smtp
|
||||
* @param {Object} options The options to be passed to the pgpMailer
|
||||
* @return {Promise}
|
||||
*/
|
||||
Email.prototype._mailerSend = function(options) {
|
||||
var self = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
self._pgpMailer.send(options, function(err, rfcText) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(rfcText);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Uploads a message to the sent folder, if necessary.
|
||||
* Calls back immediately if ignoreUploadOnSent == true or not sent folder was found.
|
||||
@ -1758,6 +1793,13 @@ Email.prototype.checkIgnoreUploadOnSent = function(hostname) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check if the user agent is online.
|
||||
*/
|
||||
Email.prototype.isOnline = function() {
|
||||
return navigator.onLine;
|
||||
};
|
||||
|
||||
//
|
||||
//
|
||||
// Helper Functions
|
||||
|
@ -240,16 +240,8 @@ Auth.prototype.useOAuth = function(hostname) {
|
||||
Auth.prototype.getOAuthToken = function() {
|
||||
var self = this;
|
||||
|
||||
if (self.oauthToken) {
|
||||
// removed cached token and get a new one
|
||||
return self._oauth.refreshToken({
|
||||
emailAddress: self.emailAddress,
|
||||
oldToken: self.oauthToken
|
||||
}).then(onToken);
|
||||
} else {
|
||||
// get a fresh oauth token
|
||||
return self._oauth.getOAuthToken(self.emailAddress).then(onToken);
|
||||
}
|
||||
// get a fresh oauth token
|
||||
return self._oauth.getOAuthToken(self.emailAddress).then(onToken);
|
||||
|
||||
function onToken(oauthToken) {
|
||||
// shortcut if the email address is already known
|
||||
@ -317,7 +309,7 @@ Auth.prototype._loadCredentials = function() {
|
||||
* @param {Function} callback The error handler
|
||||
* @param {[type]} pemEncodedCert The PEM encoded SSL certificate
|
||||
*/
|
||||
Auth.prototype.handleCertificateUpdate = function(component, onConnect, callback, pemEncodedCert) {
|
||||
Auth.prototype.handleCertificateUpdate = function(component, reconnectCallback, callback, pemEncodedCert) {
|
||||
var self = this;
|
||||
|
||||
axe.debug('new ssl certificate received: ' + pemEncodedCert);
|
||||
@ -351,7 +343,7 @@ Auth.prototype.handleCertificateUpdate = function(component, onConnect, callback
|
||||
self[component].ca = pemEncodedCert;
|
||||
self.credentialsDirty = true;
|
||||
self.storeCredentials().then(function() {
|
||||
onConnect(callback);
|
||||
reconnectCallback(callback);
|
||||
}).catch(callback);
|
||||
}
|
||||
});
|
||||
|
@ -14,7 +14,7 @@ var ImapClient = require('imap-client'),
|
||||
describe('Email DAO integration tests', function() {
|
||||
this.timeout(100000);
|
||||
|
||||
var accountService, emailDao, imapClient, imapMessages, imapFolders, imapServer, smtpServer, smtpClient, userStorage, auth,
|
||||
var accountService, emailDao, imapClient, pgpMailer, imapMessages, imapFolders, imapServer, smtpServer, smtpClient, userStorage, auth,
|
||||
mockKeyPair, inbox, spam;
|
||||
|
||||
var testAccount = {
|
||||
@ -209,6 +209,7 @@ describe('Email DAO integration tests', function() {
|
||||
});
|
||||
|
||||
function initAccountService() {
|
||||
|
||||
// create imap/smtp clients with stubbed tcp sockets
|
||||
imapClient = new ImapClient({
|
||||
auth: {
|
||||
@ -231,25 +232,10 @@ describe('Email DAO integration tests', function() {
|
||||
user: testAccount.user,
|
||||
xoauth2: testAccount.xoauth2
|
||||
},
|
||||
secure: true,
|
||||
ca: ['random string'],
|
||||
onError: console.error
|
||||
secure: true
|
||||
});
|
||||
|
||||
smtpClient._TCPSocket = smtpServer.createTCPSocket();
|
||||
|
||||
// stub the onConnect function to inject the test imap/smtp clients
|
||||
sinon.stub(accountService, 'onConnect', function(cb) {
|
||||
accountService._emailDao.onConnect({
|
||||
imapClient: imapClient,
|
||||
pgpMailer: new PgpMailer({
|
||||
tls: {
|
||||
ca: 'random string'
|
||||
}
|
||||
}, accountService._pgpbuilder)
|
||||
}).then(cb).catch(cb);
|
||||
});
|
||||
|
||||
// clear the local database before each test
|
||||
var cleanup = new DeviceStorageDAO(new LawnchairDAO());
|
||||
cleanup.init(testAccount.user).then(function() {
|
||||
@ -260,12 +246,22 @@ describe('Email DAO integration tests', function() {
|
||||
userStorage = accountService._accountStore;
|
||||
auth = accountService._auth;
|
||||
|
||||
auth.setCredentials({
|
||||
emailAddress: testAccount.user,
|
||||
password: 'asd',
|
||||
smtp: {}, // host and port don't matter here since we're using
|
||||
imap: {} // a preconfigured smtpclient with mocked tcp sockets
|
||||
});
|
||||
|
||||
auth.init().then(function() {
|
||||
accountService.init({
|
||||
emailAddress: testAccount.user
|
||||
}).then(function() {
|
||||
emailDao = accountService._emailDao;
|
||||
|
||||
// retrieve the pgpbuilder from the emaildao and initialize the pgpmailer with the existing pgpbuilder
|
||||
pgpMailer = new PgpMailer({}, emailDao._pgpbuilder);
|
||||
|
||||
// stub rest request to key server
|
||||
sinon.stub(emailDao._keychain._publicKeyDao, 'get').returns(resolves(mockKeyPair.publicKey));
|
||||
sinon.stub(emailDao._keychain._publicKeyDao, 'getByUserId').returns(resolves(mockKeyPair.publicKey));
|
||||
@ -297,9 +293,7 @@ describe('Email DAO integration tests', function() {
|
||||
passphrase: testAccount.pass,
|
||||
keypair: mockKeyPair
|
||||
}).then(function() {
|
||||
accountService.onConnect(function(err) {
|
||||
expect(err).to.not.exist;
|
||||
});
|
||||
accountService._emailDao.onConnect(imapClient);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -310,7 +304,6 @@ describe('Email DAO integration tests', function() {
|
||||
afterEach(function(done) {
|
||||
openpgp.initWorker.restore();
|
||||
mailreader.startWorker.restore();
|
||||
accountService.onConnect.restore();
|
||||
|
||||
imapClient.stopListeningForChanges(function() {
|
||||
imapClient.logout(function() {
|
||||
@ -701,7 +694,7 @@ describe('Email DAO integration tests', function() {
|
||||
subject: 'plaintext test',
|
||||
body: 'hello world!'
|
||||
}
|
||||
}).then(function() {
|
||||
}, pgpMailer).then(function() {
|
||||
expect(smtpServer.onmail.callCount).to.equal(1);
|
||||
done();
|
||||
});
|
||||
@ -726,7 +719,7 @@ describe('Email DAO integration tests', function() {
|
||||
body: 'hello world!',
|
||||
publicKeysArmored: [mockKeyPair.publicKey.publicKey]
|
||||
}
|
||||
}).then(function() {
|
||||
}, pgpMailer).then(function() {
|
||||
expect(smtpServer.onmail.callCount).to.equal(1);
|
||||
done();
|
||||
});
|
||||
@ -771,7 +764,41 @@ describe('Email DAO integration tests', function() {
|
||||
subject: 'plaintext test',
|
||||
body: expectedBody
|
||||
}
|
||||
}).then(function() {});
|
||||
}, pgpMailer).then(function() {});
|
||||
});
|
||||
|
||||
it('should send & receive a signed encrypted message', function(done) {
|
||||
var expectedBody = "asdasdasdasdasdasdasdasdasdasdasdasd asdasdasdasdasdasdasdasdasdasdasdasd";
|
||||
|
||||
emailDao.onIncomingMessage = function(messages) {
|
||||
emailDao.getBody({
|
||||
folder: inbox,
|
||||
message: messages[0]
|
||||
}).then(function(message) {
|
||||
return emailDao.decryptBody({
|
||||
message: message
|
||||
});
|
||||
}).then(function(message) {
|
||||
expect(message.encrypted).to.be.true;
|
||||
expect(message.signed).to.be.true;
|
||||
expect(message.signaturesValid).to.be.true;
|
||||
expect(message.attachments.length).to.equal(0);
|
||||
expect(message.body).to.equal(expectedBody);
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
emailDao.sendEncrypted({
|
||||
smtpclient: smtpClient,
|
||||
|
||||
email: {
|
||||
from: [testAccount.user],
|
||||
to: [testAccount.user],
|
||||
subject: 'plaintext test',
|
||||
body: expectedBody,
|
||||
publicKeysArmored: [mockKeyPair.publicKey.publicKey]
|
||||
}
|
||||
}, pgpMailer).then(function() {});
|
||||
});
|
||||
});
|
||||
});
|
@ -11,7 +11,7 @@ var Account = require('../../../src/js/email/account'),
|
||||
Dialog = require('../../../src/js/util/dialog');
|
||||
|
||||
describe('Account Service unit test', function() {
|
||||
var account, authStub, outboxStub, emailStub, devicestorageStub, keychainStub, updateHandlerStub, pgpbuilderStub, dialogStub,
|
||||
var account, authStub, outboxStub, emailStub, devicestorageStub, keychainStub, updateHandlerStub, dialogStub,
|
||||
realname = 'John Doe',
|
||||
dummyUser = 'spiderpig@springfield.com';
|
||||
|
||||
@ -25,9 +25,8 @@ describe('Account Service unit test', function() {
|
||||
outboxStub = sinon.createStubInstance(Outbox);
|
||||
keychainStub = sinon.createStubInstance(Keychain);
|
||||
updateHandlerStub = sinon.createStubInstance(UpdateHandler);
|
||||
pgpbuilderStub = {};
|
||||
dialogStub = sinon.createStubInstance(Dialog);
|
||||
account = new Account(appConfig, authStub, devicestorageStub, emailStub, outboxStub, keychainStub, updateHandlerStub, pgpbuilderStub, dialogStub);
|
||||
account = new Account(appConfig, authStub, devicestorageStub, emailStub, outboxStub, keychainStub, updateHandlerStub, dialogStub);
|
||||
});
|
||||
|
||||
afterEach(function() {});
|
||||
@ -200,47 +199,15 @@ describe('Account Service unit test', function() {
|
||||
});
|
||||
|
||||
describe('onConnect', function() {
|
||||
var credentials = {
|
||||
imap: {},
|
||||
smtp: {}
|
||||
};
|
||||
beforeEach(function() {
|
||||
emailStub._account = {};
|
||||
sinon.stub(account, 'isOnline').returns(true);
|
||||
});
|
||||
afterEach(function() {
|
||||
account.isOnline.restore();
|
||||
});
|
||||
|
||||
it('should fail due to _auth.getCredentials', function(done) {
|
||||
authStub.getCredentials.returns(rejects(new Error('asdf')));
|
||||
|
||||
dialogStub.error = function(err) {
|
||||
expect(err.message).to.match(/asdf/);
|
||||
done();
|
||||
};
|
||||
|
||||
account.onConnect();
|
||||
});
|
||||
|
||||
it('should fail due to _auth.getCredentials', function(done) {
|
||||
authStub.getCredentials.returns(rejects(new Error('asdf')));
|
||||
|
||||
account.onConnect(function(err) {
|
||||
expect(err.message).to.match(/asdf/);
|
||||
expect(dialogStub.error.called).to.be.false;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should work', function(done) {
|
||||
authStub.getCredentials.returns(resolves(credentials));
|
||||
authStub.handleCertificateUpdate.returns(resolves());
|
||||
emailStub.onConnect.returns(resolves());
|
||||
|
||||
account.onConnect(function(err) {
|
||||
expect(err).to.not.exist;
|
||||
expect(dialogStub.error.called).to.be.false;
|
||||
expect(emailStub.onConnect.calledOnce).to.be.true;
|
||||
done();
|
||||
});
|
||||
|
@ -9,6 +9,8 @@ var mailreader = require('mailreader'),
|
||||
KeychainDAO = require('../../../src/js/service/keychain'),
|
||||
PGP = require('../../../src/js/crypto/pgp'),
|
||||
DeviceStorageDAO = require('../../../src/js/service/devicestorage'),
|
||||
appConfig = require('../../../src/js/app-config'),
|
||||
Auth = require('../../../src/js/service/auth'),
|
||||
Dialog = require('../../../src/js/util/dialog');
|
||||
|
||||
|
||||
@ -20,7 +22,7 @@ describe('Email DAO unit tests', function() {
|
||||
var dao;
|
||||
|
||||
// mocks
|
||||
var keychainStub, imapClientStub, pgpMailerStub, pgpBuilderStub, pgpStub, devicestorageStub, parseStub, dialogStub;
|
||||
var keychainStub, imapClientStub, pgpMailerStub, pgpBuilderStub, pgpStub, devicestorageStub, parseStub, dialogStub, authStub;
|
||||
|
||||
// config
|
||||
var emailAddress, passphrase, asymKeySize, account;
|
||||
@ -118,11 +120,12 @@ describe('Email DAO unit tests', function() {
|
||||
parseStub = sinon.stub(mailreader, 'parse');
|
||||
devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
|
||||
dialogStub = sinon.createStubInstance(Dialog);
|
||||
authStub = sinon.createStubInstance(Auth);
|
||||
|
||||
//
|
||||
// setup the SUT
|
||||
//
|
||||
dao = new EmailDAO(keychainStub, pgpStub, devicestorageStub, pgpBuilderStub, mailreader, dialogStub);
|
||||
dao = new EmailDAO(keychainStub, pgpStub, devicestorageStub, pgpBuilderStub, mailreader, dialogStub, appConfig, authStub);
|
||||
dao._account = account;
|
||||
dao._pgpMailer = pgpMailerStub;
|
||||
dao._imapClient = imapClientStub;
|
||||
@ -1616,11 +1619,23 @@ describe('Email DAO unit tests', function() {
|
||||
});
|
||||
|
||||
describe('#sendEncrypted', function() {
|
||||
var publicKeys = ["PUBLIC KEY"],
|
||||
var credentials,
|
||||
publicKeys,
|
||||
dummyMail,
|
||||
msg;
|
||||
|
||||
beforeEach(function() {
|
||||
credentials = {
|
||||
smtp: {
|
||||
host: 'foo.io'
|
||||
}
|
||||
};
|
||||
publicKeys = ["PUBLIC KEY"];
|
||||
dummyMail = {
|
||||
publicKeysArmored: publicKeys
|
||||
},
|
||||
};
|
||||
msg = 'wow. such message. much rfc2822.';
|
||||
});
|
||||
|
||||
it('should send encrypted and upload to sent', function(done) {
|
||||
imapClientStub.uploadMessage.withArgs({
|
||||
@ -1628,6 +1643,7 @@ describe('Email DAO unit tests', function() {
|
||||
message: msg
|
||||
}).yields();
|
||||
|
||||
authStub.getCredentials.returns(resolves(credentials));
|
||||
pgpMailerStub.send.withArgs({
|
||||
encrypt: true,
|
||||
mail: dummyMail,
|
||||
@ -1637,17 +1653,20 @@ describe('Email DAO unit tests', function() {
|
||||
|
||||
dao.sendEncrypted({
|
||||
email: dummyMail
|
||||
}).then(function() {
|
||||
}, pgpMailerStub).then(function() {
|
||||
expect(authStub.getCredentials.calledOnce).to.be.true;
|
||||
expect(pgpMailerStub.send.calledOnce).to.be.true;
|
||||
expect(imapClientStub.uploadMessage.calledOnce).to.be.true;
|
||||
expect(dao.ignoreUploadOnSent).to.be.false;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should send encrypted and not upload to sent', function(done) {
|
||||
dao.ignoreUploadOnSent = true;
|
||||
credentials.smtp.host = 'smtp.gmail.com';
|
||||
|
||||
authStub.getCredentials.returns(resolves(credentials));
|
||||
pgpMailerStub.send.withArgs({
|
||||
encrypt: true,
|
||||
mail: dummyMail,
|
||||
@ -1657,9 +1676,11 @@ describe('Email DAO unit tests', function() {
|
||||
|
||||
dao.sendEncrypted({
|
||||
email: dummyMail
|
||||
}).then(function() {
|
||||
}, pgpMailerStub).then(function() {
|
||||
expect(authStub.getCredentials.calledOnce).to.be.true;
|
||||
expect(pgpMailerStub.send.calledOnce).to.be.true;
|
||||
expect(imapClientStub.uploadMessage.called).to.be.false;
|
||||
expect(dao.ignoreUploadOnSent).to.be.true;
|
||||
|
||||
done();
|
||||
});
|
||||
@ -1668,12 +1689,14 @@ describe('Email DAO unit tests', function() {
|
||||
it('should send encrypted and ignore error on upload', function(done) {
|
||||
imapClientStub.uploadMessage.yields(new Error());
|
||||
pgpMailerStub.send.yieldsAsync(null, msg);
|
||||
authStub.getCredentials.returns(resolves(credentials));
|
||||
|
||||
dao.sendEncrypted({
|
||||
email: dummyMail
|
||||
}).then(function() {
|
||||
}, pgpMailerStub).then(function() {
|
||||
expect(pgpMailerStub.send.calledOnce).to.be.true;
|
||||
expect(imapClientStub.uploadMessage.calledOnce).to.be.true;
|
||||
expect(authStub.getCredentials.calledOnce).to.be.true;
|
||||
|
||||
done();
|
||||
});
|
||||
@ -1681,12 +1704,14 @@ describe('Email DAO unit tests', function() {
|
||||
|
||||
it('should not send when pgpmailer fails', function(done) {
|
||||
pgpMailerStub.send.yieldsAsync({});
|
||||
authStub.getCredentials.returns(resolves(credentials));
|
||||
|
||||
dao.sendEncrypted({
|
||||
email: dummyMail
|
||||
}).catch(function(err) {
|
||||
}, pgpMailerStub).catch(function(err) {
|
||||
expect(err).to.exist;
|
||||
|
||||
expect(authStub.getCredentials.calledOnce).to.be.true;
|
||||
expect(pgpMailerStub.send.calledOnce).to.be.true;
|
||||
expect(imapClientStub.uploadMessage.called).to.be.false;
|
||||
|
||||
@ -1699,8 +1724,9 @@ describe('Email DAO unit tests', function() {
|
||||
|
||||
dao.sendEncrypted({
|
||||
email: dummyMail
|
||||
}).catch(function(err) {
|
||||
}, pgpMailerStub).catch(function(err) {
|
||||
expect(err.code).to.equal(42);
|
||||
expect(authStub.getCredentials.called).to.be.false;
|
||||
expect(pgpMailerStub.send.called).to.be.false;
|
||||
expect(imapClientStub.uploadMessage.called).to.be.false;
|
||||
done();
|
||||
@ -1710,14 +1736,26 @@ describe('Email DAO unit tests', function() {
|
||||
});
|
||||
|
||||
describe('#sendPlaintext', function() {
|
||||
var dummyMail = {};
|
||||
var msg = 'wow. such message. much rfc2822.';
|
||||
var credentials,
|
||||
dummyMail,
|
||||
msg;
|
||||
|
||||
beforeEach(function() {
|
||||
credentials = {
|
||||
smtp: {
|
||||
host: 'foo.io'
|
||||
}
|
||||
};
|
||||
dummyMail = {};
|
||||
msg = 'wow. such message. much rfc2822.';
|
||||
});
|
||||
|
||||
it('should send in the plain and upload to sent', function(done) {
|
||||
pgpMailerStub.send.withArgs({
|
||||
smtpclient: undefined,
|
||||
mail: dummyMail
|
||||
}).yieldsAsync(null, msg);
|
||||
authStub.getCredentials.returns(resolves(credentials));
|
||||
|
||||
imapClientStub.uploadMessage.withArgs({
|
||||
path: sentFolder.path,
|
||||
@ -1726,7 +1764,8 @@ describe('Email DAO unit tests', function() {
|
||||
|
||||
dao.sendPlaintext({
|
||||
email: dummyMail
|
||||
}).then(function() {
|
||||
}, pgpMailerStub).then(function() {
|
||||
expect(authStub.getCredentials.calledOnce).to.be.true;
|
||||
expect(pgpMailerStub.send.calledOnce).to.be.true;
|
||||
expect(imapClientStub.uploadMessage.calledOnce).to.be.true;
|
||||
done();
|
||||
@ -1735,15 +1774,18 @@ describe('Email DAO unit tests', function() {
|
||||
|
||||
it('should send in the plain and not upload to sent', function(done) {
|
||||
dao.ignoreUploadOnSent = true;
|
||||
credentials.smtp.host = 'smtp.gmail.com';
|
||||
|
||||
pgpMailerStub.send.withArgs({
|
||||
smtpclient: undefined,
|
||||
mail: dummyMail
|
||||
}).yieldsAsync(null, msg);
|
||||
authStub.getCredentials.returns(resolves(credentials));
|
||||
|
||||
dao.sendPlaintext({
|
||||
email: dummyMail
|
||||
}).then(function() {
|
||||
}, pgpMailerStub).then(function() {
|
||||
expect(authStub.getCredentials.calledOnce).to.be.true;
|
||||
expect(pgpMailerStub.send.calledOnce).to.be.true;
|
||||
expect(imapClientStub.uploadMessage.called).to.be.false;
|
||||
done();
|
||||
@ -1753,10 +1795,12 @@ describe('Email DAO unit tests', function() {
|
||||
it('should send and ignore error on upload', function(done) {
|
||||
imapClientStub.uploadMessage.yields(new Error());
|
||||
pgpMailerStub.send.yieldsAsync(null, msg);
|
||||
authStub.getCredentials.returns(resolves(credentials));
|
||||
|
||||
dao.sendEncrypted({
|
||||
dao.sendPlaintext({
|
||||
email: dummyMail
|
||||
}).then(function() {
|
||||
}, pgpMailerStub).then(function() {
|
||||
expect(authStub.getCredentials.calledOnce).to.be.true;
|
||||
expect(pgpMailerStub.send.calledOnce).to.be.true;
|
||||
expect(imapClientStub.uploadMessage.calledOnce).to.be.true;
|
||||
|
||||
@ -1766,11 +1810,13 @@ describe('Email DAO unit tests', function() {
|
||||
|
||||
it('should not send due to error', function(done) {
|
||||
pgpMailerStub.send.yieldsAsync({});
|
||||
authStub.getCredentials.returns(resolves(credentials));
|
||||
|
||||
dao.sendPlaintext({
|
||||
email: dummyMail
|
||||
}).catch(function(err) {
|
||||
}, pgpMailerStub).catch(function(err) {
|
||||
expect(err).to.exist;
|
||||
expect(authStub.getCredentials.calledOnce).to.be.true;
|
||||
expect(pgpMailerStub.send.calledOnce).to.be.true;
|
||||
expect(imapClientStub.uploadMessage.called).to.be.false;
|
||||
done();
|
||||
@ -1782,8 +1828,9 @@ describe('Email DAO unit tests', function() {
|
||||
|
||||
dao.sendPlaintext({
|
||||
email: dummyMail
|
||||
}).catch(function(err) {
|
||||
}, pgpMailerStub).catch(function(err) {
|
||||
expect(err.code).to.equal(42);
|
||||
expect(authStub.getCredentials.called).to.be.false;
|
||||
expect(pgpMailerStub.send.called).to.be.false;
|
||||
expect(imapClientStub.uploadMessage.called).to.be.false;
|
||||
done();
|
||||
@ -1805,12 +1852,15 @@ describe('Email DAO unit tests', function() {
|
||||
describe('event handlers', function() {
|
||||
|
||||
describe('#onConnect', function() {
|
||||
var initFoldersStub;
|
||||
var initFoldersStub, credentials;
|
||||
|
||||
beforeEach(function() {
|
||||
initFoldersStub = sinon.stub(dao, '_initFoldersFromImap');
|
||||
delete dao._imapClient;
|
||||
delete dao._pgpMailer;
|
||||
|
||||
credentials = {
|
||||
imap: {}
|
||||
};
|
||||
});
|
||||
|
||||
it('should connect', function(done) {
|
||||
@ -1818,16 +1868,13 @@ describe('Email DAO unit tests', function() {
|
||||
uid: 123,
|
||||
modseq: '123'
|
||||
}];
|
||||
authStub.getCredentials.returns(resolves(credentials));
|
||||
imapClientStub.login.yieldsAsync();
|
||||
imapClientStub.selectMailbox.yields();
|
||||
imapClientStub.listenForChanges.yields();
|
||||
initFoldersStub.returns(resolves());
|
||||
|
||||
dao.onConnect({
|
||||
imapClient: imapClientStub,
|
||||
pgpMailer: pgpMailerStub
|
||||
}).then(function() {
|
||||
expect(dao.ignoreUploadOnSent).to.be.false;
|
||||
dao.onConnect(imapClientStub).then(function() {
|
||||
expect(imapClientStub.login.calledOnce).to.be.true;
|
||||
expect(imapClientStub.selectMailbox.calledOnce).to.be.true;
|
||||
expect(initFoldersStub.calledOnce).to.be.true;
|
||||
|
@ -177,24 +177,6 @@ describe('Auth unit tests', function() {
|
||||
});
|
||||
|
||||
describe('#getOAuthToken', function() {
|
||||
it('should refresh token with known email address', function(done) {
|
||||
auth.emailAddress = emailAddress;
|
||||
auth.oauthToken = 'oldToken';
|
||||
|
||||
oauthStub.refreshToken.withArgs({
|
||||
emailAddress: emailAddress,
|
||||
oldToken: 'oldToken'
|
||||
}).returns(resolves(oauthToken));
|
||||
|
||||
auth.getOAuthToken().then(function() {
|
||||
expect(auth.emailAddress).to.equal(emailAddress);
|
||||
expect(auth.oauthToken).to.equal(oauthToken);
|
||||
expect(oauthStub.refreshToken.calledOnce).to.be.true;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fetch token with known email address', function(done) {
|
||||
auth.emailAddress = emailAddress;
|
||||
oauthStub.getOAuthToken.withArgs(emailAddress).returns(resolves(oauthToken));
|
||||
|
Loading…
Reference in New Issue
Block a user