2013-06-06 07:34:22 -04:00
|
|
|
/**
|
|
|
|
* The main application controller
|
|
|
|
*/
|
2013-08-20 09:19:13 -04:00
|
|
|
define(function(require) {
|
2013-08-20 13:48:49 -04:00
|
|
|
'use strict';
|
|
|
|
|
2014-07-01 13:49:19 -04:00
|
|
|
var axe = require('axe'),
|
|
|
|
Auth = require('js/bo/auth'),
|
2014-04-01 07:16:39 -04:00
|
|
|
PGP = require('js/crypto/pgp'),
|
2014-04-22 12:19:28 -04:00
|
|
|
PgpMailer = require('pgpmailer'),
|
2014-04-01 07:16:39 -04:00
|
|
|
OAuth = require('js/util/oauth'),
|
2014-04-22 12:19:28 -04:00
|
|
|
PgpBuilder = require('pgpbuilder'),
|
2014-04-01 07:16:39 -04:00
|
|
|
OutboxBO = require('js/bo/outbox'),
|
|
|
|
mailreader = require('mailreader'),
|
|
|
|
ImapClient = require('imap-client'),
|
2014-06-13 06:33:30 -04:00
|
|
|
Crypto = require('js/crypto/crypto'),
|
2014-04-01 07:16:39 -04:00
|
|
|
RestDAO = require('js/dao/rest-dao'),
|
2014-05-23 04:52:34 -04:00
|
|
|
appConfig = require('js/app-config'),
|
2014-07-01 13:49:19 -04:00
|
|
|
EmailDAO = require('js/dao/email-dao'),
|
2014-04-01 07:16:39 -04:00
|
|
|
KeychainDAO = require('js/dao/keychain-dao'),
|
2013-10-29 07:19:27 -04:00
|
|
|
PublicKeyDAO = require('js/dao/publickey-dao'),
|
|
|
|
LawnchairDAO = require('js/dao/lawnchair-dao'),
|
2014-06-13 06:33:30 -04:00
|
|
|
PrivateKeyDAO = require('js/dao/privatekey-dao'),
|
2013-11-19 10:14:48 -05:00
|
|
|
InvitationDAO = require('js/dao/invitation-dao'),
|
2014-04-01 07:16:39 -04:00
|
|
|
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
|
2014-07-01 13:49:19 -04:00
|
|
|
UpdateHandler = require('js/util/update/update-handler'),
|
|
|
|
config = appConfig.config,
|
|
|
|
str = appConfig.string;
|
2013-08-20 13:48:49 -04:00
|
|
|
|
|
|
|
var self = {};
|
|
|
|
|
|
|
|
/**
|
2013-10-09 10:40:36 -04:00
|
|
|
* Start the application
|
2013-08-20 13:48:49 -04:00
|
|
|
*/
|
2013-12-09 13:21:52 -05:00
|
|
|
self.start = function(options, callback) {
|
2014-07-01 13:49:19 -04:00
|
|
|
if (self.started) {
|
|
|
|
return callback();
|
|
|
|
}
|
|
|
|
|
|
|
|
self.started = true;
|
|
|
|
self.onError = options.onError;
|
|
|
|
|
2014-02-01 08:43:15 -05:00
|
|
|
// are we running in a cordova app or in a browser environment?
|
|
|
|
if (window.cordova) {
|
|
|
|
// wait for 'deviceready' event to make sure plugins are loaded
|
2014-06-18 11:09:04 -04:00
|
|
|
axe.debug('Assuming Cordova environment...');
|
2013-08-20 13:48:49 -04:00
|
|
|
document.addEventListener("deviceready", onDeviceReady, false);
|
2014-02-01 08:43:15 -05:00
|
|
|
} else {
|
|
|
|
// No need to wait on events... just start the app
|
2014-06-18 11:09:04 -04:00
|
|
|
axe.debug('Assuming Browser environment...');
|
2014-02-01 08:43:15 -05:00
|
|
|
onDeviceReady();
|
2013-08-20 13:48:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
function onDeviceReady() {
|
2014-06-18 11:09:04 -04:00
|
|
|
axe.debug('Starting app.');
|
2013-12-09 13:21:52 -05:00
|
|
|
|
2014-07-01 13:49:19 -04:00
|
|
|
self.buildModules();
|
2014-04-01 07:16:39 -04:00
|
|
|
|
2013-12-09 13:21:52 -05:00
|
|
|
// Handle offline and online gracefully
|
2014-07-01 13:49:19 -04:00
|
|
|
window.addEventListener('online', self.onConnect.bind(self, self.onError));
|
2014-05-23 08:23:50 -04:00
|
|
|
window.addEventListener('offline', self.onDisconnect.bind(self));
|
2013-12-09 13:21:52 -05:00
|
|
|
|
2013-10-09 10:40:36 -04:00
|
|
|
self._appConfigStore.init('app-config', callback);
|
2013-08-20 13:48:49 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-07-01 13:49:19 -04:00
|
|
|
self.buildModules = function() {
|
|
|
|
var lawnchairDao, restDao, pubkeyDao, privkeyDao, crypto, emailDao, keychain, pgp, userStorage, pgpbuilder, oauth, appConfigStore, auth;
|
2014-04-01 07:16:39 -04:00
|
|
|
|
|
|
|
// start the mailreader's worker thread
|
|
|
|
mailreader.startWorker(config.workerPath + '/../lib/mailreader-parser-worker.js');
|
|
|
|
|
|
|
|
// init objects and inject dependencies
|
|
|
|
restDao = new RestDAO();
|
|
|
|
lawnchairDao = new LawnchairDAO();
|
|
|
|
pubkeyDao = new PublicKeyDAO(restDao);
|
2014-06-13 06:33:30 -04:00
|
|
|
privkeyDao = new PrivateKeyDAO(new RestDAO(config.privkeyServerUrl));
|
2014-04-01 07:16:39 -04:00
|
|
|
oauth = new OAuth(new RestDAO('https://www.googleapis.com'));
|
|
|
|
|
2014-06-13 06:33:30 -04:00
|
|
|
crypto = new Crypto();
|
|
|
|
self._pgp = pgp = new PGP();
|
|
|
|
self._keychain = keychain = new KeychainDAO(lawnchairDao, pubkeyDao, privkeyDao, crypto, pgp);
|
2014-05-23 04:52:34 -04:00
|
|
|
keychain.requestPermissionForKeyUpdate = function(params, callback) {
|
|
|
|
var message = params.newKey ? str.updatePublicKeyMsgNewKey : str.updatePublicKeyMsgRemovedKey;
|
|
|
|
message = message.replace('{0}', params.userId);
|
|
|
|
|
2014-07-01 13:49:19 -04:00
|
|
|
self.onError({
|
2014-05-23 04:52:34 -04:00
|
|
|
title: str.updatePublicKeyTitle,
|
|
|
|
message: message,
|
|
|
|
positiveBtnStr: str.updatePublicKeyPosBtn,
|
|
|
|
negativeBtnStr: str.updatePublicKeyNegBtn,
|
|
|
|
showNegativeBtn: true,
|
|
|
|
callback: callback
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2014-04-01 07:16:39 -04:00
|
|
|
self._appConfigStore = appConfigStore = new DeviceStorageDAO(new LawnchairDAO());
|
2014-07-01 13:49:19 -04:00
|
|
|
self._auth = auth = new Auth(appConfigStore, oauth, pgp);
|
2014-04-01 07:16:39 -04:00
|
|
|
self._userStorage = userStorage = new DeviceStorageDAO(lawnchairDao);
|
|
|
|
self._invitationDao = new InvitationDAO(restDao);
|
2014-04-22 12:19:28 -04:00
|
|
|
self._pgpbuilder = pgpbuilder = new PgpBuilder();
|
2014-05-23 08:23:50 -04:00
|
|
|
self._emailDao = emailDao = new EmailDAO(keychain, pgp, userStorage, pgpbuilder, mailreader);
|
2014-04-01 07:16:39 -04:00
|
|
|
self._outboxBo = new OutboxBO(emailDao, keychain, userStorage);
|
2014-07-01 13:49:19 -04:00
|
|
|
self._updateHandler = new UpdateHandler(appConfigStore, userStorage, auth);
|
2014-05-23 08:23:50 -04:00
|
|
|
|
2014-07-01 13:49:19 -04:00
|
|
|
emailDao.onError = self.onError;
|
2014-04-01 07:16:39 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
self.isOnline = function() {
|
|
|
|
return navigator.onLine;
|
|
|
|
};
|
2013-12-09 13:21:52 -05:00
|
|
|
|
2014-05-23 08:23:50 -04:00
|
|
|
self.onDisconnect = function() {
|
|
|
|
self._emailDao.onDisconnect();
|
2013-12-09 13:21:52 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
self.onConnect = function(callback) {
|
2014-04-02 13:47:50 -04:00
|
|
|
if (!self.isOnline() || !self._emailDao || !self._emailDao._account) {
|
2013-12-09 13:21:52 -05:00
|
|
|
// prevent connection infinite loop
|
|
|
|
callback();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-01 13:49:19 -04:00
|
|
|
self._auth.getCredentials(function(err, credentials) {
|
2013-12-09 13:21:52 -05:00
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-04-01 07:16:39 -04:00
|
|
|
initClients(credentials);
|
2013-12-09 13:21:52 -05:00
|
|
|
});
|
|
|
|
|
2014-04-01 07:16:39 -04:00
|
|
|
function initClients(credentials) {
|
2014-07-01 13:49:19 -04:00
|
|
|
var pgpMailer = new PgpMailer(credentials.smtp, self._pgpbuilder);
|
|
|
|
var imapClient = new ImapClient(credentials.imap);
|
2014-08-05 10:44:39 -04:00
|
|
|
imapClient.onError = onConnectionError;
|
|
|
|
pgpMailer.onError = onConnectionError;
|
2013-12-09 13:21:52 -05:00
|
|
|
|
2014-07-01 13:49:19 -04:00
|
|
|
// certificate update handling
|
|
|
|
imapClient.onCert = self._auth.handleCertificateUpdate.bind(self._auth, 'imap', self.onConnect, self.onError);
|
|
|
|
pgpMailer.onCert = self._auth.handleCertificateUpdate.bind(self._auth, 'smtp', self.onConnect, self.onError);
|
2013-12-09 13:21:52 -05:00
|
|
|
|
2014-07-01 13:49:19 -04:00
|
|
|
// after-setup configuration depending on the provider:
|
|
|
|
// gmail does not require you to upload to the sent items folder
|
|
|
|
// after successful sending, whereas most other providers do
|
|
|
|
self._emailDao.ignoreUploadOnSent = !!(config[self._auth.provider] && config[self._auth.provider].ignoreUploadOnSent);
|
2013-12-09 13:21:52 -05:00
|
|
|
|
|
|
|
// connect to clients
|
|
|
|
self._emailDao.onConnect({
|
|
|
|
imapClient: imapClient,
|
2014-02-03 16:07:39 -05:00
|
|
|
pgpMailer: pgpMailer
|
2013-12-09 13:21:52 -05:00
|
|
|
}, callback);
|
|
|
|
}
|
|
|
|
|
2014-08-05 10:44:39 -04:00
|
|
|
function onConnectionError(error) {
|
|
|
|
axe.debug('Connection error. Attempting reconnect in ' + config.reconnectInterval + ' ms. Error: ' + (error.errMsg || error.message) + (error.stack ? ('\n' + error.stack) : ''));
|
2014-07-01 13:49:19 -04:00
|
|
|
|
|
|
|
setTimeout(function() {
|
2014-08-05 10:44:39 -04:00
|
|
|
axe.debug('Reconnecting...');
|
2014-07-01 13:49:19 -04:00
|
|
|
// re-init client modules on error
|
|
|
|
self.onConnect(function(err) {
|
|
|
|
if (err) {
|
2014-08-05 10:44:39 -04:00
|
|
|
axe.error('Reconnect attempt failed! ' + (err.errMsg || err.message) + (err.stack ? ('\n' + err.stack) : ''));
|
2014-07-01 13:49:19 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-05 10:44:39 -04:00
|
|
|
axe.debug('Reconnect attempt complete.');
|
2014-07-01 13:49:19 -04:00
|
|
|
});
|
|
|
|
}, config.reconnectInterval);
|
2014-04-01 07:16:39 -04:00
|
|
|
}
|
2013-12-09 13:21:52 -05:00
|
|
|
};
|
|
|
|
|
2013-11-08 18:30:45 -05:00
|
|
|
self.checkForUpdate = function() {
|
2014-04-01 07:16:39 -04:00
|
|
|
if (!window.chrome || !chrome.runtime || !chrome.runtime.onUpdateAvailable) {
|
2013-11-08 15:35:30 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-08 18:30:45 -05:00
|
|
|
// check for update and restart
|
2013-11-08 13:08:34 -05:00
|
|
|
chrome.runtime.onUpdateAvailable.addListener(function(details) {
|
2014-06-18 11:09:04 -04:00
|
|
|
axe.debug("Updating to version " + details.version);
|
2013-11-08 18:30:45 -05:00
|
|
|
chrome.runtime.reload();
|
2013-11-08 13:08:34 -05:00
|
|
|
});
|
|
|
|
chrome.runtime.requestUpdateCheck(function(status) {
|
|
|
|
if (status === "update_found") {
|
2014-06-18 11:09:04 -04:00
|
|
|
axe.debug("Update pending...");
|
2013-11-08 13:08:34 -05:00
|
|
|
} else if (status === "no_update") {
|
2014-06-18 11:09:04 -04:00
|
|
|
axe.debug("No update found.");
|
2013-11-08 13:08:34 -05:00
|
|
|
} else if (status === "throttled") {
|
2014-06-18 11:09:04 -04:00
|
|
|
axe.debug("Checking updates too frequently.");
|
2013-11-08 13:08:34 -05:00
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2013-12-09 13:21:52 -05:00
|
|
|
/**
|
|
|
|
* Instanciate the mail email data access object and its dependencies. Login to imap on init.
|
|
|
|
*/
|
|
|
|
self.init = function(options, callback) {
|
2014-03-11 12:49:47 -04:00
|
|
|
// init user's local database
|
2014-03-11 13:27:02 -04:00
|
|
|
self._userStorage.init(options.emailAddress, function(err) {
|
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
2013-11-14 11:41:31 -05:00
|
|
|
|
2014-03-11 12:49:47 -04:00
|
|
|
// Migrate the databases if necessary
|
|
|
|
self._updateHandler.update(onUpdate);
|
|
|
|
});
|
|
|
|
|
|
|
|
function onUpdate(err) {
|
2013-12-10 17:05:17 -05:00
|
|
|
if (err) {
|
2014-03-11 12:49:47 -04:00
|
|
|
callback({
|
|
|
|
errMsg: 'Update failed, please reinstall the app.',
|
|
|
|
err: err
|
|
|
|
});
|
2013-12-09 13:21:52 -05:00
|
|
|
return;
|
|
|
|
}
|
2013-11-14 11:41:31 -05:00
|
|
|
|
2014-03-11 12:49:47 -04:00
|
|
|
// account information for the email dao
|
|
|
|
var account = {
|
2014-07-01 13:49:19 -04:00
|
|
|
realname: options.realname,
|
2014-03-11 12:49:47 -04:00
|
|
|
emailAddress: options.emailAddress,
|
|
|
|
asymKeySize: config.asymKeySize
|
|
|
|
};
|
|
|
|
|
|
|
|
// init email dao
|
|
|
|
self._emailDao.init({
|
|
|
|
account: account
|
|
|
|
}, function(err, keypair) {
|
2013-12-09 13:21:52 -05:00
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
2013-11-14 11:41:31 -05:00
|
|
|
|
2014-03-28 13:08:04 -04:00
|
|
|
callback(null, keypair);
|
2013-12-09 13:21:52 -05:00
|
|
|
});
|
2014-03-11 12:49:47 -04:00
|
|
|
}
|
2013-08-20 13:48:49 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
return self;
|
2013-06-10 11:57:33 -04:00
|
|
|
});
|