mirror of
https://github.com/moparisthebest/mail
synced 2024-11-22 17:02:17 -05:00
integrate pgp into email dao and app
This commit is contained in:
parent
66a4921573
commit
79c9d134d3
@ -36,8 +36,8 @@ define([], function() {
|
||||
app.string = {
|
||||
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',
|
||||
cryptPrefix: '-----BEGIN ENCRYPTED MESSAGE-----',
|
||||
cryptSuffix: '-----END ENCRYPTED MESSAGE-----',
|
||||
cryptPrefix: '-----BEGIN PGP MESSAGE-----',
|
||||
cryptSuffix: '-----END PGP MESSAGE-----',
|
||||
signature: 'Sent securely from whiteout mail',
|
||||
webSite: 'http://whiteout.io'
|
||||
};
|
||||
|
@ -5,14 +5,13 @@ define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var $ = require('jquery'),
|
||||
util = require('cryptoLib/util'),
|
||||
ImapClient = require('imap-client'),
|
||||
SmtpClient = require('smtp-client'),
|
||||
EmailDAO = require('js/dao/email-dao'),
|
||||
KeychainDAO = require('js/dao/keychain-dao'),
|
||||
cloudstorage = require('js/dao/cloudstorage-dao'),
|
||||
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
|
||||
Crypto = require('js/crypto/crypto'),
|
||||
PGP = require('js/crypto/pgp'),
|
||||
config = require('js/app-config').config;
|
||||
require('cordova');
|
||||
|
||||
@ -65,18 +64,8 @@ define(function(require) {
|
||||
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
|
||||
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.
|
||||
*/
|
||||
self.login = function(userId, password, salt, token, callback) {
|
||||
self.login = function(userId, password, token, callback) {
|
||||
var auth, imapOptions, smtpOptions,
|
||||
keychain, imapClient, smtpClient, crypto, userStorage;
|
||||
keychain, imapClient, smtpClient, pgp, userStorage;
|
||||
|
||||
// create mail credentials objects for imap/smtp
|
||||
auth = {
|
||||
@ -197,17 +153,14 @@ define(function(require) {
|
||||
keychain = new KeychainDAO(cloudstorage);
|
||||
imapClient = new ImapClient(imapOptions);
|
||||
smtpClient = new SmtpClient(smtpOptions);
|
||||
crypto = new Crypto();
|
||||
pgp = new PGP();
|
||||
userStorage = new DeviceStorageDAO();
|
||||
self._emailDao = new EmailDAO(keychain, imapClient, smtpClient, crypto, userStorage);
|
||||
self._emailDao = new EmailDAO(keychain, imapClient, smtpClient, pgp, userStorage);
|
||||
|
||||
// init email dao
|
||||
var account = {
|
||||
emailAddress: userId,
|
||||
symKeySize: config.symKeySize,
|
||||
symIvSize: config.symIvSize,
|
||||
asymKeySize: config.asymKeySize,
|
||||
salt: salt
|
||||
asymKeySize: config.asymKeySize
|
||||
};
|
||||
self._emailDao.init(account, password, callback);
|
||||
};
|
||||
|
@ -25,7 +25,15 @@ define(function(require) {
|
||||
}
|
||||
|
||||
// generate keypair (keytype 1=RSA)
|
||||
try {
|
||||
keys = openpgp.generate_key_pair(1, options.keySize, options.emailAddress, options.passphrase);
|
||||
} catch (e) {
|
||||
callback({
|
||||
errMsg: 'Keygeneration failed!',
|
||||
err: e
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
keyId: util.hexstrdump(keys.privateKey.getKeyId()).toUpperCase(),
|
||||
|
@ -22,7 +22,7 @@ define(function(require) {
|
||||
/**
|
||||
* Inits all dependencies
|
||||
*/
|
||||
EmailDAO.prototype.init = function(account, password, callback) {
|
||||
EmailDAO.prototype.init = function(account, passphrase, callback) {
|
||||
var self = this;
|
||||
|
||||
self._account = account;
|
||||
@ -55,25 +55,41 @@ define(function(require) {
|
||||
}
|
||||
|
||||
function initCrypto(storedKeypair) {
|
||||
self._crypto.init({
|
||||
emailAddress: emailAddress,
|
||||
password: password,
|
||||
salt: self._account.salt,
|
||||
keySize: self._account.symKeySize,
|
||||
rsaKeySize: self._account.asymKeySize,
|
||||
storedKeypair: storedKeypair
|
||||
if (storedKeypair && storedKeypair.privateKey && storedKeypair.publicKey) {
|
||||
// import existing key pair into crypto module
|
||||
self._crypto.importKeys({
|
||||
passphrase: passphrase,
|
||||
privateKeyArmored: storedKeypair.privateKey.encryptedKey,
|
||||
publicKeyArmored: storedKeypair.publicKey.publicKey
|
||||
}, 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) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (generatedKeypair) {
|
||||
// persist newly generated keypair
|
||||
self._keychain.putUserKeyPair(generatedKeypair, callback);
|
||||
} else {
|
||||
callback();
|
||||
var newKeypair = {
|
||||
publicKey: {
|
||||
_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) {
|
||||
var self = this,
|
||||
displayList = [],
|
||||
encryptedList = [];
|
||||
|
||||
// validate options
|
||||
@ -193,8 +208,6 @@ define(function(require) {
|
||||
// find encrypted items
|
||||
emails.forEach(function(i) {
|
||||
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
|
||||
encryptedList.push(parseMessageBlock(i));
|
||||
}
|
||||
@ -206,34 +219,18 @@ define(function(require) {
|
||||
}
|
||||
|
||||
// decrypt items
|
||||
decryptList(encryptedList, function(err, decryptedList) {
|
||||
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);
|
||||
});
|
||||
decryptList(encryptedList, callback);
|
||||
});
|
||||
|
||||
function parseMessageBlock(email) {
|
||||
var ctMessageBase64, ctMessageJson, ctMessage;
|
||||
var messageBlock;
|
||||
|
||||
// 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);
|
||||
// get ascii armored message block by prefix and suffix
|
||||
messageBlock = email.body.split(str.cryptPrefix)[1].split(str.cryptSuffix)[0];
|
||||
// add prefix and suffix again
|
||||
email.body = str.cryptPrefix + messageBlock + str.cryptSuffix;
|
||||
} catch (e) {
|
||||
callback({
|
||||
errMsg: 'Error parsing encrypted message block!'
|
||||
@ -241,40 +238,32 @@ define(function(require) {
|
||||
return;
|
||||
}
|
||||
|
||||
return ctMessage;
|
||||
return email;
|
||||
}
|
||||
|
||||
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
|
||||
});
|
||||
}
|
||||
function decryptList(list, callback) {
|
||||
var after = _.after(list.length, function() {
|
||||
callback(null, list);
|
||||
});
|
||||
|
||||
// fetch public keys from keychain
|
||||
self._keychain.getPublicKeys(pubkeyIds, function(err, senderPubkeys) {
|
||||
list.forEach(function(i) {
|
||||
// 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) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// verfiy signatures and re-encrypt item keys
|
||||
self._crypto.decryptListForUser(encryptedList, senderPubkeys, function(err, decryptedList) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
decrypted = JSON.parse(decrypted);
|
||||
i.subject = decrypted.subject;
|
||||
i.body = decrypted.body;
|
||||
|
||||
callback(null, decryptedList);
|
||||
after();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -507,7 +496,7 @@ define(function(require) {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
var self = this,
|
||||
ptItems = bundleForEncryption(email),
|
||||
pt = JSON.stringify(email),
|
||||
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
|
||||
self._crypto.encryptListForUser(ptItems, receiverPubkeys, function(err, encryptedList) {
|
||||
self._crypto.encrypt(pt, receiverPubkeys, function(err, ct) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// bundle encrypted email together for sending
|
||||
bundleEncryptedItems(email, encryptedList);
|
||||
frameEncryptedMessage(email, ct);
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
function frameEncryptedMessage(email, ct) {
|
||||
var to, greeting, ctBase64;
|
||||
var to, greeting;
|
||||
|
||||
var SUBJECT = str.subject,
|
||||
MESSAGE = str.message + '\n\n\n',
|
||||
PREFIX = str.cryptPrefix + '\n',
|
||||
SUFFIX = '\n' + str.cryptSuffix,
|
||||
var MESSAGE = str.message + '\n\n\n',
|
||||
SIGNATURE = '\n\n\n' + str.signature + '\n' + str.webSite + '\n\n';
|
||||
|
||||
// get first name of recipient
|
||||
@ -618,9 +547,8 @@ define(function(require) {
|
||||
greeting = 'Hi ' + to + ',\n\n';
|
||||
|
||||
// build encrypted text body
|
||||
ctBase64 = btoa(JSON.stringify(ct));
|
||||
email.body = greeting + MESSAGE + PREFIX + ctBase64 + SUFFIX + SIGNATURE;
|
||||
email.subject = SUBJECT;
|
||||
email.body = greeting + MESSAGE + ct + SIGNATURE;
|
||||
email.subject = str.subject;
|
||||
|
||||
return email;
|
||||
}
|
||||
|
@ -210,23 +210,7 @@ define(['underscore', 'js/dao/lawnchair-dao'], function(_, jsonDao) {
|
||||
}
|
||||
|
||||
// store private key locally
|
||||
self.saveLocalPrivateKey(keypair.privateKey, function(err) {
|
||||
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);
|
||||
});
|
||||
});
|
||||
self.saveLocalPrivateKey(keypair.privateKey, callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -7424,7 +7424,7 @@ function openpgp_config() {
|
||||
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";
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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) {
|
||||
this.config = this.default_config;
|
||||
this.write();
|
||||
@ -7450,8 +7453,10 @@ function openpgp_config() {
|
||||
* Writes the config to HTML5 local storage
|
||||
*/
|
||||
function write() {
|
||||
if (typeof chrome === 'undefined' || typeof chrome.runtime === 'undefined') {
|
||||
window.localStorage.setItem("config",JSON.stringify(this.config));
|
||||
}
|
||||
}
|
||||
|
||||
this.read = read;
|
||||
this.write = write;
|
||||
@ -8463,8 +8468,11 @@ function openpgp_keyring() {
|
||||
* This method is called by openpgp.init().
|
||||
*/
|
||||
function init() {
|
||||
var sprivatekeys = JSON.parse(window.localStorage.getItem("privatekeys"));
|
||||
var spublickeys = JSON.parse(window.localStorage.getItem("publickeys"));
|
||||
var sprivatekeys, spublickeys;
|
||||
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) {
|
||||
sprivatekeys = new Array();
|
||||
}
|
||||
@ -8513,9 +8521,12 @@ function openpgp_keyring() {
|
||||
for (var i = 0; i < this.publicKeys.length; i++) {
|
||||
pub[i] = this.publicKeys[i].armored;
|
||||
}
|
||||
|
||||
if (typeof chrome === 'undefined' || typeof chrome.runtime === 'undefined') {
|
||||
window.localStorage.setItem("privatekeys",JSON.stringify(priv));
|
||||
window.localStorage.setItem("publickeys",JSON.stringify(pub));
|
||||
}
|
||||
}
|
||||
this.store = store;
|
||||
/**
|
||||
* searches all public keys in the keyring matching the address or address part of the user ids
|
||||
|
@ -15,7 +15,7 @@ define(function(require) {
|
||||
describe('App Controller unit tests', 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);
|
||||
callback();
|
||||
});
|
||||
@ -61,8 +61,8 @@ define(function(require) {
|
||||
|
||||
controller.fetchOAuthToken(appControllerTest.passphrase, function(err) {
|
||||
expect(err).to.not.exist;
|
||||
expect(controller._appConfigStore.listItems.calledTwice).to.be.true;
|
||||
expect(controller._appConfigStore.storeList.calledTwice).to.be.true;
|
||||
expect(controller._appConfigStore.listItems.calledOnce).to.be.true;
|
||||
expect(controller._appConfigStore.storeList.calledOnce).to.be.true;
|
||||
expect(window.chrome.identity.getAuthToken.calledOnce).to.be.true;
|
||||
expect($.ajax.calledOnce).to.be.true;
|
||||
done();
|
||||
@ -74,7 +74,7 @@ define(function(require) {
|
||||
|
||||
controller.fetchOAuthToken(appControllerTest.passphrase, function(err) {
|
||||
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($.ajax.called).to.be.false;
|
||||
done();
|
||||
|
@ -6,7 +6,7 @@ define(function(require) {
|
||||
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
|
||||
SmtpClient = require('smtp-client'),
|
||||
ImapClient = require('imap-client'),
|
||||
Crypto = require('js/crypto/crypto'),
|
||||
PGP = require('js/crypto/pgp'),
|
||||
app = require('js/app-config'),
|
||||
expect = chai.expect;
|
||||
|
||||
@ -23,7 +23,7 @@ define(function(require) {
|
||||
describe('Email DAO unit tests', function() {
|
||||
|
||||
var emailDao, account,
|
||||
keychainStub, imapClientStub, smtpClientStub, cryptoStub, devicestorageStub;
|
||||
keychainStub, imapClientStub, smtpClientStub, pgpStub, devicestorageStub;
|
||||
|
||||
beforeEach(function() {
|
||||
// init dummy object
|
||||
@ -49,10 +49,10 @@ define(function(require) {
|
||||
keychainStub = sinon.createStubInstance(KeychainDAO);
|
||||
imapClientStub = sinon.createStubInstance(ImapClient);
|
||||
smtpClientStub = sinon.createStubInstance(SmtpClient);
|
||||
cryptoStub = sinon.createStubInstance(Crypto);
|
||||
pgpStub = sinon.createStubInstance(PGP);
|
||||
devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
|
||||
|
||||
emailDao = new EmailDAO(keychainStub, imapClientStub, smtpClientStub, cryptoStub, devicestorageStub);
|
||||
emailDao = new EmailDAO(keychainStub, imapClientStub, smtpClientStub, pgpStub, devicestorageStub);
|
||||
});
|
||||
|
||||
afterEach(function() {});
|
||||
@ -72,18 +72,43 @@ define(function(require) {
|
||||
it('should init with new keygen', function(done) {
|
||||
devicestorageStub.init.yields();
|
||||
keychainStub.getUserKeyPair.yields();
|
||||
cryptoStub.init.yields(null, {});
|
||||
pgpStub.generateKeys.yields(null, {});
|
||||
keychainStub.putUserKeyPair.yields();
|
||||
|
||||
emailDao.init(account, emaildaoTest.passphrase, function(err) {
|
||||
expect(devicestorageStub.init.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(err).to.not.exist;
|
||||
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() {
|
||||
@ -110,13 +135,13 @@ define(function(require) {
|
||||
beforeEach(function(done) {
|
||||
devicestorageStub.init.yields();
|
||||
keychainStub.getUserKeyPair.yields();
|
||||
cryptoStub.init.yields(null, {});
|
||||
pgpStub.generateKeys.yields(null, {});
|
||||
keychainStub.putUserKeyPair.yields();
|
||||
|
||||
emailDao.init(account, emaildaoTest.passphrase, function(err) {
|
||||
expect(devicestorageStub.init.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(err).to.not.exist;
|
||||
done();
|
||||
@ -175,11 +200,14 @@ define(function(require) {
|
||||
userId: "safewithme.testuser@gmail.com",
|
||||
publicKey: publicKey
|
||||
});
|
||||
pgpStub.exportKeys.yields(null, {});
|
||||
pgpStub.encrypt.yields(null, 'asdfasfd');
|
||||
smtpClientStub.send.yields();
|
||||
cryptoStub.encryptListForUser.yields(null, []);
|
||||
|
||||
emailDao.smtpSend(dummyMail, function(err) {
|
||||
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;
|
||||
smtpClientStub.send.calledWith(sinon.match(function(o) {
|
||||
return typeof o.attachments === 'undefined';
|
||||
@ -200,11 +228,14 @@ define(function(require) {
|
||||
userId: "safewithme.testuser@gmail.com",
|
||||
publicKey: publicKey
|
||||
});
|
||||
pgpStub.exportKeys.yields(null, {});
|
||||
pgpStub.encrypt.yields(null, 'asdfasfd');
|
||||
smtpClientStub.send.yields();
|
||||
cryptoStub.encryptListForUser.yields(null, [{}, {}]);
|
||||
|
||||
emailDao.smtpSend(dummyMail, function(err) {
|
||||
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;
|
||||
smtpClientStub.send.calledWith(sinon.match(function(o) {
|
||||
var ptAt = dummyMail.attachments[0];
|
||||
@ -408,19 +439,17 @@ define(function(require) {
|
||||
|
||||
describe('IMAP: list messages from local storage', function() {
|
||||
it('should work', function(done) {
|
||||
|
||||
devicestorageStub.listItems.yields(null, [{
|
||||
body: app.string.cryptPrefix + btoa(JSON.stringify({})) + app.string.cryptSuffix
|
||||
}]);
|
||||
keychainStub.getPublicKeys.yields(null, [{
|
||||
dummyMail.body = app.string.cryptPrefix + btoa('asdf') + app.string.cryptSuffix;
|
||||
devicestorageStub.listItems.yields(null, [dummyMail, dummyMail]);
|
||||
keychainStub.getReveiverPublicKey.yields(null, {
|
||||
_id: "fcf8b4aa-5d09-4089-8b4f-e3bc5091daf3",
|
||||
userId: "safewithme.testuser@gmail.com",
|
||||
publicKey: publicKey
|
||||
}]);
|
||||
cryptoStub.decryptListForUser.yields(null, [{
|
||||
});
|
||||
pgpStub.decrypt.yields(null, JSON.stringify({
|
||||
body: 'test body',
|
||||
subject: 'test subject'
|
||||
}]);
|
||||
}));
|
||||
|
||||
emailDao.listMessages({
|
||||
folder: 'INBOX',
|
||||
@ -428,10 +457,10 @@ define(function(require) {
|
||||
num: 2
|
||||
}, function(err, emails) {
|
||||
expect(devicestorageStub.listItems.calledOnce).to.be.true;
|
||||
expect(keychainStub.getPublicKeys.calledOnce).to.be.true;
|
||||
expect(cryptoStub.decryptListForUser.calledOnce).to.be.true;
|
||||
expect(keychainStub.getReveiverPublicKey.calledTwice).to.be.true;
|
||||
expect(pgpStub.decrypt.calledTwice).to.be.true;
|
||||
expect(err).to.not.exist;
|
||||
expect(emails.length).to.equal(1);
|
||||
expect(emails.length).to.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user