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:
parent
66a4921573
commit
79c9d134d3
@ -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'
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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(),
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user