From 3d6a4698ce48999105db73492a68b7c84e7ef5ba Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Thu, 27 Feb 2014 18:14:38 +0100 Subject: [PATCH] invite user when clicking on red address label --- src/js/app-config.js | 8 ++-- src/js/bo/outbox.js | 27 +++++++++--- src/js/controller/read.js | 34 +++++++++++---- src/js/dao/email-dao.js | 2 +- src/tpl/read.html | 8 ++-- test/new-unit/outbox-bo-test.js | 75 +++++++++++++++++++++------------ 6 files changed, 104 insertions(+), 50 deletions(-) diff --git a/src/js/app-config.js b/src/js/app-config.js index 7a56ba8..3c06298 100644 --- a/src/js/app-config.js +++ b/src/js/app-config.js @@ -53,15 +53,15 @@ define(function(require) { subjectPrefix: '[whiteout] ', fallbackSubject: '(no subject)', invitationSubject: 'Invitation to a private conversation', - invitationMessage: 'Hi,\n\nI would like to invite you to a private conversation!\n\nPlease install the Whiteout Mail application. This application is used to read and write messages securely with strong encryption applied.\n\nGo to the Whiteout Networks homepage to learn more and to download the application: https://whiteout.io\n\n', - message: 'Hi,\n\nthis is a private conversation. To read my encrypted message below, simply open it in Whiteout Mail.\n\nOpen Whiteout Mail: https://chrome.google.com/webstore/detail/jjgghafhamholjigjoghcfcekhkonijg\n\n', + invitationMessage: 'Hi,\n\nI would like to invite you to a private conversation!\n\nPlease install the Whiteout Mail application. This application is used to read and write messages securely with strong encryption applied.\n\nGo to the Whiteout Networks homepage to learn more and to download the application: https://whiteout.io', + message: 'Hi,\n\nthis is a private conversation. To read my encrypted message below, simply open it in Whiteout Mail.\nOpen Whiteout Mail: https://chrome.google.com/webstore/detail/jjgghafhamholjigjoghcfcekhkonijg', cryptPrefix: '-----BEGIN PGP MESSAGE-----', cryptSuffix: '-----END PGP MESSAGE-----', - signature: '\n\n\n--\nSent from Whiteout Mail - get the app for easy end-to-end encryption\nhttps://whiteout.io\n\n', + signature: '\n\n\n--\nSent from Whiteout Mail - PGP encryption for the rest of us.\nhttps://whiteout.io\n\n', webSite: 'http://whiteout.io', verificationSubject: 'New public key uploaded', sendBtnClear: 'Send', - sendBtnSecure: 'Secure send' + sendBtnSecure: 'Send securely' }; return app; diff --git a/src/js/bo/outbox.js b/src/js/bo/outbox.js index 14f14a0..0005895 100644 --- a/src/js/bo/outbox.js +++ b/src/js/bo/outbox.js @@ -32,8 +32,10 @@ define(function(require) { * @param {Function} callback(error, pendingMailsCount) Callback that informs you about the count of pending mails. */ OutboxBO.prototype.startChecking = function(callback) { + // remember global callback + this._onError = callback; // start periodic checking of outbox - this._intervalId = setInterval(this._processOutbox.bind(this, callback), config.checkOutboxInterval); + this._intervalId = setInterval(this._processOutbox.bind(this, this._onError), config.checkOutboxInterval); }; /** @@ -65,7 +67,7 @@ define(function(require) { // check if there are unregistered recipients function checkRecipients(recipients) { var after = _.after(recipients.length, function() { - encryptAndPersist(); + checkEncrypt(); }); // find out if there are unregistered users @@ -87,11 +89,10 @@ define(function(require) { }); } - - function encryptAndPersist() { + function checkEncrypt() { // only encrypt if all recipients have public keys if (mail.publicKeysArmored.length < allReaders.length) { - self._devicestorage.storeList([mail], outboxDb, callback); + storeAndForward(mail); return; } @@ -105,7 +106,21 @@ define(function(require) { return; } - self._devicestorage.storeList([mail], outboxDb, callback); + storeAndForward(mail); + }); + } + + function storeAndForward(mail) { + // store in outbox + self._devicestorage.storeList([mail], outboxDb, function(err) { + if (err) { + callback(err); + return; + } + + callback(); + // don't wait for next round + self._processOutbox(self._onError); }); } }; diff --git a/src/js/controller/read.js b/src/js/controller/read.js index ae062db..599809f 100644 --- a/src/js/controller/read.js +++ b/src/js/controller/read.js @@ -20,7 +20,7 @@ define(function(require) { keychain = appController._keychain; // set default value so that the popover height is correct on init - $scope.keyId = 'XXXXXXXX'; + $scope.keyId = 'No key found.'; $scope.state.read = { open: false, @@ -34,7 +34,7 @@ define(function(require) { }; $scope.getKeyId = function(address) { - $scope.keyId = 'unknown user'; + $scope.keyId = 'Searching...'; keychain.getReceiverPublicKey(address, function(err, pubkey) { if (err) { $scope.onError(err); @@ -42,13 +42,15 @@ define(function(require) { } if (!pubkey) { + $scope.keyId = 'User has no key. Click to invite.'; + $scope.$apply(); return; } var fpr = crypto.getFingerprint(pubkey.publicKey); var formatted = fpr.slice(32); - $scope.keyId = formatted; + $scope.keyId = 'PGP key: ' + formatted; $scope.$apply(); }); }; @@ -116,10 +118,20 @@ define(function(require) { } }; - $scope.inviteUser = function(address) { + $scope.invite = function(user) { + // only invite non-pgp users + if (user.secure) { + return; + } + + $scope.keyId = 'Sending invitation...'; + + var sender = emailDao._account.emailAddress, + recipient = user.address; + invitationDao.invite({ - recipient: address, - sender: emailDao._account.emailAddress + recipient: recipient, + sender: sender }, function(err) { if (err) { $scope.onError(err); @@ -127,8 +139,14 @@ define(function(require) { } var invitationMail = { - from: [emailDao._account.emailAddress], - to: [address], + from: [{ + address: sender + }], + to: [{ + address: recipient + }], + cc: [], + bcc: [], subject: str.invitationSubject, body: str.invitationMessage }; diff --git a/src/js/dao/email-dao.js b/src/js/dao/email-dao.js index 8592a04..0fdebcd 100644 --- a/src/js/dao/email-dao.js +++ b/src/js/dao/email-dao.js @@ -1037,7 +1037,7 @@ define(function(require) { // mime encode, sign, encrypt and send email via smtp self._pgpMailer.send({ encrypt: true, - cleartextMessage: str.message, + cleartextMessage: str.message + str.signature, mail: options.email, publicKeysArmored: options.email.publicKeysArmored }, callback); diff --git a/src/tpl/read.html b/src/tpl/read.html index 86a17bd..4e59bf9 100644 --- a/src/tpl/read.html +++ b/src/tpl/read.html @@ -9,14 +9,14 @@

{{(state.mailList.selected.subject) ? state.mailList.selected.subject : 'No subject'}}

{{state.mailList.selected.sentDate | date:'EEEE, MMM d, yyyy h:mm a'}}

- From: {{u.name || u.address}} + From: {{u.name || u.address}}

- To: {{u.name || u.address}} + To: {{u.name || u.address}}

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

@@ -54,6 +54,6 @@
-
PGP key: {{keyId}}
+
{{keyId}}
diff --git a/test/new-unit/outbox-bo-test.js b/test/new-unit/outbox-bo-test.js index afb7ce3..c9aeb95 100644 --- a/test/new-unit/outbox-bo-test.js +++ b/test/new-unit/outbox-bo-test.js @@ -5,8 +5,7 @@ define(function(require) { OutboxBO = require('js/bo/outbox'), KeychainDAO = require('js/dao/keychain-dao'), EmailDAO = require('js/dao/email-dao'), - DeviceStorageDAO = require('js/dao/devicestorage-dao'), - InvitationDAO = require('js/dao/invitation-dao'); + DeviceStorageDAO = require('js/dao/devicestorage-dao'); chai.Assertion.includeStack = true; @@ -25,7 +24,6 @@ define(function(require) { }; devicestorageStub = sinon.createStubInstance(DeviceStorageDAO); keychainStub = sinon.createStubInstance(KeychainDAO); - invitationDaoStub = sinon.createStubInstance(InvitationDAO); outbox = new OutboxBO(emailDaoStub, keychainStub, devicestorageStub, invitationDaoStub); }); @@ -46,7 +44,7 @@ define(function(require) { }); describe('put', function() { - it('should encrypt and store a mail', function(done) { + it('should not encrypt and store a mail', function(done) { var mail, senderKey, receiverKey; senderKey = { @@ -75,9 +73,51 @@ define(function(require) { keychainStub.getReceiverPublicKey.withArgs(mail.to[0].address).yieldsAsync(null, receiverKey); keychainStub.getReceiverPublicKey.withArgs(mail.to[1].address).yieldsAsync(); + devicestorageStub.storeList.withArgs([mail]).yieldsAsync(); + + outbox.put(mail, function(error) { + expect(error).to.not.exist; + + expect(mail.publicKeysArmored.length).to.equal(2); + expect(emailDaoStub.encrypt.called).to.be.false; + expect(devicestorageStub.storeList.calledOnce).to.be.true; + + done(); + }); + }); + + it('should encrypt and store a mail', function(done) { + var mail, senderKey, receiverKey; + + senderKey = { + publicKey: 'SENDER PUBLIC KEY' + }; + receiverKey = { + publicKey: 'RECEIVER PUBLIC KEY' + }; + mail = { + from: [{ + name: 'member', + address: 'member@whiteout.io' + }], + to: [{ + name: 'member', + address: 'member' + }, { + name: 'notamember', + address: 'notamember' + }], + cc: [], + bcc: [] + }; + + keychainStub.getReceiverPublicKey.withArgs(mail.from[0].address).yieldsAsync(null, senderKey); + keychainStub.getReceiverPublicKey.withArgs(mail.to[0].address).yieldsAsync(null, receiverKey); + keychainStub.getReceiverPublicKey.withArgs(mail.to[1].address).yieldsAsync(null, receiverKey); + emailDaoStub.encrypt.withArgs({ mail: mail, - publicKeysArmored: [senderKey.publicKey, receiverKey.publicKey] + publicKeysArmored: [senderKey.publicKey, receiverKey.publicKey, receiverKey.publicKey] }).yieldsAsync(); devicestorageStub.storeList.withArgs([mail]).yieldsAsync(); @@ -85,8 +125,9 @@ define(function(require) { outbox.put(mail, function(error) { expect(error).to.not.exist; - expect(mail.publicKeysArmored.length).to.equal(2); - expect(mail.unregisteredUsers.length).to.equal(1); + expect(mail.publicKeysArmored.length).to.equal(3); + expect(emailDaoStub.encrypt.calledOnce).to.be.true; + expect(devicestorageStub.storeList.calledOnce).to.be.true; done(); }); @@ -162,28 +203,8 @@ define(function(require) { keychainStub.getReceiverPublicKey.withArgs(notinvited.unregisteredUsers[0].address).yieldsAsync(); keychainStub.getReceiverPublicKey.withArgs(newlyjoined.unregisteredUsers[0].address).yieldsAsync(null, newlyjoinedKey); - invitationDaoStub.check.withArgs({ - recipient: invited.to[0].address, - sender: invited.from[0].address - }).yieldsAsync(null, InvitationDAO.INVITE_PENDING); - - invitationDaoStub.check.withArgs({ - recipient: notinvited.to[0].address, - sender: notinvited.from[0].address - }).yieldsAsync(null, InvitationDAO.INVITE_MISSING); - - invitationDaoStub.invite.withArgs({ - recipient: notinvited.to[0].address, - sender: notinvited.from[0].address - }).yieldsAsync(null, InvitationDAO.INVITE_SUCCESS); - emailDaoStub.sendPlaintext.yieldsAsync(); - emailDaoStub.reEncrypt.withArgs({ - mail: newlyjoined, - publicKeysArmored: [newlyjoinedKey.publicKey] - }).yieldsAsync(null, newlyjoined); - emailDaoStub.sendEncrypted.withArgs({ email: newlyjoined }).yieldsAsync();