add missing methods and tests

This commit is contained in:
Felix Hammerl 2013-12-02 13:58:20 +01:00
parent 150cf23948
commit 0c1003c48f
2 changed files with 319 additions and 1 deletions

View File

@ -434,10 +434,136 @@ define(function(require) {
}
};
EmailDAO.prototype.markRead = function(options, callback) {
this._imapClient.updateFlags({
path: options.folder,
uid: options.uid,
unread: false
}, callback);
};
EmailDAO.prototype.markAnswered = function(options, callback) {
this._imapClient.updateFlags({
path: options.folder,
uid: options.uid,
answered: true
}, callback);
};
EmailDAO.prototype.encryptedSend = function(options, callback) {
var self = this,
email = options.email;
// validate the email input
if (!email.to || !email.from || !email.to[0].address || !email.from[0].address) {
callback({
errMsg: 'Invalid email object!'
});
return;
}
// validate email addresses
for (var i = email.to.length - 1; i >= 0; i--) {
if (!util.validateEmailAddress(email.to[i].address)) {
callback({
errMsg: 'Invalid recipient: ' + email.to[i].address
});
return;
}
}
if (!util.validateEmailAddress(email.from[0].address)) {
callback({
errMsg: 'Invalid sender: ' + email.from
});
return;
}
// only support single recipient for e-2-e encryption
// check if receiver has a public key
self._keychain.getReceiverPublicKey(email.to[0].address, function(err, receiverPubkey) {
if (err) {
callback(err);
return;
}
// validate public key
if (!receiverPubkey) {
callback({
errMsg: 'User has no public key yet!'
});
return;
}
// public key found... encrypt and send
self._encrypt({
email: email,
keys: receiverPubkey.publicKey
}, function(err, email) {
if (err) {
callback(err);
return;
}
self.send({
email: email
}, callback);
});
});
};
EmailDAO.prototype.send = function(options, callback) {
this._smtpClient.send(options.email, callback);
};
//
// Internal API
//
// Encryption API
EmailDAO.prototype._encrypt = function(options, callback) {
var self = this,
pt = options.email.body;
options.keys = [options.keys] || [];
// 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
options.keys.push(ownKeys.publicKeyArmored);
// encrypt the email
self._crypto.encrypt(pt, options.keys, function(err, ct) {
if (err) {
callback(err);
return;
}
// bundle encrypted email together for sending
frameEncryptedMessage(options.email, ct);
callback(null, options.email);
});
});
function frameEncryptedMessage(email, ct) {
var greeting,
message = str.message + '\n\n\n',
signature = '\n\n' + str.signature + '\n\n';
// get first name of recipient
greeting = 'Hi ' + (email.to[0].name || email.to[0].address).split('@')[0].split('.')[0].split(' ')[0] + ',\n\n';
// build encrypted text body
email.body = greeting + message + ct + signature;
email.subject = email.subject;
}
};
// Local Storage API
EmailDAO.prototype._localListMessages = function(options, callback) {

View File

@ -15,7 +15,7 @@ define(function(require) {
var dao, keychainStub, imapClientStub, smtpClientStub, pgpStub, devicestorageStub;
var emailAddress, passphrase, asymKeySize, mockkeyId, dummyEncryptedMail,
dummyDecryptedMail, mockKeyPair, account;
dummyDecryptedMail, mockKeyPair, account, publicKey;
beforeEach(function() {
emailAddress = 'asdf@asdf.com';
@ -60,6 +60,7 @@ define(function(require) {
emailAddress: emailAddress,
asymKeySize: asymKeySize,
};
publicKey = "-----BEGIN PUBLIC KEY-----\r\n" + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxy+Te5dyeWd7g0P+8LNO7fZDQ\r\n" + "g96xTb1J6pYE/pPTMlqhB6BRItIYjZ1US5q2vk5Zk/5KasBHAc9RbCqvh9v4XFEY\r\n" + "JVmTXC4p8ft1LYuNWIaDk+R3dyYXmRNct/JC4tks2+8fD3aOvpt0WNn3R75/FGBt\r\n" + "h4BgojAXDE+PRQtcVQIDAQAB\r\n" + "-----END PUBLIC KEY-----";
keychainStub = sinon.createStubInstance(KeychainDAO);
imapClientStub = sinon.createStubInstance(ImapClient);
@ -694,7 +695,198 @@ define(function(require) {
folder: folder
}, after);
});
});
describe('markAsRead', function() {
it('should work', function(done) {
imapClientStub.updateFlags.yields();
dao.markRead({
folder: 'asdf',
uid: 1
}, function(err) {
expect(imapClientStub.updateFlags.calledOnce).to.be.true;
expect(err).to.not.exist;
done();
});
});
});
describe('markAsAnswered', function() {
it('should work', function(done) {
imapClientStub.updateFlags.yields();
dao.markAnswered({
folder: 'asdf',
uid: 1
}, function(err) {
expect(imapClientStub.updateFlags.calledOnce).to.be.true;
expect(err).to.not.exist;
done();
});
});
});
describe('send', function() {
it('should work', function(done) {
smtpClientStub.send.withArgs(dummyEncryptedMail).yields();
dao.send({
email: dummyEncryptedMail
}, function(err) {
expect(err).to.not.exist;
expect(smtpClientStub.send.calledOnce).to.be.true;
done();
});
});
});
describe('encryptedSend', function() {
it('should work', function(done) {
var encryptStub = sinon.stub(dao, '_encrypt').yields(null, {});
keychainStub.getReceiverPublicKey.withArgs(dummyDecryptedMail.to[0].address).yields(null, {
_id: "fcf8b4aa-5d09-4089-8b4f-e3bc5091daf3",
userId: dummyDecryptedMail.to[0].address,
publicKey: publicKey
});
smtpClientStub.send.yields();
dao.encryptedSend({
email: dummyDecryptedMail
}, function(err) {
expect(err).to.not.exist;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
expect(encryptStub.calledOnce).to.be.true;
expect(smtpClientStub.send.calledOnce).to.be.true;
done();
});
});
it('should not work when encryption fails', function(done) {
var encryptStub = sinon.stub(dao, '_encrypt').yields({});
keychainStub.getReceiverPublicKey.withArgs(dummyDecryptedMail.to[0].address).yields(null, {
_id: "fcf8b4aa-5d09-4089-8b4f-e3bc5091daf3",
userId: dummyDecryptedMail.to[0].address,
publicKey: publicKey
});
dao.encryptedSend({
email: dummyDecryptedMail
}, function(err) {
expect(err).to.exist;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
expect(encryptStub.calledOnce).to.be.true;
expect(smtpClientStub.send.called).to.be.false;
done();
});
});
it('should not work when key retrieval fails', function(done) {
var encryptStub = sinon.stub(dao, '_encrypt');
keychainStub.getReceiverPublicKey.withArgs(dummyDecryptedMail.to[0].address).yields({});
dao.encryptedSend({
email: dummyDecryptedMail
}, function(err) {
expect(err).to.exist;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
expect(encryptStub.called).to.be.false;
expect(smtpClientStub.send.called).to.be.false;
done();
});
});
it('should not work invalid recipients', function(done) {
var encryptStub = sinon.stub(dao, '_encrypt');
dummyDecryptedMail.to[0].address = 'asd@asd';
dao.encryptedSend({
email: dummyDecryptedMail
}, function(err) {
expect(err).to.exist;
expect(keychainStub.getReceiverPublicKey.called).to.be.false;
expect(encryptStub.called).to.be.false;
expect(smtpClientStub.send.called).to.be.false;
done();
});
});
it('should not work with without sender', function(done) {
var encryptStub = sinon.stub(dao, '_encrypt');
dummyDecryptedMail.from[0].address = 'asd@asd';
dao.encryptedSend({
email: dummyDecryptedMail
}, function(err) {
expect(err).to.exist;
expect(keychainStub.getReceiverPublicKey.called).to.be.false;
expect(encryptStub.called).to.be.false;
expect(smtpClientStub.send.called).to.be.false;
done();
});
});
it('should not work without recipients', function(done) {
var encryptStub = sinon.stub(dao, '_encrypt');
delete dummyDecryptedMail.to;
dao.encryptedSend({
email: dummyDecryptedMail
}, function(err) {
expect(err).to.exist;
expect(keychainStub.getReceiverPublicKey.called).to.be.false;
expect(encryptStub.called).to.be.false;
expect(smtpClientStub.send.called).to.be.false;
done();
});
});
it('should not work with without sender', function(done) {
var encryptStub = sinon.stub(dao, '_encrypt');
delete dummyDecryptedMail.from;
dao.encryptedSend({
email: dummyDecryptedMail
}, function(err) {
expect(err).to.exist;
expect(keychainStub.getReceiverPublicKey.called).to.be.false;
expect(encryptStub.called).to.be.false;
expect(smtpClientStub.send.called).to.be.false;
done();
});
});
});
describe('_encrypt', function() {
it('should work without attachments', function(done) {
var ct = 'OMGSOENCRYPTED';
pgpStub.exportKeys.yields(null, {
privateKeyArmored: mockKeyPair.privateKey.encryptedKey,
publicKeyArmored: mockKeyPair.publicKey.publicKey
});
pgpStub.encrypt.yields(null, ct);
dao._encrypt({
email: dummyDecryptedMail
}, function(err) {
expect(err).to.not.exist;
expect(pgpStub.exportKeys.calledOnce).to.be.true;
expect(pgpStub.encrypt.calledOnce).to.be.true;
expect(dummyDecryptedMail.body).to.contain(ct);
done();
});
});
});
});
});