Merge pull request #235 from whiteout-io/dev/WO-766

Dev/wo 766
master
Tankred Hase 9 years ago
commit 37fb3f5f8d

@ -1,51 +1,52 @@
{
"indent": 4,
"strict": true,
"globalstrict": true,
"node": true,
"browser": true,
"nonew": true,
"curly": true,
"eqeqeq": true,
"immed": true,
"newcap": true,
"regexp": true,
"evil": true,
"eqnull": true,
"expr": true,
"trailing": true,
"undef": true,
"unused": true,
"indent": 4,
"strict": true,
"globalstrict": true,
"node": true,
"browser": true,
"nonew": true,
"curly": true,
"eqeqeq": true,
"immed": true,
"newcap": true,
"regexp": true,
"evil": true,
"eqnull": true,
"expr": true,
"trailing": true,
"undef": true,
"unused": true,
"predef": [
"$",
"inject",
"Promise",
"self",
"importScripts",
"console",
"process",
"chrome",
"Notification",
"Event",
"sinon",
"mocha",
"chai",
"expect",
"describe",
"it",
"before",
"beforeEach",
"after",
"afterEach",
"FastClick",
"angular",
"forge",
"Lawnchair",
"_",
"openpgp"
],
"predef": [
"$",
"inject",
"Promise",
"resolves",
"rejects",
"self",
"importScripts",
"console",
"process",
"chrome",
"Notification",
"Event",
"sinon",
"mocha",
"chai",
"expect",
"describe",
"it",
"before",
"beforeEach",
"after",
"afterEach",
"FastClick",
"angular",
"forge",
"Lawnchair",
"_",
"openpgp"
],
"globals": {
}
"globals": {}
}

