2013-08-19 15:13:32 -04:00
|
|
|
define(function(require) {
|
2013-08-16 14:50:47 -04:00
|
|
|
'use strict';
|
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
var util = require('cryptoLib/util'),
|
|
|
|
_ = require('underscore'),
|
2014-03-11 13:57:03 -04:00
|
|
|
str = require('js/app-config').string;
|
2013-08-27 13:17:06 -04:00
|
|
|
|
2014-03-11 13:57:03 -04:00
|
|
|
var EmailDAO = function(keychain, crypto, devicestorage, pgpbuilder, mailreader, emailSync) {
|
2014-02-25 11:29:12 -05:00
|
|
|
this._keychain = keychain;
|
|
|
|
this._crypto = crypto;
|
|
|
|
this._devicestorage = devicestorage;
|
|
|
|
this._pgpbuilder = pgpbuilder;
|
2014-02-25 13:18:37 -05:00
|
|
|
this._mailreader = mailreader;
|
2014-03-11 13:57:03 -04:00
|
|
|
this._emailSync = emailSync;
|
2013-08-16 14:50:47 -04:00
|
|
|
};
|
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
//
|
|
|
|
// External API
|
|
|
|
//
|
|
|
|
|
|
|
|
EmailDAO.prototype.init = function(options, callback) {
|
|
|
|
var self = this,
|
|
|
|
keypair;
|
2013-08-16 14:50:47 -04:00
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
self._account = options.account;
|
|
|
|
self._account.busy = false;
|
2013-12-09 13:21:52 -05:00
|
|
|
self._account.online = false;
|
2014-05-07 13:19:51 -04:00
|
|
|
self._account.loggingIn = false;
|
2013-08-16 14:50:47 -04:00
|
|
|
|
|
|
|
// validate email address
|
2013-08-22 10:18:48 -04:00
|
|
|
var emailAddress = self._account.emailAddress;
|
2013-08-30 05:42:32 -04:00
|
|
|
if (!util.validateEmailAddress(emailAddress)) {
|
2013-08-16 14:50:47 -04:00
|
|
|
callback({
|
|
|
|
errMsg: 'The user email address must be specified!'
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-26 11:37:56 -04:00
|
|
|
// init keychain and then crypto module
|
|
|
|
initKeychain();
|
2013-08-16 14:50:47 -04:00
|
|
|
|
|
|
|
function initKeychain() {
|
2014-03-11 12:49:47 -04:00
|
|
|
// call getUserKeyPair to read/sync keypair with devicestorage/cloud
|
|
|
|
self._keychain.getUserKeyPair(emailAddress, function(err, storedKeypair) {
|
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
2013-12-03 13:21:50 -05:00
|
|
|
|
2014-03-11 12:49:47 -04:00
|
|
|
keypair = storedKeypair;
|
2014-03-11 13:57:03 -04:00
|
|
|
initEmailSync();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function initEmailSync() {
|
|
|
|
self._emailSync.init({
|
|
|
|
account: self._account
|
|
|
|
}, function(err) {
|
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-11 12:49:47 -04:00
|
|
|
initFolders();
|
2013-12-03 13:21:50 -05:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function initFolders() {
|
2013-12-09 13:21:52 -05:00
|
|
|
// try init folders from memory, since imap client not initiated yet
|
|
|
|
self._imapListFolders(function(err, folders) {
|
2013-12-10 17:05:17 -05:00
|
|
|
// dont handle offline case this time
|
|
|
|
if (err && err.code !== 42) {
|
2013-12-03 13:21:50 -05:00
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-28 20:14:52 -04:00
|
|
|
self._account.folders = folders;
|
2014-03-28 13:08:04 -04:00
|
|
|
|
2013-12-09 13:21:52 -05:00
|
|
|
callback(null, keypair);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
2013-12-03 13:21:50 -05:00
|
|
|
|
2013-12-09 13:21:52 -05:00
|
|
|
EmailDAO.prototype.onConnect = function(options, callback) {
|
|
|
|
var self = this;
|
2013-12-06 11:47:38 -05:00
|
|
|
|
2014-05-07 13:19:51 -04:00
|
|
|
self._account.loggingIn = true;
|
|
|
|
|
2013-12-09 13:21:52 -05:00
|
|
|
self._imapClient = options.imapClient;
|
2014-02-03 16:07:39 -05:00
|
|
|
self._pgpMailer = options.pgpMailer;
|
2013-12-09 13:21:52 -05:00
|
|
|
|
2014-03-11 13:57:03 -04:00
|
|
|
// notify emailSync
|
|
|
|
self._emailSync.onConnect({
|
|
|
|
imapClient: self._imapClient
|
|
|
|
}, function(err) {
|
|
|
|
if (err) {
|
2014-05-07 13:19:51 -04:00
|
|
|
self._account.loggingIn = false;
|
2014-03-11 13:57:03 -04:00
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// connect to newly created imap client
|
|
|
|
self._imapLogin(onLogin);
|
|
|
|
});
|
|
|
|
|
|
|
|
function onLogin(err) {
|
2013-12-09 13:21:52 -05:00
|
|
|
if (err) {
|
2014-05-07 13:19:51 -04:00
|
|
|
self._account.loggingIn = false;
|
2013-12-09 13:21:52 -05:00
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set status to online
|
2014-05-07 13:19:51 -04:00
|
|
|
self._account.loggingIn = false;
|
2013-12-09 13:21:52 -05:00
|
|
|
self._account.online = true;
|
|
|
|
|
|
|
|
// init folders
|
|
|
|
self._imapListFolders(function(err, folders) {
|
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-04-29 19:04:13 -04:00
|
|
|
// only overwrite folders if they are not yet set
|
|
|
|
if (!self._account.folders) {
|
|
|
|
self._account.folders = folders;
|
|
|
|
}
|
|
|
|
|
|
|
|
var inbox = _.findWhere(self._account.folders, {
|
2014-04-28 12:09:51 -04:00
|
|
|
type: 'Inbox'
|
|
|
|
});
|
|
|
|
|
|
|
|
if (inbox) {
|
|
|
|
self._imapClient.listenForChanges({
|
|
|
|
path: inbox.path
|
2014-04-29 19:04:13 -04:00
|
|
|
}, function(error, path) {
|
2014-04-28 12:09:51 -04:00
|
|
|
if (typeof self.onNeedsSync === 'function') {
|
|
|
|
self.onNeedsSync(error, path);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-12-09 13:21:52 -05:00
|
|
|
callback();
|
2013-08-16 14:50:47 -04:00
|
|
|
});
|
2014-03-11 13:57:03 -04:00
|
|
|
}
|
2013-10-21 07:10:42 -04:00
|
|
|
};
|
|
|
|
|
2013-12-09 13:21:52 -05:00
|
|
|
EmailDAO.prototype.onDisconnect = function(options, callback) {
|
|
|
|
// set status to online
|
|
|
|
this._account.online = false;
|
|
|
|
this._imapClient = undefined;
|
2014-03-11 13:57:03 -04:00
|
|
|
this._pgpMailer = undefined;
|
2013-12-09 13:21:52 -05:00
|
|
|
|
2014-03-11 13:57:03 -04:00
|
|
|
// notify emailSync
|
|
|
|
this._emailSync.onDisconnect(null, callback);
|
2013-12-09 13:21:52 -05:00
|
|
|
};
|
2013-12-03 13:21:50 -05:00
|
|
|
|
|
|
|
EmailDAO.prototype.unlock = function(options, callback) {
|
2013-10-21 07:10:42 -04:00
|
|
|
var self = this;
|
2013-10-29 07:19:27 -04:00
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
if (options.keypair) {
|
2013-10-21 07:10:42 -04:00
|
|
|
// import existing key pair into crypto module
|
2014-03-05 14:14:23 -05:00
|
|
|
handleExistingKeypair(options.keypair);
|
2013-10-21 07:10:42 -04:00
|
|
|
return;
|
|
|
|
}
|
2013-08-16 14:50:47 -04:00
|
|
|
|
2013-10-21 07:10:42 -04:00
|
|
|
// no keypair for is stored for the user... generate a new one
|
|
|
|
self._crypto.generateKeys({
|
|
|
|
emailAddress: self._account.emailAddress,
|
|
|
|
keySize: self._account.asymKeySize,
|
2013-12-03 13:21:50 -05:00
|
|
|
passphrase: options.passphrase
|
2013-10-21 07:10:42 -04:00
|
|
|
}, function(err, generatedKeypair) {
|
|
|
|
if (err) {
|
|
|
|
callback(err);
|
2013-10-11 21:19:01 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
handleGenerated(generatedKeypair);
|
|
|
|
});
|
|
|
|
|
2014-03-05 14:14:23 -05:00
|
|
|
function handleExistingKeypair(keypair) {
|
|
|
|
var pubUserID, privUserID;
|
|
|
|
|
|
|
|
// check if key IDs match
|
|
|
|
if (!keypair.privateKey._id || keypair.privateKey._id !== keypair.publicKey._id) {
|
|
|
|
callback({
|
|
|
|
errMsg: 'Key IDs dont match!'
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if the key's user ID matches the current account
|
2014-03-06 12:19:51 -05:00
|
|
|
pubUserID = self._crypto.getKeyParams(keypair.publicKey.publicKey).userId;
|
|
|
|
privUserID = self._crypto.getKeyParams(keypair.privateKey.encryptedKey).userId;
|
2014-03-05 14:14:23 -05:00
|
|
|
if (pubUserID.indexOf(self._account.emailAddress) === -1 || privUserID.indexOf(self._account.emailAddress) === -1) {
|
|
|
|
callback({
|
|
|
|
errMsg: 'User IDs dont match!'
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// import existing key pair into crypto module
|
|
|
|
self._crypto.importKeys({
|
|
|
|
passphrase: options.passphrase,
|
|
|
|
privateKeyArmored: keypair.privateKey.encryptedKey,
|
|
|
|
publicKeyArmored: keypair.publicKey.publicKey
|
|
|
|
}, function(err) {
|
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set decrypted privateKey to pgpMailer
|
|
|
|
self._pgpbuilder._privateKey = self._crypto._privateKey;
|
|
|
|
callback();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
function handleGenerated(generatedKeypair) {
|
2013-10-21 07:10:42 -04:00
|
|
|
// import the new key pair into crypto module
|
|
|
|
self._crypto.importKeys({
|
2013-12-03 13:21:50 -05:00
|
|
|
passphrase: options.passphrase,
|
2013-10-21 07:10:42 -04:00
|
|
|
privateKeyArmored: generatedKeypair.privateKeyArmored,
|
|
|
|
publicKeyArmored: generatedKeypair.publicKeyArmored
|
|
|
|
}, function(err) {
|
2013-08-16 14:50:47 -04:00
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-21 07:10:42 -04:00
|
|
|
// persist newly generated keypair
|
|
|
|
var newKeypair = {
|
|
|
|
publicKey: {
|
|
|
|
_id: generatedKeypair.keyId,
|
|
|
|
userId: self._account.emailAddress,
|
|
|
|
publicKey: generatedKeypair.publicKeyArmored
|
|
|
|
},
|
|
|
|
privateKey: {
|
|
|
|
_id: generatedKeypair.keyId,
|
|
|
|
userId: self._account.emailAddress,
|
|
|
|
encryptedKey: generatedKeypair.privateKeyArmored
|
2013-10-11 21:19:01 -04:00
|
|
|
}
|
2013-10-21 07:10:42 -04:00
|
|
|
};
|
2014-02-24 04:14:07 -05:00
|
|
|
self._keychain.putUserKeyPair(newKeypair, function(err) {
|
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set decrypted privateKey to pgpMailer
|
2014-02-25 11:29:12 -05:00
|
|
|
self._pgpbuilder._privateKey = self._crypto._privateKey;
|
2014-02-24 04:14:07 -05:00
|
|
|
callback();
|
|
|
|
});
|
2013-08-16 14:50:47 -04:00
|
|
|
});
|
2013-10-10 13:15:16 -04:00
|
|
|
}
|
2013-09-20 12:44:14 -04:00
|
|
|
};
|
|
|
|
|
2014-02-24 04:14:07 -05:00
|
|
|
EmailDAO.prototype.syncOutbox = function(options, callback) {
|
2014-03-11 13:57:03 -04:00
|
|
|
this._emailSync.syncOutbox(options, callback);
|
2014-02-24 04:14:07 -05:00
|
|
|
};
|
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
EmailDAO.prototype.sync = function(options, callback) {
|
2014-03-11 13:57:03 -04:00
|
|
|
this._emailSync.sync(options, callback);
|
2014-02-14 11:29:16 -05:00
|
|
|
};
|
2013-09-26 07:26:57 -04:00
|
|
|
|
2014-02-14 11:29:16 -05:00
|
|
|
/**
|
|
|
|
* Streams message content
|
|
|
|
* @param {Object} options.message The message for which to retrieve the body
|
|
|
|
* @param {Object} options.folder The IMAP folder
|
|
|
|
* @param {Function} callback(error, message) Invoked when the message is streamed, or provides information if an error occurred
|
|
|
|
*/
|
2014-02-20 09:42:51 -05:00
|
|
|
EmailDAO.prototype.getBody = function(options, callback) {
|
2014-02-14 11:29:16 -05:00
|
|
|
var self = this,
|
|
|
|
message = options.message,
|
|
|
|
folder = options.folder;
|
2013-10-04 09:47:30 -04:00
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
// the message either already has a body or is fetching it right now, so no need to become active here
|
|
|
|
if (message.loadingBody || typeof message.body !== 'undefined') {
|
2014-02-14 11:29:16 -05:00
|
|
|
return;
|
2013-12-03 13:21:50 -05:00
|
|
|
}
|
2013-09-26 07:26:57 -04:00
|
|
|
|
2014-02-17 08:31:14 -05:00
|
|
|
message.loadingBody = true;
|
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
/*
|
|
|
|
* read this before inspecting the method!
|
|
|
|
*
|
|
|
|
* you will wonder about the round trip to the disk where we load the persisted object. there are two reasons for this behavior:
|
|
|
|
* 1) if you work with a message that was loaded from the disk, we strip the message.bodyParts array,
|
|
|
|
* because it is not really necessary to keep everything in memory
|
|
|
|
* 2) the message in memory is polluted by angular. angular tracks ordering of a list by adding a property
|
|
|
|
* to the model. this property is auto generated and must not be persisted.
|
|
|
|
*/
|
2013-09-28 13:04:15 -04:00
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
retrieveContent();
|
|
|
|
|
|
|
|
function retrieveContent() {
|
|
|
|
// load the local message from memory
|
2014-03-11 13:57:03 -04:00
|
|
|
self._emailSync._localListMessages({
|
2014-02-14 11:29:16 -05:00
|
|
|
folder: folder,
|
|
|
|
uid: message.uid
|
|
|
|
}, function(err, localMessages) {
|
2014-05-06 11:23:08 -04:00
|
|
|
if (err || localMessages.length === 0) {
|
|
|
|
done(err);
|
2013-09-26 07:26:57 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
var localMessage = localMessages[0];
|
2014-02-14 11:29:16 -05:00
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
// do we need to fetch content from the imap server?
|
|
|
|
var needsFetch = false;
|
|
|
|
localMessage.bodyParts.forEach(function(part) {
|
|
|
|
needsFetch = (typeof part.content === 'undefined');
|
|
|
|
});
|
2014-02-14 11:29:16 -05:00
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
if (!needsFetch) {
|
|
|
|
// if we have all the content we need,
|
|
|
|
// we can extract the content
|
|
|
|
message.bodyParts = localMessage.bodyParts;
|
|
|
|
extractContent();
|
2014-02-14 11:29:16 -05:00
|
|
|
return;
|
|
|
|
}
|
2013-09-26 07:26:57 -04:00
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
// get the raw content from the imap server
|
|
|
|
self._emailSync._getBodyParts({
|
2014-02-14 11:29:16 -05:00
|
|
|
folder: folder,
|
2014-05-06 11:23:08 -04:00
|
|
|
uid: localMessage.uid,
|
|
|
|
bodyParts: localMessage.bodyParts
|
|
|
|
}, function(err, parsedBodyParts) {
|
|
|
|
if (err) {
|
|
|
|
done(err);
|
2014-01-18 05:42:28 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
message.bodyParts = parsedBodyParts;
|
|
|
|
localMessage.bodyParts = parsedBodyParts;
|
2014-02-24 11:37:23 -05:00
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
// persist it to disk
|
2014-03-11 13:57:03 -04:00
|
|
|
self._emailSync._localStoreMessages({
|
2014-02-24 11:37:23 -05:00
|
|
|
folder: folder,
|
2014-05-06 11:23:08 -04:00
|
|
|
emails: [localMessage]
|
2014-02-24 11:37:23 -05:00
|
|
|
}, function(error) {
|
|
|
|
if (error) {
|
2014-05-06 11:23:08 -04:00
|
|
|
done(error);
|
2014-02-24 11:37:23 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
// extract the content
|
|
|
|
extractContent();
|
2014-02-24 11:37:23 -05:00
|
|
|
});
|
2013-09-26 07:26:57 -04:00
|
|
|
});
|
|
|
|
});
|
2014-02-14 11:29:16 -05:00
|
|
|
}
|
2013-08-21 07:43:19 -04:00
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
function extractContent() {
|
2014-02-14 11:29:16 -05:00
|
|
|
if (message.encrypted) {
|
2014-05-06 11:23:08 -04:00
|
|
|
// show the encrypted message
|
|
|
|
message.body = self._emailSync.filterBodyParts(message.bodyParts, 'encrypted')[0].content;
|
|
|
|
done();
|
|
|
|
return;
|
2013-08-29 10:01:40 -04:00
|
|
|
}
|
2014-02-14 11:29:16 -05:00
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
// for unencrypted messages, this is the array where the body parts are located
|
|
|
|
var root = message.bodyParts;
|
2014-02-14 11:29:16 -05:00
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
if (message.signed) {
|
|
|
|
var signedPart = self._emailSync.filterBodyParts(message.bodyParts, 'signed')[0];
|
|
|
|
message.message = signedPart.message;
|
|
|
|
message.signature = signedPart.signature;
|
|
|
|
// TODO check integrity
|
|
|
|
// in case of a signed message, you only want to show the signed content and ignore the rest
|
|
|
|
root = signedPart.content;
|
|
|
|
}
|
|
|
|
|
|
|
|
message.attachments = self._emailSync.filterBodyParts(root, 'attachment');
|
|
|
|
message.body = _.pluck(self._emailSync.filterBodyParts(root, 'text'), 'content').join('\n');
|
|
|
|
message.html = _.pluck(self._emailSync.filterBodyParts(root, 'html'), 'content').join('\n');
|
2014-02-14 11:29:16 -05:00
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
done();
|
2013-10-16 12:56:18 -04:00
|
|
|
}
|
2014-02-14 11:29:16 -05:00
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
function done(err) {
|
|
|
|
message.loadingBody = false;
|
|
|
|
callback(err, err ? undefined : message);
|
|
|
|
}
|
2014-02-14 11:29:16 -05:00
|
|
|
};
|
|
|
|
|
2014-02-24 04:14:07 -05:00
|
|
|
EmailDAO.prototype.decryptBody = function(options, callback) {
|
2014-02-14 11:29:16 -05:00
|
|
|
var self = this,
|
|
|
|
message = options.message;
|
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
// the message is decrypting has no body, is not encrypted or has already been decrypted
|
2014-02-17 08:31:14 -05:00
|
|
|
if (message.decryptingBody || !message.body || !message.encrypted || message.decrypted) {
|
2014-02-14 11:29:16 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-17 08:31:14 -05:00
|
|
|
message.decryptingBody = true;
|
|
|
|
|
2014-02-14 11:29:16 -05:00
|
|
|
// get the sender's public key for signature checking
|
|
|
|
self._keychain.getReceiverPublicKey(message.from[0].address, function(err, senderPublicKey) {
|
|
|
|
if (err) {
|
2014-05-12 07:44:02 -04:00
|
|
|
done(err);
|
2014-02-14 11:29:16 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!senderPublicKey) {
|
|
|
|
// this should only happen if a mail from another channel is in the inbox
|
2014-05-12 07:44:02 -04:00
|
|
|
showError('Public key for sender not found!');
|
2014-02-14 11:29:16 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the receiver's public key to check the message signature
|
2014-05-06 11:23:08 -04:00
|
|
|
var encryptedNode = self._emailSync.filterBodyParts(message.bodyParts, 'encrypted')[0];
|
|
|
|
self._crypto.decrypt(encryptedNode.content, senderPublicKey.publicKey, function(err, decrypted) {
|
|
|
|
if (err || !decrypted) {
|
2014-05-12 07:44:02 -04:00
|
|
|
showError(err.errMsg || err.message);
|
2014-02-14 11:29:16 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
// the mailparser works on the .raw property
|
|
|
|
encryptedNode.raw = decrypted;
|
|
|
|
|
|
|
|
// parse the decrpyted raw content in the mailparser
|
|
|
|
self._mailreader.parse({
|
|
|
|
bodyParts: [encryptedNode]
|
2014-05-12 07:44:02 -04:00
|
|
|
}, function(err, parsedBodyParts) {
|
|
|
|
if (err) {
|
|
|
|
showError(err.errMsg || err.message);
|
2014-02-14 11:29:16 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
// we have successfully interpreted the descrypted message,
|
|
|
|
// so let's update the views on the message parts
|
2014-02-14 11:29:16 -05:00
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
message.body = _.pluck(self._emailSync.filterBodyParts(parsedBodyParts, 'text'), 'content').join('\n');
|
|
|
|
message.html = _.pluck(self._emailSync.filterBodyParts(parsedBodyParts, 'html'), 'content').join('\n');
|
|
|
|
message.attachments = _.reject(self._emailSync.filterBodyParts(parsedBodyParts, 'attachment'), function(attmt) {
|
|
|
|
// remove the pgp-signature from the attachments
|
2014-02-14 11:29:16 -05:00
|
|
|
return attmt.mimeType === "application/pgp-signature";
|
|
|
|
});
|
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
message.decrypted = true;
|
|
|
|
|
|
|
|
|
2014-02-14 11:29:16 -05:00
|
|
|
// we're done here!
|
2014-05-06 11:23:08 -04:00
|
|
|
done();
|
2014-02-14 11:29:16 -05:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2013-08-20 07:30:35 -04:00
|
|
|
|
2014-05-12 07:44:02 -04:00
|
|
|
function showError(msg) {
|
|
|
|
message.body = msg;
|
|
|
|
message.decrypted = true; // display error msh in body
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
|
2014-05-06 11:23:08 -04:00
|
|
|
function done(err) {
|
|
|
|
message.decryptingBody = false;
|
|
|
|
callback(err, err ? undefined : message);
|
2014-01-16 09:37:08 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
EmailDAO.prototype.sendEncrypted = function(options, callback) {
|
2014-02-24 04:14:07 -05:00
|
|
|
var self = this;
|
2013-10-04 10:29:32 -04:00
|
|
|
|
2013-12-12 08:47:04 -05:00
|
|
|
if (!this._account.online) {
|
2013-12-09 13:21:52 -05:00
|
|
|
callback({
|
|
|
|
errMsg: 'Client is currently offline!',
|
|
|
|
code: 42
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-24 04:14:07 -05:00
|
|
|
// mime encode, sign, encrypt and send email via smtp
|
|
|
|
self._pgpMailer.send({
|
|
|
|
encrypt: true,
|
2014-02-27 12:14:38 -05:00
|
|
|
cleartextMessage: str.message + str.signature,
|
2014-02-24 04:14:07 -05:00
|
|
|
mail: options.email,
|
|
|
|
publicKeysArmored: options.email.publicKeysArmored
|
|
|
|
}, callback);
|
2013-10-04 10:29:32 -04:00
|
|
|
};
|
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
EmailDAO.prototype.sendPlaintext = function(options, callback) {
|
2013-12-12 08:47:04 -05:00
|
|
|
if (!this._account.online) {
|
2013-12-09 13:21:52 -05:00
|
|
|
callback({
|
|
|
|
errMsg: 'Client is currently offline!',
|
|
|
|
code: 42
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-03 16:07:39 -05:00
|
|
|
// mime encode, sign and send email via smtp
|
|
|
|
this._pgpMailer.send({
|
|
|
|
mail: options.email
|
|
|
|
}, callback);
|
2013-12-03 13:21:50 -05:00
|
|
|
};
|
|
|
|
|
2014-02-24 04:14:07 -05:00
|
|
|
EmailDAO.prototype.encrypt = function(options, callback) {
|
2014-02-25 11:29:12 -05:00
|
|
|
this._pgpbuilder.encrypt(options, callback);
|
2014-02-24 04:14:07 -05:00
|
|
|
};
|
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
//
|
|
|
|
// Internal API
|
|
|
|
//
|
|
|
|
|
|
|
|
// IMAP API
|
|
|
|
|
2013-10-04 10:29:32 -04:00
|
|
|
/**
|
2013-12-03 13:21:50 -05:00
|
|
|
* Login the imap client
|
2013-10-04 10:29:32 -04:00
|
|
|
*/
|
2013-12-03 13:21:50 -05:00
|
|
|
EmailDAO.prototype._imapLogin = function(callback) {
|
2013-12-09 13:21:52 -05:00
|
|
|
if (!this._imapClient) {
|
|
|
|
callback({
|
|
|
|
errMsg: 'Client is currently offline!',
|
|
|
|
code: 42
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
// login IMAP client if existent
|
|
|
|
this._imapClient.login(callback);
|
|
|
|
};
|
2013-10-04 10:29:32 -04:00
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
/**
|
|
|
|
* Cleanup by logging the user off.
|
|
|
|
*/
|
|
|
|
EmailDAO.prototype._imapLogout = function(callback) {
|
2013-12-12 08:47:04 -05:00
|
|
|
if (!this._account.online) {
|
2013-12-09 13:21:52 -05:00
|
|
|
callback({
|
|
|
|
errMsg: 'Client is currently offline!',
|
|
|
|
code: 42
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
this._imapClient.logout(callback);
|
|
|
|
};
|
2013-10-04 10:29:32 -04:00
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
/**
|
|
|
|
* List the folders in the user's IMAP mailbox.
|
|
|
|
*/
|
|
|
|
EmailDAO.prototype._imapListFolders = function(callback) {
|
|
|
|
var self = this,
|
|
|
|
dbType = 'folders';
|
|
|
|
|
|
|
|
// check local cache
|
|
|
|
self._devicestorage.listItems(dbType, 0, null, function(err, stored) {
|
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!stored || stored.length < 1) {
|
|
|
|
// no folders cached... fetch from server
|
|
|
|
fetchFromServer();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
callback(null, stored[0]);
|
|
|
|
});
|
|
|
|
|
|
|
|
function fetchFromServer() {
|
|
|
|
var folders;
|
|
|
|
|
2013-12-12 08:47:04 -05:00
|
|
|
if (!self._account.online) {
|
2013-12-09 13:21:52 -05:00
|
|
|
callback({
|
|
|
|
errMsg: 'Client is currently offline!',
|
|
|
|
code: 42
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-03 13:21:50 -05:00
|
|
|
// fetch list from imap server
|
|
|
|
self._imapClient.listWellKnownFolders(function(err, wellKnownFolders) {
|
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
folders = [
|
|
|
|
wellKnownFolders.inbox,
|
|
|
|
wellKnownFolders.sent, {
|
|
|
|
type: 'Outbox',
|
|
|
|
path: 'OUTBOX'
|
|
|
|
},
|
|
|
|
wellKnownFolders.drafts,
|
|
|
|
wellKnownFolders.trash
|
|
|
|
];
|
|
|
|
|
|
|
|
// cache locally
|
|
|
|
// persist encrypted list in device storage
|
|
|
|
self._devicestorage.storeList([folders], dbType, function(err) {
|
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
callback(null, folders);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
2013-10-04 10:29:32 -04:00
|
|
|
};
|
|
|
|
|
2013-08-16 14:50:47 -04:00
|
|
|
return EmailDAO;
|
2014-03-06 12:19:51 -05:00
|
|
|
});
|