sending end-2-end encrypted emails internally work

This commit is contained in:
Tankred Hase 2013-07-01 22:42:39 +02:00
parent a4f03bdca1
commit 699871276c
6 changed files with 160 additions and 13 deletions

View File

@ -84,6 +84,14 @@ define(['jquery', 'js/app-config'], function($, app) {
self.put(item, uri, callback);
};
/**
* Deliver an email to the user's outbox
*/
self.deliverEmail = function(email, from, to, callback) {
var uri = app.config.cloudUrl + '/email/user/' + from + '/folder/outbox/' + email.id + '?to=' + to;
self.put(email, uri, callback);
};
/**
* Delete an encrypted item from the cloud
* @param type [String] The type of item e.g. 'email'

View File

@ -143,7 +143,7 @@ define(['underscore', 'cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-da
var filter = '';
if (localItems && localItems.length > 0) {
// sync delta of last item sent date
filter = '?date=' + localItems[localItems.length - 1].sentDate;
//filter = '?date=' + localItems[localItems.length - 1].sentDate;
startSync(filter);
} else {
// do a full sync of all items on the cloud
@ -225,9 +225,9 @@ define(['underscore', 'cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-da
// validate email addresses
var invalidRecipient;
_.each(email.to, function(address) {
if (!validateEmail(address)) {
invalidRecipient = address;
_.each(email.to, function(i) {
if (!validateEmail(i.address)) {
invalidRecipient = i.address;
}
});
if (invalidRecipient) {
@ -236,7 +236,7 @@ define(['underscore', 'cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-da
});
return;
}
if (!validateEmail(email.from)) {
if (!validateEmail(email.from[0].address)) {
callback({
errMsg: 'Invalid sender: ' + email.from
});
@ -245,11 +245,59 @@ define(['underscore', 'cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-da
// generate a new UUID for the new email
email.id = util.UUID();
// set sent date
email.sentDate = util.formatDate(new Date());
// send email to cloud service
cloudstorage.putEncryptedItem(email, 'email', userId, 'outbox', function(err) {
callback(err);
// only support single recipient for e-2-e encryption
var recipient = email.to[0].address;
// check if receiver has a public key
keychain.getReveiverPublicKey(recipient, function(err, receiverPubkey) {
if (err) {
callback(err);
return;
}
if (receiverPubkey) {
// public key found... encrypt and send
encrypt(email, receiverPubkey);
} else {
// no public key found... send plaintext mail via SMTP
send(email);
}
});
function encrypt(email, receiverPubkey) {
// encrypt the email
crypto.encryptListForUser([email], [receiverPubkey], function(err, encryptedList) {
if (err) {
callback(err);
return;
}
var ct = encryptedList[0];
var envelope = {
id: email.id,
crypto: 'rsa-1024-sha-256-aes-128-cbc',
sentDate: email.sentDate,
ciphertext: ct.ciphertext,
encryptedKey: ct.encryptedKey,
iv: ct.iv,
signature: ct.signature,
senderPk: ct.senderPk
};
send(envelope);
});
}
function send(email) {
// send email to cloud service
cloudstorage.deliverEmail(email, userId, recipient, function(err) {
callback(err);
});
}
};
};

View File

@ -46,6 +46,51 @@ define(['underscore', 'js/dao/lawnchair-dao'], function(_, jsonDao) {
});
};
/**
* Look up a reveiver's public key by user id
* @param userId [String] the receiver's email address
*/
self.getReveiverPublicKey = function(userId, callback) {
// search local keyring for public key
jsonDao.list('publickey', 0, null, function(allPubkeys) {
var pubkey = _.findWhere(allPubkeys, {
userId: userId
});
if (!pubkey || !pubkey._id) {
// no public key by that user id in storage
// find from cloud by email address
cloudstorage.getPublicKeyByUserId(userId, function(err, cloudPubkey) {
if (err || !cloudPubkey) {
callback();
return;
}
if (cloudPubkey && cloudPubkey._id) {
// there is a public key for that user already in the cloud...
// save to local storage
saveLocalPublicKey(cloudPubkey, function(err) {
if (err) {
callback(err);
return;
}
callback(null, cloudPubkey);
});
} else {
// no public key for that user
callback();
return;
}
});
} else {
// that user's public key is already in local storage
callback(null, pubkey);
}
});
};
/**
* Gets the local user's key either from local storage
* or fetches it from the cloud. The private key is encrypted.

View File

@ -105,11 +105,21 @@ define(['jquery', 'underscore', 'backbone', 'js/app-config'], function($, _, Bac
var signature = '\n\nSent with whiteout mail - get your free mailbox for end-2-end encrypted messaging!\nhttps://mail.whiteout.io';
var email = {
from: self.account,
to: to,
to: [],
subject: page.find('#subjectInput').val(),
body: page.find('#bodyTextarea').val() + signature
};
email.from = [{
name: '',
address: self.account
}
];
to.forEach(function(address) {
email.to.push({
name: '',
address: address
});
});
// post message to main window
app.util.postMessage('sendEmail', {

View File

@ -161,13 +161,40 @@ define(['js/dao/email-dao', 'js/dao/keychain-dao', 'js/dao/lawnchair-dao',
});
});
asyncTest("Send Plaintext Email item", 1, function() {
asyncTest("Send e-2-e Encrypted Email item", 1, function() {
var email = {
from: cloudstoragedaoTest.user, // sender address
to: [cloudstoragedaoTest.user], // list of receivers
subject: 'Client Email DAO Test', // Subject line
body: 'Hello world' // plaintext body
};
email.from = [{
address: cloudstoragedaoTest.user
}
];
email.to = [{
address: cloudstoragedaoTest.user
}
];
cloudstoragedaoTest.emailDao.sendEmail(email, function(err) {
ok(!err, 'Email sent');
start();
});
});
asyncTest("Send Plaintext Email item", 1, function() {
var email = {
subject: 'Client Email DAO Test', // Subject line
body: 'Hello world' // plaintext body
};
email.from = [{
address: cloudstoragedaoTest.user
}
];
email.to = [{
address: 'safewithme.testuser@gmail.com'
}
];
cloudstoragedaoTest.emailDao.sendEmail(email, function(err) {
ok(!err, 'Email sent');

View File

@ -81,4 +81,13 @@ define(['js/dao/keychain-dao', 'js/dao/lawnchair-dao'], function(KeychainDAO, js
});
});
asyncTest("Get User Keypair", 2, function() {
keychaindaoTest.keychainDao.getReveiverPublicKey(keychaindaoTest.user, function(err, pubkey) {
ok(!err);
ok(pubkey && pubkey.publicKey);
start();
});
});
});