diff --git a/src/js/app-config.js b/src/js/app-config.js index 7106b4e..026f38e 100644 --- a/src/js/app-config.js +++ b/src/js/app-config.js @@ -54,7 +54,9 @@ define(function(require) { cryptSuffix: '-----END PGP MESSAGE-----', signature: 'Sent securely from Whiteout Mail', webSite: 'http://whiteout.io', - verificationSubject: 'New public key uploaded' + verificationSubject: 'New public key uploaded', + sendBtnInvite: 'Invite & send securely', + sendBtnSecure: 'Send securely' }; return app; diff --git a/src/js/controller/read.js b/src/js/controller/read.js index b93d21b..90aaac8 100644 --- a/src/js/controller/read.js +++ b/src/js/controller/read.js @@ -53,6 +53,8 @@ define(function(require) { mail.from.forEach(checkPublicKey); // display recipient security status mail.to.forEach(checkPublicKey); + // display recipient security status + Array.isArray(mail.cc) && mail.cc.forEach(checkPublicKey); }); function checkPublicKey(user) { diff --git a/src/js/controller/write.js b/src/js/controller/write.js index 9771a79..547228d 100644 --- a/src/js/controller/write.js +++ b/src/js/controller/write.js @@ -5,6 +5,7 @@ define(function(require) { appController = require('js/app-controller'), aes = require('cryptoLib/aes-cbc'), util = require('cryptoLib/util'), + str = require('js/app-config').string, emailDao; // @@ -30,7 +31,7 @@ define(function(require) { fillFields(replyTo); $scope.updatePreview(); - $scope.verifyTo(); + $scope.verify($scope.to[0]); }, close: function() { this.open = false; @@ -39,7 +40,15 @@ define(function(require) { function resetFields() { $scope.writerTitle = 'New email'; - $scope.to = ''; + $scope.to = [{ + address: '' + }]; + $scope.cc = [{ + address: '' + }]; + $scope.bcc = [{ + address: '' + }]; $scope.subject = ''; $scope.body = ''; $scope.ciphertextPreview = ''; @@ -54,7 +63,9 @@ define(function(require) { $scope.writerTitle = 'Reply'; // fill recipient field - $scope.to = re.from[0].address; + $scope.to.unshift({ + address: re.from[0].address + }); // fill subject $scope.subject = 'Re: ' + ((re.subject) ? re.subject.replace('Re: ', '') : ''); @@ -73,45 +84,98 @@ define(function(require) { // Editing headers // - $scope.verifyTo = function() { - if (!$scope.to) { - resetDisplay(); + /** + * This event is fired when editing the email address headers. It checks is space is pressed and if so, creates a new address field. + */ + $scope.onAddressUpdate = function(field, index) { + var recipient = field[index], + address = recipient.address; + + // handle number of email inputs for multiple recipients + if (address.indexOf(' ') !== -1) { + recipient.address = address.replace(' ', ''); + field.push({ + address: '' + }); + } else if (address.length === 0 && field.length > 1) { + field.splice(field.indexOf(recipient), 1); + } + + $scope.verify(recipient); + }; + + /** + * Verify and email address and fetch its public key + */ + $scope.verify = function(recipient) { + // set display to insecure while fetching keys + recipient.key = undefined; + recipient.secure = false; + + // verify email address + if (!util.validateEmailAddress(recipient.address)) { + recipient.secure = undefined; + $scope.checkSendStatus(); return; } - // set display to insecure while fetching keys - $scope.toKey = undefined; - displayInsecure(); // check if to address is contained in known public keys - emailDao._keychain.getReceiverPublicKey($scope.to, function(err, key) { + emailDao._keychain.getReceiverPublicKey(recipient.address, function(err, key) { if (err) { $scope.onError(err); return; } // compare again since model could have changed during the roundtrip - if (key && key.userId === $scope.to) { - $scope.toKey = key; - displaySecure(); - $scope.$apply(); + if (key && key.userId === recipient.address) { + recipient.key = key; + recipient.secure = true; } + + $scope.checkSendStatus(); + $scope.$apply(); }); }; - function resetDisplay() { - $scope.toSecure = undefined; + /** + * Check if it is ok to send an email depending on the invitation state of the addresses + */ + $scope.checkSendStatus = function() { + $scope.okToSend = false; $scope.sendBtnText = undefined; - } + $scope.sendBtnSecure = undefined; - function displaySecure() { - $scope.toSecure = true; - $scope.sendBtnText = 'Send securely'; - } + var allSecure = true; + var numReceivers = 0; - function displayInsecure() { - $scope.toSecure = false; - $scope.sendBtnText = 'Invite & send securely'; - } + // count number of receivers and check security + $scope.to.forEach(check); + $scope.cc.forEach(check); + $scope.bcc.forEach(check); + + function check(recipient) { + // validate address + if (!util.validateEmailAddress(recipient.address)) { + return; + } + numReceivers++; + if (!recipient.secure) { + allSecure = false; + } + } + + // sender can invite only one use at a time + if (!allSecure && numReceivers === 1) { + $scope.sendBtnText = str.sendBtnInvite; + $scope.okToSend = true; + $scope.sendBtnSecure = false; + } else if (allSecure && numReceivers > 0) { + // all recipients are secure + $scope.sendBtnText = str.sendBtnSecure; + $scope.okToSend = true; + $scope.sendBtnSecure = true; + } + }; // // Editing email body @@ -129,20 +193,13 @@ define(function(require) { }; $scope.sendToOutbox = function() { - var to, email; - - // validate recipients - to = $scope.to.replace(/\s/g, '').split(/[,;]/); - if (!to || to.length < 1) { - $scope.onError({ - errMsg: 'Seperate recipients with a comma!', - sync: true - }); - return; - } + var email; + // build email model for smtp-client email = { - to: [], // list of receivers + to: [], + cc: [], + bcc: [], subject: $scope.subject, // Subject line body: $scope.body // use parsed plaintext body }; @@ -150,13 +207,34 @@ define(function(require) { name: '', address: emailDao._account.emailAddress }]; - to.forEach(function(address) { - email.to.push({ - name: '', - address: address - }); - }); + // validate recipients and gather public keys + email.receiverKeys = []; // gather public keys for emailDao._encrypt + + appendReceivers($scope.to, email.to); + appendReceivers($scope.cc, email.cc); + appendReceivers($scope.bcc, email.bcc); + + function appendReceivers(srcField, destField) { + srcField.forEach(function(recipient) { + // validate address + if (!util.validateEmailAddress(recipient.address)) { + return; + } + + // append address to email model + destField.push({ + address: recipient.address + }); + + // add public key to list of recipient keys + if (recipient.key && recipient.key.publicKey) { + email.receiverKeys.push(recipient.key.publicKey); + } + }); + } + + // persist the email locally for later smtp transmission emailDao.store(email, function(err) { if (err) { $scope.onError(err); @@ -254,16 +332,40 @@ define(function(require) { link: function(scope, elm, attrs) { var model = $parse(attrs.autoSize); scope.$watch(model, function(value) { - if (!value) { - return; + var width; + + if (value.length < 12) { + width = (14 * 8) + 'px'; + } else { + width = ((value.length + 2) * 8) + 'px'; } - var width = ((value.length + 2) * 8) + 'px'; elm.css('width', width); }); } }; }); + ngModule.directive('addressInput', function($timeout) { + return { + //scope: true, // optionally create a child scope + link: function(scope, element, attrs) { + // get prefix for id + var idPrefix = attrs.addressInput; + element.bind('keydown', function(e) { + if (e.keyCode === 32) { + // space -> go to next input + $timeout(function() { + // find next input and focus + var index = attrs.id.replace(idPrefix, ''); + var nextId = idPrefix + (parseInt(index, 10) + 1); + document.getElementById(nextId).focus(); + }, 100); + } + }); + } + }; + }); + return WriteCtrl; }); \ No newline at end of file diff --git a/src/js/dao/email-dao.js b/src/js/dao/email-dao.js index 8352354..66800c7 100644 --- a/src/js/dao/email-dao.js +++ b/src/js/dao/email-dao.js @@ -875,58 +875,24 @@ define(function(require) { } // validate the email input - if (!email.to || !email.from || !email.to[0].address || !email.from[0].address) { + if (!email.to || !email.from || !email.to[0].address || !email.from[0].address || !Array.isArray(email.receiverKeys)) { 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) { + // public key found... encrypt and send + self._encrypt({ + email: email, + keys: email.receiverKeys // this Array is set in writer controller + }, function(err, email) { 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._smtpClient.send(email, callback); - }); + self._smtpClient.send(email, callback); }); }; diff --git a/src/sass/views/_read.scss b/src/sass/views/_read.scss index 00f6ef7..535488b 100644 --- a/src/sass/views/_read.scss +++ b/src/sass/views/_read.scss @@ -7,7 +7,7 @@ .headers { p { margin: 0px; - padding: 0px; + padding: 0px; } .subject { diff --git a/src/sass/views/_write.scss b/src/sass/views/_write.scss index a7c3780..bb309d4 100644 --- a/src/sass/views/_write.scss +++ b/src/sass/views/_write.scss @@ -20,6 +20,12 @@ .headers { margin-top: 10px; + + p { + margin: 0.2em 0; + padding: 0.2em 0; + } + span { color: $color-grey; } diff --git a/src/tpl/read.html b/src/tpl/read.html index bcaefe1..ca2dbf9 100644 --- a/src/tpl/read.html +++ b/src/tpl/read.html @@ -16,7 +16,7 @@

- CC: {{u.name || u.address}} + Cc: {{u.name || u.address}}

diff --git a/src/tpl/write.html b/src/tpl/write.html index 5f00615..c3ddf1c 100644 --- a/src/tpl/write.html +++ b/src/tpl/write.html @@ -9,17 +9,21 @@

To: - + + +

Cc: - + + +

- +
-

+

-----BEGIN ENCRYPTED PREVIEW-----
{{ciphertextPreview}}
-----END ENCRYPTED PREVIEW-----

@@ -35,7 +39,7 @@
- +
diff --git a/test/new-unit/email-dao-test.js b/test/new-unit/email-dao-test.js index f596085..146183f 100644 --- a/test/new-unit/email-dao-test.js +++ b/test/new-unit/email-dao-test.js @@ -75,7 +75,8 @@ define(function(require) { subject: 'qweasd', body: 'asd', unread: false, - answered: false + answered: false, + receiverKeys: ['-----BEGIN PGP PUBLIC KEY-----\nasd\n-----END PGP PUBLIC KEY-----'] }; nonWhitelistedMail = { uid: 1234, @@ -2409,11 +2410,7 @@ define(function(require) { describe('sendEncrypted', 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.sendEncrypted({ @@ -2421,7 +2418,6 @@ define(function(require) { }, 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; @@ -2430,72 +2426,18 @@ define(function(require) { }); 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.sendEncrypted({ 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.sendEncrypted({ - 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.sendEncrypted({ - 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.sendEncrypted({ - 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; @@ -2505,7 +2447,6 @@ define(function(require) { }, 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; @@ -2521,7 +2462,6 @@ define(function(require) { }, 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; diff --git a/test/new-unit/write-ctrl-test.js b/test/new-unit/write-ctrl-test.js index 69e3b51..c4490bf 100644 --- a/test/new-unit/write-ctrl-test.js +++ b/test/new-unit/write-ctrl-test.js @@ -47,7 +47,9 @@ define(function(require) { expect(scope.state.writer.open).to.be.false; expect(scope.state.writer.write).to.exist; expect(scope.state.writer.close).to.exist; - expect(scope.verifyTo).to.exist; + expect(scope.verify).to.exist; + expect(scope.onAddressUpdate).to.exist; + expect(scope.checkSendStatus).to.exist; expect(scope.updatePreview).to.exist; expect(scope.sendToOutbox).to.exist; }); @@ -65,22 +67,24 @@ define(function(require) { describe('write', function() { it('should prepare write view', function() { - var verifyToMock = sinon.stub(scope, 'verifyTo'); + var verifyMock = sinon.stub(scope, 'verify'); scope.state.writer.write(); expect(scope.writerTitle).to.equal('New email'); - expect(scope.to).to.equal(''); + expect(scope.to).to.deep.equal([{ + address: '' + }]); expect(scope.subject).to.equal(''); expect(scope.body).to.equal(''); expect(scope.ciphertextPreview).to.equal(''); - expect(verifyToMock.calledOnce).to.be.true; + expect(verifyMock.calledOnce).to.be.true; - scope.verifyTo.restore(); + scope.verify.restore(); }); it('should prefill write view for response', function() { - var verifyToMock = sinon.stub(scope, 'verifyTo'), + var verifyMock = sinon.stub(scope, 'verify'), address = 'pity@dafool', subject = 'Ermahgerd!', body = 'so much body!', @@ -96,61 +100,210 @@ define(function(require) { scope.state.writer.write(re); expect(scope.writerTitle).to.equal('Reply'); - expect(scope.to).to.equal(address); + expect(scope.to).to.deep.equal([{ + address: address, + }, { + address: '' + }]); expect(scope.subject).to.equal('Re: ' + subject); expect(scope.body).to.contain(body); expect(scope.ciphertextPreview).to.not.be.empty; - expect(verifyToMock.calledOnce).to.be.true; + expect(verifyMock.calledOnce).to.be.true; - scope.verifyTo.restore(); + scope.verify.restore(); }); }); - describe('verifyTo', function() { - it('should verify the recipient as secure', function() { - var id = scope.to = 'pity@da.fool'; - keychainMock.getReceiverPublicKey.withArgs(id).yields(null, { - userId: id - }); + describe('onAddressUpdate', function() { + var verifyMock; - scope.verifyTo(); - - expect(scope.toSecure).to.be.true; - expect(scope.sendBtnText).to.equal('Send securely'); + beforeEach(function() { + verifyMock = sinon.stub(scope, 'verify'); }); - it('should verify the recipient as not secure', function(done) { - var id = scope.to = 'pity@da.fool'; - keychainMock.getReceiverPublicKey.withArgs(id).yields({ + afterEach(function() { + scope.verify.restore(); + }); + + it('should add new field item if space is pressed', function() { + var to = [{ + address: 'asdf@asdf.de ' + }]; + scope.onAddressUpdate(to, 0); + + expect(to.length).to.equal(2); + expect(to[0].address).to.equal('asdf@asdf.de'); + expect(to[1].address).to.equal(''); + expect(verifyMock.calledOnce).to.be.true; + }); + + it('should remove field item if address is empty', function() { + var to = [{ + address: 'asdf@asdf.de' + }, { + address: '' + }]; + scope.onAddressUpdate(to, 1); + + expect(to.length).to.equal(1); + expect(to[0].address).to.equal('asdf@asdf.de'); + expect(verifyMock.calledOnce).to.be.true; + }); + + it('should not remove last field item if address is empty', function() { + var to = [{ + address: '' + }]; + scope.onAddressUpdate(to, 0); + + expect(to.length).to.equal(1); + expect(to[0].address).to.equal(''); + expect(verifyMock.calledOnce).to.be.true; + }); + + it('should do nothing for normal address', function() { + var to = [{ + address: 'asdf@asdf.de' + }]; + scope.onAddressUpdate(to, 0); + + expect(to.length).to.equal(1); + expect(to[0].address).to.equal('asdf@asdf.de'); + expect(verifyMock.calledOnce).to.be.true; + }); + }); + + describe('verify', function() { + var checkSendStatusMock; + + beforeEach(function() { + checkSendStatusMock = sinon.stub(scope, 'checkSendStatus'); + }); + + afterEach(function() { + scope.checkSendStatus.restore(); + }); + + it('should not work for invalid email addresses', function() { + var recipient = { + address: '' + }; + + scope.verify(recipient); + + expect(recipient.key).to.be.undefined; + expect(recipient.secure).to.be.undefined; + expect(scope.checkSendStatus.calledOnce).to.be.true; + expect(keychainMock.getReceiverPublicKey.called).to.be.false; + }); + + it('should not work for error in keychain', function(done) { + var recipient = { + address: 'asds@example.com' + }; + + keychainMock.getReceiverPublicKey.withArgs(recipient.address).yields({ errMsg: '404 not found yadda yadda' }); scope.onError = function() { - expect(scope.toSecure).to.be.false; - expect(scope.sendBtnText).to.equal('Invite & send securely'); + expect(recipient.key).to.be.undefined; + expect(recipient.secure).to.be.false; + expect(scope.checkSendStatus.called).to.be.false; + expect(keychainMock.getReceiverPublicKey.calledOnce).to.be.true; done(); }; - scope.verifyTo(); + scope.verify(recipient); }); - it('should reset display if there is no recipient', function() { - scope.to = undefined; - scope.verifyTo(); + it('should work', function(done) { + var recipient = { + address: 'asdf@example.com' + }; + + keychainMock.getReceiverPublicKey.yields(null, { + userId: 'asdf@example.com' + }); + scope.$apply = function() { + expect(recipient.key).to.deep.equal({ + userId: 'asdf@example.com' + }); + expect(recipient.secure).to.be.true; + expect(scope.checkSendStatus.calledOnce).to.be.true; + expect(keychainMock.getReceiverPublicKey.calledOnce).to.be.true; + done(); + }; + + scope.verify(recipient); + }); + }); + + describe('checkSendStatus', function() { + beforeEach(function() { + scope.state.writer.write(); + }); + + afterEach(function() {}); + + it('should not be able to send with no recipients', function() { + scope.checkSendStatus(); + + expect(scope.okToSend).to.be.false; + expect(scope.sendBtnText).to.be.undefined; + expect(scope.sendBtnSecure).to.be.undefined; + }); + + it('should not be to invite 1 user', function() { + scope.to = [{ + address: 'asdf@asdf.de' + }]; + scope.checkSendStatus(); + + expect(scope.okToSend).to.be.true; + expect(scope.sendBtnText).to.equal('Invite & send securely'); + expect(scope.sendBtnSecure).to.be.false; + }); + + it('should not be able to invite multiple recipients', function() { + scope.to = [{ + address: 'asdf@asdf.de' + }, { + address: 'asdf@asdfg.de' + }]; + scope.checkSendStatus(); + + expect(scope.okToSend).to.be.false; + expect(scope.sendBtnText).to.be.undefined; + expect(scope.sendBtnSecure).to.be.undefined; + }); + + it('should be able to send securely to multiple recipients', function() { + scope.to = [{ + address: 'asdf@asdf.de', + secure: true + }, { + address: 'asdf@asdfg.de', + secure: true + }]; + scope.checkSendStatus(); + + expect(scope.okToSend).to.be.true; + expect(scope.sendBtnText).to.equal('Send securely'); + expect(scope.sendBtnSecure).to.be.true; }); }); describe('send to outbox', function() { it('should work when offline', function(done) { - var verifyToSpy = sinon.spy(scope, 'verifyTo'), - re = { - from: [{ - address: 'pity@dafool' - }], - subject: 'Ermahgerd!', - sentDate: new Date(), - body: 'so much body!' - }; + var re = { + from: [{ + address: 'pity@dafool' + }], + subject: 'Ermahgerd!', + sentDate: new Date(), + body: 'so much body!' + }; scope.state.nav = { currentFolder: 'currentFolder' @@ -160,11 +313,9 @@ define(function(require) { scope.onError = function(err) { expect(err).to.not.exist; expect(scope.state.writer.open).to.be.false; - expect(verifyToSpy.calledOnce).to.be.true; expect(emailDaoMock.store.calledOnce).to.be.true; expect(emailDaoMock.sync.calledOnce).to.be.true; - scope.verifyTo.restore(); done(); }; @@ -178,15 +329,14 @@ define(function(require) { }); it('should work', function(done) { - var verifyToSpy = sinon.spy(scope, 'verifyTo'), - re = { - from: [{ - address: 'pity@dafool' - }], - subject: 'Ermahgerd!', - sentDate: new Date(), - body: 'so much body!' - }; + var re = { + from: [{ + address: 'pity@dafool' + }], + subject: 'Ermahgerd!', + sentDate: new Date(), + body: 'so much body!' + }; scope.state.nav = { currentFolder: 'currentFolder' @@ -196,11 +346,9 @@ define(function(require) { scope.onError = function(err) { expect(err).to.not.exist; expect(scope.state.writer.open).to.be.false; - expect(verifyToSpy.calledOnce).to.be.true; expect(emailDaoMock.store.calledOnce).to.be.true; expect(emailDaoMock.sync.calledOnce).to.be.true; - scope.verifyTo.restore(); done(); }; @@ -212,15 +360,14 @@ define(function(require) { }); it('should fail', function(done) { - var verifyToSpy = sinon.spy(scope, 'verifyTo'), - re = { - from: [{ - address: 'pity@dafool' - }], - subject: 'Ermahgerd!', - sentDate: new Date(), - body: 'so much body!' - }; + var re = { + from: [{ + address: 'pity@dafool' + }], + subject: 'Ermahgerd!', + sentDate: new Date(), + body: 'so much body!' + }; scope.state.nav = { currentFolder: 'currentFolder' @@ -230,11 +377,9 @@ define(function(require) { scope.onError = function(err) { expect(err).to.exist; expect(scope.state.writer.open).to.be.false; - expect(verifyToSpy.calledOnce).to.be.true; expect(emailDaoMock.store.calledOnce).to.be.true; expect(emailDaoMock.sync.calledOnce).to.be.true; - scope.verifyTo.restore(); done(); }; @@ -246,14 +391,20 @@ define(function(require) { }); it('should not work and not close the write view', function(done) { - scope.state.writer.open = true; - scope.to = 'a, b, c'; + scope.state.writer.write(); + + scope.to = [{ + address: 'pity@dafool.de', + key: { + publicKey: '----- PGP Stuff -----' + } + }]; scope.body = 'asd'; scope.subject = 'yaddablabla'; scope.toKey = 'Public Key'; emailDaoMock.store.withArgs(sinon.match(function(mail) { - return mail.from[0].address === emailAddress && mail.to.length === 3; + return mail.from[0].address === emailAddress && mail.to.length === 1 && mail.receiverKeys.length === 1; })).yields({ errMsg: 'snafu' }); @@ -264,7 +415,6 @@ define(function(require) { expect(emailDaoMock.store.calledOnce).to.be.true; done(); }; - scope.sendToOutbox(); }); });