@ -1,6 +1,6 @@
'use strict';
var AccountCtrl = function($scope, auth, keychain, pgp, appConfig, download, dialog) {
var AccountCtrl = function($scope, $q, auth, keychain, pgp, appConfig, download, dialog) {
var userId = auth.emailAddress;
if (!userId) {
return;
@ -34,12 +34,13 @@ var AccountCtrl = function($scope, auth, keychain, pgp, appConfig, download, dia
//
$scope.exportKeyFile = function() {
keychain.getUserKeyPair(userId, function(err, keys) {
if (err) {
dialog.error(err);
return;
}
return $q(function(resolve) {
resolve();
}).then(function() {
return keychain.getUserKeyPair(userId);
}).then(function(keys) {
var keyId = keys.publicKey._id;
var file = 'whiteout_mail_' + userId + '_' + keyId.substring(8, keyId.length);
@ -48,7 +49,8 @@ var AccountCtrl = function($scope, auth, keychain, pgp, appConfig, download, dia
filename: file + '.asc',
contentType: 'text/plain'
});
});
}).catch(dialog.error);
};
};

@ -2,7 +2,7 @@
var JUNK_FOLDER_TYPE = 'Junk';
var ActionBarCtrl = function($scope, email, dialog, status) {
var ActionBarCtrl = function($scope, $q, email, dialog, status) {
//
// scope functions
@ -23,24 +23,28 @@ var ActionBarCtrl = function($scope, email, dialog, status) {
// show message
status.update('Moving message...');
email.moveMessage({
folder: currentFolder(),
destination: destination,
message: message
}, function(err) {
if (err) {
// show errors where appropriate
if (err.code === 42) {
$scope.select(message);
status.update('Unable to move message in offline mode!');
return;
}
status.update('Error during move!');
dialog.error(err);
return $q(function(resolve) {
resolve();
}).then(function() {
return email.moveMessage({
folder: currentFolder(),
destination: destination,
message: message
});
}).then(function() {
status.update('Online');
}).catch(function(err) {
// show errors where appropriate
if (err.code === 42) {
$scope.select(message);
status.update('Unable to move message in offline mode!');
return;
}
status.update('Message moved.');
$scope.$apply();
status.update('Error during move!');
return dialog.error(err);
});
};
@ -83,23 +87,27 @@ var ActionBarCtrl = function($scope, email, dialog, status) {
status.setReading(false);
status.update('Deleting message...');
email.deleteMessage({
folder: currentFolder(),
message: message
}, function(err) {
if (err) {
// show errors where appropriate
if (err.code === 42) {
$scope.select(message);
status.update('Unable to delete message in offline mode!');
return;
}
status.update('Error during delete!');
dialog.error(err);
return $q(function(resolve) {
resolve();
}).then(function() {
return email.deleteMessage({
folder: currentFolder(),
message: message
});
}).then(function() {
status.update('Online');
}).catch(function(err) {
// show errors where appropriate
if (err.code === 42) {
$scope.select(message);
status.update('Unable to delete message in offline mode!');
return;
}
status.update('Message deleted.');
$scope.$apply();
status.update('Error during delete!');
return dialog.error(err);
});
};
@ -130,25 +138,29 @@ var ActionBarCtrl = function($scope, email, dialog, status) {
var originalState = message.unread;
message.unread = unread;
email.setFlags({
folder: currentFolder(),
message: message
}, function(err) {
if (err && err.code === 42) {
return $q(function(resolve) {
resolve();
}).then(function() {
return email.setFlags({
folder: currentFolder(),
message: message
});
}).then(function() {
status.update('Online');
}).catch(function(err) {
if (err.code === 42) {
// offline, restore
message.unread = originalState;
status.update('Unable to mark message in offline mode!');
return;
}
if (err) {
status.update('Error on sync!');
dialog.error(err);
return;
}
status.update('Online');
$scope.$apply();
status.update('Error on sync!');
return dialog.error(err);
});
};
@ -176,25 +188,29 @@ var ActionBarCtrl = function($scope, email, dialog, status) {
var originalState = message.flagged;
message.flagged = flagged;
email.setFlags({
folder: currentFolder(),
message: message
}, function(err) {
if (err && err.code === 42) {
return $q(function(resolve) {
resolve();
}).then(function() {
return email.setFlags({
folder: currentFolder(),
message: message
});
}).then(function() {
status.update('Online');
}).catch(function(err) {
if (err.code === 42) {
// offline, restore
message.unread = originalState;
status.update('Unable to ' + (flagged ? 'add star to' : 'remove star from') + ' message in offline mode!');
return;
}
if (err) {
status.update('Error on sync!');
dialog.error(err);
return;
}
status.update('Online');
$scope.$apply();
status.update('Error on sync!');
return dialog.error(err);
});
};
@ -208,12 +224,27 @@ var ActionBarCtrl = function($scope, email, dialog, status) {
});
};
/**
* This method is called when the user changes the searchText
*/
$scope.displaySearchResults = function(searchText) {
$scope.$root.$broadcast('search', searchText);
};
//
// scope state
//
// share local scope functions with root state
$scope.state.actionBar = {
markMessage: $scope.markMessage,
flagMessage: $scope.flagMessage
};
//
// Helper functions
//
function currentFolder() {
return $scope.state.nav.currentFolder;
}
@ -223,13 +254,6 @@ var ActionBarCtrl = function($scope, email, dialog, status) {
return message.checked;
});
}
/**
* This method is called when the user changes the searchText
*/
$scope.displaySearchResults = function(searchText) {
$scope.$root.$broadcast('search', searchText);
};
};
module.exports = ActionBarCtrl;

@ -4,7 +4,7 @@
// Controller
//
var ContactsCtrl = function($scope, keychain, pgp, dialog) {
var ContactsCtrl = function($scope, $q, keychain, pgp, dialog) {
//
// scope state
@ -13,7 +13,7 @@ var ContactsCtrl = function($scope, keychain, pgp, dialog) {
$scope.state.contacts = {
toggle: function(to) {
$scope.state.lightbox = (to) ? 'contacts' : undefined;
$scope.listKeys();
return $scope.listKeys();
}
};
@ -22,22 +22,21 @@ var ContactsCtrl = function($scope, keychain, pgp, dialog) {
//
$scope.listKeys = function() {
keychain.listLocalPublicKeys(function(err, keys) {
if (err) {
dialog.error(err);
return;
}
return $q(function(resolve) {
resolve();
keys.forEach(addParams);
}).then(function() {
return keychain.listLocalPublicKeys();
$scope.keys = keys;
$scope.$apply();
function addParams(key) {
}).then(function(keys) {
// add params to key objects
keys.forEach(function(key) {
var params = pgp.getKeyParams(key.publicKey);
_.extend(key, params);
}
});
});
$scope.keys = keys;
}).catch(dialog.error);
};
$scope.getFingerprint = function(key) {
@ -74,29 +73,18 @@ var ContactsCtrl = function($scope, keychain, pgp, dialog) {
imported: true // mark manually imported keys
};
keychain.saveLocalPublicKey(pubkey, function(err) {
if (err) {
dialog.error(err);
return;
}
return keychain.saveLocalPublicKey(pubkey).then(function() {
// update displayed keys
$scope.listKeys();
});
return $scope.listKeys();
}).catch(dialog.error);
};
$scope.removeKey = function(key) {
keychain.removeLocalPublicKey(key._id, function(err) {
if (err) {
dialog.error(err);
return;
}
return keychain.removeLocalPublicKey(key._id).then(function() {
// update displayed keys
$scope.listKeys();
});
return $scope.listKeys();
}).catch(dialog.error);
};
};
module.exports = ContactsCtrl;

@ -40,6 +40,7 @@ var DialogCtrl = function($scope, dialog) {
$scope.positiveBtnStr = options.positiveBtnStr || 'Ok';
$scope.negativeBtnStr = options.negativeBtnStr || 'Cancel';
$scope.showNegativeBtn = options.showNegativeBtn || false;
$scope.showBugReporter = false;
$scope.callback = options.callback;
}

@ -11,7 +11,7 @@ var INIT_DISPLAY_LEN = 50,
FOLDER_TYPE_INBOX = 'Inbox',
NOTIFICATION_INBOX_TIMEOUT = 5000;
var MailListCtrl = function($scope, $timeout, $location, $filter, status, notification, email, keychain, dialog, search, dummy) {
var MailListCtrl = function($scope, $timeout, $location, $filter, $q, status, notification, email, keychain, dialog, search, dummy) {
//
// scope state
@ -55,23 +55,26 @@ var MailListCtrl = function($scope, $timeout, $location, $filter, status, notifi
//
$scope.getBody = function(message) {
email.getBody({
folder: currentFolder(),
message: message
}, function(err) {
if (err && err.code !== 42) {
dialog.error(err);
return;
}
return $q(function(resolve) {
resolve();
// display fetched body
$scope.$digest();
}).then(function() {
return email.getBody({
folder: currentFolder(),
message: message
});
}).then(function() {
// automatically decrypt if it's the selected message
if (message === currentMessage()) {
email.decryptBody({
return email.decryptBody({
message: message
}, dialog.error);
});
}
}).catch(function(err) {
if (err.code !== 42) {
dialog.error(err);
}
});
};
@ -93,19 +96,20 @@ var MailListCtrl = function($scope, $timeout, $location, $filter, status, notifi
return;
}
keychain.refreshKeyForUserId({
userId: message.from[0].address
}, onKeyRefreshed);
return $q(function(resolve) {
resolve();
function onKeyRefreshed(err) {
if (err) {
dialog.error(err);
}
}).then(function() {
return keychain.refreshKeyForUserId({
userId: message.from[0].address
});
email.decryptBody({
}).then(function() {
return email.decryptBody({
message: message
}, dialog.error);
});
}).then(function() {
// if the message is unread, please sync the new state.
// otherweise forget about it.
if (!message.unread) {
@ -119,12 +123,13 @@ var MailListCtrl = function($scope, $timeout, $location, $filter, status, notifi
}
}
$scope.state.actionBar.markMessage(message, false, true);
}
return $scope.state.actionBar.markMessage(message, false, true);
}).catch(dialog.error);
};
$scope.flag = function(message, flagged) {
$scope.state.actionBar.flagMessage(message, flagged);
return $scope.state.actionBar.flagMessage(message, flagged);
};
/**
@ -164,7 +169,7 @@ var MailListCtrl = function($scope, $timeout, $location, $filter, status, notifi
}
// display and select first
openCurrentFolder();
return openCurrentFolder();
});
$scope.watchMessages = $scope.$watchCollection('state.nav.currentFolder.messages', function(messages) {
@ -246,10 +251,10 @@ var MailListCtrl = function($scope, $timeout, $location, $filter, status, notifi
*/
$scope.watchOnline = $scope.$watch('account.online', function(isOnline) {
// wait one cycle for the status display controllers to init
$timeout(function() {
return $timeout(function() {
if (isOnline) {
status.update('Online');
openCurrentFolder();
return openCurrentFolder();
} else {
status.update('Offline mode');
}
@ -265,18 +270,24 @@ var MailListCtrl = function($scope, $timeout, $location, $filter, status, notifi
return;
}
email.openFolder({
folder: currentFolder()
}, function(error) {
return $q(function(resolve) {
resolve();
}).then(function() {
return email.openFolder({
folder: currentFolder()
}).catch(function(err) {
// don't display err for offline case
if (err.code !== 42) {
throw err;
}
});
}).then(function() {
// dont wait until scroll to load visible mail bodies
$scope.loadVisibleBodies();
// don't display error for offline case
if (error && error.code === 42) {
return;
}
dialog.error(error);
});
}).catch(dialog.error);
}
function currentFolder() {

@ -11,7 +11,7 @@ var NOTIFICATION_SENT_TIMEOUT = 2000;
// Controller
//
var NavigationCtrl = function($scope, $location, account, email, outbox, notification, appConfig, dialog, dummy) {
var NavigationCtrl = function($scope, $location, $q, account, email, outbox, notification, appConfig, dialog, dummy) {
if (!$location.search().dev && !account.isLoggedIn()) {
$location.path('/'); // init app
return;
@ -102,18 +102,24 @@ var NavigationCtrl = function($scope, $location, account, email, outbox, notific
});
ob.count = count;
email.refreshFolder({
folder: ob
}, dialog.error);
return $q(function(resolve) {
resolve();
}).then(function() {
return email.refreshFolder({
folder: ob
});
}).catch(dialog.error);
};
$scope.logout = function() {
dialog.confirm({
return dialog.confirm({
title: str.logoutTitle,
message: str.logoutMessage,
callback: function(confirm) {
if (confirm) {
account.logout();
account.logout().catch(dialog.error);
}
}
});

@ -2,7 +2,7 @@
var util = require('crypto-lib').util;
var PrivateKeyUploadCtrl = function($scope, keychain, pgp, dialog, auth) {
var PrivateKeyUploadCtrl = function($scope, $q, keychain, pgp, dialog, auth) {
//
// scope state
@ -19,16 +19,15 @@ var PrivateKeyUploadCtrl = function($scope, keychain, pgp, dialog, auth) {
// show syncing status
$scope.step = 4;
// check if key is already synced
$scope.checkServerForKey(function(privateKeySynced) {
return $scope.checkServerForKey().then(function(privateKeySynced) {
if (privateKeySynced) {
// close lightbox
$scope.state.lightbox = undefined;
// show message
dialog.info({
return dialog.info({
title: 'Info',
message: 'Your PGP key has already been synced.'
});
return;
}
// show sync ui if key is not synced
@ -41,24 +40,22 @@ var PrivateKeyUploadCtrl = function($scope, keychain, pgp, dialog, auth) {
// scope functions
//
$scope.checkServerForKey = function(callback) {
$scope.checkServerForKey = function() {
var keyParams = pgp.getKeyParams();
keychain.hasPrivateKey({
userId: keyParams.userId,
keyId: keyParams._id
}, function(err, privateKeySynced) {
if (err) {
dialog.error(err);
return;
}
if (privateKeySynced) {
callback(privateKeySynced);
return;
}
return $q(function(resolve) {
resolve();
callback();
});
}).then(function() {
return keychain.hasPrivateKey({
userId: keyParams.userId,
keyId: keyParams._id
});
}).then(function(privateKeySynced) {
return privateKeySynced ? privateKeySynced : undefined;
}).catch(dialog.error);
};
$scope.displayUploadUi = function() {
@ -82,29 +79,37 @@ var PrivateKeyUploadCtrl = function($scope, keychain, pgp, dialog, auth) {
return true;
};
$scope.setDeviceName = function(callback) {
keychain.setDeviceName($scope.deviceName, callback);
$scope.setDeviceName = function() {
return $q(function(resolve) {
resolve();
}).then(function() {
return keychain.setDeviceName($scope.deviceName);
});
};
$scope.encryptAndUploadKey = function(callback) {
$scope.encryptAndUploadKey = function() {
var userId = auth.emailAddress;
var code = $scope.code;
// register device to keychain service
keychain.registerDevice({
userId: userId
}, function(err) {
if (err) {
dialog.error(err);
return;
}
return $q(function(resolve) {
resolve();
}).then(function() {
// register the device
return keychain.registerDevice({
userId: userId
});
}).then(function() {
// encrypt private PGP key using code and upload
keychain.uploadPrivateKey({
return keychain.uploadPrivateKey({
userId: userId,
code: code
}, callback);
});
});
}).catch(dialog.error);
};
$scope.goBack = function() {
@ -126,32 +131,22 @@ var PrivateKeyUploadCtrl = function($scope, keychain, pgp, dialog, auth) {
if ($scope.step === 3) {
// set device name to local storage
$scope.setDeviceName(function(err) {
if (err) {
dialog.error(err);
return;
}
return $scope.setDeviceName().then(function() {
// show spinner
$scope.step++;
$scope.$apply();
// init key sync
$scope.encryptAndUploadKey(function(err) {
if (err) {
dialog.error(err);
return;
}
// close sync dialog
$scope.state.privateKeyUpload.toggle(false);
// show success message
dialog.info({
title: 'Success',
message: 'Whiteout Keychain setup successful!'
});
return $scope.encryptAndUploadKey();
}).then(function() {
// close sync dialog
$scope.state.privateKeyUpload.toggle(false);
// show success message
dialog.info({
title: 'Success',
message: 'Whiteout Keychain setup successful!'
});
});
}).catch(dialog.error);
}
};

@ -4,7 +4,7 @@
// Controller
//
var ReadCtrl = function($scope, $location, email, invitation, outbox, pgp, keychain, appConfig, download, auth, dialog) {
var ReadCtrl = function($scope, $location, $q, email, invitation, outbox, pgp, keychain, appConfig, download, auth, dialog) {
var str = appConfig.string;
@ -52,25 +52,24 @@ var ReadCtrl = function($scope, $location, email, invitation, outbox, pgp, keych
return;
}
$scope.keyId = 'Searching...';
keychain.getReceiverPublicKey(address, function(err, pubkey) {
if (err) {
dialog.error(err);
return;
}
return $q(function(resolve) {
$scope.keyId = 'Searching...';
resolve();
}).then(function() {
return keychain.getReceiverPublicKey(address);
}).then(function(pubkey) {
if (!pubkey) {
$scope.keyId = 'User has no key. Click to invite.';
$scope.$apply();
return;
}
var fpr = pgp.getFingerprint(pubkey.publicKey);
var formatted = fpr.slice(32);
$scope.keyId = 'PGP key: ' + formatted;
$scope.$apply();
});
}).catch(dialog.error);
};
$scope.$watch('state.mailList.selected', function(mail) {
@ -89,24 +88,20 @@ var ReadCtrl = function($scope, $location, email, invitation, outbox, pgp, keych
function checkPublicKey(user) {
user.secure = undefined;
if (!keychain) {
return;
}
return $q(function(resolve) {
resolve();
keychain.getReceiverPublicKey(user.address, function(err, pubkey) {
if (err) {
dialog.error(err);
return;
}
}).then(function() {
return keychain.getReceiverPublicKey(user.address);
}).then(function(pubkey) {
if (pubkey && pubkey.publicKey) {
user.secure = true;
} else {
user.secure = false;
}
$scope.$apply();
});
}).catch(dialog.error);
}
$scope.download = function(attachment) {
@ -122,11 +117,18 @@ var ReadCtrl = function($scope, $location, email, invitation, outbox, pgp, keych
var folder = $scope.state.nav.currentFolder;
var message = $scope.state.mailList.selected;
email.getAttachment({
folder: folder,
uid: message.uid,
attachment: attachment
}, dialog.error);
return $q(function(resolve) {
resolve();
}).then(function() {
return email.getAttachment({
folder: folder,
uid: message.uid,
attachment: attachment
});
}).catch(dialog.error);
};
$scope.invite = function(user) {
@ -135,20 +137,20 @@ var ReadCtrl = function($scope, $location, email, invitation, outbox, pgp, keych
return;
}
$scope.keyId = 'Sending invitation...';
var sender = auth.emailAddress,
recipient = user.address;
invitation.invite({
recipient: recipient,
sender: sender
}, function(err) {
if (err) {
dialog.error(err);
return;
}
return $q(function(resolve) {
$scope.keyId = 'Sending invitation...';
resolve();
}).then(function() {
return invitation.invite({
recipient: recipient,
sender: sender
});
}).then(function() {
var invitationMail = {
from: [{
address: sender
@ -161,10 +163,10 @@ var ReadCtrl = function($scope, $location, email, invitation, outbox, pgp, keych
subject: str.invitationSubject,
body: str.invitationMessage
};
// send invitation mail
outbox.put(invitationMail, dialog.error);
});
return outbox.put(invitationMail);
}).catch(dialog.error);
};
};

@ -1,6 +1,6 @@
'use strict';
var SetPassphraseCtrl = function($scope, pgp, keychain, dialog) {
var SetPassphraseCtrl = function($scope, $q, pgp, keychain, dialog) {
//
// scope variables
@ -76,52 +76,44 @@ var SetPassphraseCtrl = function($scope, pgp, keychain, dialog) {
$scope.setPassphrase = function() {
var keyId = pgp.getKeyParams()._id;
keychain.lookupPrivateKey(keyId, function(err, savedKey) {
if (err) {
dialog.error(err);
return;
}
pgp.changePassphrase({
return $q(function(resolve) {
resolve();
}).then(function() {
return keychain.lookupPrivateKey(keyId);
}).then(function(savedKey) {
// change passphrase
return pgp.changePassphrase({
privateKeyArmored: savedKey.encryptedKey,
oldPassphrase: $scope.oldPassphrase,
newPassphrase: $scope.newPassphrase
}, onPassphraseChanged);
});
}).catch(function(err) {
err.showBugReporter = false;
throw err;
});
}).then(function(newPrivateKeyArmored) {
// persist new armored key
var keyParams = pgp.getKeyParams(newPrivateKeyArmored);
var privateKey = {
_id: keyParams._id,
userId: keyParams.userId,
userIds: keyParams.userIds,
encryptedKey: newPrivateKeyArmored
};
return keychain.saveLocalPrivateKey(privateKey);
}).then(function() {
$scope.state.setPassphrase.toggle(false);
return dialog.info({
title: 'Success',
message: 'Passphrase change complete.'
});
}).catch(dialog.error);
};
function onPassphraseChanged(err, newPrivateKeyArmored) {
if (err) {
err.showBugReporter = false;
dialog.error(err);
return;
}
// persist new armored key
var keyParams = pgp.getKeyParams(newPrivateKeyArmored);
var privateKey = {
_id: keyParams._id,
userId: keyParams.userId,
userIds: keyParams.userIds,
encryptedKey: newPrivateKeyArmored
};
keychain.saveLocalPrivateKey(privateKey, onKeyPersisted);
}
function onKeyPersisted(err) {
if (err) {
dialog.error(err);
return;
}
$scope.state.setPassphrase.toggle(false);
$scope.$apply();
dialog.info({
title: 'Success',
message: 'Passphrase change complete.'
});
}
};
module.exports = SetPassphraseCtrl;

@ -218,34 +218,31 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain
return;
}
// 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
keychain.refreshKeyForUserId({
// 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
return $q(function(resolve) {
resolve();
}).then(function() {
return keychain.refreshKeyForUserId({
userId: recipient.address
}, function(err, key) {
if (err) {
dialog.error(err);
return;
}
});
if (key) {
// compare again since model could have changed during the roundtrip
var matchingUserId = _.findWhere(key.userIds, {
emailAddress: recipient.address
});
// compare either primary userId or (if available) multiple IDs
if (key.userId === recipient.address || matchingUserId) {
recipient.key = key;
recipient.secure = true;
}
}).then(function(key) {
if (key) {
// compare again since model could have changed during the roundtrip
var matchingUserId = _.findWhere(key.userIds, {
emailAddress: recipient.address
});
// compare either primary userId or (if available) multiple IDs
if (key.userId === recipient.address || matchingUserId) {
recipient.key = key;
recipient.secure = true;
}
}
$scope.checkSendStatus();
$scope.checkSendStatus();
$scope.$digest();
});
}
}).catch(dialog.error);
};
/**
@ -347,12 +344,13 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain
}
// persist the email to disk for later sending
outbox.put(message, function(err) {
if (err) {
dialog.error(err);
return;
}
return $q(function(resolve) {
resolve();
}).then(function() {
return outbox.put(message);
}).then(function() {
// if we need to synchronize replyTo.answered = true to imap,
// let's do that. otherwise, we're done
if (!$scope.replyTo || $scope.replyTo.answered) {
@ -360,20 +358,16 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain
}
$scope.replyTo.answered = true;
email.setFlags({
return email.setFlags({
folder: currentFolder(),
message: $scope.replyTo
}, function(err) {
if (err && err.code !== 42) {
dialog.error(err);
return;
}
// offline or no error, let's apply the ui changes
$scope.$apply();
});
});
}).catch(function(err) {
if (err.code !== 42) {
dialog.error(err);
}
});
};
//
@ -389,37 +383,29 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain
};
$scope.lookupAddressBook = function(query) {
var deferred = $q.defer();
return $q(function(resolve) {
resolve();
if (!$scope.addressBookCache) {
}).then(function() {
if ($scope.addressBookCache) {
return;
}
// populate address book cache
keychain.listLocalPublicKeys(function(err, keys) {
if (err) {
dialog.error(err);
return;
}
return keychain.listLocalPublicKeys().then(function(keys) {
$scope.addressBookCache = keys.map(function(key) {
return {
address: key.userId
};
});
filter();
});
} else {
filter();
}
// query address book cache
function filter() {
var addresses = $scope.addressBookCache.filter(function(i) {
}).then(function() {
// filter the address book cache
return $scope.addressBookCache.filter(function(i) {
return i.address.indexOf(query) !== -1;
});
deferred.resolve(addresses);
}
return deferred.promise;
}).catch(dialog.error);
};
//

@ -1,6 +1,6 @@
'use strict';
var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig, auth, dialog) {
var AddAccountCtrl = function($scope, $location, $routeParams, $timeout, $q, mailConfig, auth, dialog) {
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
$scope.getAccountSettings = function() {
@ -9,10 +9,15 @@ var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig, auth,
return;
}
$scope.busy = true;
$scope.errMsg = undefined; // reset error msg
return $q(function(resolve) {
$scope.busy = true;
$scope.errMsg = undefined; // reset error msg
resolve();
return mailConfig.get($scope.emailAddress).then(function(config) {
}).then(function() {
return mailConfig.get($scope.emailAddress);
}).then(function(config) {
$scope.busy = false;
$scope.state.login = {
mailConfig: config,
@ -22,10 +27,10 @@ var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig, auth,
var hostname = config.imap.hostname;
if (auth.useOAuth(hostname)) {
// check for oauth support
$scope.oauthPossible();
return $scope.oauthPossible();
} else {
// use standard password login
$scope.setCredentials();
return $scope.setCredentials();
}
}).catch(function() {
@ -36,7 +41,7 @@ var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig, auth,
$scope.oauthPossible = function() {
// ask user to use the platform's native OAuth api
dialog.confirm({
return 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',
@ -46,29 +51,28 @@ var AddAccountCtrl = function($scope, $location, $routeParams, mailConfig, auth,
callback: function(granted) {
if (granted) {
// query oauth token
getOAuthToken();
return getOAuthToken();
} else {
// use normal user/password login
$scope.setCredentials();
$scope.$apply();
}
}
});
function getOAuthToken() {
// fetches the email address from the chrome identity api
auth.getOAuthToken(function(err) {
if (err) {
return dialog.error(err);
}
$scope.setCredentials();
$scope.$apply();
});
return auth.getOAuthToken().then(function() {
// continue to setting credentials
return $scope.setCredentials();
}).catch(dialog.error);
}
};
$scope.setCredentials = function() {
$location.path('/login-set-credentials');
return $timeout(function() {
$location.path('/login-set-credentials');
});
};
};

@ -1,6 +1,6 @@
'use strict';
var CreateAccountCtrl = function($scope, $location, $routeParams, auth, admin, appConfig) {
var CreateAccountCtrl = function($scope, $location, $routeParams, $q, auth, admin, appConfig) {
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
$scope.createWhiteoutAccount = function() {
@ -9,35 +9,37 @@ var CreateAccountCtrl = function($scope, $location, $routeParams, auth, admin, a
return;
}
$scope.busy = true;
$scope.errMsg = undefined; // reset error msg
var emailAddress = $scope.user + '@' + appConfig.config.wmailDomain;
// set to state for next view
auth.setCredentials({
emailAddress: emailAddress,
password: $scope.pass,
realname: $scope.realname
});
// call REST api
admin.createUser({
emailAddress: emailAddress,
password: $scope.pass,
phone: $scope.phone.replace(/\s+/g, ''), // remove spaces from the phone number
betaCode: $scope.betaCode.toUpperCase()
}, function(err) {
return $q(function(resolve) {
$scope.busy = true;
$scope.errMsg = undefined; // reset error msg
resolve();
}).then(function() {
// set to state for next view
auth.setCredentials({
emailAddress: emailAddress,
password: $scope.pass,
realname: $scope.realname
});
// call REST api
return admin.createUser({
emailAddress: emailAddress,
password: $scope.pass,
phone: $scope.phone.replace(/\s+/g, ''), // remove spaces from the phone number
betaCode: $scope.betaCode.toUpperCase()
});
}).then(function() {
$scope.busy = false;
if (err) {
$scope.errMsg = err.errMsg || err.message;
$scope.$apply();
return;
}
// proceed to login and keygen
$location.path('/validate-phone');
$scope.$apply();
}).catch(function(err) {
$scope.busy = false;
$scope.errMsg = err.errMsg || err.message;
});
};
};

@ -1,6 +1,6 @@
'use strict';
var LoginExistingCtrl = function($scope, $location, $routeParams, email, auth, keychain) {
var LoginExistingCtrl = function($scope, $location, $routeParams, $q, email, auth, keychain) {
!$routeParams.dev && !auth.isInitialized() && $location.path('/'); // init app
$scope.confirmPassphrase = function() {
@ -9,50 +9,39 @@ var LoginExistingCtrl = function($scope, $location, $routeParams, email, auth, k
return;
}
$scope.busy = true;
$scope.errMsg = undefined;
$scope.incorrect = false;
return $q(function(resolve) {
$scope.busy = true;
$scope.errMsg = undefined;
$scope.incorrect = false;
resolve();
unlockCrypto();
};
function unlockCrypto() {
var userId = auth.emailAddress;
keychain.getUserKeyPair(userId, function(err, keypair) {
if (err) {
displayError(err);
return;
}
}).then(function() {
// key keypair
var userId = auth.emailAddress;
return keychain.getUserKeyPair(userId);
email.unlock({
}).then(function(keypair) {
// unlock email service
return email.unlock({
keypair: keypair,
passphrase: $scope.passphrase
}, onUnlock);