mirror of
https://github.com/moparisthebest/mail
synced 2024-11-28 11:52:16 -05:00
refactor test and storage code
This commit is contained in:
parent
a3f11befdc
commit
38b0a8e8b1
@ -135,7 +135,8 @@ module.exports = function(grunt) {
|
|||||||
'imap-client/node_modules/mimelib/node_modules/encoding/node_modules/iconv-lite/src/*.js',
|
'imap-client/node_modules/mimelib/node_modules/encoding/node_modules/iconv-lite/src/*.js',
|
||||||
'imap-client/node_modules/mimelib/node_modules/encoding/node_modules/mime/src/*.js',
|
'imap-client/node_modules/mimelib/node_modules/encoding/node_modules/mime/src/*.js',
|
||||||
'imap-client/node_modules/mailparser/src/*.js',
|
'imap-client/node_modules/mailparser/src/*.js',
|
||||||
'imap-client/node_modules/mailparser/node_modules/mime/src/mime.js'
|
'imap-client/node_modules/mailparser/node_modules/mime/src/mime.js',
|
||||||
|
'smtp-client/src-gen/*.js'
|
||||||
],
|
],
|
||||||
dest: 'src/lib/'
|
dest: 'src/lib/'
|
||||||
},
|
},
|
||||||
|
@ -8,7 +8,7 @@ cd ..
|
|||||||
|
|
||||||
# build imap/smtp modules and copy
|
# build imap/smtp modules and copy
|
||||||
cd ./node_modules/smtp-client/
|
cd ./node_modules/smtp-client/
|
||||||
node build.js && cp ./src-gen/*.js ../../src/lib/
|
node build.js
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
echo "\n--> finished building dependencies.\n"
|
echo "\n--> finished building dependencies.\n"
|
||||||
|
BIN
src/img/icon.png
Normal file
BIN
src/img/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 17 KiB |
@ -10,6 +10,8 @@ define(function(require) {
|
|||||||
EmailDAO = require('js/dao/email-dao'),
|
EmailDAO = require('js/dao/email-dao'),
|
||||||
KeychainDAO = require('js/dao/keychain-dao'),
|
KeychainDAO = require('js/dao/keychain-dao'),
|
||||||
cloudstorage = require('js/dao/cloudstorage-dao'),
|
cloudstorage = require('js/dao/cloudstorage-dao'),
|
||||||
|
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
|
||||||
|
Crypto = require('js/crypto/crypto'),
|
||||||
config = require('js/app-config').config;
|
config = require('js/app-config').config;
|
||||||
require('cordova');
|
require('cordova');
|
||||||
|
|
||||||
@ -66,7 +68,7 @@ define(function(require) {
|
|||||||
|
|
||||||
self.login = function(userId, password, token, callback) {
|
self.login = function(userId, password, token, callback) {
|
||||||
var auth, imapOptions, smtpOptions,
|
var auth, imapOptions, smtpOptions,
|
||||||
keychain, imapClient, smtpClient;
|
keychain, imapClient, smtpClient, crypto, deviceStorage;
|
||||||
|
|
||||||
// create mail credentials objects for imap/smtp
|
// create mail credentials objects for imap/smtp
|
||||||
auth = {
|
auth = {
|
||||||
@ -93,7 +95,9 @@ define(function(require) {
|
|||||||
keychain = new KeychainDAO(cloudstorage);
|
keychain = new KeychainDAO(cloudstorage);
|
||||||
imapClient = new ImapClient(imapOptions);
|
imapClient = new ImapClient(imapOptions);
|
||||||
smtpClient = new SmtpClient(smtpOptions);
|
smtpClient = new SmtpClient(smtpOptions);
|
||||||
self._emailDao = new EmailDAO(keychain, imapClient, smtpClient);
|
crypto = new Crypto();
|
||||||
|
deviceStorage = new DeviceStorageDAO();
|
||||||
|
self._emailDao = new EmailDAO(keychain, imapClient, smtpClient, crypto, deviceStorage);
|
||||||
|
|
||||||
// init email dao
|
// init email dao
|
||||||
var account = {
|
var account = {
|
||||||
|
@ -3,10 +3,13 @@ define(function(require) {
|
|||||||
|
|
||||||
var _ = require('underscore'),
|
var _ = require('underscore'),
|
||||||
appController = require('js/app-controller'),
|
appController = require('js/app-controller'),
|
||||||
moment = require('moment'),
|
|
||||||
emailDao;
|
emailDao;
|
||||||
|
|
||||||
var MailListCtrl = function($scope) {
|
var MailListCtrl = function($scope) {
|
||||||
|
var offset = -6,
|
||||||
|
num = 0;
|
||||||
|
|
||||||
|
// show inbox at the beginning
|
||||||
$scope.folder = 'INBOX';
|
$scope.folder = 'INBOX';
|
||||||
emailDao = appController._emailDao;
|
emailDao = appController._emailDao;
|
||||||
|
|
||||||
@ -17,72 +20,83 @@ define(function(require) {
|
|||||||
$scope.$parent.selected = $scope.selected;
|
$scope.$parent.selected = $scope.selected;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// production... in chrome packaged app
|
||||||
if (window.chrome && chrome.identity) {
|
if (window.chrome && chrome.identity) {
|
||||||
fetchList($scope.folder, function(emails) {
|
initList();
|
||||||
$scope.emails = emails;
|
|
||||||
$scope.select($scope.emails[0]);
|
|
||||||
$scope.$apply();
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// development
|
||||||
createDummyMails(function(emails) {
|
createDummyMails(function(emails) {
|
||||||
$scope.emails = emails;
|
$scope.emails = emails;
|
||||||
$scope.select($scope.emails[0]);
|
$scope.select($scope.emails[0]);
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
function fetchList(folder, callback) {
|
function initList() {
|
||||||
// fetch imap folder's message list
|
// list messaged from local db
|
||||||
emailDao.imapListMessages({
|
listLocalMessages({
|
||||||
folder: folder,
|
folder: $scope.folder,
|
||||||
offset: -6,
|
offset: offset,
|
||||||
num: 0
|
num: num
|
||||||
}, function(err, emails) {
|
}, function() {
|
||||||
|
// sync from imap to local db
|
||||||
|
syncImapFolder({
|
||||||
|
folder: $scope.folder,
|
||||||
|
offset: offset,
|
||||||
|
num: num
|
||||||
|
}, function() {
|
||||||
|
// list again from local db after syncing
|
||||||
|
listLocalMessages({
|
||||||
|
folder: $scope.folder,
|
||||||
|
offset: offset,
|
||||||
|
num: num
|
||||||
|
}, function() {
|
||||||
|
console.log('syncing ' + $scope.folder + ' complete');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncImapFolder(options, callback) {
|
||||||
|
// sync if emails are empty
|
||||||
|
emailDao.imapSync(options, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch message bodies
|
callback();
|
||||||
fetchBodies(emails, folder, function(messages) {
|
|
||||||
addDisplayDate(messages);
|
|
||||||
callback(messages);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchBodies(messageList, folder, callback) {
|
function listLocalMessages(options, callback) {
|
||||||
var emails = [];
|
emailDao.listMessages(options, function(err, emails) {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// add display dates
|
||||||
|
displayEmails(emails);
|
||||||
|
|
||||||
var after = _.after(messageList.length, function() {
|
|
||||||
callback(emails);
|
callback(emails);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
_.each(messageList, function(messageItem) {
|
function displayEmails(emails) {
|
||||||
emailDao.imapGetMessage({
|
if (!emails || emails.length < 1) {
|
||||||
folder: folder,
|
|
||||||
uid: messageItem.uid
|
|
||||||
}, function(err, message) {
|
|
||||||
if (err) {
|
|
||||||
console.log(err);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emails.push(message);
|
// sort by uid
|
||||||
after();
|
emails = _.sortBy(emails, function(e) {
|
||||||
});
|
return -e.uid;
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function addDisplayDate(emails) {
|
|
||||||
emails.forEach(function(email) {
|
|
||||||
// set display date
|
|
||||||
email.displayDate = moment(email.sentDate).format('DD.MM.YY');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return emails;
|
$scope.emails = emails;
|
||||||
|
$scope.select($scope.emails[0]);
|
||||||
|
$scope.$apply();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function createDummyMails(callback) {
|
function createDummyMails(callback) {
|
||||||
var Email = function(unread, attachments, replied) {
|
var Email = function(unread, attachments, replied) {
|
||||||
@ -97,8 +111,7 @@ define(function(require) {
|
|||||||
this.attachments = (attachments) ? [true] : undefined;
|
this.attachments = (attachments) ? [true] : undefined;
|
||||||
this.unread = unread;
|
this.unread = unread;
|
||||||
this.replied = replied;
|
this.replied = replied;
|
||||||
this.displayDate = '23.08.13';
|
this.sentDate = new Date('Thu Sep 19 2013 20:41:23 GMT+0200 (CEST)');
|
||||||
this.longDisplayDate = 'Wednesday, 23.08.2013 19:23';
|
|
||||||
this.subject = "Welcome Max"; // Subject line
|
this.subject = "Welcome Max"; // Subject line
|
||||||
this.body = "Hi Max,\n\n" +
|
this.body = "Hi Max,\n\n" +
|
||||||
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.\n\n" +
|
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.\n\n" +
|
||||||
|
@ -12,16 +12,21 @@ define(function(require) {
|
|||||||
pbkdf2 = require('js/crypto/pbkdf2'),
|
pbkdf2 = require('js/crypto/pbkdf2'),
|
||||||
config = require('js/app-config').config;
|
config = require('js/app-config').config;
|
||||||
|
|
||||||
var self = {},
|
var passBasedKey,
|
||||||
passBasedKey,
|
|
||||||
BATCH_WORKER = '/crypto/crypto-batch-worker.js',
|
BATCH_WORKER = '/crypto/crypto-batch-worker.js',
|
||||||
PBKDF2_WORKER = '/crypto/pbkdf2-worker.js';
|
PBKDF2_WORKER = '/crypto/pbkdf2-worker.js';
|
||||||
|
|
||||||
|
var Crypto = function() {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the crypto modules by fetching the user's
|
* Initializes the crypto modules by fetching the user's
|
||||||
* encrypted secret key from storage and storing it in memory.
|
* encrypted secret key from storage and storing it in memory.
|
||||||
*/
|
*/
|
||||||
self.init = function(args, callback) {
|
Crypto.prototype.init = function(args, callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
// valdiate input
|
// valdiate input
|
||||||
if (!args.emailAddress || !args.keySize || !args.rsaKeySize) {
|
if (!args.emailAddress || !args.keySize || !args.rsaKeySize) {
|
||||||
callback({
|
callback({
|
||||||
@ -119,7 +124,7 @@ define(function(require) {
|
|||||||
/**
|
/**
|
||||||
* Do PBKDF2 key derivation in a WebWorker thread
|
* Do PBKDF2 key derivation in a WebWorker thread
|
||||||
*/
|
*/
|
||||||
self.deriveKey = function(password, keySize, callback) {
|
Crypto.prototype.deriveKey = function(password, keySize, callback) {
|
||||||
startWorker({
|
startWorker({
|
||||||
script: PBKDF2_WORKER,
|
script: PBKDF2_WORKER,
|
||||||
args: {
|
args: {
|
||||||
@ -137,8 +142,9 @@ define(function(require) {
|
|||||||
// En/Decrypt a list of items with AES in a WebWorker thread
|
// En/Decrypt a list of items with AES in a WebWorker thread
|
||||||
//
|
//
|
||||||
|
|
||||||
self.symEncryptList = function(list, callback) {
|
Crypto.prototype.symEncryptList = function(list, callback) {
|
||||||
var key, envelope, envelopes = [];
|
var self = this,
|
||||||
|
key, envelope, envelopes = [];
|
||||||
|
|
||||||
// generate single secret key shared for all list items
|
// generate single secret key shared for all list items
|
||||||
key = util.random(self.keySize);
|
key = util.random(self.keySize);
|
||||||
@ -173,7 +179,7 @@ define(function(require) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.symDecryptList = function(list, keys, callback) {
|
Crypto.prototype.symDecryptList = function(list, keys, callback) {
|
||||||
startWorker({
|
startWorker({
|
||||||
script: BATCH_WORKER,
|
script: BATCH_WORKER,
|
||||||
args: {
|
args: {
|
||||||
@ -192,8 +198,9 @@ define(function(require) {
|
|||||||
// En/Decrypt something speficially using the user's secret key
|
// En/Decrypt something speficially using the user's secret key
|
||||||
//
|
//
|
||||||
|
|
||||||
self.encryptListForUser = function(list, receiverPubkeys, callback) {
|
Crypto.prototype.encryptListForUser = function(list, receiverPubkeys, callback) {
|
||||||
var envelope, envelopes = [];
|
var self = this,
|
||||||
|
envelope, envelopes = [];
|
||||||
|
|
||||||
if (!receiverPubkeys || receiverPubkeys.length !== 1) {
|
if (!receiverPubkeys || receiverPubkeys.length !== 1) {
|
||||||
callback({
|
callback({
|
||||||
@ -235,7 +242,7 @@ define(function(require) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.decryptListForUser = function(list, senderPubkeys, callback) {
|
Crypto.prototype.decryptListForUser = function(list, senderPubkeys, callback) {
|
||||||
if (!senderPubkeys || senderPubkeys < 1) {
|
if (!senderPubkeys || senderPubkeys < 1) {
|
||||||
callback({
|
callback({
|
||||||
errMsg: 'Sender public keys must be set!'
|
errMsg: 'Sender public keys must be set!'
|
||||||
@ -268,7 +275,7 @@ define(function(require) {
|
|||||||
// Re-encrypt keys item and items seperately
|
// Re-encrypt keys item and items seperately
|
||||||
//
|
//
|
||||||
|
|
||||||
self.reencryptListKeysForUser = function(list, senderPubkeys, callback) {
|
Crypto.prototype.reencryptListKeysForUser = function(list, senderPubkeys, callback) {
|
||||||
var keypair = rsa.exportKeys();
|
var keypair = rsa.exportKeys();
|
||||||
var receiverPrivkey = {
|
var receiverPrivkey = {
|
||||||
_id: keypair._id,
|
_id: keypair._id,
|
||||||
@ -291,7 +298,7 @@ define(function(require) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.decryptKeysAndList = function(list, callback) {
|
Crypto.prototype.decryptKeysAndList = function(list, callback) {
|
||||||
startWorker({
|
startWorker({
|
||||||
script: BATCH_WORKER,
|
script: BATCH_WORKER,
|
||||||
args: {
|
args: {
|
||||||
@ -351,5 +358,5 @@ define(function(require) {
|
|||||||
options.callback(null, result);
|
options.callback(null, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return Crypto;
|
||||||
});
|
});
|
@ -4,17 +4,26 @@
|
|||||||
* through transparent encryption. If not, the crypto API is
|
* through transparent encryption. If not, the crypto API is
|
||||||
* used to encrypt data on the fly before persisting via a JSON store.
|
* used to encrypt data on the fly before persisting via a JSON store.
|
||||||
*/
|
*/
|
||||||
define(['cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-dao'], function(util, crypto, jsonDao) {
|
define(function(require) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var self = {};
|
var util = require('cryptoLib/util'),
|
||||||
|
jsonDao = require('js/dao/lawnchair-dao');
|
||||||
|
|
||||||
|
var DeviceStorageDAO = function() {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
DeviceStorageDAO.prototype.init = function(emailAddress, callback) {
|
||||||
|
jsonDao.init(emailAddress, callback);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a list of encrypted items in the object store
|
* Stores a list of encrypted items in the object store
|
||||||
* @param list [Array] The list of items to be persisted
|
* @param list [Array] The list of items to be persisted
|
||||||
* @param type [String] The type of item to be persisted e.g. 'email'
|
* @param type [String] The type of item to be persisted e.g. 'email'
|
||||||
*/
|
*/
|
||||||
self.storeEcryptedList = function(list, type, callback) {
|
DeviceStorageDAO.prototype.storeEcryptedList = function(list, type, callback) {
|
||||||
var date, key, items = [];
|
var date, key, items = [];
|
||||||
|
|
||||||
// nothing to store
|
// nothing to store
|
||||||
@ -25,9 +34,10 @@ define(['cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-dao'], function(
|
|||||||
|
|
||||||
// format items for batch storing in dao
|
// format items for batch storing in dao
|
||||||
list.forEach(function(i) {
|
list.forEach(function(i) {
|
||||||
|
// put uid in key if available... for easy querying
|
||||||
// put date in key if available... for easy querying
|
if (i.uid) {
|
||||||
if (i.sentDate) {
|
key = type + '_' + i.uid;
|
||||||
|
} else if (i.sentDate) {
|
||||||
date = util.parseDate(i.sentDate);
|
date = util.parseDate(i.sentDate);
|
||||||
key = type + '_' + i.sentDate + '_' + i.id;
|
key = type + '_' + i.sentDate + '_' + i.id;
|
||||||
} else {
|
} else {
|
||||||
@ -38,7 +48,6 @@ define(['cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-dao'], function(
|
|||||||
key: key,
|
key: key,
|
||||||
object: i
|
object: i
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
jsonDao.batch(items, function() {
|
jsonDao.batch(items, function() {
|
||||||
@ -52,7 +61,7 @@ define(['cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-dao'], function(
|
|||||||
* @param offset [Number] The offset of items to fetch (0 is the last stored item)
|
* @param offset [Number] The offset of items to fetch (0 is the last stored item)
|
||||||
* @param num [Number] The number of items to fetch (null means fetch all)
|
* @param num [Number] The number of items to fetch (null means fetch all)
|
||||||
*/
|
*/
|
||||||
self.listEncryptedItems = function(type, offset, num, callback) {
|
DeviceStorageDAO.prototype.listEncryptedItems = function(type, offset, num, callback) {
|
||||||
// fetch all items of a certain type from the data-store
|
// fetch all items of a certain type from the data-store
|
||||||
jsonDao.list(type, offset, num, function(encryptedList) {
|
jsonDao.list(type, offset, num, function(encryptedList) {
|
||||||
|
|
||||||
@ -63,9 +72,9 @@ define(['cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-dao'], function(
|
|||||||
/**
|
/**
|
||||||
* Clear the whole device data-store
|
* Clear the whole device data-store
|
||||||
*/
|
*/
|
||||||
self.clear = function(callback) {
|
DeviceStorageDAO.prototype.clear = function(callback) {
|
||||||
jsonDao.clear(callback);
|
jsonDao.clear(callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
return self;
|
return DeviceStorageDAO;
|
||||||
});
|
});
|
@ -3,20 +3,20 @@ define(function(require) {
|
|||||||
|
|
||||||
var _ = require('underscore'),
|
var _ = require('underscore'),
|
||||||
util = require('cryptoLib/util'),
|
util = require('cryptoLib/util'),
|
||||||
crypto = require('js/crypto/crypto'),
|
|
||||||
jsonDB = require('js/dao/lawnchair-dao'),
|
|
||||||
str = require('js/app-config').string;
|
str = require('js/app-config').string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A high-level Data-Access Api for handling Email synchronization
|
* A high-level Data-Access Api for handling Email synchronization
|
||||||
* between the cloud service and the device's local storage
|
* between the cloud service and the device's local storage
|
||||||
*/
|
*/
|
||||||
var EmailDAO = function(keychain, imapClient, smtpClient) {
|
var EmailDAO = function(keychain, imapClient, smtpClient, crypto, devicestorage) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self._keychain = keychain;
|
self._keychain = keychain;
|
||||||
self._imapClient = imapClient;
|
self._imapClient = imapClient;
|
||||||
self._smtpClient = smtpClient;
|
self._smtpClient = smtpClient;
|
||||||
|
self._crypto = crypto;
|
||||||
|
self._devicestorage = devicestorage;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,8 +51,7 @@ define(function(require) {
|
|||||||
|
|
||||||
function initKeychain() {
|
function initKeychain() {
|
||||||
// init user's local database
|
// init user's local database
|
||||||
jsonDB.init(emailAddress);
|
self._devicestorage.init(emailAddress, function() {
|
||||||
|
|
||||||
// call getUserKeyPair to read/sync keypair with devicestorage/cloud
|
// call getUserKeyPair to read/sync keypair with devicestorage/cloud
|
||||||
self._keychain.getUserKeyPair(emailAddress, function(err, storedKeypair) {
|
self._keychain.getUserKeyPair(emailAddress, function(err, storedKeypair) {
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -62,10 +61,11 @@ define(function(require) {
|
|||||||
// init crypto
|
// init crypto
|
||||||
initCrypto(storedKeypair);
|
initCrypto(storedKeypair);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initCrypto(storedKeypair) {
|
function initCrypto(storedKeypair) {
|
||||||
crypto.init({
|
self._crypto.init({
|
||||||
emailAddress: emailAddress,
|
emailAddress: emailAddress,
|
||||||
password: password,
|
password: password,
|
||||||
keySize: self._account.symKeySize,
|
keySize: self._account.symKeySize,
|
||||||
@ -144,8 +144,11 @@ define(function(require) {
|
|||||||
|
|
||||||
// validate public key
|
// validate public key
|
||||||
if (!receiverPubkey) {
|
if (!receiverPubkey) {
|
||||||
|
callback({
|
||||||
|
errMsg: 'User has no public key yet!'
|
||||||
|
});
|
||||||
// user hasn't registered a public key yet... invite
|
// user hasn't registered a public key yet... invite
|
||||||
self.encryptForNewUser(email, callback);
|
//self.encryptForNewUser(email, callback);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +166,7 @@ define(function(require) {
|
|||||||
receiverPubkeys = [receiverPubkey];
|
receiverPubkeys = [receiverPubkey];
|
||||||
|
|
||||||
// encrypt the email
|
// encrypt the email
|
||||||
crypto.encryptListForUser(ptItems, receiverPubkeys, function(err, encryptedList) {
|
self._crypto.encryptListForUser(ptItems, receiverPubkeys, function(err, encryptedList) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
@ -183,7 +186,7 @@ define(function(require) {
|
|||||||
var self = this,
|
var self = this,
|
||||||
ptItems = bundleForEncryption(email);
|
ptItems = bundleForEncryption(email);
|
||||||
|
|
||||||
crypto.symEncryptList(ptItems, function(err, result) {
|
self._crypto.symEncryptList(ptItems, function(err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
@ -295,6 +298,168 @@ define(function(require) {
|
|||||||
self._imapClient.unreadMessages(path, callback);
|
self._imapClient.unreadMessages(path, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a list of emails from the device's local storage
|
||||||
|
*/
|
||||||
|
EmailDAO.prototype.listMessages = function(options, callback) {
|
||||||
|
var self = this,
|
||||||
|
encryptedList = [];
|
||||||
|
|
||||||
|
// validate options
|
||||||
|
if (!options.folder || typeof options.offset === 'undefined' || typeof options.num === 'undefined') {
|
||||||
|
callback({
|
||||||
|
errMsg: 'Invalid options!'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch items from device storage
|
||||||
|
self._devicestorage.listEncryptedItems('email_' + options.folder, options.offset, options.num, function(err, emails) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (emails.length === 0) {
|
||||||
|
callback(null, []);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find encrypted items
|
||||||
|
emails.forEach(function(i) {
|
||||||
|
if (i.body.indexOf(str.cryptPrefix) !== -1 && i.body.indexOf(str.cryptSuffix) !== -1) {
|
||||||
|
// parse ct object from ascii armored message block
|
||||||
|
encryptedList.push(parseMessageBlock(i));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// decrypt items
|
||||||
|
decryptList(encryptedList, function(err, decryptedList) {
|
||||||
|
// return only decrypted items
|
||||||
|
callback(null, decryptedList);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function parseMessageBlock(email) {
|
||||||
|
var ctMessageBase64, ctMessageJson, ctMessage;
|
||||||
|
|
||||||
|
// parse email body for encrypted message block
|
||||||
|
try {
|
||||||
|
// get base64 encoded message block
|
||||||
|
ctMessageBase64 = email.body.split(str.cryptPrefix)[1].split(str.cryptSuffix)[0].trim();
|
||||||
|
// decode bae64
|
||||||
|
ctMessageJson = atob(ctMessageBase64);
|
||||||
|
// parse json string to get ciphertext object
|
||||||
|
ctMessage = JSON.parse(ctMessageJson);
|
||||||
|
} catch (e) {
|
||||||
|
callback({
|
||||||
|
errMsg: 'Error parsing encrypted message block!'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decryptList(encryptedList, callback) {
|
||||||
|
var already, pubkeyIds = [];
|
||||||
|
|
||||||
|
// gather public key ids required to verify signatures
|
||||||
|
encryptedList.forEach(function(i) {
|
||||||
|
already = null;
|
||||||
|
already = _.findWhere(pubkeyIds, {
|
||||||
|
_id: i.senderPk
|
||||||
|
});
|
||||||
|
if (!already) {
|
||||||
|
pubkeyIds.push({
|
||||||
|
_id: i.senderPk
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// fetch public keys from keychain
|
||||||
|
self._keychain.getPublicKeys(pubkeyIds, function(err, senderPubkeys) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// verfiy signatures and re-encrypt item keys
|
||||||
|
self._crypto.decryptListForUser(encryptedList, senderPubkeys, function(err, decryptedList) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, decryptedList);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* High level sync operation for the delta from the user's IMAP inbox
|
||||||
|
*/
|
||||||
|
EmailDAO.prototype.imapSync = function(options, callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// validate options
|
||||||
|
if (!options.folder || typeof options.offset === 'undefined' || typeof options.num === 'undefined') {
|
||||||
|
callback({
|
||||||
|
errMsg: 'Invalid options!'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchList(options, function(emails) {
|
||||||
|
// persist encrypted list in device storage
|
||||||
|
self._devicestorage.storeEcryptedList(emails, 'email_' + options.folder, function() {
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function fetchList(folder, callback) {
|
||||||
|
// fetch imap folder's message list
|
||||||
|
self.imapListMessages({
|
||||||
|
folder: options.folder,
|
||||||
|
offset: options.offset,
|
||||||
|
num: options.num
|
||||||
|
}, function(err, emails) {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch message bodies
|
||||||
|
fetchBodies(emails, folder, function(messages) {
|
||||||
|
callback(messages);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchBodies(messageList, folder, callback) {
|
||||||
|
var emails = [];
|
||||||
|
|
||||||
|
var after = _.after(messageList.length, function() {
|
||||||
|
callback(emails);
|
||||||
|
});
|
||||||
|
|
||||||
|
_.each(messageList, function(messageItem) {
|
||||||
|
self.imapGetMessage({
|
||||||
|
folder: folder,
|
||||||
|
uid: messageItem.uid
|
||||||
|
}, function(err, message) {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emails.push(message);
|
||||||
|
after();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List messages from an imap folder. This will not yet fetch the email body.
|
* List messages from an imap folder. This will not yet fetch the email body.
|
||||||
* @param {String} options.folderName The name of the imap folder.
|
* @param {String} options.folderName The name of the imap folder.
|
||||||
@ -337,16 +502,6 @@ define(function(require) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try fetching from cache before doing a roundtrip
|
|
||||||
message = self.readCache(options.folder, options.uid);
|
|
||||||
if (message) {
|
|
||||||
// message was fetched from cache successfully
|
|
||||||
callback(null, message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* message was not found in cache... fetch from imap server */
|
|
||||||
|
|
||||||
function messageReady(err, gottenMessage) {
|
function messageReady(err, gottenMessage) {
|
||||||
message = gottenMessage;
|
message = gottenMessage;
|
||||||
itemCounter++;
|
itemCounter++;
|
||||||
@ -358,68 +513,12 @@ define(function(require) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrypt Message body
|
// return message
|
||||||
if (message.body.indexOf(str.cryptPrefix) !== -1 && message.body.indexOf(str.cryptSuffix) !== -1) {
|
|
||||||
decryptBody(message, function(err, ptMessage) {
|
|
||||||
message = ptMessage;
|
|
||||||
// return decrypted message
|
|
||||||
callback(err, message);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return unencrypted message
|
|
||||||
callback(null, message);
|
callback(null, message);
|
||||||
|
|
||||||
//check();
|
//check();
|
||||||
}
|
}
|
||||||
|
|
||||||
function decryptBody(email, callback) {
|
|
||||||
var ctMessageBase64, ctMessageJson, ctMessage, pubkeyIds;
|
|
||||||
|
|
||||||
// parse email body for encrypted message block
|
|
||||||
try {
|
|
||||||
// get base64 encoded message block
|
|
||||||
ctMessageBase64 = email.body.split(str.cryptPrefix)[1].split(str.cryptSuffix)[0].trim();
|
|
||||||
// decode bae64
|
|
||||||
ctMessageJson = atob(ctMessageBase64);
|
|
||||||
// parse json string to get ciphertext object
|
|
||||||
ctMessage = JSON.parse(ctMessageJson);
|
|
||||||
} catch (e) {
|
|
||||||
callback({
|
|
||||||
errMsg: 'Error parsing encrypted message block!'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// gather public key ids required to verify signatures
|
|
||||||
pubkeyIds = [{
|
|
||||||
_id: ctMessage.senderPk
|
|
||||||
}];
|
|
||||||
|
|
||||||
// fetch public keys from keychain
|
|
||||||
self._keychain.getPublicKeys(pubkeyIds, function(err, senderPubkeys) {
|
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// verfiy signatures and re-encrypt item keys
|
|
||||||
crypto.decryptListForUser([ctMessage], senderPubkeys, function(err, decryptedList) {
|
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var ptEmail = decryptedList[0];
|
|
||||||
email.body = ptEmail.body;
|
|
||||||
email.subject = ptEmail.subject;
|
|
||||||
|
|
||||||
callback(null, email);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// function attachmentReady(err, gottenAttachment) {
|
// function attachmentReady(err, gottenAttachment) {
|
||||||
// attachments.push(gottenAttachment);
|
// attachments.push(gottenAttachment);
|
||||||
// itemCounter++;
|
// itemCounter++;
|
||||||
|
@ -7,17 +7,22 @@ define(['lawnchair', 'lawnchairSQL', 'lawnchairIDB'], function(Lawnchair) {
|
|||||||
var self = {},
|
var self = {},
|
||||||
db;
|
db;
|
||||||
|
|
||||||
self.init = function(dbName) {
|
self.init = function(dbName, callback) {
|
||||||
|
var temp;
|
||||||
|
|
||||||
if (!dbName) {
|
if (!dbName) {
|
||||||
throw new Error('Lawnchair DB name must be specified!');
|
throw new Error('Lawnchair DB name must be specified!');
|
||||||
}
|
}
|
||||||
|
|
||||||
db = new Lawnchair({
|
temp = new Lawnchair({
|
||||||
name: dbName
|
name: dbName
|
||||||
}, function(lc) {
|
}, function(lc) {
|
||||||
if (!lc) {
|
if (!lc) {
|
||||||
throw new Error('Lawnchair init failed!');
|
throw new Error('Lawnchair init failed!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db = lc;
|
||||||
|
callback();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
6
src/lib/moment/moment.min.js
vendored
6
src/lib/moment/moment.min.js
vendored
File diff suppressed because one or more lines are too long
@ -5,7 +5,7 @@
|
|||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"offline_enabled": true,
|
"offline_enabled": true,
|
||||||
"icons": {
|
"icons": {
|
||||||
"128": "img/mail-128.png"
|
"128": "img/icon.png"
|
||||||
},
|
},
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"https://storage.whiteout.io/",
|
"https://storage.whiteout.io/",
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
angular: 'angular/angular.min',
|
angular: 'angular/angular.min',
|
||||||
angularRoute: 'angular/angular-route.min',
|
angularRoute: 'angular/angular-route.min',
|
||||||
angularTouch: 'angular/angular-touch.min',
|
angularTouch: 'angular/angular-touch.min',
|
||||||
moment: 'moment/moment.min',
|
|
||||||
uuid: 'uuid/uuid'
|
uuid: 'uuid/uuid'
|
||||||
},
|
},
|
||||||
shim: {
|
shim: {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<h3>{{email.from[0].name || email.from[0].address}}</h3>
|
<h3>{{email.from[0].name || email.from[0].address}}</h3>
|
||||||
<div class="head">
|
<div class="head">
|
||||||
<p class="subject">{{email.subject}}</p>
|
<p class="subject">{{email.subject}}</p>
|
||||||
<time>{{email.displayDate}}</time>
|
<time>{{email.sentDate | date:'mediumDate'}}</time>
|
||||||
</div>
|
</div>
|
||||||
<p class="body">{{email.body}}</p>
|
<p class="body">{{email.body}}</p>
|
||||||
</li>
|
</li>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<div class="view-read">
|
<div class="view-read">
|
||||||
<div class="headers">
|
<div class="headers">
|
||||||
<p class="subject">{{selected.subject}}</p>
|
<p class="subject">{{selected.subject}}</p>
|
||||||
<p class="date">{{selected.longDisplayDate}}</p>
|
<p class="date">{{selected.sentDate | date:'EEEE, MMM d, yyyy h:mm a'}}</p>
|
||||||
<p class="address">From: <span class="label">{{selected.from[0].name || selected.from[0].address}}</span></p>
|
<p class="address">From: <span class="label">{{selected.from[0].name || selected.from[0].address}}</span></p>
|
||||||
<p class="address">To: <span class="label" ng-repeat="t in selected.to">{{t.address}} </span></p>
|
<p class="address">To: <span class="label" ng-repeat="t in selected.to">{{t.address}} </span></p>
|
||||||
<div ng-switch="selected.cc !== undefined">
|
<div ng-switch="selected.cc !== undefined">
|
||||||
|
@ -3,8 +3,10 @@ define(function(require) {
|
|||||||
|
|
||||||
var KeychainDAO = require('js/dao/keychain-dao'),
|
var KeychainDAO = require('js/dao/keychain-dao'),
|
||||||
EmailDAO = require('js/dao/email-dao'),
|
EmailDAO = require('js/dao/email-dao'),
|
||||||
|
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
|
||||||
SmtpClient = require('smtp-client'),
|
SmtpClient = require('smtp-client'),
|
||||||
ImapClient = require('imap-client'),
|
ImapClient = require('imap-client'),
|
||||||
|
Crypto = require('js/crypto/crypto'),
|
||||||
app = require('js/app-config'),
|
app = require('js/app-config'),
|
||||||
expect = chai.expect;
|
expect = chai.expect;
|
||||||
|
|
||||||
@ -19,12 +21,12 @@ define(function(require) {
|
|||||||
var publicKey = "-----BEGIN PUBLIC KEY-----\r\n" + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxy+Te5dyeWd7g0P+8LNO7fZDQ\r\n" + "g96xTb1J6pYE/pPTMlqhB6BRItIYjZ1US5q2vk5Zk/5KasBHAc9RbCqvh9v4XFEY\r\n" + "JVmTXC4p8ft1LYuNWIaDk+R3dyYXmRNct/JC4tks2+8fD3aOvpt0WNn3R75/FGBt\r\n" + "h4BgojAXDE+PRQtcVQIDAQAB\r\n" + "-----END PUBLIC KEY-----";
|
var publicKey = "-----BEGIN PUBLIC KEY-----\r\n" + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxy+Te5dyeWd7g0P+8LNO7fZDQ\r\n" + "g96xTb1J6pYE/pPTMlqhB6BRItIYjZ1US5q2vk5Zk/5KasBHAc9RbCqvh9v4XFEY\r\n" + "JVmTXC4p8ft1LYuNWIaDk+R3dyYXmRNct/JC4tks2+8fD3aOvpt0WNn3R75/FGBt\r\n" + "h4BgojAXDE+PRQtcVQIDAQAB\r\n" + "-----END PUBLIC KEY-----";
|
||||||
|
|
||||||
describe('Email DAO unit tests', function() {
|
describe('Email DAO unit tests', function() {
|
||||||
this.timeout(20000);
|
|
||||||
|
|
||||||
var emailDao, account,
|
var emailDao, account,
|
||||||
keychainStub, imapClientStub, smtpClientStub;
|
keychainStub, imapClientStub, smtpClientStub, cryptoStub, devicestorageStub;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
// init dummy object
|
||||||
dummyMail = {
|
dummyMail = {
|
||||||
from: [{
|
from: [{
|
||||||
name: 'Whiteout Test',
|
name: 'Whiteout Test',
|
||||||
@ -47,8 +49,10 @@ define(function(require) {
|
|||||||
keychainStub = sinon.createStubInstance(KeychainDAO);
|
keychainStub = sinon.createStubInstance(KeychainDAO);
|
||||||
imapClientStub = sinon.createStubInstance(ImapClient);
|
imapClientStub = sinon.createStubInstance(ImapClient);
|
||||||
smtpClientStub = sinon.createStubInstance(SmtpClient);
|
smtpClientStub = sinon.createStubInstance(SmtpClient);
|
||||||
|
cryptoStub = sinon.createStubInstance(Crypto);
|
||||||
|
devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
|
||||||
|
|
||||||
emailDao = new EmailDAO(keychainStub, imapClientStub, smtpClientStub);
|
emailDao = new EmailDAO(keychainStub, imapClientStub, smtpClientStub, cryptoStub, devicestorageStub);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {});
|
afterEach(function() {});
|
||||||
@ -65,9 +69,11 @@ define(function(require) {
|
|||||||
|
|
||||||
it('should fail due to error in getUserKeyPair', function(done) {
|
it('should fail due to error in getUserKeyPair', function(done) {
|
||||||
imapClientStub.login.yields();
|
imapClientStub.login.yields();
|
||||||
|
devicestorageStub.init.yields();
|
||||||
keychainStub.getUserKeyPair.yields(42);
|
keychainStub.getUserKeyPair.yields(42);
|
||||||
|
|
||||||
emailDao.init(account, emaildaoTest.passphrase, function(err) {
|
emailDao.init(account, emaildaoTest.passphrase, function(err) {
|
||||||
|
expect(devicestorageStub.init.calledOnce).to.be.true;
|
||||||
expect(imapClientStub.login.calledOnce).to.be.true;
|
expect(imapClientStub.login.calledOnce).to.be.true;
|
||||||
expect(err).to.equal(42);
|
expect(err).to.equal(42);
|
||||||
done();
|
done();
|
||||||
@ -76,12 +82,16 @@ define(function(require) {
|
|||||||
|
|
||||||
it('should init with new keygen', function(done) {
|
it('should init with new keygen', function(done) {
|
||||||
imapClientStub.login.yields();
|
imapClientStub.login.yields();
|
||||||
|
devicestorageStub.init.yields();
|
||||||
keychainStub.getUserKeyPair.yields();
|
keychainStub.getUserKeyPair.yields();
|
||||||
|
cryptoStub.init.yields(null, {});
|
||||||
keychainStub.putUserKeyPair.yields();
|
keychainStub.putUserKeyPair.yields();
|
||||||
|
|
||||||
emailDao.init(account, emaildaoTest.passphrase, function(err) {
|
emailDao.init(account, emaildaoTest.passphrase, function(err) {
|
||||||
expect(imapClientStub.login.calledOnce).to.be.true;
|
expect(imapClientStub.login.calledOnce).to.be.true;
|
||||||
|
expect(devicestorageStub.init.calledOnce).to.be.true;
|
||||||
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
||||||
|
expect(cryptoStub.init.calledOnce).to.be.true;
|
||||||
expect(keychainStub.putUserKeyPair.calledOnce).to.be.true;
|
expect(keychainStub.putUserKeyPair.calledOnce).to.be.true;
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
done();
|
done();
|
||||||
@ -92,12 +102,16 @@ define(function(require) {
|
|||||||
describe('IMAP/SMTP tests', function() {
|
describe('IMAP/SMTP tests', function() {
|
||||||
beforeEach(function(done) {
|
beforeEach(function(done) {
|
||||||
imapClientStub.login.yields();
|
imapClientStub.login.yields();
|
||||||
|
devicestorageStub.init.yields();
|
||||||
keychainStub.getUserKeyPair.yields();
|
keychainStub.getUserKeyPair.yields();
|
||||||
|
cryptoStub.init.yields(null, {});
|
||||||
keychainStub.putUserKeyPair.yields();
|
keychainStub.putUserKeyPair.yields();
|
||||||
|
|
||||||
emailDao.init(account, emaildaoTest.passphrase, function(err) {
|
emailDao.init(account, emaildaoTest.passphrase, function(err) {
|
||||||
expect(imapClientStub.login.calledOnce).to.be.true;
|
expect(imapClientStub.login.calledOnce).to.be.true;
|
||||||
|
expect(devicestorageStub.init.calledOnce).to.be.true;
|
||||||
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
||||||
|
expect(cryptoStub.init.calledOnce).to.be.true;
|
||||||
expect(keychainStub.putUserKeyPair.calledOnce).to.be.true;
|
expect(keychainStub.putUserKeyPair.calledOnce).to.be.true;
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
done();
|
done();
|
||||||
@ -141,11 +155,11 @@ define(function(require) {
|
|||||||
|
|
||||||
emailDao.smtpSend(dummyMail, function(err) {
|
emailDao.smtpSend(dummyMail, function(err) {
|
||||||
expect(keychainStub.getReveiverPublicKey.calledOnce).to.be.true;
|
expect(keychainStub.getReveiverPublicKey.calledOnce).to.be.true;
|
||||||
expect(smtpClientStub.send.calledOnce).to.be.true;
|
// expect(smtpClientStub.send.called).to.be.true;
|
||||||
smtpClientStub.send.calledWith(sinon.match(function(o) {
|
// smtpClientStub.send.calledWith(sinon.match(function(o) {
|
||||||
return typeof o.attachments === 'undefined';
|
// return typeof o.attachments === 'undefined';
|
||||||
}));
|
// }));
|
||||||
expect(err).to.not.exist;
|
expect(err).to.exist;
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -157,6 +171,7 @@ define(function(require) {
|
|||||||
publicKey: publicKey
|
publicKey: publicKey
|
||||||
});
|
});
|
||||||
smtpClientStub.send.yields();
|
smtpClientStub.send.yields();
|
||||||
|
cryptoStub.encryptListForUser.yields(null, []);
|
||||||
|
|
||||||
emailDao.smtpSend(dummyMail, function(err) {
|
emailDao.smtpSend(dummyMail, function(err) {
|
||||||
expect(keychainStub.getReveiverPublicKey.calledOnce).to.be.true;
|
expect(keychainStub.getReveiverPublicKey.calledOnce).to.be.true;
|
||||||
@ -181,6 +196,7 @@ define(function(require) {
|
|||||||
publicKey: publicKey
|
publicKey: publicKey
|
||||||
});
|
});
|
||||||
smtpClientStub.send.yields();
|
smtpClientStub.send.yields();
|
||||||
|
cryptoStub.encryptListForUser.yields(null, [{}, {}]);
|
||||||
|
|
||||||
emailDao.smtpSend(dummyMail, function(err) {
|
emailDao.smtpSend(dummyMail, function(err) {
|
||||||
expect(keychainStub.getReveiverPublicKey.calledOnce).to.be.true;
|
expect(keychainStub.getReveiverPublicKey.calledOnce).to.be.true;
|
||||||
@ -344,6 +360,61 @@ define(function(require) {
|
|||||||
// });
|
// });
|
||||||
// });
|
// });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('IMAP: sync messages to local storage', function() {
|
||||||
|
it('should work', function(done) {
|
||||||
|
imapClientStub.listMessages.yields(null, [{
|
||||||
|
uid: 413,
|
||||||
|
}, {
|
||||||
|
uid: 414,
|
||||||
|
}]);
|
||||||
|
imapClientStub.getMessage.yields(null, {
|
||||||
|
body: 'asdf'
|
||||||
|
});
|
||||||
|
devicestorageStub.storeEcryptedList.yields();
|
||||||
|
|
||||||
|
emailDao.imapSync({
|
||||||
|
folder: 'INBOX',
|
||||||
|
offset: 0,
|
||||||
|
num: 2
|
||||||
|
}, function(err) {
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
expect(imapClientStub.listMessages.calledOnce).to.be.true;
|
||||||
|
expect(imapClientStub.getMessage.calledTwice).to.be.true;
|
||||||
|
expect(devicestorageStub.storeEcryptedList.calledOnce).to.be.true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('IMAP: list messages from local storage', function() {
|
||||||
|
it('should work', function(done) {
|
||||||
|
|
||||||
|
devicestorageStub.listEncryptedItems.yields(null, [{
|
||||||
|
body: ''
|
||||||
|
}]);
|
||||||
|
keychainStub.getPublicKeys.yields(null, [{
|
||||||
|
_id: "fcf8b4aa-5d09-4089-8b4f-e3bc5091daf3",
|
||||||
|
userId: "safewithme.testuser@gmail.com",
|
||||||
|
publicKey: publicKey
|
||||||
|
}]);
|
||||||
|
cryptoStub.decryptListForUser.yields(null, []);
|
||||||
|
|
||||||
|
emailDao.listMessages({
|
||||||
|
folder: 'INBOX',
|
||||||
|
offset: 0,
|
||||||
|
num: 2
|
||||||
|
}, function(err, emails) {
|
||||||
|
expect(devicestorageStub.listEncryptedItems.calledOnce).to.be.true;
|
||||||
|
expect(keychainStub.getPublicKeys.calledOnce).to.be.true;
|
||||||
|
expect(cryptoStub.decryptListForUser.calledOnce).to.be.true;
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
expect(emails.length).to.equal(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
define(['js/crypto/crypto', 'cryptoLib/util', 'test/test-data'], function(crypto, util, testData) {
|
define(['js/crypto/crypto', 'cryptoLib/util', 'test/test-data'], function(Crypto, util, testData) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module("Crypto Api");
|
module("Crypto Api");
|
||||||
@ -11,7 +11,10 @@ define(['js/crypto/crypto', 'cryptoLib/util', 'test/test-data'], function(crypto
|
|||||||
rsaKeySize: 1024
|
rsaKeySize: 1024
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var crypto;
|
||||||
|
|
||||||
asyncTest("Init without keypair", 4, function() {
|
asyncTest("Init without keypair", 4, function() {
|
||||||
|
crypto = new Crypto();
|
||||||
// init dependencies
|
// init dependencies
|
||||||
ok(crypto, 'Crypto');
|
ok(crypto, 'Crypto');
|
||||||
|
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
define(['underscore', 'cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-dao',
|
define(['underscore', 'cryptoLib/util', 'js/crypto/crypto', 'js/dao/devicestorage-dao', 'test/test-data'], function(_, util, Crypto, DeviceStorageDAO, testData) {
|
||||||
'js/dao/devicestorage-dao', 'test/test-data'
|
|
||||||
], function(_, util, crypto, jsonDao, storage, testData) {
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module("DeviceStorage");
|
module("DeviceStorage");
|
||||||
@ -13,15 +11,19 @@ define(['underscore', 'cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-da
|
|||||||
rsaKeySize: 1024
|
rsaKeySize: 1024
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var crypto, storage;
|
||||||
|
|
||||||
asyncTest("Init", 3, function() {
|
asyncTest("Init", 3, function() {
|
||||||
// init dependencies
|
// init dependencies
|
||||||
jsonDao.init(devicestorageTest.user);
|
storage = new DeviceStorageDAO();
|
||||||
|
storage.init(devicestorageTest.user, function() {
|
||||||
ok(storage, 'DeviceStorageDAO');
|
ok(storage, 'DeviceStorageDAO');
|
||||||
|
|
||||||
// generate test data
|
// generate test data
|
||||||
devicestorageTest.list = testData.getEmailCollection(100);
|
devicestorageTest.list = testData.getEmailCollection(100);
|
||||||
|
|
||||||
// init crypto
|
// init crypto
|
||||||
|
crypto = new Crypto();
|
||||||
crypto.init({
|
crypto.init({
|
||||||
emailAddress: devicestorageTest.user,
|
emailAddress: devicestorageTest.user,
|
||||||
password: devicestorageTest.password,
|
password: devicestorageTest.password,
|
||||||
@ -32,7 +34,7 @@ define(['underscore', 'cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-da
|
|||||||
devicestorageTest.generatedKeypair = generatedKeypair;
|
devicestorageTest.generatedKeypair = generatedKeypair;
|
||||||
|
|
||||||
// clear db before tests
|
// clear db before tests
|
||||||
jsonDao.clear(function(err) {
|
storage.clear(function(err) {
|
||||||
ok(!err, 'DB cleared. Error status: ' + err);
|
ok(!err, 'DB cleared. Error status: ' + err);
|
||||||
|
|
||||||
start();
|
start();
|
||||||
@ -40,6 +42,7 @@ define(['underscore', 'cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-da
|
|||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
asyncTest("Encrypt list for user", 2, function() {
|
asyncTest("Encrypt list for user", 2, function() {
|
||||||
var receiverPubkeys = [devicestorageTest.generatedKeypair.publicKey];
|
var receiverPubkeys = [devicestorageTest.generatedKeypair.publicKey];
|
||||||
|
@ -28,13 +28,14 @@ define(['js/dao/keychain-dao', 'js/dao/lawnchair-dao'], function(KeychainDAO, js
|
|||||||
ok(keychaindaoTest.keychainDao);
|
ok(keychaindaoTest.keychainDao);
|
||||||
|
|
||||||
// init and clear db before test
|
// init and clear db before test
|
||||||
jsonDao.init(keychaindaoTest.user);
|
jsonDao.init(keychaindaoTest.user, function() {
|
||||||
jsonDao.clear(function() {
|
jsonDao.clear(function() {
|
||||||
ok(true, 'cleared db');
|
ok(true, 'cleared db');
|
||||||
|
|
||||||
start();
|
start();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
asyncTest("Put User Keypair", 1, function() {
|
asyncTest("Put User Keypair", 1, function() {
|
||||||
|
|
||||||
@ -71,8 +72,7 @@ define(['js/dao/keychain-dao', 'js/dao/lawnchair-dao'], function(KeychainDAO, js
|
|||||||
asyncTest("Get Public Keys", 2, function() {
|
asyncTest("Get Public Keys", 2, function() {
|
||||||
var pubkeyIds = [{
|
var pubkeyIds = [{
|
||||||
_id: keychaindaoTest.keypair.publicKey._id
|
_id: keychaindaoTest.keypair.publicKey._id
|
||||||
}
|
}];
|
||||||
];
|
|
||||||
keychaindaoTest.keychainDao.getPublicKeys(pubkeyIds, function(err, pubkeys) {
|
keychaindaoTest.keychainDao.getPublicKeys(pubkeyIds, function(err, pubkeys) {
|
||||||
ok(!err);
|
ok(!err);
|
||||||
deepEqual(pubkeys[0], keychaindaoTest.keypair.publicKey, "Fetch public key");
|
deepEqual(pubkeys[0], keychaindaoTest.keypair.publicKey, "Fetch public key");
|
||||||
|
@ -9,8 +9,8 @@ define(['js/dao/lawnchair-dao'], function(jsonDao) {
|
|||||||
|
|
||||||
asyncTest("Init", 2, function() {
|
asyncTest("Init", 2, function() {
|
||||||
// init dependencies
|
// init dependencies
|
||||||
jsonDao.init(lawnchairdaoTest.user);
|
jsonDao.init(lawnchairdaoTest.user, function() {
|
||||||
ok(jsonDao, 'LanwchairDAO');
|
ok(true, 'init db');
|
||||||
|
|
||||||
// clear db before test
|
// clear db before test
|
||||||
jsonDao.clear(function() {
|
jsonDao.clear(function() {
|
||||||
@ -19,6 +19,7 @@ define(['js/dao/lawnchair-dao'], function(jsonDao) {
|
|||||||
start();
|
start();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
asyncTest("CRUD object literal", 4, function() {
|
asyncTest("CRUD object literal", 4, function() {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user