mirror of https://github.com/moparisthebest/mail
Refactor login controllers and delete AppController
This commit is contained in:
parent
e6b22bd0a0
commit
4c04ba4e74
|
@ -1,5 +1,5 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html ng-app="mail" ng-csp manifest="appcache.manifest">
|
<html ng-csp manifest="appcache.manifest">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Whiteout Mail</title>
|
<title>Whiteout Mail</title>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
var appCfg = {};
|
var appCfg = {};
|
||||||
|
|
||||||
var ngModule = angular.module('mail');
|
var ngModule = angular.module('woAppConfig');
|
||||||
ngModule.factory('appConfig', function() {
|
ngModule.factory('appConfig', function() {
|
||||||
return appCfg;
|
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'),
|
AddAccountCtrl = require('./controller/add-account'),
|
||||||
CreateAccountCtrl = require('./controller/create-account'),
|
CreateAccountCtrl = require('./controller/create-account'),
|
||||||
ValidatePhoneCtrl = require('./controller/validate-phone'),
|
ValidatePhoneCtrl = require('./controller/validate-phone'),
|
||||||
|
@ -36,13 +37,26 @@ var DialogCtrl = require('./controller/dialog'),
|
||||||
ActionBarCtrl = require('./controller/action-bar'),
|
ActionBarCtrl = require('./controller/action-bar'),
|
||||||
errorUtil = require('./util/error'),
|
errorUtil = require('./util/error'),
|
||||||
backButtonUtil = require('./util/backbutton-handler');
|
backButtonUtil = require('./util/backbutton-handler');
|
||||||
require('./directive/common'),
|
|
||||||
|
// include angular modules
|
||||||
|
require('./app-config');
|
||||||
|
require('./directive/common');
|
||||||
|
require('./util');
|
||||||
|
require('./crypto');
|
||||||
require('./service');
|
require('./service');
|
||||||
|
require('./email');
|
||||||
|
|
||||||
// init main angular module including dependencies
|
// init main angular module including dependencies
|
||||||
var app = angular.module('mail', [
|
var app = angular.module('mail', [
|
||||||
'ngRoute',
|
'ngRoute',
|
||||||
'ngAnimate',
|
'ngAnimate',
|
||||||
|
'ngTagsInput',
|
||||||
|
'woAppConfig',
|
||||||
|
'woDirectives',
|
||||||
|
'woUtil',
|
||||||
|
'woCrypto,',
|
||||||
|
'woServices',
|
||||||
|
'woEmail',
|
||||||
'navigation',
|
'navigation',
|
||||||
'mail-list',
|
'mail-list',
|
||||||
'write',
|
'write',
|
||||||
|
@ -50,10 +64,7 @@ var app = angular.module('mail', [
|
||||||
'contacts',
|
'contacts',
|
||||||
'login-new-device',
|
'login-new-device',
|
||||||
'privatekey-upload',
|
'privatekey-upload',
|
||||||
'infinite-scroll',
|
'infinite-scroll'
|
||||||
'ngTagsInput',
|
|
||||||
'woDirectives',
|
|
||||||
'woServices'
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// set router paths
|
// set router paths
|
||||||
|
@ -131,3 +142,24 @@ app.controller('ContactsCtrl', ContactsCtrl);
|
||||||
app.controller('AboutCtrl', AboutCtrl);
|
app.controller('AboutCtrl', AboutCtrl);
|
||||||
app.controller('DialogCtrl', DialogCtrl);
|
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'),
|
backBtnHandler = require('../util/backbutton-handler'),
|
||||||
appCfg = require('../app-config'),
|
appCfg = require('../app-config'),
|
||||||
config = appCfg.config,
|
config = appCfg.config,
|
||||||
str = appCfg.string,
|
str = appCfg.string;
|
||||||
emailDao, outboxBo;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Constants
|
// Constants
|
||||||
|
@ -19,14 +18,8 @@ var NOTIFICATION_SENT_TIMEOUT = 2000;
|
||||||
// Controller
|
// Controller
|
||||||
//
|
//
|
||||||
|
|
||||||
var NavigationCtrl = function($scope, $routeParams, $location) {
|
var NavigationCtrl = function($scope, $routeParams, $location, account, email, outbox) {
|
||||||
if (!appController._emailDao && !$routeParams.dev) {
|
!$routeParams.dev && !account.isLoggedIn() && $location.path('/'); // init app
|
||||||
$location.path('/'); // init app
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
emailDao = appController._emailDao;
|
|
||||||
outboxBo = appController._outboxBo;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// scope functions
|
// scope functions
|
||||||
|
@ -51,14 +44,14 @@ var NavigationCtrl = function($scope, $routeParams, $location) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the outbox mail count
|
// update the outbox mail count
|
||||||
var outbox = _.findWhere($scope.account.folders, {
|
var ob = _.findWhere($scope.account.folders, {
|
||||||
type: config.outboxMailboxType
|
type: config.outboxMailboxType
|
||||||
});
|
});
|
||||||
outbox.count = count;
|
ob.count = count;
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
|
|
||||||
emailDao.refreshFolder({
|
email.refreshFolder({
|
||||||
folder: outbox
|
folder: ob
|
||||||
}, $scope.onError);
|
}, $scope.onError);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -114,18 +107,19 @@ var NavigationCtrl = function($scope, $routeParams, $location) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get pointer to account/folder/message tree on root scope
|
// 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
|
// set notificatio handler for sent messages
|
||||||
outboxBo.onSent = sentNotification;
|
outbox.onSent = sentNotification;
|
||||||
// start checking outbox periodically
|
// start checking outbox periodically
|
||||||
outboxBo.startChecking($scope.onOutboxUpdate);
|
outbox.startChecking($scope.onOutboxUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sentNotification(email) {
|
function sentNotification(message) {
|
||||||
notification.create({
|
notification.create({
|
||||||
title: 'Message sent',
|
title: 'Message sent',
|
||||||
message: email.subject,
|
message: message.subject,
|
||||||
timeout: NOTIFICATION_SENT_TIMEOUT
|
timeout: NOTIFICATION_SENT_TIMEOUT
|
||||||
}, function() {});
|
}, function() {});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var appCtrl = require('../app-controller');
|
var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig, auth) {
|
||||||
|
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||||
var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig) {
|
|
||||||
if (!appCtrl._auth && !$routeParams.dev) {
|
|
||||||
$location.path('/'); // init app
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.getAccountSettings = function() {
|
$scope.getAccountSettings = function() {
|
||||||
if ($scope.form.$invalid) {
|
if ($scope.form.$invalid) {
|
||||||
|
@ -25,7 +20,7 @@ var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig) {
|
||||||
};
|
};
|
||||||
|
|
||||||
var hostname = config.imap.hostname;
|
var hostname = config.imap.hostname;
|
||||||
if (appCtrl._auth.useOAuth(hostname)) {
|
if (auth.useOAuth(hostname)) {
|
||||||
// check for oauth support
|
// check for oauth support
|
||||||
$scope.oauthPossible();
|
$scope.oauthPossible();
|
||||||
} else {
|
} else {
|
||||||
|
@ -62,7 +57,7 @@ var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig) {
|
||||||
|
|
||||||
function getOAuthToken() {
|
function getOAuthToken() {
|
||||||
// fetches the email address from the chrome identity api
|
// fetches the email address from the chrome identity api
|
||||||
appCtrl._auth.getOAuthToken(function(err) {
|
auth.getOAuthToken(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return $scope.onError(err);
|
return $scope.onError(err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var appCtrl = require('../app-controller'),
|
var CreateAccountCtrl = function($scope, $location, $routeParams, auth, admin, appConfig) {
|
||||||
cfg = require('../app-config').config;
|
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||||
|
|
||||||
var CreateAccountCtrl = function($scope, $location, $routeParams) {
|
|
||||||
if (!appCtrl._auth && !$routeParams.dev) {
|
|
||||||
$location.path('/'); // init app
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.createWhiteoutAccount = function() {
|
$scope.createWhiteoutAccount = function() {
|
||||||
if ($scope.form.$invalid) {
|
if ($scope.form.$invalid) {
|
||||||
|
@ -17,17 +11,17 @@ var CreateAccountCtrl = function($scope, $location, $routeParams) {
|
||||||
|
|
||||||
$scope.busy = true;
|
$scope.busy = true;
|
||||||
$scope.errMsg = undefined; // reset error msg
|
$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
|
// set to state for next view
|
||||||
$scope.state.createAccount = {
|
auth.setCredentials({
|
||||||
emailAddress: emailAddress,
|
emailAddress: emailAddress,
|
||||||
pass: $scope.pass,
|
password: $scope.pass,
|
||||||
realname: $scope.realname
|
realname: $scope.realname
|
||||||
};
|
});
|
||||||
|
|
||||||
// call REST api
|
// call REST api
|
||||||
appCtrl._adminDao.createUser({
|
admin.createUser({
|
||||||
emailAddress: emailAddress,
|
emailAddress: emailAddress,
|
||||||
password: $scope.pass,
|
password: $scope.pass,
|
||||||
phone: $scope.phone.replace(/\s+/g, ''), // remove spaces from the phone number
|
phone: $scope.phone.replace(/\s+/g, ''), // remove spaces from the phone number
|
||||||
|
|
|
@ -1,14 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var appController = require('../app-controller');
|
var LoginExistingCtrl = function($scope, $location, $routeParams, email, auth, keychain) {
|
||||||
|
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||||
var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
|
||||||
if (!appController._emailDao && !$routeParams.dev) {
|
|
||||||
$location.path('/'); // init app
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var emailDao = appController._emailDao;
|
|
||||||
|
|
||||||
$scope.confirmPassphrase = function() {
|
$scope.confirmPassphrase = function() {
|
||||||
if ($scope.form.$invalid) {
|
if ($scope.form.$invalid) {
|
||||||
|
@ -24,14 +17,14 @@ var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||||
};
|
};
|
||||||
|
|
||||||
function unlockCrypto() {
|
function unlockCrypto() {
|
||||||
var userId = emailDao._account.emailAddress;
|
var userId = auth.emailAddress;
|
||||||
emailDao._keychain.getUserKeyPair(userId, function(err, keypair) {
|
keychain.getUserKeyPair(userId, function(err, keypair) {
|
||||||
if (err) {
|
if (err) {
|
||||||
displayError(err);
|
displayError(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emailDao.unlock({
|
email.unlock({
|
||||||
keypair: keypair,
|
keypair: keypair,
|
||||||
passphrase: $scope.passphrase
|
passphrase: $scope.passphrase
|
||||||
}, onUnlock);
|
}, onUnlock);
|
||||||
|
@ -44,7 +37,7 @@ var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
appController._auth.storeCredentials(function(err) {
|
auth.storeCredentials(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
displayError(err);
|
displayError(err);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,17 +1,9 @@
|
||||||
'use strict';
|
'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) {
|
var emailAddress = auth.emailAddress;
|
||||||
if (!appController._emailDao && !$routeParams.dev) {
|
|
||||||
$location.path('/'); // init app
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (appController._emailDao) {
|
|
||||||
var emailDao = appController._emailDao,
|
|
||||||
emailAddress = emailDao._account.emailAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
var termsMsg = 'You must accept the Terms of Service to continue.',
|
var termsMsg = 'You must accept the Terms of Service to continue.',
|
||||||
states = {
|
states = {
|
||||||
|
@ -59,7 +51,7 @@ var LoginInitialCtrl = function($scope, $location, $routeParams, newsletter) {
|
||||||
// go to set keygen screen
|
// go to set keygen screen
|
||||||
$scope.setState(states.PROCESSING);
|
$scope.setState(states.PROCESSING);
|
||||||
|
|
||||||
emailDao.unlock({
|
email.unlock({
|
||||||
passphrase: undefined // generate key without passphrase
|
passphrase: undefined // generate key without passphrase
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -67,7 +59,7 @@ var LoginInitialCtrl = function($scope, $location, $routeParams, newsletter) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
appController._auth.storeCredentials(function(err) {
|
auth.storeCredentials(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
displayError(err);
|
displayError(err);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,15 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var appController = require('../app-controller');
|
var LoginExistingCtrl = function($scope, $location, $routeParams, email, auth, pgp, keychain) {
|
||||||
|
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||||
var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
|
||||||
if (!appController._emailDao && !$routeParams.dev) {
|
|
||||||
$location.path('/'); // init app
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var emailDao = appController._emailDao,
|
|
||||||
pgp = appController._pgp;
|
|
||||||
|
|
||||||
$scope.incorrect = false;
|
$scope.incorrect = false;
|
||||||
|
|
||||||
|
@ -27,9 +19,9 @@ var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||||
};
|
};
|
||||||
|
|
||||||
function unlockCrypto() {
|
function unlockCrypto() {
|
||||||
var userId = emailDao._account.emailAddress;
|
var userId = auth.emailAddress;
|
||||||
// check if user already has a public key on the key server
|
// 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) {
|
if (err) {
|
||||||
$scope.displayError(err);
|
$scope.displayError(err);
|
||||||
return;
|
return;
|
||||||
|
@ -76,7 +68,7 @@ var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// import and validate keypair
|
// import and validate keypair
|
||||||
emailDao.unlock({
|
email.unlock({
|
||||||
keypair: keypair,
|
keypair: keypair,
|
||||||
passphrase: $scope.passphrase
|
passphrase: $scope.passphrase
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
|
@ -86,7 +78,7 @@ var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emailDao._keychain.putUserKeyPair(keypair, onUnlock);
|
keychain.putUserKeyPair(keypair, onUnlock);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -97,7 +89,7 @@ var LoginExistingCtrl = function($scope, $location, $routeParams) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
appController._auth.storeCredentials(function(err) {
|
auth.storeCredentials(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
$scope.displayError(err);
|
$scope.displayError(err);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,18 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var appController = require('../app-controller');
|
var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams, auth, email, keychain) {
|
||||||
|
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.step = 1;
|
$scope.step = 1;
|
||||||
|
|
||||||
|
@ -38,6 +27,7 @@ var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams) {
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.verifyRecoveryToken = function(callback) {
|
$scope.verifyRecoveryToken = function(callback) {
|
||||||
|
var userId = auth.emailAddress;
|
||||||
keychain.getUserKeyPair(userId, function(err, keypair) {
|
keychain.getUserKeyPair(userId, function(err, keypair) {
|
||||||
if (err) {
|
if (err) {
|
||||||
displayError(err);
|
displayError(err);
|
||||||
|
@ -95,7 +85,7 @@ var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams) {
|
||||||
$scope.cachedKeypair.privateKey = privateKey;
|
$scope.cachedKeypair.privateKey = privateKey;
|
||||||
|
|
||||||
// try empty passphrase
|
// try empty passphrase
|
||||||
emailDao.unlock({
|
email.unlock({
|
||||||
keypair: $scope.cachedKeypair,
|
keypair: $scope.cachedKeypair,
|
||||||
passphrase: undefined
|
passphrase: undefined
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
|
@ -106,7 +96,7 @@ var LoginPrivateKeyDownloadCtrl = function($scope, $location, $routeParams) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// passphrase is corrent ... go to main app
|
// passphrase is corrent ... go to main app
|
||||||
appController._auth.storeCredentials(function(err) {
|
auth.storeCredentials(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
displayError(err);
|
displayError(err);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -4,16 +4,8 @@ var ENCRYPTION_METHOD_NONE = 0;
|
||||||
var ENCRYPTION_METHOD_STARTTLS = 1;
|
var ENCRYPTION_METHOD_STARTTLS = 1;
|
||||||
var ENCRYPTION_METHOD_TLS = 2;
|
var ENCRYPTION_METHOD_TLS = 2;
|
||||||
|
|
||||||
var appCtrl = require('../app-controller');
|
var SetCredentialsCtrl = function($scope, $location, $routeParams, auth, connectionDoctor) {
|
||||||
|
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||||
var SetCredentialsCtrl = function($scope, $location, $routeParams) {
|
|
||||||
if (!appCtrl._auth && !$routeParams.dev) {
|
|
||||||
$location.path('/'); // init app
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var auth = appCtrl._auth;
|
|
||||||
var doctor = appCtrl._doctor;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Presets and Settings
|
// Presets and Settings
|
||||||
|
@ -87,11 +79,11 @@ var SetCredentialsCtrl = function($scope, $location, $routeParams) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// use the credentials in the connection doctor
|
// use the credentials in the connection doctor
|
||||||
doctor.configure(credentials);
|
connectionDoctor.configure(credentials);
|
||||||
|
|
||||||
// run connection doctor test suite
|
// run connection doctor test suite
|
||||||
$scope.busy = true;
|
$scope.busy = true;
|
||||||
doctor.check(function(err) {
|
connectionDoctor.check(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
// display the error in the settings UI
|
// display the error in the settings UI
|
||||||
$scope.connectionError = err;
|
$scope.connectionError = err;
|
||||||
|
|
|
@ -1,31 +1,19 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var appController = require('../app-controller');
|
var LoginCtrl = function($scope, $location, updateHandler, account, auth, email, keychain, dialog) {
|
||||||
|
|
||||||
var LoginCtrl = function($scope, $location) {
|
// check for app update
|
||||||
|
updateHandler.checkForUpdate();
|
||||||
// start main application controller
|
// initialize the user account
|
||||||
appController.start({
|
initializeUser();
|
||||||
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
|
|
||||||
|
|
||||||
function initializeUser() {
|
function initializeUser() {
|
||||||
|
// init the auth modules
|
||||||
|
auth.init();
|
||||||
// get OAuth token from chrome
|
// get OAuth token from chrome
|
||||||
appController._auth.getEmailAddress(function(err, info) {
|
auth.getEmailAddress(function(err, info) {
|
||||||
if (err) {
|
if (err) {
|
||||||
$scope.onError(err);
|
dialog.error(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,13 +23,13 @@ var LoginCtrl = function($scope, $location) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// initiate controller by creating email dao
|
// initiate the account by initializing the email dao and user storage
|
||||||
appController.init({
|
account.init({
|
||||||
emailAddress: info.emailAddress,
|
emailAddress: info.emailAddress,
|
||||||
realname: info.realname
|
realname: info.realname
|
||||||
}, function(err, availableKeys) {
|
}, function(err, availableKeys) {
|
||||||
if (err) {
|
if (err) {
|
||||||
$scope.onError(err);
|
dialog.error(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +41,7 @@ var LoginCtrl = function($scope, $location) {
|
||||||
function redirect(availableKeys) {
|
function redirect(availableKeys) {
|
||||||
if (availableKeys && availableKeys.publicKey && availableKeys.privateKey) {
|
if (availableKeys && availableKeys.publicKey && availableKeys.privateKey) {
|
||||||
// public and private key available, try empty passphrase
|
// public and private key available, try empty passphrase
|
||||||
appController._emailDao.unlock({
|
email.unlock({
|
||||||
keypair: availableKeys,
|
keypair: availableKeys,
|
||||||
passphrase: undefined
|
passphrase: undefined
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
|
@ -62,9 +50,9 @@ var LoginCtrl = function($scope, $location) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
appController._auth.storeCredentials(function(err) {
|
auth.storeCredentials(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return $scope.onError(err);
|
return dialog.error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
goTo('/desktop');
|
goTo('/desktop');
|
||||||
|
@ -72,12 +60,12 @@ var LoginCtrl = function($scope, $location) {
|
||||||
});
|
});
|
||||||
} else if (availableKeys && availableKeys.publicKey && !availableKeys.privateKey) {
|
} else if (availableKeys && availableKeys.publicKey && !availableKeys.privateKey) {
|
||||||
// check if private key is synced
|
// check if private key is synced
|
||||||
appController._keychain.requestPrivateKeyDownload({
|
keychain.requestPrivateKeyDownload({
|
||||||
userId: availableKeys.publicKey.userId,
|
userId: availableKeys.publicKey.userId,
|
||||||
keyId: availableKeys.publicKey._id,
|
keyId: availableKeys.publicKey._id,
|
||||||
}, function(err, privateKeySynced) {
|
}, function(err, privateKeySynced) {
|
||||||
if (err) {
|
if (err) {
|
||||||
$scope.onError(err);
|
dialog.error(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var appCtrl = require('../app-controller');
|
var ValidatePhoneCtrl = function($scope, $location, $routeParams, mailConfig, auth, admin) {
|
||||||
|
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
|
||||||
var ValidatePhoneCtrl = function($scope, $location, $routeParams, mailConfig) {
|
|
||||||
if (!appCtrl._auth && !$routeParams.dev) {
|
|
||||||
$location.path('/'); // init app
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: move to Account service create function
|
// TODO: move to Account service create function
|
||||||
|
|
||||||
|
@ -20,8 +15,8 @@ var ValidatePhoneCtrl = function($scope, $location, $routeParams, mailConfig) {
|
||||||
$scope.errMsg = undefined; // reset error msg
|
$scope.errMsg = undefined; // reset error msg
|
||||||
|
|
||||||
// verify user to REST api
|
// verify user to REST api
|
||||||
appCtrl._adminDao.validateUser({
|
admin.validateUser({
|
||||||
emailAddress: $scope.state.createAccount.emailAddress,
|
emailAddress: auth.emailAddress,
|
||||||
token: $scope.token.toUpperCase()
|
token: $scope.token.toUpperCase()
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -37,14 +32,14 @@ var ValidatePhoneCtrl = function($scope, $location, $routeParams, mailConfig) {
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.login = function() {
|
$scope.login = function() {
|
||||||
var address = $scope.state.createAccount.emailAddress;
|
var address = auth.emailAddress;
|
||||||
return mailConfig.get(address).then(function(config) {
|
return mailConfig.get(address).then(function(config) {
|
||||||
// store credentials in memory
|
// store credentials in memory
|
||||||
appCtrl._auth.setCredentials({
|
auth.setCredentials({
|
||||||
emailAddress: $scope.state.createAccount.emailAddress,
|
emailAddress: auth.emailAddress,
|
||||||
username: $scope.state.createAccount.emailAddress,
|
username: auth.emailAddress,
|
||||||
realname: $scope.state.createAccount.realname,
|
realname: auth.realname,
|
||||||
password: $scope.state.createAccount.pass,
|
password: auth.password,
|
||||||
imap: {
|
imap: {
|
||||||
host: config.imap.hostname,
|
host: config.imap.hostname,
|
||||||
port: parseInt(config.imap.port, 10),
|
port: parseInt(config.imap.port, 10),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('woCrypto', []);
|
angular.module('woCrypto', ['woAppConfig', 'woUtil']);
|
||||||
|
|
||||||
require('./pgp');
|
require('./pgp');
|
||||||
require('./crypto');
|
require('./crypto');
|
|
@ -4,41 +4,240 @@ var ngModule = angular.module('woServices');
|
||||||
ngModule.service('account', Account);
|
ngModule.service('account', Account);
|
||||||
module.exports = Account;
|
module.exports = Account;
|
||||||
|
|
||||||
function Account(email, outbox) {
|
var axe = require('axe-logger'),
|
||||||
this._emailDAOs = [email];
|
util = require('crypto-lib').util,
|
||||||
this._outboxes = [outbox];
|
PgpMailer = require('pgpmailer'),
|
||||||
this._accounts = undefined;
|
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
|
* Lists all of the current accounts connected to the app
|
||||||
* @return {Array<Object>} The account objects containing folder and message objects
|
* @return {Array<Object>} The account objects containing folder and message objects
|
||||||
*/
|
*/
|
||||||
Account.prototype.list = function() {
|
Account.prototype.list = function() {
|
||||||
this._accounts = this._emailDAOs.map(function(emailDao) {
|
|
||||||
return emailDao._account;
|
|
||||||
});
|
|
||||||
|
|
||||||
return this._accounts;
|
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.
|
* Fire up the database, retrieve the available keys for the user and initialize the email data access object
|
||||||
* @param {String} options.emailAddress The account's email address
|
|
||||||
*/
|
*/
|
||||||
Account.prototype.login = function(options) {
|
Account.prototype.init = function(options, callback) {
|
||||||
var emailDao = new Email();
|
var self = this;
|
||||||
this._emailDAOs.push(emailDao);
|
|
||||||
|
// 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.
|
* 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
|
* @param {String} options.emailAddress The account's email address
|
||||||
*/
|
*/
|
||||||
Account.prototype.create = function(options) {};
|
Account.prototype.create = function() {};
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {};
|
|
|
@ -50,12 +50,14 @@ var MSG_PART_TYPE_HTML = 'html';
|
||||||
* @param {Object} pgpbuilder Generates and encrypts MIME and SMTP messages
|
* @param {Object} pgpbuilder Generates and encrypts MIME and SMTP messages
|
||||||
* @param {Object} mailreader Parses MIME messages received from IMAP
|
* @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._keychain = keychain;
|
||||||
this._pgp = pgp;
|
this._pgp = pgp;
|
||||||
this._devicestorage = devicestorage;
|
this._devicestorage = deviceStorage;
|
||||||
this._pgpbuilder = pgpbuilder;
|
this._pgpbuilder = pgpbuilder;
|
||||||
this._mailreader = mailreader;
|
this._mailreader = mailreader;
|
||||||
|
|
||||||
|
this.onError = dialog.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('woEmail', []);
|
angular.module('woEmail', ['woAppConfig', 'woUtil', 'woServices']);
|
||||||
|
|
||||||
|
require('./mailreader');
|
||||||
|
require('./pgpbuilder');
|
||||||
require('./email');
|
require('./email');
|
||||||
|
require('./outbox');
|
||||||
require('./account');
|
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.
|
* 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.
|
* 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 */
|
/** @private */
|
||||||
this._emailDao = emailDao;
|
this._emailDao = email;
|
||||||
|
|
||||||
/** @private */
|
/** @private */
|
||||||
this._keychain = keychain;
|
this._keychain = keychain;
|
||||||
|
|
||||||
/** @private */
|
/** @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.
|
* 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);
|
ngModule.service('admin', Admin);
|
||||||
module.exports = Admin;
|
module.exports = Admin;
|
||||||
|
|
||||||
function Admin(restDao) {
|
function Admin(restDao, appConfig) {
|
||||||
this._restDao = restDao;
|
this._restDao = restDao;
|
||||||
|
this._restDao.setBaseUri(appConfig.config.adminUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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,
|
* auth.getCredentials(...); // called to gather all the information to connect to IMAP/SMTP,
|
||||||
* username, password / oauth token, IMAP/SMTP server host names, ...
|
* username, password / oauth token, IMAP/SMTP server host names, ...
|
||||||
*/
|
*/
|
||||||
function Auth(deviceStorage, oauth, pgp) {
|
function Auth(appConfigStore, oauth, pgp) {
|
||||||
this._appConfigStore = deviceStorage;
|
this._appConfigStore = appConfigStore;
|
||||||
this._oauth = oauth;
|
this._oauth = oauth;
|
||||||
this._pgp = pgp;
|
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:
|
* Retrieves credentials and IMAP/SMTP settings:
|
||||||
* 1) Fetches the credentials from disk, then...
|
* 1) Fetches the credentials from disk, then...
|
||||||
|
|
|
@ -1,22 +1,18 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var ngModule = angular.module('woServices');
|
var ngModule = angular.module('woServices');
|
||||||
ngModule.factory('deviceStorage', ['lawnchairDAO',
|
ngModule.service('deviceStorage', DeviceStorage);
|
||||||
function(lawnchairDAO) {
|
|
||||||
return new DeviceStorage(lawnchairDAO);
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
module.exports = 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) {
|
function DeviceStorage(lawnchairDAO) {
|
||||||
this._localDbDao = lawnchairDAO;
|
this._localDbDao = lawnchairDAO;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceStorage.prototype.init = function(dbName, callback) {
|
DeviceStorage.prototype.init = function(dbName) {
|
||||||
this._localDbDao.init(dbName, callback);
|
this._localDbDao.init(dbName);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('woServices', []);
|
angular.module('woServices', ['woAppConfig', 'woUtil', 'woCrypto']);
|
||||||
|
|
||||||
require('./newsletter');
|
require('./rest');
|
||||||
|
require('./invitation');
|
||||||
require('./mail-config');
|
require('./mail-config');
|
||||||
require('./account');
|
require('./newsletter');
|
||||||
require('.pgpbuilder');
|
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);
|
ngModule.service('invitation', Invitation);
|
||||||
module.exports = 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.
|
* 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
|
* @param {Object} restDao The REST Data Access Object abstraction
|
||||||
*/
|
*/
|
||||||
function Invitation(restDao) {
|
function Invitation(restDao, appConfig) {
|
||||||
this._restDao = restDao;
|
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
|
* A high-level Data-Access Api for handling Keypair synchronization
|
||||||
* between the cloud service and the device's local storage
|
* between the cloud service and the device's local storage
|
||||||
*/
|
*/
|
||||||
function Keychain(localDbDao, publicKeyDao, privateKeyDao, crypto, pgp) {
|
function Keychain(lawnchairDAO, publicKey, privateKey, crypto, pgp, dialog, appConfig) {
|
||||||
this._localDbDao = localDbDao;
|
this._lawnchairDAO = lawnchairDAO;
|
||||||
this._publicKeyDao = publicKeyDao;
|
this._publicKeyDao = publicKey;
|
||||||
this._privateKeyDao = privateKeyDao;
|
this._privateKeyDao = privateKey;
|
||||||
this._crypto = crypto;
|
this._crypto = crypto;
|
||||||
this._pgp = pgp;
|
this._pgp = pgp;
|
||||||
|
this._dialog = dialog;
|
||||||
|
this._appConfig = appConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Public key functions
|
// 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
|
* Verifies the public key of a user o nthe public key store
|
||||||
* @param {String} uuid The uuid to verify the key
|
* @param {String} uuid The uuid to verify the key
|
||||||
|
@ -196,7 +218,7 @@ Keychain.prototype.getReceiverPublicKey = function(userId, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// search local keyring for public key
|
// 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) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
|
@ -275,7 +297,7 @@ Keychain.prototype.setDeviceName = function(deviceName, callback) {
|
||||||
return;
|
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) {
|
Keychain.prototype.getDeviceName = function(callback) {
|
||||||
// check if deviceName is already persisted in storage
|
// 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) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
|
@ -308,7 +330,7 @@ Keychain.prototype.getDeviceSecret = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// generate random deviceSecret or get from storage
|
// 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) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
|
@ -323,7 +345,7 @@ Keychain.prototype.getDeviceSecret = function(callback) {
|
||||||
// generate random deviceSecret
|
// generate random deviceSecret
|
||||||
var deviceSecret = util.random(config.symKeySize);
|
var deviceSecret = util.random(config.symKeySize);
|
||||||
// persist deviceSecret to local storage (in plaintext)
|
// 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) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
|
@ -763,7 +785,7 @@ Keychain.prototype.getUserKeyPair = function(userId, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// search for user's public key locally
|
// 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) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
|
@ -886,7 +908,7 @@ Keychain.prototype.lookupPublicKey = function(id, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// lookup in local storage
|
// lookup in local storage
|
||||||
self._localDbDao.read(DB_PUBLICKEY + '_' + id, function(err, pubkey) {
|
self._lawnchairDAO.read(DB_PUBLICKEY + '_' + id, function(err, pubkey) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
|
@ -922,26 +944,26 @@ Keychain.prototype.lookupPublicKey = function(id, callback) {
|
||||||
*/
|
*/
|
||||||
Keychain.prototype.listLocalPublicKeys = function(callback) {
|
Keychain.prototype.listLocalPublicKeys = function(callback) {
|
||||||
// search local keyring for public key
|
// 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) {
|
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) {
|
Keychain.prototype.lookupPrivateKey = function(id, callback) {
|
||||||
// lookup in local storage
|
// lookup in local storage
|
||||||
this._localDbDao.read(DB_PRIVATEKEY + '_' + id, callback);
|
this._lawnchairDAO.read(DB_PRIVATEKEY + '_' + id, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Keychain.prototype.saveLocalPublicKey = function(pubkey, callback) {
|
Keychain.prototype.saveLocalPublicKey = function(pubkey, callback) {
|
||||||
// persist public key (email, _id)
|
// persist public key (email, _id)
|
||||||
var pkLookupKey = DB_PUBLICKEY + '_' + pubkey._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) {
|
Keychain.prototype.saveLocalPrivateKey = function(privkey, callback) {
|
||||||
// persist private key (email, _id)
|
// persist private key (email, _id)
|
||||||
var prkLookupKey = DB_PRIVATEKEY + '_' + privkey._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
|
* Initialize the lawnchair database
|
||||||
* @param {String} dbName The name of the database
|
* @param {String} dbName The name of the database
|
||||||
*/
|
*/
|
||||||
LawnchairDAO.prototype.init = function(dbName, callback) {
|
LawnchairDAO.prototype.init = function(dbName) {
|
||||||
if (!dbName) {
|
if (!dbName) {
|
||||||
callback({
|
throw new Error('Lawnchair DB name must be specified!');
|
||||||
errMsg: 'Lawnchair DB name must be specified!'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._db = new Lawnchair({
|
this._db = new Lawnchair({
|
||||||
name: dbName
|
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);
|
ngModule.service('privateKey', PrivateKey);
|
||||||
module.exports = PrivateKey;
|
module.exports = PrivateKey;
|
||||||
|
|
||||||
var config = require('../app-config').config;
|
function PrivateKey(restDao, appConfig) {
|
||||||
|
|
||||||
function PrivateKey(restDao) {
|
|
||||||
this._restDao = restDao;
|
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);
|
ngModule.service('publicKey', PublicKey);
|
||||||
module.exports = PublicKey;
|
module.exports = PublicKey;
|
||||||
|
|
||||||
var config = require('../app-config').config;
|
function PublicKey(restDao, appConfig) {
|
||||||
|
|
||||||
function PublicKey(restDao) {
|
|
||||||
this._restDao = restDao;
|
this._restDao = restDao;
|
||||||
this._restDao.setBaseUri(config.cloudUrl);
|
this._restDao.setBaseUri(appConfig.config.cloudUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var ngModule = angular.module('woUtil');
|
var ngModule = angular.module('woUtil');
|
||||||
ngModule.service('updateHandler', ['deviceStorage', 'deviceStorage', 'auth', UpdateHandler]);
|
ngModule.service('updateHandler', UpdateHandler);
|
||||||
module.exports = UpdateHandler;
|
module.exports = UpdateHandler;
|
||||||
|
|
||||||
var axe = require('axe-logger'),
|
var axe = require('axe-logger'),
|
||||||
|
@ -15,11 +15,12 @@ var axe = require('axe-logger'),
|
||||||
/**
|
/**
|
||||||
* Handles database migration
|
* Handles database migration
|
||||||
*/
|
*/
|
||||||
function UpdateHandler(appConfigStorage, userStorage, auth) {
|
function UpdateHandler(appConfigStore, deviceStorage, auth, dialog) {
|
||||||
this._appConfigStorage = appConfigStorage;
|
this._appConfigStorage = appConfigStore;
|
||||||
this._userStorage = userStorage;
|
this._userStorage = deviceStorage;
|
||||||
this._updateScripts = [updateV1, updateV2, updateV3, updateV4, updateV5];
|
this._updateScripts = [updateV1, updateV2, updateV3, updateV4, updateV5];
|
||||||
this._auth = auth;
|
this._auth = auth;
|
||||||
|
this._dialog = dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,14 +100,16 @@ UpdateHandler.prototype._applyUpdate = function(options, callback) {
|
||||||
/**
|
/**
|
||||||
* Check application version and update correspondingly
|
* Check application version and update correspondingly
|
||||||
*/
|
*/
|
||||||
UpdateHandler.prototype.checkForUpdate = function(dialog) {
|
UpdateHandler.prototype.checkForUpdate = function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
// Chrome Packaged App
|
// Chrome Packaged App
|
||||||
if (typeof window.chrome !== 'undefined' && chrome.runtime && chrome.runtime.onUpdateAvailable) {
|
if (typeof window.chrome !== 'undefined' && chrome.runtime && chrome.runtime.onUpdateAvailable) {
|
||||||
// check for Chrome app update and restart
|
// check for Chrome app update and restart
|
||||||
chrome.runtime.onUpdateAvailable.addListener(function(details) {
|
chrome.runtime.onUpdateAvailable.addListener(function(details) {
|
||||||
axe.debug('New Chrome App update... requesting reload.');
|
axe.debug('New Chrome App update... requesting reload.');
|
||||||
// Chrome downloaded a new app version
|
// Chrome downloaded a new app version
|
||||||
dialog({
|
self._dialog.confirm({
|
||||||
title: 'Update available',
|
title: 'Update available',
|
||||||
message: 'A new version ' + details.version + ' of the app is available. Restart the app to update?',
|
message: 'A new version ' + details.version + ' of the app is available. Restart the app to update?',
|
||||||
positiveBtnStr: 'Restart',
|
positiveBtnStr: 'Restart',
|
||||||
|
|
Loading…
Reference in New Issue