mirror of
https://github.com/moparisthebest/mail
synced 2025-02-16 15:10:10 -05:00
Refactor login controllers and delete AppController
This commit is contained in:
parent
e6b22bd0a0
commit
4c04ba4e74
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="mail" ng-csp manifest="appcache.manifest">
|
||||
<html ng-csp manifest="appcache.manifest">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Whiteout Mail</title>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
var appCfg = {};
|
||||
|
||||
var ngModule = angular.module('mail');
|
||||
var ngModule = angular.module('woAppConfig');
|
||||
ngModule.factory('appConfig', function() {
|
||||
return appCfg;
|
||||
});
|
||||
|
@ -1,319 +0,0 @@
|
||||
/**
|
||||
* The main application controller
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var axe = require('axe-logger'),
|
||||
Auth = require('./bo/auth'),
|
||||
PGP = require('./crypto/pgp'),
|
||||
OAuth = require('./util/oauth'),
|
||||
PgpMailer = require('pgpmailer'),
|
||||
util = require('crypto-lib').util,
|
||||
PgpBuilder = require('pgpbuilder'),
|
||||
OutboxBO = require('./bo/outbox'),
|
||||
mailreader = require('mailreader'),
|
||||
ImapClient = require('imap-client'),
|
||||
Crypto = require('./crypto/crypto'),
|
||||
RestDAO = require('./dao/rest-dao'),
|
||||
appConfig = require('./app-config'),
|
||||
EmailDAO = require('./dao/email-dao'),
|
||||
AdminDao = require('./dao/admin-dao'),
|
||||
KeychainDAO = require('./dao/keychain-dao'),
|
||||
PublicKeyDAO = require('./dao/publickey-dao'),
|
||||
LawnchairDAO = require('./dao/lawnchair-dao'),
|
||||
PrivateKeyDAO = require('./dao/privatekey-dao'),
|
||||
InvitationDAO = require('./dao/invitation-dao'),
|
||||
DeviceStorageDAO = require('./dao/devicestorage-dao'),
|
||||
ConnectionDoctor = require('./util/connection-doctor'),
|
||||
UpdateHandler = require('./util/update/update-handler'),
|
||||
config = appConfig.config,
|
||||
str = appConfig.string;
|
||||
|
||||
var ctrl = {};
|
||||
|
||||
/**
|
||||
* Start the application.
|
||||
*/
|
||||
ctrl.start = function(options, callback) {
|
||||
if (ctrl.started) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
ctrl.started = true;
|
||||
ctrl.onError = options.onError; // TODO: replace by errorService
|
||||
|
||||
// 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
|
||||
axe.debug('Assuming Cordova environment...');
|
||||
document.addEventListener("deviceready", onDeviceReady, false);
|
||||
} else {
|
||||
// No need to wait on events... just start the app
|
||||
axe.debug('Assuming Browser environment...');
|
||||
onDeviceReady();
|
||||
}
|
||||
|
||||
function onDeviceReady() {
|
||||
axe.debug('Starting app.');
|
||||
|
||||
// TODO: will be replaced by angular dependency management
|
||||
ctrl.buildModules();
|
||||
|
||||
// TODO: move self-contained connection management in emailDao
|
||||
// Handle offline and online gracefully
|
||||
window.addEventListener('online', ctrl.onConnect.bind(ctrl, ctrl.onError));
|
||||
window.addEventListener('offline', ctrl.onDisconnect.bind(ctrl));
|
||||
|
||||
// TODO: move appConfigService shared singleton
|
||||
ctrl._appConfigStore.init('app-config', callback);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: will be replaced by angular dependency management
|
||||
|
||||
/**
|
||||
* Initialize the dependency tree.
|
||||
*/
|
||||
ctrl.buildModules = function() {
|
||||
var lawnchairDao, restDao, pubkeyDao, privkeyDao, crypto, emailDao, keychain, pgp, userStorage, pgpbuilder, oauth, appConfigStore, auth;
|
||||
|
||||
// init objects and inject dependencies
|
||||
restDao = new RestDAO();
|
||||
lawnchairDao = new LawnchairDAO();
|
||||
pubkeyDao = new PublicKeyDAO(restDao);
|
||||
privkeyDao = new PrivateKeyDAO(new RestDAO(config.privkeyServerUrl));
|
||||
oauth = new OAuth(new RestDAO('https://www.googleapis.com'));
|
||||
|
||||
crypto = new Crypto();
|
||||
ctrl._pgp = pgp = new PGP();
|
||||
ctrl._keychain = keychain = new KeychainDAO(lawnchairDao, pubkeyDao, privkeyDao, crypto, pgp);
|
||||
|
||||
// TODO: inject dialog service directly into keychain service
|
||||
keychain.requestPermissionForKeyUpdate = function(params, callback) {
|
||||
var message = params.newKey ? str.updatePublicKeyMsgNewKey : str.updatePublicKeyMsgRemovedKey;
|
||||
message = message.replace('{0}', params.userId);
|
||||
|
||||
ctrl.onError({
|
||||
title: str.updatePublicKeyTitle,
|
||||
message: message,
|
||||
positiveBtnStr: str.updatePublicKeyPosBtn,
|
||||
negativeBtnStr: str.updatePublicKeyNegBtn,
|
||||
showNegativeBtn: true,
|
||||
callback: callback
|
||||
});
|
||||
};
|
||||
|
||||
ctrl._appConfigStore = appConfigStore = new DeviceStorageDAO(new LawnchairDAO());
|
||||
ctrl._auth = auth = new Auth(appConfigStore, oauth, pgp);
|
||||
ctrl._userStorage = userStorage = new DeviceStorageDAO(lawnchairDao);
|
||||
ctrl._invitationDao = new InvitationDAO(restDao);
|
||||
ctrl._pgpbuilder = pgpbuilder = new PgpBuilder();
|
||||
ctrl._emailDao = emailDao = new EmailDAO(keychain, pgp, userStorage, pgpbuilder, mailreader);
|
||||
ctrl._outboxBo = new OutboxBO(emailDao, keychain, userStorage);
|
||||
ctrl._updateHandler = new UpdateHandler(appConfigStore, userStorage, auth);
|
||||
ctrl._adminDao = new AdminDao(new RestDAO(config.adminUrl));
|
||||
ctrl._doctor = new ConnectionDoctor();
|
||||
|
||||
emailDao.onError = ctrl.onError;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calls runtime hooks to check if an app update is available.
|
||||
*/
|
||||
ctrl.checkForUpdate = function() {
|
||||
ctrl._updateHandler.checkForUpdate(ctrl.onError);
|
||||
};
|
||||
|
||||
// TODO: move to AccountService
|
||||
|
||||
/**
|
||||
* Fire up the database, retrieve the available keys for the user and initialize the email data access object
|
||||
*/
|
||||
ctrl.init = function(options, callback) {
|
||||
// account information for the email dao
|
||||
var account = {
|
||||
realname: options.realname,
|
||||
emailAddress: options.emailAddress,
|
||||
asymKeySize: config.asymKeySize
|
||||
};
|
||||
|
||||
// Pre-Flight check: don't even start to initialize stuff if the email address is not valid
|
||||
if (!util.validateEmailAddress(options.emailAddress)) {
|
||||
return callback(new Error('The user email address is invalid!'));
|
||||
}
|
||||
|
||||
prepareDatabase();
|
||||
|
||||
// Pre-Flight check: initialize and prepare user's local database
|
||||
function prepareDatabase() {
|
||||
ctrl._userStorage.init(options.emailAddress, function(err) {
|
||||
if (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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the user agent is online.
|
||||
*/
|
||||
ctrl.isOnline = function() {
|
||||
return navigator.onLine;
|
||||
};
|
||||
|
||||
// TODO: move to AccountService
|
||||
|
||||
/**
|
||||
* Event handler that is called when the user agent goes offline.
|
||||
*/
|
||||
ctrl.onDisconnect = function() {
|
||||
ctrl._emailDao.onDisconnect();
|
||||
};
|
||||
|
||||
// TODO: move to AccountService
|
||||
|
||||
/**
|
||||
* Log the current user out by clear the app config store and deleting instances of imap-client and pgp-mailer.
|
||||
*/
|
||||
ctrl.logout = function() {
|
||||
// clear app config store
|
||||
ctrl._auth.logout(function(err) {
|
||||
if (err) {
|
||||
ctrl.onError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// delete instance of imap-client and pgp-mailer
|
||||
ctrl._emailDao.onDisconnect(function(err) {
|
||||
if (err) {
|
||||
ctrl.onError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof window.chrome !== 'undefined' && chrome.runtime && chrome.runtime.reload) {
|
||||
// reload chrome app
|
||||
chrome.runtime.reload();
|
||||
} else {
|
||||
// navigate to login
|
||||
window.location.href = '/';
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: move onConnect to Account service
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
ctrl.onConnect = function(callback) {
|
||||
if (!ctrl.isOnline() || !ctrl._emailDao || !ctrl._emailDao._account) {
|
||||
// prevent connection infinite loop
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
ctrl._auth.getCredentials(function(err, credentials) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
initClients(credentials);
|
||||
});
|
||||
|
||||
function initClients(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, ctrl._pgpbuilder);
|
||||
var imapClient = new ImapClient(credentials.imap);
|
||||
imapClient.onError = onConnectionError;
|
||||
pgpMailer.onError = onConnectionError;
|
||||
|
||||
// certificate update handling
|
||||
imapClient.onCert = ctrl._auth.handleCertificateUpdate.bind(ctrl._auth, 'imap', ctrl.onConnect, ctrl.onError);
|
||||
pgpMailer.onCert = ctrl._auth.handleCertificateUpdate.bind(ctrl._auth, 'smtp', ctrl.onConnect, ctrl.onError);
|
||||
|
||||
// connect to clients
|
||||
ctrl._emailDao.onConnect({
|
||||
imapClient: imapClient,
|
||||
pgpMailer: pgpMailer,
|
||||
ignoreUploadOnSent: ctrl._emailDao.checkIgnoreUploadOnSent(credentials.imap.host)
|
||||
}, 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
|
||||
ctrl.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);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ctrl;
|
@ -14,7 +14,8 @@ if (typeof window.applicationCache !== 'undefined') {
|
||||
};
|
||||
}
|
||||
|
||||
var DialogCtrl = require('./controller/dialog'),
|
||||
var axe = require('axe-logger'),
|
||||
DialogCtrl = require('./controller/dialog'),
|
||||
AddAccountCtrl = require('./controller/add-account'),
|
||||
CreateAccountCtrl = require('./controller/create-account'),
|
||||
ValidatePhoneCtrl = require('./controller/validate-phone'),
|
||||
@ -36,13 +37,26 @@ var DialogCtrl = require('./controller/dialog'),
|
||||
ActionBarCtrl = require('./controller/action-bar'),
|
||||
errorUtil = require('./util/error'),
|
||||
backButtonUtil = require('./util/backbutton-handler');
|
||||
require('./directive/common'),
|
||||
|
||||
// include angular modules
|
||||
require('./app-config');
|
||||
require('./directive/common');
|
||||
require('./util');
|
||||
require('./crypto');
|
||||
require('./service');
|
||||
require('./email');
|
||||
|
||||
// init main angular module including dependencies
|
||||
var app = angular.module('mail', [
|
||||
'ngRoute',
|
||||
'ngAnimate',
|
||||
'ngTagsInput',
|
||||
'woAppConfig',
|
||||
'woDirectives',
|
||||
'woUtil',
|
||||
'woCrypto,',
|
||||
'woServices',
|
||||
'woEmail',
|
||||
'navigation',
|
||||
'mail-list',
|
||||
'write',
|
||||
@ -50,10 +64,7 @@ var app = angular.module('mail', [
|
||||
'contacts',
|
||||
'login-new-device',
|
||||
'privatekey-upload',
|
||||
'infinite-scroll',
|
||||
'ngTagsInput',
|
||||
'woDirectives',
|
||||
'woServices'
|
||||
'infinite-scroll'
|
||||
]);
|
||||
|
||||
// set router paths
|
||||
@ -130,4 +141,25 @@ app.controller('PrivateKeyUploadCtrl', PrivateKeyUploadCtrl);
|
||||
app.controller('ContactsCtrl', ContactsCtrl);
|
||||
app.controller('AboutCtrl', AboutCtrl);
|
||||
app.controller('DialogCtrl', DialogCtrl);
|
||||
app.controller('ActionBarCtrl', ActionBarCtrl);
|
||||
app.controller('ActionBarCtrl', ActionBarCtrl);
|
||||
|
||||
//
|
||||
// Manual angular bootstraping
|
||||
//
|
||||
|
||||
// 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
|
||||
axe.debug('Assuming Cordova environment...');
|
||||
document.addEventListener('deviceready', bootstrap, false);
|
||||
} else {
|
||||
// No need to wait on events... just start the app
|
||||
axe.debug('Assuming Browser environment...');
|
||||
bootstrap();
|
||||
}
|
||||
|
||||
function bootstrap() {
|
||||
angular.element(document).ready(function() {
|
||||
angular.bootstrap(document, ['mail']);
|
||||
});
|
||||
}
|
@ -5,8 +5,7 @@ var appController = require('../app-controller'),
|
||||
backBtnHandler = require('../util/backbutton-handler'),
|
||||
appCfg = require('../app-config'),
|
||||
config = appCfg.config,
|
||||
str = appCfg.string,
|
||||
emailDao, outboxBo;
|
||||
str = appCfg.string;
|
||||
|
||||
//
|
||||
// Constants
|
||||
@ -19,14 +18,8 @@ var NOTIFICATION_SENT_TIMEOUT = 2000;
|
||||
// Controller
|
||||
//
|
||||
|
||||
var NavigationCtrl = function($scope, $routeParams, $location) {
|
||||
if (!appController._emailDao && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
}
|
||||
|
||||
emailDao = appController._emailDao;
|
||||
outboxBo = appController._outboxBo;
|
||||
var NavigationCtrl = function($scope, $routeParams, $location, account, email, outbox) {
|
||||
!$routeParams.dev && !account.isLoggedIn() && $location.path('/'); // init app
|
||||
|
||||
//
|
||||
// scope functions
|
||||
@ -51,14 +44,14 @@ var NavigationCtrl = function($scope, $routeParams, $location) {
|
||||
}
|
||||
|
||||
// update the outbox mail count
|
||||
var outbox = _.findWhere($scope.account.folders, {
|
||||
var ob = _.findWhere($scope.account.folders, {
|
||||
type: config.outboxMailboxType
|
||||
});
|
||||
outbox.count = count;
|
||||
ob.count = count;
|
||||
$scope.$apply();
|
||||
|
||||
emailDao.refreshFolder({
|
||||
folder: outbox
|
||||
email.refreshFolder({
|
||||
folder: ob
|
||||
}, $scope.onError);
|
||||
};
|
||||
|
||||
@ -114,18 +107,19 @@ var NavigationCtrl = function($scope, $routeParams, $location) {
|
||||
}
|
||||
|
||||
// get pointer to account/folder/message tree on root scope
|
||||
$scope.$root.account = emailDao._account;
|
||||
$scope.$root.account = email._account;
|
||||
// TODO: $scope.accounts = account.list();
|
||||
|
||||
// set notificatio handler for sent messages
|
||||
outboxBo.onSent = sentNotification;
|
||||
outbox.onSent = sentNotification;
|
||||
// start checking outbox periodically
|
||||
outboxBo.startChecking($scope.onOutboxUpdate);
|
||||
outbox.startChecking($scope.onOutboxUpdate);
|
||||
}
|
||||
|
||||
function sentNotification(email) {
|
||||
function sentNotification(message) {
|
||||
notification.create({
|
||||
title: 'Message sent',
|
||||
message: email.subject,
|
||||
message: message.subject,
|
||||
timeout: NOTIFICATION_SENT_TIMEOUT
|
||||
}, function() {});
|
||||
}
|
||||
|
@ -1,12 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var appCtrl = require('../app-controller');
|
||||
|
||||
var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig) {
|
||||
if (!appCtrl._auth && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
}
|
||||
var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig, auth) {
|
||||
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||
|
||||
$scope.getAccountSettings = function() {
|
||||
if ($scope.form.$invalid) {
|
||||
@ -25,7 +20,7 @@ var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig) {
|
||||
};
|
||||
|
||||
var hostname = config.imap.hostname;
|
||||
if (appCtrl._auth.useOAuth(hostname)) {
|
||||
if (auth.useOAuth(hostname)) {
|
||||
// check for oauth support
|
||||
$scope.oauthPossible();
|
||||
} else {
|
||||
@ -62,7 +57,7 @@ var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig) {
|
||||
|
||||
function getOAuthToken() {
|
||||
// fetches the email address from the chrome identity api
|
||||
appCtrl._auth.getOAuthToken(function(err) {
|
||||
auth.getOAuthToken(function(err) {
|
||||
if (err) {
|
||||
return $scope.onError(err);
|
||||
}
|
||||
|
@ -1,13 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var appCtrl = require('../app-controller'),
|
||||
cfg = require('../app-config').config;
|
||||
|
||||
var CreateAccountCtrl = function($scope, $location, $routeParams) {
|
||||
if (!appCtrl._auth && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
}
|
||||
var CreateAccountCtrl = function($scope, $location, $routeParams, auth, admin, appConfig) {
|
||||
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||
|
||||
$scope.createWhiteoutAccount = function() {
|
||||
if ($scope.form.$invalid) {
|
||||
@ -17,17 +11,17 @@ var CreateAccountCtrl = function($scope, $location, $routeParams) {
|
||||
|
||||
$scope.busy = true;
|
||||
$scope.errMsg = undefined; // reset error msg
|
||||
var emailAddress = $scope.user + '@' + cfg.wmailDomain;
|
||||
var emailAddress = $scope.user + '@' + appConfig.config.wmailDomain;
|
||||
|
||||
// set to state for next view
|
||||
$scope.state.createAccount = {
|
||||
auth.setCredentials({
|
||||
emailAddress: emailAddress,
|
||||
pass: $scope.pass,
|
||||
password: $scope.pass,
|
||||
realname: $scope.realname
|
||||
};
|
||||
});
|
||||
|
||||
// call REST api
|
||||
appCtrl._adminDao.createUser({
|
||||
admin.createUser({
|
||||
emailAddress: emailAddress,
|
||||
password: $scope.pass,
|
||||
phone: $scope.phone.replace(/\s+/g, ''), // remove spaces from the phone number
|
||||
|
@ -1,14 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller');
|
||||
|
||||
var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||
if (!appController._emailDao && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
}
|
||||
|
||||
var emailDao = appController._emailDao;
|
||||
var LoginExistingCtrl = function($scope, $location, $routeParams, email, auth, keychain) {
|
||||
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||
|
||||
$scope.confirmPassphrase = function() {
|
||||
if ($scope.form.$invalid) {
|
||||
@ -24,14 +17,14 @@ var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||
};
|
||||
|
||||
function unlockCrypto() {
|
||||
var userId = emailDao._account.emailAddress;
|
||||
emailDao._keychain.getUserKeyPair(userId, function(err, keypair) {
|
||||
var userId = auth.emailAddress;
|
||||
keychain.getUserKeyPair(userId, function(err, keypair) {
|
||||
if (err) {
|
||||
displayError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
emailDao.unlock({
|
||||
email.unlock({
|
||||
keypair: keypair,
|
||||
passphrase: $scope.passphrase
|
||||
}, onUnlock);
|
||||
@ -44,7 +37,7 @@ var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||
return;
|
||||
}
|
||||
|
||||
appController._auth.storeCredentials(function(err) {
|
||||
auth.storeCredentials(function(err) {
|
||||
if (err) {
|
||||
displayError(err);
|
||||
return;
|
||||
|
@ -1,17 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller');
|
||||
var LoginInitialCtrl = function($scope, $location, $routeParams, newsletter, email, auth) {
|
||||
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||
|
||||
var LoginInitialCtrl = function($scope, $location, $routeParams, newsletter) {
|
||||
if (!appController._emailDao && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
}
|
||||
|
||||
if (appController._emailDao) {
|
||||
var emailDao = appController._emailDao,
|
||||
emailAddress = emailDao._account.emailAddress;
|
||||
}
|
||||
var emailAddress = auth.emailAddress;
|
||||
|
||||
var termsMsg = 'You must accept the Terms of Service to continue.',
|
||||
states = {
|
||||
@ -59,7 +51,7 @@ var LoginInitialCtrl = function($scope, $location, $routeParams, newsletter) {
|
||||
// go to set keygen screen
|
||||
$scope.setState(states.PROCESSING);
|
||||
|
||||
emailDao.unlock({
|
||||
email.unlock({
|
||||
passphrase: undefined // generate key without passphrase
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
@ -67,7 +59,7 @@ var LoginInitialCtrl = function($scope, $location, $routeParams, newsletter) {
|
||||
return;
|
||||
}
|
||||
|
||||
appController._auth.storeCredentials(function(err) {
|
||||
auth.storeCredentials(function(err) {
|
||||
if (err) {
|
||||
displayError(err);
|
||||
return;
|
||||
|
@ -1,15 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller');
|
||||
|
||||
var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||
if (!appController._emailDao && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
}
|
||||
|
||||
var emailDao = appController._emailDao,
|
||||
pgp = appController._pgp;
|
||||
var LoginExistingCtrl = function($scope, $location, $routeParams, email, auth, pgp, keychain) {
|
||||
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||
|
||||
$scope.incorrect = false;
|
||||
|
||||
@ -27,9 +19,9 @@ var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||
};
|
||||
|
||||
function unlockCrypto() {
|
||||
var userId = emailDao._account.emailAddress;
|
||||
var userId = auth.emailAddress;
|
||||
// check if user already has a public key on the key server
|
||||
emailDao._keychain.getUserKeyPair(userId, function(err, keypair) {
|
||||
keychain.getUserKeyPair(userId, function(err, keypair) {
|
||||
if (err) {
|
||||
$scope.displayError(err);
|
||||
return;
|
||||
@ -76,7 +68,7 @@ var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||
}
|
||||
|
||||
// import and validate keypair
|
||||
emailDao.unlock({
|
||||
email.unlock({
|
||||
keypair: keypair,
|
||||
passphrase: $scope.passphrase
|
||||
}, function(err) {
|
||||
@ -86,7 +78,7 @@ var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||
return;
|
||||
}
|
||||
|
||||
emailDao._keychain.putUserKeyPair(keypair, onUnlock);
|
||||
keychain.putUserKeyPair(keypair, onUnlock);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -97,7 +89,7 @@ var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||
return;
|
||||
}
|
||||
|
||||
appController._auth.storeCredentials(function(err) {
|
||||
auth.storeCredentials(function(err) {
|
||||
if (err) {
|
||||
$scope.displayError(err);
|
||||
return;
|
||||
|
@ -1,18 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller');
|
||||
|
||||
var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams) {
|
||||
if (!appController._emailDao && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
}
|
||||
|
||||
if (appController._emailDao) {
|
||||
var keychain = appController._keychain,
|
||||
emailDao = appController._emailDao,
|
||||
userId = emailDao._account.emailAddress;
|
||||
}
|
||||
var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams, auth, email, keychain) {
|
||||
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||
|
||||
$scope.step = 1;
|
||||
|
||||
@ -38,6 +27,7 @@ var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams) {
|
||||
};
|
||||
|
||||
$scope.verifyRecoveryToken = function(callback) {
|
||||
var userId = auth.emailAddress;
|
||||
keychain.getUserKeyPair(userId, function(err, keypair) {
|
||||
if (err) {
|
||||
displayError(err);
|
||||
@ -95,7 +85,7 @@ var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams) {
|
||||
$scope.cachedKeypair.privateKey = privateKey;
|
||||
|
||||
// try empty passphrase
|
||||
emailDao.unlock({
|
||||
email.unlock({
|
||||
keypair: $scope.cachedKeypair,
|
||||
passphrase: undefined
|
||||
}, function(err) {
|
||||
@ -106,7 +96,7 @@ var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams) {
|
||||
}
|
||||
|
||||
// passphrase is corrent ... go to main app
|
||||
appController._auth.storeCredentials(function(err) {
|
||||
auth.storeCredentials(function(err) {
|
||||
if (err) {
|
||||
displayError(err);
|
||||
return;
|
||||
|
@ -4,16 +4,8 @@ var ENCRYPTION_METHOD_NONE = 0;
|
||||
var ENCRYPTION_METHOD_STARTTLS = 1;
|
||||
var ENCRYPTION_METHOD_TLS = 2;
|
||||
|
||||
var appCtrl = require('../app-controller');
|
||||
|
||||
var SetCredentialsCtrl = function($scope, $location, $routeParams) {
|
||||
if (!appCtrl._auth && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
}
|
||||
|
||||
var auth = appCtrl._auth;
|
||||
var doctor = appCtrl._doctor;
|
||||
var SetCredentialsCtrl = function($scope, $location, $routeParams, auth, connectionDoctor) {
|
||||
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||
|
||||
//
|
||||
// Presets and Settings
|
||||
@ -87,11 +79,11 @@ var SetCredentialsCtrl = function($scope, $location, $routeParams) {
|
||||
};
|
||||
|
||||
// use the credentials in the connection doctor
|
||||
doctor.configure(credentials);
|
||||
connectionDoctor.configure(credentials);
|
||||
|
||||
// run connection doctor test suite
|
||||
$scope.busy = true;
|
||||
doctor.check(function(err) {
|
||||
connectionDoctor.check(function(err) {
|
||||
if (err) {
|
||||
// display the error in the settings UI
|
||||
$scope.connectionError = err;
|
||||
|
@ -1,31 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
var appController = require('../app-controller');
|
||||
var LoginCtrl = function($scope, $location, updateHandler, account, auth, email, keychain, dialog) {
|
||||
|
||||
var LoginCtrl = function($scope, $location) {
|
||||
|
||||
// start main application controller
|
||||
appController.start({
|
||||
onError: $scope.onError
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// check for app update
|
||||
appController.checkForUpdate();
|
||||
|
||||
initializeUser();
|
||||
});
|
||||
|
||||
// TODO: move to Account service login function
|
||||
// check for app update
|
||||
updateHandler.checkForUpdate();
|
||||
// initialize the user account
|
||||
initializeUser();
|
||||
|
||||
function initializeUser() {
|
||||
// init the auth modules
|
||||
auth.init();
|
||||
// get OAuth token from chrome
|
||||
appController._auth.getEmailAddress(function(err, info) {
|
||||
auth.getEmailAddress(function(err, info) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -35,13 +23,13 @@ var LoginCtrl = function($scope, $location) {
|
||||
return;
|
||||
}
|
||||
|
||||
// initiate controller by creating email dao
|
||||
appController.init({
|
||||
// initiate the account by initializing the email dao and user storage
|
||||
account.init({
|
||||
emailAddress: info.emailAddress,
|
||||
realname: info.realname
|
||||
}, function(err, availableKeys) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -53,7 +41,7 @@ var LoginCtrl = function($scope, $location) {
|
||||
function redirect(availableKeys) {
|
||||
if (availableKeys && availableKeys.publicKey && availableKeys.privateKey) {
|
||||
// public and private key available, try empty passphrase
|
||||
appController._emailDao.unlock({
|
||||
email.unlock({
|
||||
keypair: availableKeys,
|
||||
passphrase: undefined
|
||||
}, function(err) {
|
||||
@ -62,9 +50,9 @@ var LoginCtrl = function($scope, $location) {
|
||||
return;
|
||||
}
|
||||
|
||||
appController._auth.storeCredentials(function(err) {
|
||||
auth.storeCredentials(function(err) {
|
||||
if (err) {
|
||||
return $scope.onError(err);
|
||||
return dialog.error(err);
|
||||
}
|
||||
|
||||
goTo('/desktop');
|
||||
@ -72,12 +60,12 @@ var LoginCtrl = function($scope, $location) {
|
||||
});
|
||||
} else if (availableKeys && availableKeys.publicKey && !availableKeys.privateKey) {
|
||||
// check if private key is synced
|
||||
appController._keychain.requestPrivateKeyDownload({
|
||||
keychain.requestPrivateKeyDownload({
|
||||
userId: availableKeys.publicKey.userId,
|
||||
keyId: availableKeys.publicKey._id,
|
||||
}, function(err, privateKeySynced) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var appCtrl = require('../app-controller');
|
||||
|
||||
var ValidatePhoneCtrl = function($scope, $location, $routeParams, mailConfig) {
|
||||
if (!appCtrl._auth && !$routeParams.dev) {
|
||||
$location.path('/'); // init app
|
||||
return;
|
||||
}
|
||||
var ValidatePhoneCtrl = function($scope, $location, $routeParams, mailConfig, auth, admin) {
|
||||
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||
|
||||
// TODO: move to Account service create function
|
||||
|
||||
@ -20,8 +15,8 @@ var ValidatePhoneCtrl = function($scope, $location, $routeParams, mailConfig) {
|
||||
$scope.errMsg = undefined; // reset error msg
|
||||
|
||||
// verify user to REST api
|
||||
appCtrl._adminDao.validateUser({
|
||||
emailAddress: $scope.state.createAccount.emailAddress,
|
||||
admin.validateUser({
|
||||
emailAddress: auth.emailAddress,
|
||||
token: $scope.token.toUpperCase()
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
@ -37,14 +32,14 @@ var ValidatePhoneCtrl = function($scope, $location, $routeParams, mailConfig) {
|
||||
};
|
||||
|
||||
$scope.login = function() {
|
||||
var address = $scope.state.createAccount.emailAddress;
|
||||
var address = auth.emailAddress;
|
||||
return mailConfig.get(address).then(function(config) {
|
||||
// store credentials in memory
|
||||
appCtrl._auth.setCredentials({
|
||||
emailAddress: $scope.state.createAccount.emailAddress,
|
||||
username: $scope.state.createAccount.emailAddress,
|
||||
realname: $scope.state.createAccount.realname,
|
||||
password: $scope.state.createAccount.pass,
|
||||
auth.setCredentials({
|
||||
emailAddress: auth.emailAddress,
|
||||
username: auth.emailAddress,
|
||||
realname: auth.realname,
|
||||
password: auth.password,
|
||||
imap: {
|
||||
host: config.imap.hostname,
|
||||
port: parseInt(config.imap.port, 10),
|
||||
|
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('woCrypto', []);
|
||||
angular.module('woCrypto', ['woAppConfig', 'woUtil']);
|
||||
|
||||
require('./pgp');
|
||||
require('./crypto');
|
@ -4,41 +4,240 @@ var ngModule = angular.module('woServices');
|
||||
ngModule.service('account', Account);
|
||||
module.exports = Account;
|
||||
|
||||
function Account(email, outbox) {
|
||||
this._emailDAOs = [email];
|
||||
this._outboxes = [outbox];
|
||||
this._accounts = undefined;
|
||||
var axe = require('axe-logger'),
|
||||
util = require('crypto-lib').util,
|
||||
PgpMailer = require('pgpmailer'),
|
||||
ImapClient = require('imap-client');
|
||||
|
||||
function Account(appConfig, auth, admin, mailConfig, keychain, pgpbuilder, email, outbox, deviceStorage, updateHandler) {
|
||||
this._appConfig = appConfig;
|
||||
this._auth = auth;
|
||||
this._admin = admin;
|
||||
this._mailConfig = mailConfig;
|
||||
this._keychain = keychain;
|
||||
this._emailDao = email;
|
||||
this._pgpbuilder = pgpbuilder;
|
||||
this._outbox = outbox;
|
||||
this._deviceStorage = deviceStorage;
|
||||
this._updateHandler = updateHandler;
|
||||
this._accounts = []; // init accounts list
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the account is already logged in.
|
||||
* @return {Boolean} if the account is logged in
|
||||
*/
|
||||
Account.prototype.isLoggedIn = function() {
|
||||
return (this._accounts.length > 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Lists all of the current accounts connected to the app
|
||||
* @return {Array<Object>} The account objects containing folder and message objects
|
||||
*/
|
||||
Account.prototype.list = function() {
|
||||
this._accounts = this._emailDAOs.map(function(emailDao) {
|
||||
return emailDao._account;
|
||||
});
|
||||
|
||||
return this._accounts;
|
||||
};
|
||||
|
||||
/**
|
||||
* Login to an existing email account. This creates a new email data access object instance for that account and logs in via IMAP.
|
||||
* @param {String} options.emailAddress The account's email address
|
||||
* Fire up the database, retrieve the available keys for the user and initialize the email data access object
|
||||
*/
|
||||
Account.prototype.login = function(options) {
|
||||
var emailDao = new Email();
|
||||
this._emailDAOs.push(emailDao);
|
||||
Account.prototype.init = function(options, callback) {
|
||||
var self = this;
|
||||
|
||||
// account information for the email dao
|
||||
var account = {
|
||||
realname: options.realname,
|
||||
emailAddress: options.emailAddress,
|
||||
asymKeySize: this._appConfig.asymKeySize
|
||||
};
|
||||
|
||||
// Pre-Flight check: don't even start to initialize stuff if the email address is not valid
|
||||
if (!util.validateEmailAddress(options.emailAddress)) {
|
||||
return callback(new Error('The user email address is invalid!'));
|
||||
}
|
||||
|
||||
prepareDatabase();
|
||||
|
||||
// Pre-Flight check: initialize and prepare user's local database
|
||||
function prepareDatabase() {
|
||||
self._deviceStorage.init(options.emailAddress, function(err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// Migrate the databases if necessary
|
||||
self._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() {
|
||||
self._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) {
|
||||
self._keychain.refreshKeyForUserId({
|
||||
userId: options.emailAddress,
|
||||
overridePermission: true
|
||||
}, function(err, publicKey) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
initEmailDao({
|
||||
publicKey: publicKey
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// either signup was complete or no pubkey is available, so we're good here.
|
||||
initEmailDao(keys);
|
||||
});
|
||||
}
|
||||
|
||||
function initEmailDao(keys) {
|
||||
self._emailDao.init({
|
||||
account: account
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// Handle offline and online gracefully ... arm dom event
|
||||
window.addEventListener('online', self.onConnect.bind(self));
|
||||
window.addEventListener('offline', self.onDisconnect.bind(self));
|
||||
|
||||
// add account object to the accounts array for the ng controllers
|
||||
self._accounts.push(account);
|
||||
|
||||
callback(null, keys);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
if (!self.isOnline() || !self._emailDao || !self._emailDao._account) {
|
||||
// prevent connection infinite loop
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
self._auth.getCredentials(function(err, credentials) {
|
||||
if (err) {
|
||||
self._dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
initClients(credentials);
|
||||
});
|
||||
|
||||
function initClients(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, self._dialog.error);
|
||||
pgpMailer.onCert = self._auth.handleCertificateUpdate.bind(self._auth, 'smtp', self.onConnect, self._dialog.error);
|
||||
|
||||
// connect to clients
|
||||
self._emailDao.onConnect({
|
||||
imapClient: imapClient,
|
||||
pgpMailer: pgpMailer,
|
||||
ignoreUploadOnSent: self._emailDao.checkIgnoreUploadOnSent(credentials.imap.host)
|
||||
}, self._dialog.error);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler that is called when the user agent goes offline.
|
||||
*/
|
||||
Account.prototype.onDisconnect = function() {
|
||||
this._emailDao.onDisconnect();
|
||||
};
|
||||
|
||||
/**
|
||||
* Logout of an email account. Log the current user out by clear the app config store and deleting instances of imap-client and pgp-mailer.
|
||||
*/
|
||||
Account.prototype.logout = function() {
|
||||
var self = this;
|
||||
|
||||
// clear app config store
|
||||
self._auth.logout(function(err) {
|
||||
if (err) {
|
||||
self._dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// delete instance of imap-client and pgp-mailer
|
||||
self._emailDao.onDisconnect(function(err) {
|
||||
if (err) {
|
||||
self._dialog.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof window.chrome !== 'undefined' && chrome.runtime && chrome.runtime.reload) {
|
||||
// reload chrome app
|
||||
chrome.runtime.reload();
|
||||
} else {
|
||||
// navigate to login
|
||||
window.location.href = '/';
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new whiteout account. This creates a new email data access object instance for that account and logs in via IMAP.
|
||||
* @param {String} options.emailAddress The account's email address
|
||||
*/
|
||||
Account.prototype.create = function(options) {};
|
||||
|
||||
/**
|
||||
* Logout of an email account. This creates a new email data access object instance for that account and logs in via IMAP.
|
||||
* @param {String} options.emailAddress The account's email address
|
||||
*/
|
||||
Account.prototype.logout = function(options) {};
|
||||
Account.prototype.create = function() {};
|
@ -50,12 +50,14 @@ 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, devicestorage, pgpbuilder, mailreader) {
|
||||
function Email(keychain, pgp, deviceStorage, pgpbuilder, mailreader, dialog) {
|
||||
this._keychain = keychain;
|
||||
this._pgp = pgp;
|
||||
this._devicestorage = devicestorage;
|
||||
this._devicestorage = deviceStorage;
|
||||
this._pgpbuilder = pgpbuilder;
|
||||
this._mailreader = mailreader;
|
||||
|
||||
this.onError = dialog.error;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('woEmail', []);
|
||||
angular.module('woEmail', ['woAppConfig', 'woUtil', 'woServices']);
|
||||
|
||||
require('./mailreader');
|
||||
require('./pgpbuilder');
|
||||
require('./email');
|
||||
require('./outbox');
|
||||
require('./account');
|
@ -13,15 +13,15 @@ var util = require('crypto-lib').util,
|
||||
* The local outbox takes care of the emails before they are being sent.
|
||||
* It also checks periodically if there are any mails in the local device storage to be sent.
|
||||
*/
|
||||
function Outbox(emailDao, keychain, devicestorage) {
|
||||
function Outbox(email, keychain, deviceStorage) {
|
||||
/** @private */
|
||||
this._emailDao = emailDao;
|
||||
this._emailDao = email;
|
||||
|
||||
/** @private */
|
||||
this._keychain = keychain;
|
||||
|
||||
/** @private */
|
||||
this._devicestorage = devicestorage;
|
||||
this._devicestorage = deviceStorage;
|
||||
|
||||
/**
|
||||
* Semaphore-esque flag to avoid 'concurrent' calls to _processOutbox when the timeout fires, but a call is still in process.
|
||||
|
@ -4,8 +4,9 @@ var ngModule = angular.module('woServices');
|
||||
ngModule.service('admin', Admin);
|
||||
module.exports = Admin;
|
||||
|
||||
function Admin(restDao) {
|
||||
function Admin(restDao, appConfig) {
|
||||
this._restDao = restDao;
|
||||
this._restDao.setBaseUri(appConfig.config.adminUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
15
src/js/service/app-config-store.js
Normal file
15
src/js/service/app-config-store.js
Normal file
@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
var ngModule = angular.module('woServices');
|
||||
ngModule.service('appConfigStore', AppConfigStore);
|
||||
module.exports = AppConfigStore;
|
||||
|
||||
/**
|
||||
* A service for storing app configuration and user credential data locally
|
||||
*/
|
||||
function AppConfigStore(lawnchairDAO) {
|
||||
this._localDbDao = lawnchairDAO;
|
||||
this._localDbDao.init('app-config');
|
||||
}
|
||||
|
||||
// TODO: inherit DeviceStorage service api
|
@ -25,12 +25,26 @@ var SMTP_DB_KEY = 'smtp';
|
||||
* auth.getCredentials(...); // called to gather all the information to connect to IMAP/SMTP,
|
||||
* username, password / oauth token, IMAP/SMTP server host names, ...
|
||||
*/
|
||||
function Auth(deviceStorage, oauth, pgp) {
|
||||
this._appConfigStore = deviceStorage;
|
||||
function Auth(appConfigStore, oauth, pgp) {
|
||||
this._appConfigStore = appConfigStore;
|
||||
this._oauth = oauth;
|
||||
this._pgp = pgp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the service
|
||||
*/
|
||||
Auth.prototype.init = function() {
|
||||
this._initialized = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the service has been initialized.
|
||||
*/
|
||||
Auth.prototype.isInitialized = function() {
|
||||
return this._initialized;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves credentials and IMAP/SMTP settings:
|
||||
* 1) Fetches the credentials from disk, then...
|
||||
|
@ -1,22 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
var ngModule = angular.module('woServices');
|
||||
ngModule.factory('deviceStorage', ['lawnchairDAO',
|
||||
function(lawnchairDAO) {
|
||||
return new DeviceStorage(lawnchairDAO);
|
||||
}
|
||||
]);
|
||||
ngModule.service('deviceStorage', DeviceStorage);
|
||||
module.exports = DeviceStorage;
|
||||
|
||||
/**
|
||||
* High level storage api that handles all persistence on the device.
|
||||
* High level storage api that handles all persistence of a user's data on the device.
|
||||
*/
|
||||
function DeviceStorage(lawnchairDAO) {
|
||||
this._localDbDao = lawnchairDAO;
|
||||
}
|
||||
|
||||
DeviceStorage.prototype.init = function(dbName, callback) {
|
||||
this._localDbDao.init(dbName, callback);
|
||||
DeviceStorage.prototype.init = function(dbName) {
|
||||
this._localDbDao.init(dbName);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1,8 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('woServices', []);
|
||||
angular.module('woServices', ['woAppConfig', 'woUtil', 'woCrypto']);
|
||||
|
||||
require('./newsletter');
|
||||
require('./rest');
|
||||
require('./invitation');
|
||||
require('./mail-config');
|
||||
require('./account');
|
||||
require('.pgpbuilder');
|
||||
require('./newsletter');
|
||||
require('./oauth');
|
||||
require('./privatekey');
|
||||
require('./publickey');
|
||||
require('./admin');
|
||||
require('./lawnchair');
|
||||
require('./devicestorage');
|
||||
require('./app-config-store');
|
||||
require('./auth');
|
||||
require('./keychain');
|
@ -4,15 +4,13 @@ var ngModule = angular.module('woServices');
|
||||
ngModule.service('invitation', Invitation);
|
||||
module.exports = Invitation;
|
||||
|
||||
var config = require('../app-config').config;
|
||||
|
||||
/**
|
||||
* The Invitation is a high level Data Access Object that access the invitation service REST endpoint.
|
||||
* @param {Object} restDao The REST Data Access Object abstraction
|
||||
*/
|
||||
function Invitation(restDao) {
|
||||
function Invitation(restDao, appConfig) {
|
||||
this._restDao = restDao;
|
||||
this._restDao.setBaseUri(config.cloudUrl);
|
||||
this._restDao.setBaseUri(appConfig.config.cloudUrl);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -16,18 +16,40 @@ var DB_PUBLICKEY = 'publickey',
|
||||
* A high-level Data-Access Api for handling Keypair synchronization
|
||||
* between the cloud service and the device's local storage
|
||||
*/
|
||||
function Keychain(localDbDao, publicKeyDao, privateKeyDao, crypto, pgp) {
|
||||
this._localDbDao = localDbDao;
|
||||
this._publicKeyDao = publicKeyDao;
|
||||
this._privateKeyDao = privateKeyDao;
|
||||
function Keychain(lawnchairDAO, publicKey, privateKey, crypto, pgp, dialog, appConfig) {
|
||||
this._lawnchairDAO = lawnchairDAO;
|
||||
this._publicKeyDao = publicKey;
|
||||
this._privateKeyDao = privateKey;
|
||||
this._crypto = crypto;
|
||||
this._pgp = pgp;
|
||||
this._dialog = dialog;
|
||||
this._appConfig = appConfig;
|
||||
}
|
||||
|
||||
//
|
||||
// Public key functions
|
||||
//
|
||||
|
||||
/**
|
||||
* Display confirmation dialog to request a public key update
|
||||
* @param {Object} params.newKey The user's updated public key object
|
||||
* @param {String} params.userId The user's email address
|
||||
*/
|
||||
Keychain.prototype.requestPermissionForKeyUpdate = function(params, callback) {
|
||||
var str = this._appConfig.string;
|
||||
var message = params.newKey ? str.updatePublicKeyMsgNewKey : str.updatePublicKeyMsgRemovedKey;
|
||||
message = message.replace('{0}', params.userId);
|
||||
|
||||
this._dialog.confirm({
|
||||
title: str.updatePublicKeyTitle,
|
||||
message: message,
|
||||
positiveBtnStr: str.updatePublicKeyPosBtn,
|
||||
negativeBtnStr: str.updatePublicKeyNegBtn,
|
||||
showNegativeBtn: true,
|
||||
callback: callback
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Verifies the public key of a user o nthe public key store
|
||||
* @param {String} uuid The uuid to verify the key
|
||||
@ -196,7 +218,7 @@ Keychain.prototype.getReceiverPublicKey = function(userId, callback) {
|
||||
var self = this;
|
||||
|
||||
// search local keyring for public key
|
||||
self._localDbDao.list(DB_PUBLICKEY, 0, null, function(err, allPubkeys) {
|
||||
self._lawnchairDAO.list(DB_PUBLICKEY, 0, null, function(err, allPubkeys) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
@ -275,7 +297,7 @@ Keychain.prototype.setDeviceName = function(deviceName, callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._localDbDao.persist(DB_DEVICENAME, deviceName, callback);
|
||||
this._lawnchairDAO.persist(DB_DEVICENAME, deviceName, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -285,7 +307,7 @@ Keychain.prototype.setDeviceName = function(deviceName, callback) {
|
||||
*/
|
||||
Keychain.prototype.getDeviceName = function(callback) {
|
||||
// check if deviceName is already persisted in storage
|
||||
this._localDbDao.read(DB_DEVICENAME, function(err, deviceName) {
|
||||
this._lawnchairDAO.read(DB_DEVICENAME, function(err, deviceName) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
@ -308,7 +330,7 @@ Keychain.prototype.getDeviceSecret = function(callback) {
|
||||
var self = this;
|
||||
|
||||
// generate random deviceSecret or get from storage
|
||||
self._localDbDao.read(DB_DEVICE_SECRET, function(err, storedDevSecret) {
|
||||
self._lawnchairDAO.read(DB_DEVICE_SECRET, function(err, storedDevSecret) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
@ -323,7 +345,7 @@ Keychain.prototype.getDeviceSecret = function(callback) {
|
||||
// generate random deviceSecret
|
||||
var deviceSecret = util.random(config.symKeySize);
|
||||
// persist deviceSecret to local storage (in plaintext)
|
||||
self._localDbDao.persist(DB_DEVICE_SECRET, deviceSecret, function(err) {
|
||||
self._lawnchairDAO.persist(DB_DEVICE_SECRET, deviceSecret, function(err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
@ -763,7 +785,7 @@ Keychain.prototype.getUserKeyPair = function(userId, callback) {
|
||||
var self = this;
|
||||
|
||||
// search for user's public key locally
|
||||
self._localDbDao.list(DB_PUBLICKEY, 0, null, function(err, allPubkeys) {
|
||||
self._lawnchairDAO.list(DB_PUBLICKEY, 0, null, function(err, allPubkeys) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
@ -886,7 +908,7 @@ Keychain.prototype.lookupPublicKey = function(id, callback) {
|
||||
}
|
||||
|
||||
// lookup in local storage
|
||||
self._localDbDao.read(DB_PUBLICKEY + '_' + id, function(err, pubkey) {
|
||||
self._lawnchairDAO.read(DB_PUBLICKEY + '_' + id, function(err, pubkey) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
@ -922,26 +944,26 @@ Keychain.prototype.lookupPublicKey = function(id, callback) {
|
||||
*/
|
||||
Keychain.prototype.listLocalPublicKeys = function(callback) {
|
||||
// search local keyring for public key
|
||||
this._localDbDao.list(DB_PUBLICKEY, 0, null, callback);
|
||||
this._lawnchairDAO.list(DB_PUBLICKEY, 0, null, callback);
|
||||
};
|
||||
|
||||
Keychain.prototype.removeLocalPublicKey = function(id, callback) {
|
||||
this._localDbDao.remove(DB_PUBLICKEY + '_' + id, callback);
|
||||
this._lawnchairDAO.remove(DB_PUBLICKEY + '_' + id, callback);
|
||||
};
|
||||
|
||||
Keychain.prototype.lookupPrivateKey = function(id, callback) {
|
||||
// lookup in local storage
|
||||
this._localDbDao.read(DB_PRIVATEKEY + '_' + id, callback);
|
||||
this._lawnchairDAO.read(DB_PRIVATEKEY + '_' + id, callback);
|
||||
};
|
||||
|
||||
Keychain.prototype.saveLocalPublicKey = function(pubkey, callback) {
|
||||
// persist public key (email, _id)
|
||||
var pkLookupKey = DB_PUBLICKEY + '_' + pubkey._id;
|
||||
this._localDbDao.persist(pkLookupKey, pubkey, callback);
|
||||
this._lawnchairDAO.persist(pkLookupKey, pubkey, callback);
|
||||
};
|
||||
|
||||
Keychain.prototype.saveLocalPrivateKey = function(privkey, callback) {
|
||||
// persist private key (email, _id)
|
||||
var prkLookupKey = DB_PRIVATEKEY + '_' + privkey._id;
|
||||
this._localDbDao.persist(prkLookupKey, privkey, callback);
|
||||
this._lawnchairDAO.persist(prkLookupKey, privkey, callback);
|
||||
};
|
@ -15,25 +15,13 @@ function LawnchairDAO() {}
|
||||
* Initialize the lawnchair database
|
||||
* @param {String} dbName The name of the database
|
||||
*/
|
||||
LawnchairDAO.prototype.init = function(dbName, callback) {
|
||||
LawnchairDAO.prototype.init = function(dbName) {
|
||||
if (!dbName) {
|
||||
callback({
|
||||
errMsg: 'Lawnchair DB name must be specified!'
|
||||
});
|
||||
return;
|
||||
throw new Error('Lawnchair DB name must be specified!');
|
||||
}
|
||||
|
||||
this._db = new Lawnchair({
|
||||
name: dbName
|
||||
}, function(lc) {
|
||||
if (!lc) {
|
||||
callback({
|
||||
errMsg: 'Lawnchair init failed!'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -4,11 +4,9 @@ var ngModule = angular.module('woServices');
|
||||
ngModule.service('privateKey', PrivateKey);
|
||||
module.exports = PrivateKey;
|
||||
|
||||
var config = require('../app-config').config;
|
||||
|
||||
function PrivateKey(restDao) {
|
||||
function PrivateKey(restDao, appConfig) {
|
||||
this._restDao = restDao;
|
||||
this._restDao.setBaseUri(config.privkeyServerUrl);
|
||||
this._restDao.setBaseUri(appConfig.config.privkeyServerUrl);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -4,11 +4,9 @@ var ngModule = angular.module('woServices');
|
||||
ngModule.service('publicKey', PublicKey);
|
||||
module.exports = PublicKey;
|
||||
|
||||
var config = require('../app-config').config;
|
||||
|
||||
function PublicKey(restDao) {
|
||||
function PublicKey(restDao, appConfig) {
|
||||
this._restDao = restDao;
|
||||
this._restDao.setBaseUri(config.cloudUrl);
|
||||
this._restDao.setBaseUri(appConfig.config.cloudUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var ngModule = angular.module('woUtil');
|
||||
ngModule.service('updateHandler', ['deviceStorage', 'deviceStorage', 'auth', UpdateHandler]);
|
||||
ngModule.service('updateHandler', UpdateHandler);
|
||||
module.exports = UpdateHandler;
|
||||
|
||||
var axe = require('axe-logger'),
|
||||
@ -15,11 +15,12 @@ var axe = require('axe-logger'),
|
||||
/**
|
||||
* Handles database migration
|
||||
*/
|
||||
function UpdateHandler(appConfigStorage, userStorage, auth) {
|
||||
this._appConfigStorage = appConfigStorage;
|
||||
this._userStorage = userStorage;
|
||||
function UpdateHandler(appConfigStore, deviceStorage, auth, dialog) {
|
||||
this._appConfigStorage = appConfigStore;
|
||||
this._userStorage = deviceStorage;
|
||||
this._updateScripts = [updateV1, updateV2, updateV3, updateV4, updateV5];
|
||||
this._auth = auth;
|
||||
this._dialog = dialog;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,14 +100,16 @@ UpdateHandler.prototype._applyUpdate = function(options, callback) {
|
||||
/**
|
||||
* Check application version and update correspondingly
|
||||
*/
|
||||
UpdateHandler.prototype.checkForUpdate = function(dialog) {
|
||||
UpdateHandler.prototype.checkForUpdate = function() {
|
||||
var self = this;
|
||||
|
||||
// Chrome Packaged App
|
||||
if (typeof window.chrome !== 'undefined' && chrome.runtime && chrome.runtime.onUpdateAvailable) {
|
||||
// check for Chrome app update and restart
|
||||
chrome.runtime.onUpdateAvailable.addListener(function(details) {
|
||||
axe.debug('New Chrome App update... requesting reload.');
|
||||
// Chrome downloaded a new app version
|
||||
dialog({
|
||||
self._dialog.confirm({
|
||||
title: 'Update available',
|
||||
message: 'A new version ' + details.version + ' of the app is available. Restart the app to update?',
|
||||
positiveBtnStr: 'Restart',
|
||||
|
Loading…
Reference in New Issue
Block a user