diff --git a/Gruntfile.js b/Gruntfile.js
index 3795c37..3656fa2 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -155,46 +155,49 @@ module.exports = function(grunt) {
unitTest: {
files: {
'test/unit/index.browserified.js': [
- 'test/unit/oauth-test.js',
- 'test/unit/auth-test.js',
- 'test/unit/email-dao-test.js',
- 'test/unit/app-controller-test.js',
- 'test/unit/pgp-test.js',
- 'test/unit/crypto-test.js',
- 'test/unit/backbutton-handler-test.js',
- 'test/unit/rest-dao-test.js',
- 'test/unit/admin-dao-test.js',
- 'test/unit/publickey-dao-test.js',
- 'test/unit/privatekey-dao-test.js',
- 'test/unit/lawnchair-dao-test.js',
- 'test/unit/keychain-dao-test.js',
- 'test/unit/devicestorage-dao-test.js',
- 'test/unit/newsletter-service-test.js',
- 'test/unit/mail-config-service-test.js',
- 'test/unit/dialog-ctrl-test.js',
- 'test/unit/add-account-ctrl-test.js',
- 'test/unit/create-account-ctrl-test.js',
- 'test/unit/validate-phone-ctrl-test.js',
- 'test/unit/account-ctrl-test.js',
- 'test/unit/set-passphrase-ctrl-test.js',
- 'test/unit/contacts-ctrl-test.js',
- 'test/unit/login-existing-ctrl-test.js',
- 'test/unit/login-initial-ctrl-test.js',
- 'test/unit/login-new-device-ctrl-test.js',
- 'test/unit/login-privatekey-download-ctrl-test.js',
- 'test/unit/login-set-credentials-ctrl-test.js',
- 'test/unit/privatekey-upload-ctrl-test.js',
- 'test/unit/login-ctrl-test.js',
- 'test/unit/read-ctrl-test.js',
- 'test/unit/navigation-ctrl-test.js',
- 'test/unit/mail-list-ctrl-test.js',
- 'test/unit/write-ctrl-test.js',
- 'test/unit/action-bar-ctrl-test.js',
- 'test/unit/outbox-bo-test.js',
- 'test/unit/invitation-dao-test.js',
- 'test/unit/update-handler-test.js',
- 'test/unit/connection-doctor-test.js',
- 'test/main.js'
+ 'test/main.js',
+ 'test/unit/util/dialog-test.js',
+ 'test/unit/util/connection-doctor-test.js',
+ 'test/unit/util/update-handler-test.js',
+ 'test/unit/util/backbutton-handler-test.js',
+ 'test/unit/util/status-display-test.js',
+ 'test/unit/crypto/pgp-test.js',
+ 'test/unit/crypto/crypto-test.js',
+ 'test/unit/service/rest-dao-test.js',
+ 'test/unit/service/admin-dao-test.js',
+ 'test/unit/service/auth-test.js',
+ 'test/unit/service/oauth-test.js',
+ 'test/unit/service/publickey-dao-test.js',
+ 'test/unit/service/privatekey-dao-test.js',
+ 'test/unit/service/lawnchair-dao-test.js',
+ 'test/unit/service/keychain-dao-test.js',
+ 'test/unit/service/devicestorage-dao-test.js',
+ 'test/unit/service/newsletter-service-test.js',
+ 'test/unit/service/mail-config-service-test.js',
+ 'test/unit/service/invitation-dao-test.js',
+ 'test/unit/email/outbox-bo-test.js',
+ 'test/unit/email/email-dao-test.js',
+ 'test/unit/email/account-test.js',
+ 'test/unit/email/search-test.js',
+ 'test/unit/controller/login/add-account-ctrl-test.js',
+ 'test/unit/controller/login/create-account-ctrl-test.js',
+ 'test/unit/controller/login/validate-phone-ctrl-test.js',
+ 'test/unit/controller/login/login-existing-ctrl-test.js',
+ 'test/unit/controller/login/login-initial-ctrl-test.js',
+ 'test/unit/controller/login/login-new-device-ctrl-test.js',
+ 'test/unit/controller/login/login-privatekey-download-ctrl-test.js',
+ 'test/unit/controller/login/login-set-credentials-ctrl-test.js',
+ 'test/unit/controller/login/login-ctrl-test.js',
+ 'test/unit/controller/app/dialog-ctrl-test.js',
+ 'test/unit/controller/app/privatekey-upload-ctrl-test.js',
+ 'test/unit/controller/app/account-ctrl-test.js',
+ 'test/unit/controller/app/set-passphrase-ctrl-test.js',
+ 'test/unit/controller/app/contacts-ctrl-test.js',
+ 'test/unit/controller/app/read-ctrl-test.js',
+ 'test/unit/controller/app/navigation-ctrl-test.js',
+ 'test/unit/controller/app/mail-list-ctrl-test.js',
+ 'test/unit/controller/app/write-ctrl-test.js',
+ 'test/unit/controller/app/action-bar-ctrl-test.js',
]
},
options: browserifyOpt
@@ -202,8 +205,8 @@ module.exports = function(grunt) {
integrationTest: {
files: {
'test/integration/index.browserified.js': [
- 'test/integration/email-dao-test.js',
- 'test/main.js'
+ 'test/main.js',
+ 'test/integration/email-dao-test.js'
]
},
options: browserifyOpt
@@ -256,7 +259,7 @@ module.exports = function(grunt) {
readSandbox: {
src: [
'node_modules/dompurify/purify.js',
- 'src/js/controller/read-sandbox.js'
+ 'src/js/controller/app/read-sandbox.js'
],
dest: 'dist/js/read-sandbox.min.js'
},
@@ -278,7 +281,6 @@ module.exports = function(grunt) {
'node_modules/jquery/dist/jquery.min.js',
'src/lib/angular/angular.js',
'src/lib/angular/angular-route.js',
- 'src/lib/angular/angular-animate.js',
'src/lib/angular/angular-mocks.js',
'src/lib/lawnchair/lawnchair-git.js',
'src/lib/lawnchair/lawnchair-adapter-webkit-sqlite-git.js',
@@ -293,6 +295,9 @@ module.exports = function(grunt) {
integrationTest: {
src: [
'src/lib/underscore/underscore.js',
+ 'node_modules/jquery/dist/jquery.min.js',
+ 'src/lib/angular/angular.js',
+ 'src/lib/angular/angular-mocks.js',
'src/lib/lawnchair/lawnchair-git.js',
'src/lib/lawnchair/lawnchair-adapter-webkit-sqlite-git.js',
'src/lib/lawnchair/lawnchair-adapter-indexed-db-git.js',
@@ -446,11 +451,11 @@ module.exports = function(grunt) {
tasks: ['dist-js-app']
},
jsUnitTest: {
- files: ['test/unit/*-test.js'],
+ files: ['test/unit/**/*-test.js', 'test/*.js'],
tasks: ['dist-js-unitTest']
},
jsIntegrationTest: {
- files: ['test/integration/*-test.js'],
+ files: ['test/integration/*-test.js', 'test/*.js'],
tasks: ['dist-js-integrationTest']
},
icons: {
diff --git a/src/index.html b/src/index.html
index 8f12cd6..dc456e1 100644
--- a/src/index.html
+++ b/src/index.html
@@ -1,5 +1,5 @@
-
+
Whiteout Mail
diff --git a/src/js/app-config.js b/src/js/app-config.js
index 460b117..d058d35 100644
--- a/src/js/app-config.js
+++ b/src/js/app-config.js
@@ -1,9 +1,17 @@
'use strict';
+var appCfg = {};
+
+var ngModule = angular.module('woAppConfig', []);
+ngModule.factory('appConfig', function() {
+ return appCfg;
+});
+module.exports = appCfg;
+
/**
* Global app configurations
*/
-exports.config = {
+appCfg.config = {
cloudUrl: 'https://keys.whiteout.io',
privkeyServerUrl: 'https://keychain.whiteout.io',
adminUrl: 'https://admin-node.whiteout.io',
@@ -38,7 +46,7 @@ if (typeof chrome !== 'undefined' && chrome.runtime && chrome.runtime.getManifes
}
function setConfigParams(manifest) {
- var cfg = exports.config;
+ var cfg = appCfg.config;
function getUrl(beginsWith) {
return _.find(manifest.permissions, function(permission) {
@@ -57,7 +65,7 @@ function setConfigParams(manifest) {
/**
* Strings are maintained here
*/
-exports.string = {
+appCfg.string = {
fallbackSubject: '(no subject)',
invitationSubject: 'Invitation to a private conversation',
invitationMessage: 'Hi,\n\nI use Whiteout Mail to send and receive encrypted email. I would like to exchange encrypted messages with you as well.\n\nPlease install the Whiteout Mail application. This application makes it easy to read and write messages securely with PGP encryption applied.\n\nGo to the Whiteout Networks homepage to learn more and to download the application: https://whiteout.io\n\n',
diff --git a/src/js/app-controller.js b/src/js/app-controller.js
deleted file mode 100644
index 0c6059c..0000000
--- a/src/js/app-controller.js
+++ /dev/null
@@ -1,307 +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;
-
- // 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.');
-
- ctrl.buildModules();
-
- // Handle offline and online gracefully
- window.addEventListener('online', ctrl.onConnect.bind(ctrl, ctrl.onError));
- window.addEventListener('offline', ctrl.onDisconnect.bind(ctrl));
-
- ctrl._appConfigStore.init('app-config', callback);
- }
-};
-
-/**
- * Initialize the dependency tree.
- */
-ctrl.buildModules = function() {
- var lawnchairDao, restDao, pubkeyDao, privkeyDao, crypto, emailDao, keychain, pgp, userStorage, pgpbuilder, oauth, appConfigStore, auth;
-
- // start the mailreader's worker thread
- mailreader.startWorker(config.workerPath + '/mailreader-parser-worker.min.js');
-
- // 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);
- 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);
-};
-
-/**
- * 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;
-};
-
-/**
- * Event handler that is called when the user agent goes offline.
- */
-ctrl.onDisconnect = function() {
- ctrl._emailDao.onDisconnect();
-};
-
-/**
- * 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 = '/';
- }
- });
- });
-};
-
-/**
- * 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;
\ No newline at end of file
diff --git a/src/js/app.js b/src/js/app.js
index 7480f02..8ca9f99 100644
--- a/src/js/app.js
+++ b/src/js/app.js
@@ -14,36 +14,49 @@ if (typeof window.applicationCache !== 'undefined') {
};
}
-var DialogCtrl = require('./controller/dialog'),
- AddAccountCtrl = require('./controller/add-account'),
- CreateAccountCtrl = require('./controller/create-account'),
- ValidatePhoneCtrl = require('./controller/validate-phone'),
- AccountCtrl = require('./controller/account'),
- SetPassphraseCtrl = require('./controller/set-passphrase'),
- PrivateKeyUploadCtrl = require('./controller/privatekey-upload'),
- ContactsCtrl = require('./controller/contacts'),
- AboutCtrl = require('./controller/about'),
- LoginCtrl = require('./controller/login'),
- LoginInitialCtrl = require('./controller/login-initial'),
- LoginNewDeviceCtrl = require('./controller/login-new-device'),
- LoginExistingCtrl = require('./controller/login-existing'),
- LoginPrivateKeyDownloadCtrl = require('./controller/login-privatekey-download'),
- LoginSetCredentialsCtrl = require('./controller/login-set-credentials'),
- MailListCtrl = require('./controller/mail-list'),
- ReadCtrl = require('./controller/read'),
- WriteCtrl = require('./controller/write'),
- NavigationCtrl = require('./controller/navigation'),
- ActionBarCtrl = require('./controller/action-bar'),
- errorUtil = require('./util/error'),
+var axe = require('axe-logger'),
+ AddAccountCtrl = require('./controller/login/add-account'),
+ CreateAccountCtrl = require('./controller/login/create-account'),
+ ValidatePhoneCtrl = require('./controller/login/validate-phone'),
+ LoginCtrl = require('./controller/login/login'),
+ LoginInitialCtrl = require('./controller/login/login-initial'),
+ LoginNewDeviceCtrl = require('./controller/login/login-new-device'),
+ LoginExistingCtrl = require('./controller/login/login-existing'),
+ LoginPrivateKeyDownloadCtrl = require('./controller/login/login-privatekey-download'),
+ LoginSetCredentialsCtrl = require('./controller/login/login-set-credentials'),
+ DialogCtrl = require('./controller/app/dialog'),
+ AccountCtrl = require('./controller/app/account'),
+ SetPassphraseCtrl = require('./controller/app/set-passphrase'),
+ PrivateKeyUploadCtrl = require('./controller/app/privatekey-upload'),
+ ContactsCtrl = require('./controller/app/contacts'),
+ AboutCtrl = require('./controller/app/about'),
+ MailListCtrl = require('./controller/app/mail-list'),
+ ReadCtrl = require('./controller/app/read'),
+ WriteCtrl = require('./controller/app/write'),
+ NavigationCtrl = require('./controller/app/navigation'),
+ ActionBarCtrl = require('./controller/app/action-bar'),
+ StatusDisplayCtrl = require('./controller/app/status-display'),
backButtonUtil = require('./util/backbutton-handler');
-require('./directive/common'),
-require('./service/newsletter'),
-require('./service/mail-config');
+
+// 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',
@@ -51,10 +64,7 @@ var app = angular.module('mail', [
'contacts',
'login-new-device',
'privatekey-upload',
- 'infinite-scroll',
- 'ngTagsInput',
- 'woDirectives',
- 'woServices'
+ 'infinite-scroll'
]);
// set router paths
@@ -111,9 +121,6 @@ app.run(function($rootScope) {
// global state... inherited to all child scopes
$rootScope.state = {};
- // attach global error handler
- errorUtil.attachHandler($rootScope);
-
// attach the back button handler to the root scope
backButtonUtil.attachHandler($rootScope);
@@ -131,4 +138,26 @@ app.controller('PrivateKeyUploadCtrl', PrivateKeyUploadCtrl);
app.controller('ContactsCtrl', ContactsCtrl);
app.controller('AboutCtrl', AboutCtrl);
app.controller('DialogCtrl', DialogCtrl);
-app.controller('ActionBarCtrl', ActionBarCtrl);
\ No newline at end of file
+app.controller('ActionBarCtrl', ActionBarCtrl);
+app.controller('StatusDisplayCtrl', StatusDisplayCtrl);
+
+//
+// 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']);
+ });
+}
\ No newline at end of file
diff --git a/src/js/controller/about.js b/src/js/controller/app/about.js
similarity index 66%
rename from src/js/controller/about.js
rename to src/js/controller/app/about.js
index ce627b0..b5f1269 100644
--- a/src/js/controller/about.js
+++ b/src/js/controller/app/about.js
@@ -1,12 +1,6 @@
'use strict';
-var cfg = require('../app-config').config;
-
-//
-// Controller
-//
-
-var AboutCtrl = function($scope) {
+var AboutCtrl = function($scope, appConfig) {
$scope.state.about = {
toggle: function(to) {
@@ -18,7 +12,7 @@ var AboutCtrl = function($scope) {
// scope variables
//
- $scope.version = cfg.appVersion + ' (beta)';
+ $scope.version = appConfig.config.appVersion + ' (beta)';
$scope.date = new Date();
//
diff --git a/src/js/controller/account.js b/src/js/controller/app/account.js
similarity index 72%
rename from src/js/controller/account.js
rename to src/js/controller/app/account.js
index ba1a46b..2e4270e 100644
--- a/src/js/controller/account.js
+++ b/src/js/controller/app/account.js
@@ -1,18 +1,10 @@
'use strict';
-var appController = require('../app-controller'),
- dl = require('../util/download'),
- config = require('../app-config').config,
- pgp, keychain, userId;
-
-//
-// Controller
-//
-
-var AccountCtrl = function($scope) {
- userId = appController._emailDao._account.emailAddress;
- keychain = appController._keychain;
- pgp = appController._pgp;
+var AccountCtrl = function($scope, auth, keychain, pgp, appConfig, download, dialog) {
+ var userId = auth.emailAddress;
+ if (!userId) {
+ return;
+ }
$scope.state.account = {
toggle: function(to) {
@@ -31,7 +23,7 @@ var AccountCtrl = function($scope) {
var fpr = keyParams.fingerprint;
$scope.fingerprint = fpr.slice(0, 4) + ' ' + fpr.slice(4, 8) + ' ' + fpr.slice(8, 12) + ' ' + fpr.slice(12, 16) + ' ' + fpr.slice(16, 20) + ' ' + fpr.slice(20, 24) + ' ' + fpr.slice(24, 28) + ' ' + fpr.slice(28, 32) + ' ' + fpr.slice(32, 36) + ' ' + fpr.slice(36);
$scope.keysize = keyParams.bitSize;
- $scope.publicKeyUrl = config.cloudUrl + '/' + userId;
+ $scope.publicKeyUrl = appConfig.config.cloudUrl + '/' + userId;
//
// scope functions
@@ -40,14 +32,14 @@ var AccountCtrl = function($scope) {
$scope.exportKeyFile = function() {
keychain.getUserKeyPair(userId, function(err, keys) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
var keyId = keys.publicKey._id;
var file = 'whiteout_mail_' + userId + '_' + keyId.substring(8, keyId.length);
- dl.createDownload({
+ download.createDownload({
content: keys.publicKey.publicKey + '\r\n' + keys.privateKey.encryptedKey,
filename: file + '.asc',
contentType: 'text/plain'
diff --git a/src/js/controller/action-bar.js b/src/js/controller/app/action-bar.js
similarity index 73%
rename from src/js/controller/action-bar.js
rename to src/js/controller/app/action-bar.js
index d1d6aa3..79a377d 100644
--- a/src/js/controller/action-bar.js
+++ b/src/js/controller/app/action-bar.js
@@ -1,15 +1,6 @@
'use strict';
-var appController = require('../app-controller'),
- emailDao;
-
-//
-// Controller
-//
-
-var ActionBarCtrl = function($scope) {
-
- emailDao = appController._emailDao;
+var ActionBarCtrl = function($scope, email, dialog, statusDisplay) {
/**
* Move a single message from the currently selected folder to another folder
@@ -24,9 +15,9 @@ var ActionBarCtrl = function($scope) {
// close read state
$scope.state.read.open = false;
- $scope.state.mailList.updateStatus('Moving message...');
+ statusDisplay.update('Moving message...');
- emailDao.moveMessage({
+ email.moveMessage({
folder: currentFolder(),
destination: destination,
message: message
@@ -35,14 +26,14 @@ var ActionBarCtrl = function($scope) {
// show errors where appropriate
if (err.code === 42) {
$scope.select(message);
- $scope.state.mailList.updateStatus('Unable to move message in offline mode!');
+ statusDisplay.update('Unable to move message in offline mode!');
return;
}
- $scope.state.mailList.updateStatus('Error during move!');
- $scope.onError(err);
+ statusDisplay.update('Error during move!');
+ dialog.error(err);
return;
}
- $scope.state.mailList.updateStatus('Message moved.');
+ statusDisplay.update('Message moved.');
$scope.$apply();
});
};
@@ -70,9 +61,9 @@ var ActionBarCtrl = function($scope) {
// close read state
$scope.state.read.open = false;
- $scope.state.mailList.updateStatus('Deleting message...');
+ statusDisplay.update('Deleting message...');
- emailDao.deleteMessage({
+ email.deleteMessage({
folder: currentFolder(),
message: message
}, function(err) {
@@ -80,14 +71,14 @@ var ActionBarCtrl = function($scope) {
// show errors where appropriate
if (err.code === 42) {
$scope.select(message);
- $scope.state.mailList.updateStatus('Unable to delete message in offline mode!');
+ statusDisplay.update('Unable to delete message in offline mode!');
return;
}
- $scope.state.mailList.updateStatus('Error during delete!');
- $scope.onError(err);
+ statusDisplay.update('Error during delete!');
+ dialog.error(err);
return;
}
- $scope.state.mailList.updateStatus('Message deleted.');
+ statusDisplay.update('Message deleted.');
$scope.$apply();
});
};
@@ -105,36 +96,38 @@ var ActionBarCtrl = function($scope) {
* @param {Object} message The message to be marked
* @param {boolean} unread If the message should be marked as read or unread
*/
- $scope.markMessage = function(message, unread) {
+ $scope.markMessage = function(message, unread, keepOpen) {
if (!message) {
return;
}
- $scope.state.mailList.updateStatus('Updating unread flag...');
+ statusDisplay.update('Updating unread flag...');
// close read state
- $scope.state.read.open = false;
+ if (!keepOpen) {
+ $scope.state.read.open = false;
+ }
var originalState = message.unread;
message.unread = unread;
- emailDao.setFlags({
+ email.setFlags({
folder: currentFolder(),
message: message
}, function(err) {
if (err && err.code === 42) {
// offline, restore
message.unread = originalState;
- $scope.state.mailList.updateStatus('Unable to mark message in offline mode!');
+ statusDisplay.update('Unable to mark message in offline mode!');
return;
}
if (err) {
- $scope.state.mailList.updateStatus('Error on sync!');
- $scope.onError(err);
+ statusDisplay.update('Error on sync!');
+ dialog.error(err);
return;
}
- $scope.state.mailList.updateStatus('Online');
+ statusDisplay.update('Online');
$scope.$apply();
});
};
diff --git a/src/js/controller/contacts.js b/src/js/controller/app/contacts.js
similarity index 88%
rename from src/js/controller/contacts.js
rename to src/js/controller/app/contacts.js
index 4eb604d..d5ed11f 100644
--- a/src/js/controller/contacts.js
+++ b/src/js/controller/app/contacts.js
@@ -1,15 +1,10 @@
'use strict';
-var appController = require('../app-controller'),
- keychain, pgp;
-
//
// Controller
//
-var ContactsCtrl = function($scope) {
- keychain = appController._keychain,
- pgp = appController._pgp;
+var ContactsCtrl = function($scope, keychain, pgp, dialog) {
$scope.state.contacts = {
toggle: function(to) {
@@ -26,7 +21,7 @@ var ContactsCtrl = function($scope) {
$scope.listKeys = function() {
keychain.listLocalPublicKeys(function(err, keys) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -54,7 +49,7 @@ var ContactsCtrl = function($scope) {
// verifiy public key string
if (publicKeyArmored.indexOf('-----BEGIN PGP PUBLIC KEY BLOCK-----') < 0) {
- $scope.onError({
+ dialog.error({
showBugReporter: false,
message: 'Invalid public key!'
});
@@ -64,7 +59,7 @@ var ContactsCtrl = function($scope) {
try {
keyParams = pgp.getKeyParams(publicKeyArmored);
} catch (e) {
- $scope.onError(new Error('Error reading public key params!'));
+ dialog.error(new Error('Error reading public key params!'));
return;
}
@@ -78,7 +73,7 @@ var ContactsCtrl = function($scope) {
keychain.saveLocalPublicKey(pubkey, function(err) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -90,7 +85,7 @@ var ContactsCtrl = function($scope) {
$scope.removeKey = function(key) {
keychain.removeLocalPublicKey(key._id, function(err) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
diff --git a/src/js/controller/app/dialog.js b/src/js/controller/app/dialog.js
new file mode 100644
index 0000000..58d8cde
--- /dev/null
+++ b/src/js/controller/app/dialog.js
@@ -0,0 +1,62 @@
+'use strict';
+
+var DialogCtrl = function($scope, $timeout, dialog) {
+
+ $scope.state.dialog = {
+ open: false
+ };
+
+ //
+ // Set dialog disply functions
+ //
+
+ dialog.displayInfo = function(options) {
+ return $timeout(function() {
+ setOptions(options);
+ });
+ };
+
+ dialog.displayError = function(options) {
+ return $timeout(function() {
+ if (!options) {
+ return;
+ }
+
+ setOptions(options);
+ $scope.title = options.title || 'Error';
+ $scope.showBugReporter = (typeof options.showBugReporter !== 'undefined' ? options.showBugReporter : !options.title); // if title is set, presume it's not an error by default
+ });
+ };
+
+ dialog.displayConfirm = function(options) {
+ return $timeout(function() {
+ setOptions(options);
+ });
+ };
+
+ function setOptions(options) {
+ $scope.state.dialog.open = true;
+ $scope.title = options.title;
+ $scope.message = options.errMsg || options.message;
+ $scope.faqLink = options.faqLink;
+ $scope.positiveBtnStr = options.positiveBtnStr || 'Ok';
+ $scope.negativeBtnStr = options.negativeBtnStr || 'Cancel';
+ $scope.showNegativeBtn = options.showNegativeBtn || false;
+ $scope.callback = options.callback;
+ }
+
+ //
+ // Scope functions
+ //
+
+ $scope.confirm = function(ok) {
+ $scope.state.dialog.open = false;
+
+ if ($scope.callback) {
+ $scope.callback(ok);
+ }
+ $scope.callback = undefined;
+ };
+};
+
+module.exports = DialogCtrl;
\ No newline at end of file
diff --git a/src/js/controller/mail-list.js b/src/js/controller/app/mail-list.js
similarity index 58%
rename from src/js/controller/mail-list.js
rename to src/js/controller/app/mail-list.js
index 968238c..3e142eb 100644
--- a/src/js/controller/mail-list.js
+++ b/src/js/controller/app/mail-list.js
@@ -1,8 +1,6 @@
'use strict';
-var appController = require('../app-controller'),
- notification = require('../util/notification'),
- emailDao, outboxBo, keychainDao, searchTimeout, firstSelect;
+var searchTimeout, firstSelect;
//
// Constants
@@ -13,14 +11,13 @@ var INIT_DISPLAY_LEN = 20,
FOLDER_TYPE_INBOX = 'Inbox',
NOTIFICATION_INBOX_TIMEOUT = 5000;
-var MailListCtrl = function($scope, $routeParams) {
+var MailListCtrl = function($scope, $timeout, $routeParams, statusDisplay, notification, email, keychain, dialog, search, dummy) {
+
//
// Init
//
- emailDao = appController._emailDao;
- outboxBo = appController._outboxBo;
- keychainDao = appController._keychain;
+ $scope.state.mailList = {};
/**
* Gathers unread notifications to be cancelled later
@@ -31,39 +28,39 @@ var MailListCtrl = function($scope, $routeParams) {
// scope functions
//
- $scope.getBody = function(email) {
- emailDao.getBody({
+ $scope.getBody = function(message) {
+ email.getBody({
folder: currentFolder(),
- message: email
+ message: message
}, function(err) {
if (err && err.code !== 42) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
// display fetched body
$scope.$digest();
- // automatically decrypt if it's the selected email
- if (email === currentMessage()) {
- emailDao.decryptBody({
- message: email
- }, $scope.onError);
+ // automatically decrypt if it's the selected message
+ if (message === currentMessage()) {
+ email.decryptBody({
+ message: message
+ }, dialog.error);
}
});
};
/**
- * Called when clicking on an email list item
+ * Called when clicking on an message list item
*/
- $scope.select = function(email) {
+ $scope.select = function(message) {
// unselect an item
- if (!email) {
+ if (!message) {
$scope.state.mailList.selected = undefined;
return;
}
- $scope.state.mailList.selected = email;
+ $scope.state.mailList.selected = message;
if (!firstSelect) {
// only toggle to read view on 2nd select in mobile mode
@@ -71,22 +68,22 @@ var MailListCtrl = function($scope, $routeParams) {
}
firstSelect = false;
- keychainDao.refreshKeyForUserId({
- userId: email.from[0].address
+ keychain.refreshKeyForUserId({
+ userId: message.from[0].address
}, onKeyRefreshed);
function onKeyRefreshed(err) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
}
- emailDao.decryptBody({
- message: email
- }, $scope.onError);
+ email.decryptBody({
+ message: message
+ }, dialog.error);
- // if the email is unread, please sync the new state.
+ // if the message is unread, please sync the new state.
// otherweise forget about it.
- if (!email.unread) {
+ if (!message.unread) {
return;
}
@@ -97,21 +94,16 @@ var MailListCtrl = function($scope, $routeParams) {
}
}
- $scope.state.actionBar.markMessage(email, false);
+ $scope.state.actionBar.markMessage(message, false, true);
}
};
- // share local scope functions with root state
- $scope.state.mailList = {
- updateStatus: updateStatus
- };
-
//
// watch tasks
//
/**
- * List emails from folder when user changes folder
+ * List messages from folder when user changes folder
*/
$scope._stopWatchTask = $scope.$watch('state.nav.currentFolder', function() {
if (!currentFolder()) {
@@ -123,8 +115,8 @@ var MailListCtrl = function($scope, $routeParams) {
// in development, display dummy mail objects
if ($routeParams.dev) {
- updateStatus('Last update: ', new Date());
- currentFolder().messages = createDummyMails();
+ statusDisplay.update('Last update: ', new Date());
+ currentFolder().messages = dummy.listMails();
return;
}
@@ -183,104 +175,37 @@ var MailListCtrl = function($scope, $routeParams) {
if (!searchText) {
// set display buffer to first messages
$scope.displayMessages = currentFolder().messages.slice(0, INIT_DISPLAY_LEN);
- setSearching(false);
- updateStatus('Online');
+ statusDisplay.setSearching(false);
+ statusDisplay.update('Online');
return;
}
// display searching spinner
- setSearching(true);
- updateStatus('Searching ...');
+ statusDisplay.setSearching(true);
+ statusDisplay.update('Searching ...');
searchTimeout = setTimeout(function() {
$scope.$apply(function() {
// filter relevant messages
- $scope.displayMessages = $scope.search(currentFolder().messages, searchText);
- setSearching(false);
- updateStatus('Matches in this folder');
+ $scope.displayMessages = search.filter(currentFolder().messages, searchText);
+ statusDisplay.setSearching(false);
+ statusDisplay.update('Matches in this folder');
});
}, 500);
};
- /**
- * Do full text search on messages. Parse meta data first
- */
- $scope.search = function(messages, searchText) {
- // don't filter on empty searchText
- if (!searchText) {
- return messages;
- }
-
- // escape search string
- searchText = searchText.replace(/([.*+?^${}()|\[\]\/\\])/g, "\\$1");
- // compare all strings (case insensitive)
- var regex = new RegExp(searchText, 'i');
-
- function contains(input) {
- if (!input) {
- return false;
- }
- return regex.test(input);
- }
-
- function checkAddresses(header) {
- if (!header || !header.length) {
- return false;
- }
-
- for (var i = 0; i < header.length; i++) {
- if (contains(header[i].name) || contains(header[i].address)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Filter meta data first and then only look at plaintext and decrypted message bodies
- */
- function matchMetaDataFirst(m) {
- // compare subject
- if (contains(m.subject)) {
- return true;
- }
- // compares address headers
- if (checkAddresses(m.from) || checkAddresses(m.to) || checkAddresses(m.cc) || checkAddresses(m.bcc)) {
- return true;
- }
- // compare plaintext body
- if (m.body && !m.encrypted && contains(m.body)) {
- return true;
- }
- // compare decrypted body
- if (m.body && m.encrypted && m.decrypted && contains(m.body)) {
- return true;
- }
- // compare plaintex html body
- if (m.html && !m.encrypted && contains(m.html)) {
- return true;
- }
- // compare decrypted html body
- if (m.html && m.encrypted && m.decrypted && contains(m.html)) {
- return true;
- }
- return false;
- }
-
- // user native js Array.filter
- return messages.filter(matchMetaDataFirst);
- };
-
/**
* Sync current folder when client comes back online
*/
$scope.watchOnline = $scope.$watch('account.online', function(isOnline) {
- if (isOnline) {
- updateStatus('Online');
- openCurrentFolder();
- } else {
- updateStatus('Offline mode');
- }
+ // wait one cycle for the status display controllers to init
+ $timeout(function() {
+ if (isOnline) {
+ statusDisplay.update('Online');
+ openCurrentFolder();
+ } else {
+ statusDisplay.update('Offline mode');
+ }
+ });
}, true);
//
@@ -292,7 +217,7 @@ var MailListCtrl = function($scope, $routeParams) {
return;
}
- emailDao.openFolder({
+ email.openFolder({
folder: currentFolder()
}, function(error) {
// dont wait until scroll to load visible mail bodies
@@ -302,21 +227,12 @@ var MailListCtrl = function($scope, $routeParams) {
if (error && error.code === 42) {
return;
}
- $scope.onError(error);
+ dialog.error(error);
});
}
- function updateStatus(lbl, time) {
- $scope.state.mailList.lastUpdateLbl = lbl;
- $scope.state.mailList.lastUpdate = (time) ? time : '';
- }
-
- function setSearching(state) {
- $scope.state.mailList.searching = state;
- }
-
function currentFolder() {
- return $scope.state.nav.currentFolder;
+ return $scope.state.nav && $scope.state.nav.currentFolder;
}
function currentMessage() {
@@ -327,7 +243,7 @@ var MailListCtrl = function($scope, $routeParams) {
// Notification API
//
- (emailDao || {}).onIncomingMessage = function(msgs) {
+ (email || {}).onIncomingMessage = function(msgs) {
var note, title, message, unreadMsgs;
unreadMsgs = msgs.filter(function(msg) {
@@ -402,7 +318,7 @@ ngModule.directive('listScroll', function() {
}
for (var i = 0, len = listItems.length; i < len; i++) {
- // the n-th list item (the dom representation of an email) corresponds to
+ // the n-th list item (the dom representation of an message) corresponds to
// the n-th message model in the filteredMessages array
listItem = listItems.item(i).getBoundingClientRect();
@@ -458,72 +374,4 @@ function byUidDescending(a, b) {
}
}
-// Helper for development mode
-
-function createDummyMails() {
- var uid = 1000000;
-
- var Email = function(unread, attachments, answered) {
- this.uid = uid--;
- this.from = [{
- name: 'Whiteout Support',
- address: 'support@whiteout.io'
- }]; // sender address
- this.to = [{
- address: 'max.musterman@gmail.com'
- }, {
- address: 'max.musterman@gmail.com'
- }]; // list of receivers
- this.cc = [{
- address: 'john.doe@gmail.com'
- }]; // list of receivers
- this.attachments = attachments ? [{
- "filename": "a.md",
- "filesize": 123,
- "mimeType": "text/x-markdown",
- "part": "2",
- "content": null
- }, {
- "filename": "b.md",
- "filesize": 456,
- "mimeType": "text/x-markdown",
- "part": "3",
- "content": null
- }, {
- "filename": "c.md",
- "filesize": 789,
- "mimeType": "text/x-markdown",
- "part": "4",
- "content": null
- }] : [];
- this.unread = unread;
- this.answered = answered;
- this.sentDate = new Date('Thu Sep 19 2013 20:41:23 GMT+0200 (CEST)');
- this.subject = 'Getting started'; // Subject line
- this.body = 'And a good day to you too sir. \n' +
- '\n' +
- 'Thursday, Apr 24, 2014 3:33 PM safewithme.testuser@gmail.com wrote:\n' +
- '> adsfadfasdfasdfasfdasdfasdfas\n' +
- '\n' +
- 'http://example.com\n' +
- '\n' +
- '> Tuesday, Mar 25, 2014 4:19 PM gianniarcore@gmail.com wrote:\n' +
- '>> from 0.7.0.1\n' +
- '>>\n' +
- '>> God speed!'; // plaintext body
- //this.html = 'Hello there' + Math.random() + '
';
- this.encrypted = true;
- this.decrypted = true;
- };
-
- var dummies = [],
- i = 100;
- while (i--) {
- // every second/third/fourth dummy mail with unread/attachments/answered
- dummies.push(new Email((i % 2 === 0), (i % 3 === 0), (i % 5 === 0)));
- }
-
- return dummies;
-}
-
module.exports = MailListCtrl;
\ No newline at end of file
diff --git a/src/js/controller/navigation.js b/src/js/controller/app/navigation.js
similarity index 80%
rename from src/js/controller/navigation.js
rename to src/js/controller/app/navigation.js
index 1ec4080..5986b8c 100644
--- a/src/js/controller/navigation.js
+++ b/src/js/controller/app/navigation.js
@@ -1,12 +1,6 @@
'use strict';
-var appController = require('../app-controller'),
- notification = require('../util/notification'),
- backBtnHandler = require('../util/backbutton-handler'),
- appCfg = require('../app-config'),
- config = appCfg.config,
- str = appCfg.string,
- emailDao, outboxBo;
+var backBtnHandler = require('../../util/backbutton-handler');
//
// Constants
@@ -19,14 +13,14 @@ var NOTIFICATION_SENT_TIMEOUT = 2000;
// Controller
//
-var NavigationCtrl = function($scope, $routeParams, $location) {
- if (!appController._emailDao && !$routeParams.dev) {
+var NavigationCtrl = function($scope, $routeParams, $location, account, email, outbox, notification, appConfig, dialog) {
+ if (!$routeParams.dev && !account.isLoggedIn()) {
$location.path('/'); // init app
return;
}
- emailDao = appController._emailDao;
- outboxBo = appController._outboxBo;
+ var str = appConfig.string,
+ config = appConfig.config;
//
// scope functions
@@ -46,32 +40,31 @@ var NavigationCtrl = function($scope, $routeParams, $location) {
$scope.onOutboxUpdate = function(err, count) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
// 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
- }, $scope.onError);
+ email.refreshFolder({
+ folder: ob
+ }, dialog.error);
};
$scope.logout = function() {
- $scope.onError({
+ dialog.confirm({
title: str.logoutTitle,
message: str.logoutMessage,
callback: function(confirm) {
if (confirm) {
- appController.logout();
+ account.logout();
}
- },
- sync: true
+ }
});
};
@@ -89,9 +82,9 @@ var NavigationCtrl = function($scope, $routeParams, $location) {
$scope.openFolder($scope.account.folders[0]);
}
// connect imap/smtp clients on first startup
- appController.onConnect(function(err) {
+ account.onConnect(function(err) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -114,18 +107,18 @@ var NavigationCtrl = function($scope, $routeParams, $location) {
}
// get pointer to account/folder/message tree on root scope
- $scope.$root.account = emailDao._account;
+ $scope.$root.account = account.list()[0];
// 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() {});
}
diff --git a/src/js/controller/privatekey-upload.js b/src/js/controller/app/privatekey-upload.js
similarity index 90%
rename from src/js/controller/privatekey-upload.js
rename to src/js/controller/app/privatekey-upload.js
index 5a77c72..779a101 100644
--- a/src/js/controller/privatekey-upload.js
+++ b/src/js/controller/app/privatekey-upload.js
@@ -1,12 +1,8 @@
'use strict';
-var appController = require('../app-controller'),
- util = require('crypto-lib').util,
- keychain, pgp;
+var util = require('crypto-lib').util;
-var PrivateKeyUploadCtrl = function($scope) {
- keychain = appController._keychain;
- pgp = keychain._pgp;
+var PrivateKeyUploadCtrl = function($scope, keychain, pgp, dialog, auth) {
$scope.state.privateKeyUpload = {
toggle: function(to) {
@@ -24,7 +20,7 @@ var PrivateKeyUploadCtrl = function($scope) {
// close lightbox
$scope.state.lightbox = undefined;
// show message
- $scope.onError({
+ dialog.info({
title: 'Info',
message: 'Your PGP key has already been synced.'
});
@@ -64,7 +60,7 @@ var PrivateKeyUploadCtrl = function($scope) {
keyId: keyParams._id
}, function(err, privateKeySynced) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -93,8 +89,7 @@ var PrivateKeyUploadCtrl = function($scope) {
if (inputCode.toUpperCase() !== $scope.code) {
var err = new Error('The code does not match. Please go back and check the generated code.');
- err.sync = true;
- $scope.onError(err);
+ dialog.error(err);
return false;
}
@@ -106,7 +101,7 @@ var PrivateKeyUploadCtrl = function($scope) {
};
$scope.encryptAndUploadKey = function(callback) {
- var userId = appController._emailDao._account.emailAddress;
+ var userId = auth.emailAddress;
var code = $scope.code;
// register device to keychain service
@@ -114,7 +109,7 @@ var PrivateKeyUploadCtrl = function($scope) {
userId: userId
}, function(err) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -147,7 +142,7 @@ var PrivateKeyUploadCtrl = function($scope) {
// set device name to local storage
$scope.setDeviceName(function(err) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -158,14 +153,14 @@ var PrivateKeyUploadCtrl = function($scope) {
// init key sync
$scope.encryptAndUploadKey(function(err) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
// close sync dialog
$scope.state.privateKeyUpload.toggle(false);
// show success message
- $scope.onError({
+ dialog.info({
title: 'Success',
message: 'Whiteout Keychain setup successful!'
});
diff --git a/src/js/controller/read-sandbox.js b/src/js/controller/app/read-sandbox.js
similarity index 100%
rename from src/js/controller/read-sandbox.js
rename to src/js/controller/app/read-sandbox.js
diff --git a/src/js/controller/read.js b/src/js/controller/app/read.js
similarity index 90%
rename from src/js/controller/read.js
rename to src/js/controller/app/read.js
index 26aea1c..4092644 100644
--- a/src/js/controller/read.js
+++ b/src/js/controller/app/read.js
@@ -1,21 +1,12 @@
'use strict';
-var appController = require('../app-controller'),
- download = require('../util/download'),
- str = require('../app-config').string,
- emailDao, invitationDao, outbox, pgp, keychain;
-
//
// Controller
//
-var ReadCtrl = function($scope) {
+var ReadCtrl = function($scope, email, invitation, outbox, pgp, keychain, appConfig, download, auth, dialog) {
- emailDao = appController._emailDao;
- invitationDao = appController._invitationDao;
- outbox = appController._outboxBo;
- pgp = appController._pgp;
- keychain = appController._keychain;
+ var str = appConfig.string;
// set default value so that the popover height is correct on init
$scope.keyId = 'No key found.';
@@ -31,7 +22,7 @@ var ReadCtrl = function($scope) {
$scope.keyId = 'Searching...';
keychain.getReceiverPublicKey(address, function(err, pubkey) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -71,7 +62,7 @@ var ReadCtrl = function($scope) {
keychain.getReceiverPublicKey(user.address, function(err, pubkey) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -97,12 +88,12 @@ var ReadCtrl = function($scope) {
}
var folder = $scope.state.nav.currentFolder;
- var email = $scope.state.mailList.selected;
- emailDao.getAttachment({
+ var message = $scope.state.mailList.selected;
+ email.getAttachment({
folder: folder,
- uid: email.uid,
+ uid: message.uid,
attachment: attachment
- }, $scope.onError);
+ }, dialog.error);
};
$scope.invite = function(user) {
@@ -113,15 +104,15 @@ var ReadCtrl = function($scope) {
$scope.keyId = 'Sending invitation...';
- var sender = emailDao._account.emailAddress,
+ var sender = auth.emailAddress,
recipient = user.address;
- invitationDao.invite({
+ invitation.invite({
recipient: recipient,
sender: sender
}, function(err) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -139,7 +130,7 @@ var ReadCtrl = function($scope) {
};
// send invitation mail
- outbox.put(invitationMail, $scope.onError);
+ outbox.put(invitationMail, dialog.error);
});
};
};
diff --git a/src/js/controller/set-passphrase.js b/src/js/controller/app/set-passphrase.js
similarity index 91%
rename from src/js/controller/set-passphrase.js
rename to src/js/controller/app/set-passphrase.js
index 724af8d..acbe04b 100644
--- a/src/js/controller/set-passphrase.js
+++ b/src/js/controller/app/set-passphrase.js
@@ -1,15 +1,10 @@
'use strict';
-var appController = require('../app-controller'),
- pgp, keychain;
+var SetPassphraseCtrl = function($scope, pgp, keychain, dialog) {
-//
-// Controller
-//
-
-var SetPassphraseCtrl = function($scope) {
- keychain = appController._keychain;
- pgp = appController._pgp;
+ //
+ // scope variables
+ //
$scope.state.setPassphrase = {
toggle: function(to) {
@@ -22,10 +17,6 @@ var SetPassphraseCtrl = function($scope) {
}
};
- //
- // scope variables
- //
-
//
// scope functions
//
@@ -87,7 +78,7 @@ var SetPassphraseCtrl = function($scope) {
var keyId = pgp.getKeyParams()._id;
keychain.lookupPrivateKey(keyId, function(err, savedKey) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -102,7 +93,7 @@ var SetPassphraseCtrl = function($scope) {
function onPassphraseChanged(err, newPrivateKeyArmored) {
if (err) {
err.showBugReporter = false;
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -120,13 +111,13 @@ var SetPassphraseCtrl = function($scope) {
function onKeyPersisted(err) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
$scope.state.setPassphrase.toggle(false);
$scope.$apply();
- $scope.onError({
+ dialog.info({
title: 'Success',
message: 'Passphrase change complete.'
});
diff --git a/src/js/controller/app/status-display.js b/src/js/controller/app/status-display.js
new file mode 100644
index 0000000..f20c898
--- /dev/null
+++ b/src/js/controller/app/status-display.js
@@ -0,0 +1,16 @@
+'use strict';
+
+var StatusDisplayCtrl = function($scope) {
+
+ $scope.$on('status', function(e, text, time) {
+ $scope.text = text;
+ $scope.time = (time) ? time : '';
+ });
+
+ $scope.$on('searching', function(e, state) {
+ $scope.searching = state;
+ });
+
+};
+
+module.exports = StatusDisplayCtrl;
\ No newline at end of file
diff --git a/src/js/controller/write.js b/src/js/controller/app/write.js
similarity index 91%
rename from src/js/controller/write.js
rename to src/js/controller/app/write.js
index 5713ec6..b447a19 100644
--- a/src/js/controller/write.js
+++ b/src/js/controller/app/write.js
@@ -1,21 +1,14 @@
'use strict';
-var appController = require('../app-controller'),
- axe = require('axe-logger'),
- util = require('crypto-lib').util,
- str = require('../app-config').string,
- pgp, emailDao, outbox, keychainDao, auth;
+var util = require('crypto-lib').util;
//
// Controller
//
-var WriteCtrl = function($scope, $filter, $q) {
- pgp = appController._pgp;
- auth = appController._auth;
- emailDao = appController._emailDao;
- outbox = appController._outboxBo;
- keychainDao = appController._keychain;
+var WriteCtrl = function($scope, $filter, $q, appConfig, auth, keychain, pgp, email, outbox, dialog, axe) {
+
+ var str = appConfig.string;
// set default value so that the popover height is correct on init
$scope.keyId = 'XXXXXXXX';
@@ -133,7 +126,7 @@ var WriteCtrl = function($scope, $filter, $q) {
}
if (replyAll) {
re.to.concat(re.cc).forEach(function(recipient) {
- var me = emailDao._account.emailAddress;
+ var me = auth.emailAddress;
if (recipient.address === me && replyTo !== me) {
// don't reply to yourself
return;
@@ -225,15 +218,15 @@ var WriteCtrl = function($scope, $filter, $q) {
return;
}
- // keychainDao is undefined in local dev environment
- if (keychainDao) {
+ // keychain is undefined in local dev environment
+ if (keychain) {
// check if to address is contained in known public keys
// when we write an email, we always need to work with the latest keys available
- keychainDao.refreshKeyForUserId({
+ keychain.refreshKeyForUserId({
userId: recipient.address
}, function(err, key) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -318,13 +311,13 @@ var WriteCtrl = function($scope, $filter, $q) {
//
$scope.sendToOutbox = function() {
- var email;
+ var message;
// build email model for smtp-client
- email = {
+ message = {
from: [{
- name: emailDao._account.realname,
- address: emailDao._account.emailAddress
+ name: auth.realname,
+ address: auth.emailAddress
}],
to: $scope.to.filter(filterEmptyAddresses),
cc: $scope.cc.filter(filterEmptyAddresses),
@@ -337,11 +330,11 @@ var WriteCtrl = function($scope, $filter, $q) {
};
if ($scope.inReplyTo) {
- email.headers['in-reply-to'] = '<' + $scope.inReplyTo + '>';
+ message.headers['in-reply-to'] = '<' + $scope.inReplyTo + '>';
}
if ($scope.references && $scope.references.length) {
- email.headers.references = $scope.references.map(function(reference) {
+ message.headers.references = $scope.references.map(function(reference) {
return '<' + reference + '>';
}).join(' ');
}
@@ -350,9 +343,9 @@ var WriteCtrl = function($scope, $filter, $q) {
$scope.state.writer.close();
// persist the email to disk for later sending
- outbox.put(email, function(err) {
+ outbox.put(message, function(err) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -363,12 +356,12 @@ var WriteCtrl = function($scope, $filter, $q) {
}
$scope.replyTo.answered = true;
- emailDao.setFlags({
+ email.setFlags({
folder: currentFolder(),
message: $scope.replyTo
}, function(err) {
if (err && err.code !== 42) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
@@ -396,9 +389,9 @@ var WriteCtrl = function($scope, $filter, $q) {
if (!$scope.addressBookCache) {
// populate address book cache
- keychainDao.listLocalPublicKeys(function(err, keys) {
+ keychain.listLocalPublicKeys(function(err, keys) {
if (err) {
- $scope.onError(err);
+ dialog.error(err);
return;
}
diff --git a/src/js/controller/dialog.js b/src/js/controller/dialog.js
deleted file mode 100644
index 8e33e22..0000000
--- a/src/js/controller/dialog.js
+++ /dev/null
@@ -1,14 +0,0 @@
-'use strict';
-
-var DialogCtrl = function($scope) {
- $scope.confirm = function(ok) {
- $scope.state.dialog.open = false;
-
- if ($scope.state.dialog.callback) {
- $scope.state.dialog.callback(ok);
- }
- $scope.state.dialog.callback = undefined;
- };
-};
-
-module.exports = DialogCtrl;
\ No newline at end of file
diff --git a/src/js/controller/add-account.js b/src/js/controller/login/add-account.js
similarity index 86%
rename from src/js/controller/add-account.js
rename to src/js/controller/login/add-account.js
index 28276da..18e1698 100644
--- a/src/js/controller/add-account.js
+++ b/src/js/controller/login/add-account.js
@@ -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, dialog) {
+ !$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 {
@@ -41,7 +36,7 @@ var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig) {
$scope.oauthPossible = function() {
// ask user to use the platform's native OAuth api
- $scope.onError({
+ dialog.confirm({
title: 'Google Account Login',
message: 'You are signing into a Google account. Would you like to sign in with Google or just continue with a password login?',
positiveBtnStr: 'Google sign in',
@@ -62,9 +57,9 @@ 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);
+ return dialog.error(err);
}
$scope.setCredentials();
$scope.$apply();
diff --git a/src/js/controller/create-account.js b/src/js/controller/login/create-account.js
similarity index 74%
rename from src/js/controller/create-account.js
rename to src/js/controller/login/create-account.js
index 7222d3d..a9b0c8e 100644
--- a/src/js/controller/create-account.js
+++ b/src/js/controller/login/create-account.js
@@ -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
diff --git a/src/js/controller/login-existing.js b/src/js/controller/login/login-existing.js
similarity index 72%
rename from src/js/controller/login-existing.js
rename to src/js/controller/login/login-existing.js
index 24cf496..505f1d2 100644
--- a/src/js/controller/login-existing.js
+++ b/src/js/controller/login/login-existing.js
@@ -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;
diff --git a/src/js/controller/login-initial.js b/src/js/controller/login/login-initial.js
similarity index 81%
rename from src/js/controller/login-initial.js
rename to src/js/controller/login/login-initial.js
index ced1bd1..08408d6 100644
--- a/src/js/controller/login-initial.js
+++ b/src/js/controller/login/login-initial.js
@@ -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;
diff --git a/src/js/controller/login-new-device.js b/src/js/controller/login/login-new-device.js
similarity index 88%
rename from src/js/controller/login-new-device.js
rename to src/js/controller/login/login-new-device.js
index fc24b17..44a3292 100644
--- a/src/js/controller/login-new-device.js
+++ b/src/js/controller/login/login-new-device.js
@@ -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;
diff --git a/src/js/controller/login-privatekey-download.js b/src/js/controller/login/login-privatekey-download.js
similarity index 88%
rename from src/js/controller/login-privatekey-download.js
rename to src/js/controller/login/login-privatekey-download.js
index e45106c..2d9715b 100644
--- a/src/js/controller/login-privatekey-download.js
+++ b/src/js/controller/login/login-privatekey-download.js
@@ -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;
diff --git a/src/js/controller/login-set-credentials.js b/src/js/controller/login/login-set-credentials.js
similarity index 91%
rename from src/js/controller/login-set-credentials.js
rename to src/js/controller/login/login-set-credentials.js
index 795ec37..c5bfbd2 100644
--- a/src/js/controller/login-set-credentials.js
+++ b/src/js/controller/login/login-set-credentials.js
@@ -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;
diff --git a/src/js/controller/login.js b/src/js/controller/login/login.js
similarity index 59%
rename from src/js/controller/login.js
rename to src/js/controller/login/login.js
index 30854ec..6db122b 100644
--- a/src/js/controller/login.js
+++ b/src/js/controller/login/login.js
@@ -1,45 +1,35 @@
'use strict';
-var appController = require('../app-controller');
+var LoginCtrl = function($scope, $timeout, $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();
- });
+ // 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;
}
// check if account needs to be selected
if (!info.emailAddress) {
- goTo('/add-account');
+ $scope.goTo('/add-account');
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;
}
@@ -51,54 +41,54 @@ 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) {
if (err) {
- goTo('/login-existing');
+ $scope.goTo('/login-existing');
return;
}
- appController._auth.storeCredentials(function(err) {
+ auth.storeCredentials(function(err) {
if (err) {
- return $scope.onError(err);
+ return dialog.error(err);
}
- goTo('/desktop');
+ $scope.goTo('/desktop');
});
});
} 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;
}
if (privateKeySynced) {
// private key is synced, proceed to download
- goTo('/login-privatekey-download');
+ $scope.goTo('/login-privatekey-download');
return;
}
// no private key, import key file
- goTo('/login-new-device');
+ $scope.goTo('/login-new-device');
});
} else {
// no public key available, start onboarding process
- goTo('/login-initial');
+ $scope.goTo('/login-initial');
}
}
- function goTo(location) {
- $scope.$apply(function() {
+ $scope.goTo = function(location) {
+ return $timeout(function() {
$location.path(location);
});
- }
+ };
};
module.exports = LoginCtrl;
\ No newline at end of file
diff --git a/src/js/controller/validate-phone.js b/src/js/controller/login/validate-phone.js
similarity index 68%
rename from src/js/controller/validate-phone.js
rename to src/js/controller/login/validate-phone.js
index fd261b8..5d4c9ab 100644
--- a/src/js/controller/validate-phone.js
+++ b/src/js/controller/login/validate-phone.js
@@ -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
$scope.validateUser = function() {
if ($scope.form.$invalid) {
@@ -18,8 +13,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) {
@@ -35,14 +30,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),
@@ -65,4 +60,4 @@ var ValidatePhoneCtrl = function($scope, $location, $routeParams, mailConfig) {
};
};
-module.exports = ValidatePhoneCtrl;
\ No newline at end of file
+module.exports = ValidatePhoneCtrl;
diff --git a/src/js/crypto/crypto.js b/src/js/crypto/crypto.js
index f19093a..04c13d8 100644
--- a/src/js/crypto/crypto.js
+++ b/src/js/crypto/crypto.js
@@ -1,16 +1,19 @@
-/**
- * High level crypto api that invokes native crypto (if available) and
- * gracefully degrades to JS crypto (if unavailable)
- */
-
'use strict';
+var ngModule = angular.module('woCrypto');
+ngModule.service('crypto', Crypto);
+module.exports = Crypto;
+
var aes = require('crypto-lib').aes,
pbkdf2 = require('./pbkdf2'),
config = require('../app-config').config,
axe = require('axe-logger');
-var Crypto = function() {};
+/**
+ * High level crypto api that invokes native crypto (if available) and
+ * gracefully degrades to JS crypto (if unavailable)
+ */
+function Crypto() {}
/**
* Encrypt plaintext using AES-GCM.
@@ -115,6 +118,4 @@ function startWorker(options) {
return;
}
options.callback(null, result);
-}
-
-module.exports = Crypto;
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/js/crypto/index.js b/src/js/crypto/index.js
new file mode 100644
index 0000000..6a77bcc
--- /dev/null
+++ b/src/js/crypto/index.js
@@ -0,0 +1,6 @@
+'use strict';
+
+angular.module('woCrypto', ['woAppConfig', 'woUtil']);
+
+require('./pgp');
+require('./crypto');
\ No newline at end of file
diff --git a/src/js/crypto/pgp.js b/src/js/crypto/pgp.js
index 429085e..847532e 100644
--- a/src/js/crypto/pgp.js
+++ b/src/js/crypto/pgp.js
@@ -1,16 +1,19 @@
-/**
- * High level crypto api that handles all calls to OpenPGP.js
- */
-
'use strict';
+var ngModule = angular.module('woCrypto');
+ngModule.service('pgp', PGP);
+module.exports = PGP;
+
var util = openpgp.util,
config = require('../app-config').config;
-var PGP = function() {
+/**
+ * High level crypto api that handles all calls to OpenPGP.js
+ */
+function PGP() {
openpgp.config.prefer_hash_algorithm = openpgp.enums.hash.sha256;
openpgp.initWorker(config.workerPath + '/openpgp.worker.min.js');
-};
+}
/**
* Generate a key pair for the user
@@ -426,6 +429,4 @@ function checkSignatureValidity(signatures) {
// everything is in order
return true;
-}
-
-module.exports = PGP;
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/js/email/account.js b/src/js/email/account.js
new file mode 100644
index 0000000..2d383c4
--- /dev/null
+++ b/src/js/email/account.js
@@ -0,0 +1,236 @@
+'use strict';
+
+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');
+
+function Account(appConfig, auth, accountStore, email, outbox, keychain, updateHandler, pgpbuilder, dialog) {
+ this._appConfig = appConfig;
+ this._auth = auth;
+ this._accountStore = accountStore;
+ this._emailDao = email;
+ this._outbox = outbox;
+ this._keychain = keychain;
+ this._updateHandler = updateHandler;
+ this._pgpbuilder = pgpbuilder;
+ this._dialog = dialog;
+ 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