mirror of
https://github.com/moparisthebest/mail
synced 2025-02-16 15:10:10 -05:00
finished refactoring email dao for unit tests
This commit is contained in:
parent
0fb0e7c1e7
commit
dca3b252ce
@ -16,21 +16,22 @@ app.dao.DeviceStorage = function(util, crypto, jsonDao, sqlcipherDao) {
|
||||
var i, date, key, items = [];
|
||||
|
||||
// format items for batch storing in dao
|
||||
for (i = 0; i < list.length; i++) {
|
||||
list.forEach(function(i) {
|
||||
|
||||
// put date in key if available... for easy querying
|
||||
if (list[i].sentDate) {
|
||||
date = util.parseDate(list[i].sentDate);
|
||||
key = crypto.emailAddress + '_' + type + '_' + date.getTime() + '_' + list[i].id;
|
||||
if (i.sentDate) {
|
||||
date = util.parseDate(i.sentDate);
|
||||
key = crypto.emailAddress + '_' + type + '_' + date.getTime() + '_' + i.id;
|
||||
} else {
|
||||
key = crypto.emailAddress + '_' + type + '_' + list[i].id;
|
||||
key = crypto.emailAddress + '_' + type + '_' + i.id;
|
||||
}
|
||||
|
||||
items.push({
|
||||
key: key,
|
||||
object: list[i]
|
||||
object: i
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
jsonDao.batch(items, function() {
|
||||
callback();
|
||||
@ -38,20 +39,16 @@ app.dao.DeviceStorage = function(util, crypto, jsonDao, sqlcipherDao) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Decrypts the stored items of a given type and returns them
|
||||
* List stored items of a given type
|
||||
* @param type [String] The type of item e.g. 'email'
|
||||
* @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)
|
||||
*/
|
||||
this.listItems = function(type, offset, num, senderPubkeys, callback) {
|
||||
|
||||
this.listEncryptedItems = function(type, offset, num, callback) {
|
||||
// fetch all items of a certain type from the data-store
|
||||
jsonDao.list(crypto.emailAddress + '_' + type, offset, num, function(encryptedList) {
|
||||
|
||||
// decrypt list
|
||||
crypto.decryptListForUser(encryptedList, senderPubkeys, function(err, decryptedList) {
|
||||
callback(err, decryptedList);
|
||||
});
|
||||
callback(null, encryptedList);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* A high-level Data-Access Api for handling Email synchronization
|
||||
* between the cloud service and the device's local storage
|
||||
*/
|
||||
app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util) {
|
||||
app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util, keychain) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
@ -11,54 +11,46 @@ app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util) {
|
||||
this.init = function(account, password, callback) {
|
||||
this.account = account;
|
||||
|
||||
// TODO: call getUserKeyPair to read/sync keypair with devicestorage/cloud
|
||||
|
||||
// sync user's cloud key with local storage
|
||||
var storedKey = crypto.getEncryptedPrivateKey(account.get('emailAddress'));
|
||||
cloudstorage.syncPrivateKey(account.get('emailAddress'), storedKey, function(err) {
|
||||
// call getUserKeyPair to read/sync keypair with devicestorage/cloud
|
||||
keychain.getUserKeyPair(account.get('emailAddress'), function(err, storedKeypair) {
|
||||
if (err) {
|
||||
console.log('Error syncing private key to cloud: ' + err);
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
// init crypto
|
||||
initCrypto();
|
||||
initCrypto(storedKeypair);
|
||||
|
||||
}, function(fetchedKey) {
|
||||
// replace local key with cloud key
|
||||
crypto.putEncryptedPrivateKey(fetchedKey);
|
||||
// whipe local storage
|
||||
}, function(err, keypairReplacement) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
// whipe local storage in case local keypair was replaced with cloud keypair
|
||||
devicestorage.clear(function() {
|
||||
initCrypto();
|
||||
// init crypto and generate new keypair
|
||||
initCrypto(keypairReplacement);
|
||||
});
|
||||
});
|
||||
|
||||
function initCrypto() {
|
||||
|
||||
// TODO: passed fetched keypair from keychain dao
|
||||
|
||||
function initCrypto(storedKeypair) {
|
||||
crypto.init({
|
||||
emailAddress: account.get('emailAddress'),
|
||||
password: password,
|
||||
keySize: account.get('symKeySize'),
|
||||
rsaKeySize: account.get('asymKeySize')
|
||||
}, function(err) {
|
||||
rsaKeySize: account.get('asymKeySize'),
|
||||
storedKeypair: storedKeypair
|
||||
}, function(err, generatedKeypair) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
publishPublicKey();
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: refactor to be part of sync in getUserKeypair
|
||||
|
||||
function publishPublicKey() {
|
||||
// get public key from crypto
|
||||
var pubkey = crypto.getPublicKey();
|
||||
|
||||
//publish public key to cloud service
|
||||
cloudstorage.putPublicKey(pubkey, function(err) {
|
||||
callback(err);
|
||||
if (generatedKeypair) {
|
||||
// persist newly generated keypair
|
||||
keychain.putUserKeyPair(generatedKeypair, callback);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -82,7 +74,8 @@ app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util) {
|
||||
* @param num [Number] The number of items to fetch (null means fetch all)
|
||||
*/
|
||||
this.listItems = function(folderName, offset, num, callback) {
|
||||
var collection, folder, self = this;
|
||||
var collection, folder, already, pubkeyIds = [],
|
||||
self = this;
|
||||
|
||||
// check if items are in memory already (account.folders model)
|
||||
folder = this.account.get('folders').where({
|
||||
@ -90,26 +83,56 @@ app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util) {
|
||||
})[0];
|
||||
|
||||
if (!folder) {
|
||||
// get items from storage
|
||||
devicestorage.listItems('email_' + folderName, offset, num, null, function(err, decryptedList) {
|
||||
// get encrypted items from storage
|
||||
devicestorage.listEncryptedItems('email_' + folderName, offset, num, function(err, encryptedList) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// parse to backbone model collection
|
||||
collection = new app.model.EmailCollection(decryptedList);
|
||||
|
||||
// cache collection in folder memory
|
||||
if (decryptedList.length > 0) {
|
||||
folder = new app.model.Folder({
|
||||
name: folderName
|
||||
// gather public key ids required to verify signatures
|
||||
encryptedList.forEach(function(i) {
|
||||
already = null;
|
||||
already = _.findWhere(pubkeyIds, {
|
||||
_id: i.senderPk
|
||||
});
|
||||
folder.set('items', collection);
|
||||
self.account.get('folders').add(folder);
|
||||
}
|
||||
if (!already) {
|
||||
pubkeyIds.push({
|
||||
_id: i.senderPk
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
callback(null, collection);
|
||||
// fetch public keys from keychain
|
||||
keychain.getPublicKeys(pubkeyIds, function(err, senderPubkeys) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// decrypt list
|
||||
crypto.decryptListForUser(encryptedList, senderPubkeys, function(err, decryptedList) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// parse to backbone model collection
|
||||
collection = new app.model.EmailCollection(decryptedList);
|
||||
|
||||
// cache collection in folder memory
|
||||
if (decryptedList.length > 0) {
|
||||
folder = new app.model.Folder({
|
||||
name: folderName
|
||||
});
|
||||
folder.set('items', collection);
|
||||
self.account.get('folders').add(folder);
|
||||
}
|
||||
|
||||
callback(null, collection);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
} else {
|
||||
|
@ -12,32 +12,59 @@ app.dao.KeychainDAO = function(jsonDao, cloudstorage) {
|
||||
* @return [PublicKeyCollection] The requiested public keys
|
||||
*/
|
||||
this.getPublicKeys = function(ids, callback) {
|
||||
var already, pubkeys = [];
|
||||
|
||||
var after = _.after(ids.length, function() {
|
||||
callback(null, pubkeys);
|
||||
});
|
||||
|
||||
_.each(ids, function(i) {
|
||||
// try to read public key from local storage
|
||||
jsonDao.read('publickey_' + i._id, function(pubkey) {
|
||||
if (!pubkey) {
|
||||
// TODO: fetch from cloud storage
|
||||
callback({
|
||||
errMsg: 'Not implemented yet!'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// check if public key with that id has already been fetched
|
||||
already = null;
|
||||
already = _.findWhere(pubkeys, {
|
||||
_id: i._id
|
||||
});
|
||||
if (!already) {
|
||||
pubkeys.push(pubkey);
|
||||
}
|
||||
|
||||
after(); // asynchronously iterate through objects
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the local user's key either from local storage
|
||||
* or syncronizes from the cloud. The private key is encrypted.
|
||||
* or fetches it from the cloud. The private key is encrypted.
|
||||
* If no key pair exists, null is returned.
|
||||
* return [Object] The user's key pair {publicKey, privateKey}
|
||||
*/
|
||||
this.getUserKeyPair = function(userId, callback) {
|
||||
// loojup public key id
|
||||
// lookup public key id
|
||||
jsonDao.read('publickey_' + userId, function(pubkeyId) {
|
||||
if (!pubkeyId || !pubkeyId._id) {
|
||||
// no public key in storage
|
||||
// TODO: fetch from cloud
|
||||
// TODO: persist in local storage
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// try to read public key from local storage
|
||||
jsonDao.read('publickey_' + pubkeyId._id, function(pubkey) {
|
||||
if (!pubkey) {
|
||||
// no public key in storage
|
||||
// TODO: fetch from cloud
|
||||
// TODO: persist in local storage
|
||||
callback({
|
||||
errMsg: 'Not implemented yet!'
|
||||
});
|
||||
} else {
|
||||
// public key found
|
||||
// get corresponding private key
|
||||
fetchEncryptedPrivateKey(pubkey);
|
||||
}
|
||||
// public key found
|
||||
// get corresponding private key
|
||||
fetchEncryptedPrivateKey(pubkey);
|
||||
});
|
||||
});
|
||||
|
||||
@ -76,6 +103,8 @@ app.dao.KeychainDAO = function(jsonDao, cloudstorage) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: persist in the cloud
|
||||
|
||||
// persist public key (email, _id)
|
||||
var pkLookupKey = 'publickey_' + keypair.publicKey.userId;
|
||||
jsonDao.persist(pkLookupKey, {
|
||||
|
@ -59,28 +59,33 @@ asyncTest("Store encrypted list", 1, function() {
|
||||
});
|
||||
});
|
||||
|
||||
asyncTest("List items", 3, function() {
|
||||
asyncTest("List items", 4, function() {
|
||||
|
||||
var senderPubkeys = [devicestorage_test.generatedKeypair.publicKey];
|
||||
|
||||
var offset = 2,
|
||||
num = 6;
|
||||
|
||||
// list items from storage (decrypted)
|
||||
devicestorage_test.storage.listItems('email_inbox_5', offset, num, senderPubkeys, function(err, decryptedList) {
|
||||
// list encrypted items from storage
|
||||
devicestorage_test.storage.listEncryptedItems('email_inbox_5', offset, num, function(err, encryptedList) {
|
||||
ok(!err);
|
||||
equal(decryptedList.length, num, 'Found ' + decryptedList.length + ' items in store (and decrypted)');
|
||||
|
||||
var decrypted, orig = devicestorage_test.list[54];
|
||||
// decrypt list
|
||||
devicestorage_test.crypto.decryptListForUser(encryptedList, senderPubkeys, function(err, decryptedList) {
|
||||
ok(!err);
|
||||
equal(decryptedList.length, num, 'Found ' + decryptedList.length + ' items in store (and decrypted)');
|
||||
|
||||
// check ids
|
||||
for (var i = 0; i < decryptedList.length; i++) {
|
||||
if (decryptedList[i].id === orig.id && decryptedList[i].from === orig.from) {
|
||||
deepEqual(decryptedList[i], orig, 'Messages decrypted correctly');
|
||||
break;
|
||||
var decrypted, orig = devicestorage_test.list[54];
|
||||
|
||||
// check ids
|
||||
for (var i = 0; i < decryptedList.length; i++) {
|
||||
if (decryptedList[i].id === orig.id && decryptedList[i].from === orig.from) {
|
||||
deepEqual(decryptedList[i], orig, 'Messages decrypted correctly');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start();
|
||||
start();
|
||||
});
|
||||
});
|
||||
});
|
@ -23,7 +23,8 @@ asyncTest("Init", 3, function() {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
emaildao_test.emailDao = new app.dao.EmailDAO(_, emaildao_test.crypto, emaildao_test.storage, cloudstorageStub, util);
|
||||
emaildao_test.keychain = new app.dao.KeychainDAO(jsonDao, cloudstorageStub);
|
||||
emaildao_test.emailDao = new app.dao.EmailDAO(_, emaildao_test.crypto, emaildao_test.storage, cloudstorageStub, util, emaildao_test.keychain);
|
||||
|
||||
// generate test data
|
||||
emaildao_test.list = new TestData().getEmailCollection(100);
|
||||
@ -35,33 +36,39 @@ asyncTest("Init", 3, function() {
|
||||
asymKeySize: emaildao_test.rsaKeySize
|
||||
});
|
||||
|
||||
emaildao_test.emailDao.init(account, emaildao_test.password, function(err) {
|
||||
ok(!err);
|
||||
equal(emaildao_test.emailDao.account.get('emailAddress'), emaildao_test.user, 'Email DAO Account');
|
||||
// clear db before tests
|
||||
jsonDao.clear(function(err) {
|
||||
ok(!err, 'DB cleared. Error status: ' + err);
|
||||
|
||||
// clear db before tests
|
||||
jsonDao.clear(function(err) {
|
||||
ok(!err, 'DB cleared. Error status: ' + err);
|
||||
emaildao_test.emailDao.init(account, emaildao_test.password, function(err) {
|
||||
ok(!err);
|
||||
equal(emaildao_test.emailDao.account.get('emailAddress'), emaildao_test.user, 'Email DAO Account');
|
||||
|
||||
start();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
asyncTest("Persist test emails", 3, function() {
|
||||
emaildao_test.crypto.encryptListForUser(emaildao_test.list.toJSON(), null, function(err, encryptedList) {
|
||||
ok(!err);
|
||||
equal(encryptedList.length, emaildao_test.list.length, 'Encrypt list');
|
||||
asyncTest("Persist test emails", 4, function() {
|
||||
emaildao_test.keychain.getUserKeyPair(emaildao_test.user, function(err, keypair) {
|
||||
ok(!err && keypair, 'Fetch keypair from keychain');
|
||||
|
||||
// add sent date to encrypted items
|
||||
for (var i = 0; i < encryptedList.length; i++) {
|
||||
encryptedList[i].sentDate = emaildao_test.list.at(i).get('sentDate');
|
||||
}
|
||||
var receiverPubkeys = [keypair.publicKey];
|
||||
|
||||
emaildao_test.storage.storeEcryptedList(encryptedList, 'email_inbox', function() {
|
||||
ok(true, 'Store encrypted list');
|
||||
emaildao_test.crypto.encryptListForUser(emaildao_test.list.toJSON(), receiverPubkeys, function(err, encryptedList) {
|
||||
ok(!err);
|
||||
equal(encryptedList.length, emaildao_test.list.length, 'Encrypt list');
|
||||
|
||||
start();
|
||||
// add sent date to encrypted items
|
||||
for (var i = 0; i < encryptedList.length; i++) {
|
||||
encryptedList[i].sentDate = emaildao_test.list.at(i).get('sentDate');
|
||||
}
|
||||
|
||||
emaildao_test.storage.storeEcryptedList(encryptedList, 'email_inbox', function() {
|
||||
ok(true, 'Store encrypted list');
|
||||
|
||||
start();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -66,6 +66,14 @@ asyncTest("Get User Keypair", 2, function() {
|
||||
});
|
||||
});
|
||||
|
||||
// asyncTest("Get Public Keys", 1, function() {
|
||||
asyncTest("Get Public Keys", 2, function() {
|
||||
var pubkeyIds = [{
|
||||
_id: keychaindao_test.keypair.publicKey._id
|
||||
}];
|
||||
keychaindao_test.keychainDao.getPublicKeys(pubkeyIds, function(err, pubkeys) {
|
||||
ok(!err);
|
||||
deepEqual(pubkeys[0], keychaindao_test.keypair.publicKey, "Fetch public key");
|
||||
|
||||
// });
|
||||
start();
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user