1
0
mirror of https://github.com/moparisthebest/mail synced 2024-11-26 10:52:17 -05:00

integrate pgp into email dao and app

This commit is contained in:
Tankred Hase 2013-10-12 03:19:01 +02:00
parent 66a4921573
commit 79c9d134d3
8 changed files with 169 additions and 256 deletions

View File

@ -36,8 +36,8 @@ define([], function() {
app.string = { app.string = {
subject: '[whiteout] Encrypted message', subject: '[whiteout] Encrypted message',
message: 'this is a private conversation. To read my encrypted message below, simply install Whiteout Mail for Chrome. The app is really easy to use and automatically encrypts sent emails, so that only the two of us can read them: https://chrome.google.com/webstore/detail/whiteout-mail/jjgghafhamholjigjoghcfcekhkonijg', message: 'this is a private conversation. To read my encrypted message below, simply install Whiteout Mail for Chrome. The app is really easy to use and automatically encrypts sent emails, so that only the two of us can read them: https://chrome.google.com/webstore/detail/whiteout-mail/jjgghafhamholjigjoghcfcekhkonijg',
cryptPrefix: '-----BEGIN ENCRYPTED MESSAGE-----', cryptPrefix: '-----BEGIN PGP MESSAGE-----',
cryptSuffix: '-----END ENCRYPTED MESSAGE-----', cryptSuffix: '-----END PGP MESSAGE-----',
signature: 'Sent securely from whiteout mail', signature: 'Sent securely from whiteout mail',
webSite: 'http://whiteout.io' webSite: 'http://whiteout.io'
}; };

View File

@ -5,14 +5,13 @@ define(function(require) {
'use strict'; 'use strict';
var $ = require('jquery'), var $ = require('jquery'),
util = require('cryptoLib/util'),
ImapClient = require('imap-client'), ImapClient = require('imap-client'),
SmtpClient = require('smtp-client'), SmtpClient = require('smtp-client'),
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'), DeviceStorageDAO = require('js/dao/devicestorage-dao'),
Crypto = require('js/crypto/crypto'), PGP = require('js/crypto/pgp'),
config = require('js/app-config').config; config = require('js/app-config').config;
require('cordova'); require('cordova');
@ -65,18 +64,8 @@ define(function(require) {
return; return;
} }
self.getSalt(function(err, salt) {
if (err || !salt) {
callback({
errMsg: 'Error gettin salt on login!',
err: err
});
return;
}
// login using the received email address // login using the received email address
self.login(emailAddress, password, salt, token, callback); self.login(emailAddress, password, token, callback);
});
}); });
} }
); );
@ -132,45 +121,12 @@ define(function(require) {
} }
}; };
/**
* Fetch a random salt from the app storage or generate a new one
*/
self.getSalt = function(callback) {
var itemKey = 'salt',
salt;
self._appConfigStore.listItems(itemKey, 0, null, function(err, cachedItems) {
if (err) {
callback(err);
return;
}
// generate random salt if non exists
if (!cachedItems || cachedItems.length < 1) {
salt = util.random(config.symKeySize);
// store the salt locally
self._appConfigStore.storeList([salt], itemKey, function(err) {
if (err) {
callback(err);
return;
}
callback(null, salt);
});
return;
}
callback(null, cachedItems[0]);
});
};
/** /**
* Instanciate the mail email data access object and its dependencies. Login to imap on init. * Instanciate the mail email data access object and its dependencies. Login to imap on init.
*/ */
self.login = function(userId, password, salt, token, callback) { self.login = function(userId, password, token, callback) {
var auth, imapOptions, smtpOptions, var auth, imapOptions, smtpOptions,
keychain, imapClient, smtpClient, crypto, userStorage; keychain, imapClient, smtpClient, pgp, userStorage;
// create mail credentials objects for imap/smtp // create mail credentials objects for imap/smtp
auth = { auth = {
@ -197,17 +153,14 @@ 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);
crypto = new Crypto(); pgp = new PGP();
userStorage = new DeviceStorageDAO(); userStorage = new DeviceStorageDAO();
self._emailDao = new EmailDAO(keychain, imapClient, smtpClient, crypto, userStorage); self._emailDao = new EmailDAO(keychain, imapClient, smtpClient, pgp, userStorage);
// init email dao // init email dao
var account = { var account = {
emailAddress: userId, emailAddress: userId,
symKeySize: config.symKeySize, asymKeySize: config.asymKeySize
symIvSize: config.symIvSize,
asymKeySize: config.asymKeySize,
salt: salt
}; };
self._emailDao.init(account, password, callback); self._emailDao.init(account, password, callback);
}; };

View File

@ -25,7 +25,15 @@ define(function(require) {
} }
// generate keypair (keytype 1=RSA) // generate keypair (keytype 1=RSA)
try {
keys = openpgp.generate_key_pair(1, options.keySize, options.emailAddress, options.passphrase); keys = openpgp.generate_key_pair(1, options.keySize, options.emailAddress, options.passphrase);
} catch (e) {
callback({
errMsg: 'Keygeneration failed!',
err: e
});
return;
}
callback(null, { callback(null, {
keyId: util.hexstrdump(keys.privateKey.getKeyId()).toUpperCase(), keyId: util.hexstrdump(keys.privateKey.getKeyId()).toUpperCase(),

View File

@ -22,7 +22,7 @@ define(function(require) {
/** /**
* Inits all dependencies * Inits all dependencies
*/ */
EmailDAO.prototype.init = function(account, password, callback) { EmailDAO.prototype.init = function(account, passphrase, callback) {
var self = this; var self = this;
self._account = account; self._account = account;
@ -55,25 +55,41 @@ define(function(require) {
} }
function initCrypto(storedKeypair) { function initCrypto(storedKeypair) {
self._crypto.init({ if (storedKeypair && storedKeypair.privateKey && storedKeypair.publicKey) {
emailAddress: emailAddress, // import existing key pair into crypto module
password: password, self._crypto.importKeys({
salt: self._account.salt, passphrase: passphrase,
keySize: self._account.symKeySize, privateKeyArmored: storedKeypair.privateKey.encryptedKey,
rsaKeySize: self._account.asymKeySize, publicKeyArmored: storedKeypair.publicKey.publicKey
storedKeypair: storedKeypair }, callback);
return;
}
// no keypair for is stored for the user... generate a new one
self._crypto.generateKeys({
emailAddress: self._account.emailAddress,
keySize: self._account.asymKeySize,
passphrase: passphrase
}, function(err, generatedKeypair) { }, function(err, generatedKeypair) {
if (err) { if (err) {
callback(err); callback(err);
return; return;
} }
if (generatedKeypair) {
// persist newly generated keypair // persist newly generated keypair
self._keychain.putUserKeyPair(generatedKeypair, callback); var newKeypair = {
} else { publicKey: {
callback(); _id: generatedKeypair.keyId,
userId: self._account.emailAddress,
publicKey: generatedKeypair.publicKeyArmored
},
privateKey: {
_id: generatedKeypair.keyId,
userId: self._account.emailAddress,
encryptedKey: generatedKeypair.privateKeyArmored
} }
};
self._keychain.putUserKeyPair(newKeypair, callback);
}); });
} }
}; };
@ -172,7 +188,6 @@ define(function(require) {
*/ */
EmailDAO.prototype.listMessages = function(options, callback) { EmailDAO.prototype.listMessages = function(options, callback) {
var self = this, var self = this,
displayList = [],
encryptedList = []; encryptedList = [];
// validate options // validate options
@ -193,8 +208,6 @@ define(function(require) {
// find encrypted items // find encrypted items
emails.forEach(function(i) { emails.forEach(function(i) {
if (typeof i.body === 'string' && i.body.indexOf(str.cryptPrefix) !== -1 && i.body.indexOf(str.cryptSuffix) !== -1) { if (typeof i.body === 'string' && i.body.indexOf(str.cryptPrefix) !== -1 && i.body.indexOf(str.cryptSuffix) !== -1) {
// add item to plaintext list for display later
displayList.push(i);
// parse ct object from ascii armored message block // parse ct object from ascii armored message block
encryptedList.push(parseMessageBlock(i)); encryptedList.push(parseMessageBlock(i));
} }
@ -206,34 +219,18 @@ define(function(require) {
} }
// decrypt items // decrypt items
decryptList(encryptedList, function(err, decryptedList) { decryptList(encryptedList, callback);
if (err) {
callback(err);
return;
}
// replace encrypted subject and body
for (var j = 0; j < displayList.length; j++) {
displayList[j].subject = decryptedList[j].subject;
displayList[j].body = decryptedList[j].body;
}
// return only decrypted items
callback(null, displayList);
});
}); });
function parseMessageBlock(email) { function parseMessageBlock(email) {
var ctMessageBase64, ctMessageJson, ctMessage; var messageBlock;
// parse email body for encrypted message block // parse email body for encrypted message block
try { try {
// get base64 encoded message block // get ascii armored message block by prefix and suffix
ctMessageBase64 = email.body.split(str.cryptPrefix)[1].split(str.cryptSuffix)[0].trim(); messageBlock = email.body.split(str.cryptPrefix)[1].split(str.cryptSuffix)[0];
// decode bae64 // add prefix and suffix again
ctMessageJson = atob(ctMessageBase64); email.body = str.cryptPrefix + messageBlock + str.cryptSuffix;
// parse json string to get ciphertext object
ctMessage = JSON.parse(ctMessageJson);
} catch (e) { } catch (e) {
callback({ callback({
errMsg: 'Error parsing encrypted message block!' errMsg: 'Error parsing encrypted message block!'
@ -241,40 +238,32 @@ define(function(require) {
return; return;
} }
return ctMessage; return email;
} }
function decryptList(encryptedList, callback) { function decryptList(list, callback) {
var already, pubkeyIds = []; var after = _.after(list.length, function() {
callback(null, list);
// 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 list.forEach(function(i) {
self._keychain.getPublicKeys(pubkeyIds, function(err, senderPubkeys) { // gather public keys required to verify signatures
var sender = i.from[0].address;
self._keychain.getReveiverPublicKey(sender, function(err, senderPubkey) {
// decrypt and verfiy signatures
self._crypto.decrypt(i.body, senderPubkey.publicKey, function(err, decrypted) {
if (err) { if (err) {
callback(err); callback(err);
return; return;
} }
// verfiy signatures and re-encrypt item keys decrypted = JSON.parse(decrypted);
self._crypto.decryptListForUser(encryptedList, senderPubkeys, function(err, decryptedList) { i.subject = decrypted.subject;
if (err) { i.body = decrypted.body;
callback(err);
return;
}
callback(null, decryptedList); after();
});
}); });
}); });
} }
@ -507,7 +496,7 @@ define(function(require) {
} }
// public key found... encrypt and send // public key found... encrypt and send
self.encryptForUser(email, receiverPubkey, callback); self.encryptForUser(email, receiverPubkey.publicKey, callback);
}); });
}; };
@ -516,101 +505,41 @@ define(function(require) {
*/ */
EmailDAO.prototype.encryptForUser = function(email, receiverPubkey, callback) { EmailDAO.prototype.encryptForUser = function(email, receiverPubkey, callback) {
var self = this, var self = this,
ptItems = bundleForEncryption(email), pt = JSON.stringify(email),
receiverPubkeys = [receiverPubkey]; receiverPubkeys = [receiverPubkey];
// get own public key so send message can be read
self._crypto.exportKeys(function(err, ownKeys) {
if (err) {
callback(err);
return;
}
// add own public key to receiver list
receiverPubkeys.push(ownKeys.publicKeyArmored);
// encrypt the email // encrypt the email
self._crypto.encryptListForUser(ptItems, receiverPubkeys, function(err, encryptedList) { self._crypto.encrypt(pt, receiverPubkeys, function(err, ct) {
if (err) { if (err) {
callback(err); callback(err);
return; return;
} }
// bundle encrypted email together for sending // bundle encrypted email together for sending
bundleEncryptedItems(email, encryptedList); frameEncryptedMessage(email, ct);
self.send(email, callback); self.send(email, callback);
}); });
};
/**
* Encrypt an email symmetrically for a new user, write the secret one time key to the cloudstorage REST service, and send the email client side via SMTP.
*/
EmailDAO.prototype.encryptForNewUser = function(email, callback) {
var self = this,
ptItems = bundleForEncryption(email);
self._crypto.symEncryptList(ptItems, function(err, result) {
if (err) {
callback(err);
return;
}
// bundle encrypted email together for sending
bundleEncryptedItems(email, result.list);
// TODO: write result.key to REST endpoint
self.send(email, callback);
}); });
}; };
/**
* Give the email a newly generated UUID, remove its attachments, and bundle all plaintext items to a batchable array for encryption.
*/
function bundleForEncryption(email) {
var ptItems = [email];
// generate a new UUID for the new email
email.id = util.UUID();
// add attachment to encryption batch and remove from email object
if (email.attachments) {
email.attachments.forEach(function(attachment) {
attachment.id = email.id;
ptItems.push(attachment);
});
delete email.attachments;
}
return ptItems;
}
/**
* Frame the encrypted email message and append the encrypted attachments.
*/
function bundleEncryptedItems(email, encryptedList) {
var i;
// replace body and subject of the email with encrypted versions
email = frameEncryptedMessage(email, encryptedList[0]);
// add encrypted attachments
if (encryptedList.length > 1) {
email.attachments = [];
}
for (i = 1; i < encryptedList.length; i++) {
email.attachments.push({
fileName: 'Encrypted Attachment ' + i,
contentType: 'application/octet-stream',
uint8Array: util.binStr2Uint8Arr(JSON.stringify(encryptedList[i]))
});
}
}
/** /**
* Frames an encrypted message in base64 Format. * Frames an encrypted message in base64 Format.
*/ */
function frameEncryptedMessage(email, ct) { function frameEncryptedMessage(email, ct) {
var to, greeting, ctBase64; var to, greeting;
var SUBJECT = str.subject, var MESSAGE = str.message + '\n\n\n',
MESSAGE = str.message + '\n\n\n',
PREFIX = str.cryptPrefix + '\n',
SUFFIX = '\n' + str.cryptSuffix,
SIGNATURE = '\n\n\n' + str.signature + '\n' + str.webSite + '\n\n'; SIGNATURE = '\n\n\n' + str.signature + '\n' + str.webSite + '\n\n';
// get first name of recipient // get first name of recipient
@ -618,9 +547,8 @@ define(function(require) {
greeting = 'Hi ' + to + ',\n\n'; greeting = 'Hi ' + to + ',\n\n';
// build encrypted text body // build encrypted text body
ctBase64 = btoa(JSON.stringify(ct)); email.body = greeting + MESSAGE + ct + SIGNATURE;
email.body = greeting + MESSAGE + PREFIX + ctBase64 + SUFFIX + SIGNATURE; email.subject = str.subject;
email.subject = SUBJECT;
return email; return email;
} }

View File

@ -210,23 +210,7 @@ define(['underscore', 'js/dao/lawnchair-dao'], function(_, jsonDao) {
} }
// store private key locally // store private key locally
self.saveLocalPrivateKey(keypair.privateKey, function(err) { self.saveLocalPrivateKey(keypair.privateKey, callback);
if (err) {
callback(err);
return;
}
// persist private key in cloud storage
self._cloudstorage.putPrivateKey(keypair.privateKey, function(err) {
// validate result
if (err) {
callback(err);
return;
}
callback(null);
});
});
}); });
}); });
}; };

View File

@ -7424,7 +7424,7 @@ function openpgp_config() {
keyserver: "keyserver.linux.it" // "pgp.mit.edu:11371" keyserver: "keyserver.linux.it" // "pgp.mit.edu:11371"
}; };
this.versionstring ="OpenPGP.js v.1.20131011"; this.versionstring ="OpenPGP.js v.1.20131012";
this.commentstring ="http://openpgpjs.org"; this.commentstring ="http://openpgpjs.org";
/** /**
* Reads the config out of the HTML5 local storage * Reads the config out of the HTML5 local storage
@ -7432,7 +7432,10 @@ function openpgp_config() {
* if config is null the default config will be used * if config is null the default config will be used
*/ */
function read() { function read() {
var cf = JSON.parse(window.localStorage.getItem("config")); var cf = null;
if (typeof chrome === 'undefined' || typeof chrome.runtime === 'undefined') {
cf = JSON.parse(window.localStorage.getItem("config"));
}
if (cf == null) { if (cf == null) {
this.config = this.default_config; this.config = this.default_config;
this.write(); this.write();
@ -7450,8 +7453,10 @@ function openpgp_config() {
* Writes the config to HTML5 local storage * Writes the config to HTML5 local storage
*/ */
function write() { function write() {
if (typeof chrome === 'undefined' || typeof chrome.runtime === 'undefined') {
window.localStorage.setItem("config",JSON.stringify(this.config)); window.localStorage.setItem("config",JSON.stringify(this.config));
} }
}
this.read = read; this.read = read;
this.write = write; this.write = write;
@ -8463,8 +8468,11 @@ function openpgp_keyring() {
* This method is called by openpgp.init(). * This method is called by openpgp.init().
*/ */
function init() { function init() {
var sprivatekeys = JSON.parse(window.localStorage.getItem("privatekeys")); var sprivatekeys, spublickeys;
var spublickeys = JSON.parse(window.localStorage.getItem("publickeys")); if (typeof chrome === 'undefined' || typeof chrome.runtime === 'undefined') {
sprivatekeys = JSON.parse(window.localStorage.getItem("privatekeys"));
spublickeys = JSON.parse(window.localStorage.getItem("publickeys"));
}
if (sprivatekeys == null || sprivatekeys.length == 0) { if (sprivatekeys == null || sprivatekeys.length == 0) {
sprivatekeys = new Array(); sprivatekeys = new Array();
} }
@ -8513,9 +8521,12 @@ function openpgp_keyring() {
for (var i = 0; i < this.publicKeys.length; i++) { for (var i = 0; i < this.publicKeys.length; i++) {
pub[i] = this.publicKeys[i].armored; pub[i] = this.publicKeys[i].armored;
} }
if (typeof chrome === 'undefined' || typeof chrome.runtime === 'undefined') {
window.localStorage.setItem("privatekeys",JSON.stringify(priv)); window.localStorage.setItem("privatekeys",JSON.stringify(priv));
window.localStorage.setItem("publickeys",JSON.stringify(pub)); window.localStorage.setItem("publickeys",JSON.stringify(pub));
} }
}
this.store = store; this.store = store;
/** /**
* searches all public keys in the keyring matching the address or address part of the user ids * searches all public keys in the keyring matching the address or address part of the user ids

View File

@ -15,7 +15,7 @@ define(function(require) {
describe('App Controller unit tests', function() { describe('App Controller unit tests', function() {
beforeEach(function() { beforeEach(function() {
sinon.stub(controller, 'login', function(userId, password, salt, token, callback) { sinon.stub(controller, 'login', function(userId, password, token, callback) {
controller._emailDao = sinon.createStubInstance(EmailDAO); controller._emailDao = sinon.createStubInstance(EmailDAO);
callback(); callback();
}); });
@ -61,8 +61,8 @@ define(function(require) {
controller.fetchOAuthToken(appControllerTest.passphrase, function(err) { controller.fetchOAuthToken(appControllerTest.passphrase, function(err) {
expect(err).to.not.exist; expect(err).to.not.exist;
expect(controller._appConfigStore.listItems.calledTwice).to.be.true; expect(controller._appConfigStore.listItems.calledOnce).to.be.true;
expect(controller._appConfigStore.storeList.calledTwice).to.be.true; expect(controller._appConfigStore.storeList.calledOnce).to.be.true;
expect(window.chrome.identity.getAuthToken.calledOnce).to.be.true; expect(window.chrome.identity.getAuthToken.calledOnce).to.be.true;
expect($.ajax.calledOnce).to.be.true; expect($.ajax.calledOnce).to.be.true;
done(); done();
@ -74,7 +74,7 @@ define(function(require) {
controller.fetchOAuthToken(appControllerTest.passphrase, function(err) { controller.fetchOAuthToken(appControllerTest.passphrase, function(err) {
expect(err).to.not.exist; expect(err).to.not.exist;
expect(controller._appConfigStore.listItems.calledTwice).to.be.true; expect(controller._appConfigStore.listItems.calledOnce).to.be.true;
expect(window.chrome.identity.getAuthToken.calledOnce).to.be.true; expect(window.chrome.identity.getAuthToken.calledOnce).to.be.true;
expect($.ajax.called).to.be.false; expect($.ajax.called).to.be.false;
done(); done();

View File

@ -6,7 +6,7 @@ define(function(require) {
DeviceStorageDAO = require('js/dao/devicestorage-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'), PGP = require('js/crypto/pgp'),
app = require('js/app-config'), app = require('js/app-config'),
expect = chai.expect; expect = chai.expect;
@ -23,7 +23,7 @@ define(function(require) {
describe('Email DAO unit tests', function() { describe('Email DAO unit tests', function() {
var emailDao, account, var emailDao, account,
keychainStub, imapClientStub, smtpClientStub, cryptoStub, devicestorageStub; keychainStub, imapClientStub, smtpClientStub, pgpStub, devicestorageStub;
beforeEach(function() { beforeEach(function() {
// init dummy object // init dummy object
@ -49,10 +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); pgpStub = sinon.createStubInstance(PGP);
devicestorageStub = sinon.createStubInstance(DeviceStorageDAO); devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
emailDao = new EmailDAO(keychainStub, imapClientStub, smtpClientStub, cryptoStub, devicestorageStub); emailDao = new EmailDAO(keychainStub, imapClientStub, smtpClientStub, pgpStub, devicestorageStub);
}); });
afterEach(function() {}); afterEach(function() {});
@ -72,18 +72,43 @@ define(function(require) {
it('should init with new keygen', function(done) { it('should init with new keygen', function(done) {
devicestorageStub.init.yields(); devicestorageStub.init.yields();
keychainStub.getUserKeyPair.yields(); keychainStub.getUserKeyPair.yields();
cryptoStub.init.yields(null, {}); pgpStub.generateKeys.yields(null, {});
keychainStub.putUserKeyPair.yields(); keychainStub.putUserKeyPair.yields();
emailDao.init(account, emaildaoTest.passphrase, function(err) { emailDao.init(account, emaildaoTest.passphrase, function(err) {
expect(devicestorageStub.init.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(pgpStub.generateKeys.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();
}); });
}); });
it('should init with stored keygen', function(done) {
devicestorageStub.init.yields();
keychainStub.getUserKeyPair.yields(null, {
publicKey: {
_id: 'keyId',
userId: emaildaoTest.user,
publicKey: 'publicKeyArmored'
},
privateKey: {
_id: 'keyId',
userId: emaildaoTest.user,
encryptedKey: 'privateKeyArmored'
}
});
pgpStub.importKeys.yields();
emailDao.init(account, emaildaoTest.passphrase, function(err) {
expect(devicestorageStub.init.calledOnce).to.be.true;
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
expect(pgpStub.importKeys.calledOnce).to.be.true;
expect(err).to.not.exist;
done();
});
});
}); });
describe('login', function() { describe('login', function() {
@ -110,13 +135,13 @@ define(function(require) {
beforeEach(function(done) { beforeEach(function(done) {
devicestorageStub.init.yields(); devicestorageStub.init.yields();
keychainStub.getUserKeyPair.yields(); keychainStub.getUserKeyPair.yields();
cryptoStub.init.yields(null, {}); pgpStub.generateKeys.yields(null, {});
keychainStub.putUserKeyPair.yields(); keychainStub.putUserKeyPair.yields();
emailDao.init(account, emaildaoTest.passphrase, function(err) { emailDao.init(account, emaildaoTest.passphrase, function(err) {
expect(devicestorageStub.init.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(pgpStub.generateKeys.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();
@ -175,11 +200,14 @@ define(function(require) {
userId: "safewithme.testuser@gmail.com", userId: "safewithme.testuser@gmail.com",
publicKey: publicKey publicKey: publicKey
}); });
pgpStub.exportKeys.yields(null, {});
pgpStub.encrypt.yields(null, 'asdfasfd');
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;
expect(pgpStub.exportKeys.calledOnce).to.be.true;
expect(pgpStub.encrypt.calledOnce).to.be.true;
expect(smtpClientStub.send.calledOnce).to.be.true; expect(smtpClientStub.send.calledOnce).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';
@ -200,11 +228,14 @@ define(function(require) {
userId: "safewithme.testuser@gmail.com", userId: "safewithme.testuser@gmail.com",
publicKey: publicKey publicKey: publicKey
}); });
pgpStub.exportKeys.yields(null, {});
pgpStub.encrypt.yields(null, 'asdfasfd');
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;
expect(pgpStub.exportKeys.calledOnce).to.be.true;
expect(pgpStub.encrypt.calledOnce).to.be.true;
expect(smtpClientStub.send.calledOnce).to.be.true; expect(smtpClientStub.send.calledOnce).to.be.true;
smtpClientStub.send.calledWith(sinon.match(function(o) { smtpClientStub.send.calledWith(sinon.match(function(o) {
var ptAt = dummyMail.attachments[0]; var ptAt = dummyMail.attachments[0];
@ -408,19 +439,17 @@ define(function(require) {
describe('IMAP: list messages from local storage', function() { describe('IMAP: list messages from local storage', function() {
it('should work', function(done) { it('should work', function(done) {
dummyMail.body = app.string.cryptPrefix + btoa('asdf') + app.string.cryptSuffix;
devicestorageStub.listItems.yields(null, [{ devicestorageStub.listItems.yields(null, [dummyMail, dummyMail]);
body: app.string.cryptPrefix + btoa(JSON.stringify({})) + app.string.cryptSuffix keychainStub.getReveiverPublicKey.yields(null, {
}]);
keychainStub.getPublicKeys.yields(null, [{
_id: "fcf8b4aa-5d09-4089-8b4f-e3bc5091daf3", _id: "fcf8b4aa-5d09-4089-8b4f-e3bc5091daf3",
userId: "safewithme.testuser@gmail.com", userId: "safewithme.testuser@gmail.com",
publicKey: publicKey publicKey: publicKey
}]); });
cryptoStub.decryptListForUser.yields(null, [{ pgpStub.decrypt.yields(null, JSON.stringify({
body: 'test body', body: 'test body',
subject: 'test subject' subject: 'test subject'
}]); }));
emailDao.listMessages({ emailDao.listMessages({
folder: 'INBOX', folder: 'INBOX',
@ -428,10 +457,10 @@ define(function(require) {
num: 2 num: 2
}, function(err, emails) { }, function(err, emails) {
expect(devicestorageStub.listItems.calledOnce).to.be.true; expect(devicestorageStub.listItems.calledOnce).to.be.true;
expect(keychainStub.getPublicKeys.calledOnce).to.be.true; expect(keychainStub.getReveiverPublicKey.calledTwice).to.be.true;
expect(cryptoStub.decryptListForUser.calledOnce).to.be.true; expect(pgpStub.decrypt.calledTwice).to.be.true;
expect(err).to.not.exist; expect(err).to.not.exist;
expect(emails.length).to.equal(1); expect(emails.length).to.equal(2);
done(); done();
}); });
}); });