1
0
mirror of https://github.com/moparisthebest/mail synced 2024-11-26 02:42:17 -05:00

invite user when clicking on red address label

This commit is contained in:
Tankred Hase 2014-02-27 18:14:38 +01:00
parent badea7ab8a
commit 3d6a4698ce
6 changed files with 104 additions and 50 deletions

View File

@ -53,15 +53,15 @@ define(function(require) {
subjectPrefix: '[whiteout] ', subjectPrefix: '[whiteout] ',
fallbackSubject: '(no subject)', fallbackSubject: '(no subject)',
invitationSubject: 'Invitation to a private conversation', 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', 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.\n\nOpen Whiteout Mail: https://chrome.google.com/webstore/detail/jjgghafhamholjigjoghcfcekhkonijg\n\n', 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-----', cryptPrefix: '-----BEGIN PGP MESSAGE-----',
cryptSuffix: '-----END 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', webSite: 'http://whiteout.io',
verificationSubject: 'New public key uploaded', verificationSubject: 'New public key uploaded',
sendBtnClear: 'Send', sendBtnClear: 'Send',
sendBtnSecure: 'Secure send' sendBtnSecure: 'Send securely'
}; };
return app; return app;

View File

@ -32,8 +32,10 @@ define(function(require) {
* @param {Function} callback(error, pendingMailsCount) Callback that informs you about the count of pending mails. * @param {Function} callback(error, pendingMailsCount) Callback that informs you about the count of pending mails.
*/ */
OutboxBO.prototype.startChecking = function(callback) { OutboxBO.prototype.startChecking = function(callback) {
// remember global callback
this._onError = callback;
// start periodic checking of outbox // 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 // check if there are unregistered recipients
function checkRecipients(recipients) { function checkRecipients(recipients) {
var after = _.after(recipients.length, function() { var after = _.after(recipients.length, function() {
encryptAndPersist(); checkEncrypt();
}); });
// find out if there are unregistered users // find out if there are unregistered users
@ -87,11 +89,10 @@ define(function(require) {
}); });
} }
function checkEncrypt() {
function encryptAndPersist() {
// only encrypt if all recipients have public keys // only encrypt if all recipients have public keys
if (mail.publicKeysArmored.length < allReaders.length) { if (mail.publicKeysArmored.length < allReaders.length) {
self._devicestorage.storeList([mail], outboxDb, callback); storeAndForward(mail);
return; return;
} }
@ -105,7 +106,21 @@ define(function(require) {
return; 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);
}); });
} }
}; };

View File

@ -20,7 +20,7 @@ define(function(require) {
keychain = appController._keychain; keychain = appController._keychain;
// set default value so that the popover height is correct on init // set default value so that the popover height is correct on init
$scope.keyId = 'XXXXXXXX'; $scope.keyId = 'No key found.';
$scope.state.read = { $scope.state.read = {
open: false, open: false,
@ -34,7 +34,7 @@ define(function(require) {
}; };
$scope.getKeyId = function(address) { $scope.getKeyId = function(address) {
$scope.keyId = 'unknown user'; $scope.keyId = 'Searching...';
keychain.getReceiverPublicKey(address, function(err, pubkey) { keychain.getReceiverPublicKey(address, function(err, pubkey) {
if (err) { if (err) {
$scope.onError(err); $scope.onError(err);
@ -42,13 +42,15 @@ define(function(require) {
} }
if (!pubkey) { if (!pubkey) {
$scope.keyId = 'User has no key. Click to invite.';
$scope.$apply();
return; return;
} }
var fpr = crypto.getFingerprint(pubkey.publicKey); var fpr = crypto.getFingerprint(pubkey.publicKey);
var formatted = fpr.slice(32); var formatted = fpr.slice(32);
$scope.keyId = formatted; $scope.keyId = 'PGP key: ' + formatted;
$scope.$apply(); $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({ invitationDao.invite({
recipient: address, recipient: recipient,
sender: emailDao._account.emailAddress sender: sender
}, function(err) { }, function(err) {
if (err) { if (err) {
$scope.onError(err); $scope.onError(err);
@ -127,8 +139,14 @@ define(function(require) {
} }
var invitationMail = { var invitationMail = {
from: [emailDao._account.emailAddress], from: [{
to: [address], address: sender
}],
to: [{
address: recipient
}],
cc: [],
bcc: [],
subject: str.invitationSubject, subject: str.invitationSubject,
body: str.invitationMessage body: str.invitationMessage
}; };

View File

@ -1037,7 +1037,7 @@ define(function(require) {
// mime encode, sign, encrypt and send email via smtp // mime encode, sign, encrypt and send email via smtp
self._pgpMailer.send({ self._pgpMailer.send({
encrypt: true, encrypt: true,
cleartextMessage: str.message, cleartextMessage: str.message + str.signature,
mail: options.email, mail: options.email,
publicKeysArmored: options.email.publicKeysArmored publicKeysArmored: options.email.publicKeysArmored
}, callback); }, callback);

View File

@ -9,14 +9,14 @@
<p class="subject" ng-click="state.read.toggle(false)">{{(state.mailList.selected.subject) ? state.mailList.selected.subject : 'No subject'}}</p> <p class="subject" ng-click="state.read.toggle(false)">{{(state.mailList.selected.subject) ? state.mailList.selected.subject : 'No subject'}}</p>
<p class="date">{{state.mailList.selected.sentDate | date:'EEEE, MMM d, yyyy h:mm a'}}</p> <p class="date">{{state.mailList.selected.sentDate | date:'EEEE, MMM d, yyyy h:mm a'}}</p>
<p class="address"> <p class="address">
From: <span ng-repeat="u in state.mailList.selected.from" class="label" ng-class="{'label-primary': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : ''}}" ng-mouseover="getKeyId(u.address)" popover="#fingerprint-info">{{u.name || u.address}}</span> From: <span ng-repeat="u in state.mailList.selected.from" class="label" ng-class="{'label-primary': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : ''}}" ng-mouseover="getKeyId(u.address)" ng-click="invite(u)" popover="#fingerprint-info">{{u.name || u.address}}</span>
</p> </p>
<p class="address"> <p class="address">
To: <span ng-repeat="u in state.mailList.selected.to" class="label" ng-class="{'label-primary': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : ''}}" ng-mouseover="getKeyId(u.address)" popover="#fingerprint-info">{{u.name || u.address}}</span> To: <span ng-repeat="u in state.mailList.selected.to" class="label" ng-class="{'label-primary': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : ''}}" ng-mouseover="getKeyId(u.address)" ng-click="invite(u)" popover="#fingerprint-info">{{u.name || u.address}}</span>
</p> </p>
<div ng-switch="state.mailList.selected.cc !== undefined"> <div ng-switch="state.mailList.selected.cc !== undefined">
<p class="address" ng-switch-when="true"> <p class="address" ng-switch-when="true">
Cc: <span ng-repeat="u in state.mailList.selected.cc" class="label" ng-class="{'label-primary': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : ''}}" ng-mouseover="getKeyId(u.address)" popover="#fingerprint-info">{{u.name || u.address}}</span> Cc: <span ng-repeat="u in state.mailList.selected.cc" class="label" ng-class="{'label-primary': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : ''}}" ng-mouseover="getKeyId(u.address)" ng-click="invite(u)" popover="#fingerprint-info">{{u.name || u.address}}</span>
</p> </p>
</div> </div>
</div><!--/.headers--> </div><!--/.headers-->
@ -54,6 +54,6 @@
<!-- popovers --> <!-- popovers -->
<div id="fingerprint-info" class="popover right" ng-controller="PopoverCtrl"> <div id="fingerprint-info" class="popover right" ng-controller="PopoverCtrl">
<div class="arrow"></div> <div class="arrow"></div>
<div class="popover-content"><b>PGP key:</b> {{keyId}}</div> <div class="popover-content">{{keyId}}</div>
</div><!--/.popover--> </div><!--/.popover-->
</div><!--/.view-read--> </div><!--/.view-read-->

View File

@ -5,8 +5,7 @@ define(function(require) {
OutboxBO = require('js/bo/outbox'), OutboxBO = require('js/bo/outbox'),
KeychainDAO = require('js/dao/keychain-dao'), KeychainDAO = require('js/dao/keychain-dao'),
EmailDAO = require('js/dao/email-dao'), EmailDAO = require('js/dao/email-dao'),
DeviceStorageDAO = require('js/dao/devicestorage-dao'), DeviceStorageDAO = require('js/dao/devicestorage-dao');
InvitationDAO = require('js/dao/invitation-dao');
chai.Assertion.includeStack = true; chai.Assertion.includeStack = true;
@ -25,7 +24,6 @@ define(function(require) {
}; };
devicestorageStub = sinon.createStubInstance(DeviceStorageDAO); devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
keychainStub = sinon.createStubInstance(KeychainDAO); keychainStub = sinon.createStubInstance(KeychainDAO);
invitationDaoStub = sinon.createStubInstance(InvitationDAO);
outbox = new OutboxBO(emailDaoStub, keychainStub, devicestorageStub, invitationDaoStub); outbox = new OutboxBO(emailDaoStub, keychainStub, devicestorageStub, invitationDaoStub);
}); });
@ -46,7 +44,7 @@ define(function(require) {
}); });
describe('put', function() { 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; var mail, senderKey, receiverKey;
senderKey = { senderKey = {
@ -75,9 +73,51 @@ define(function(require) {
keychainStub.getReceiverPublicKey.withArgs(mail.to[0].address).yieldsAsync(null, receiverKey); keychainStub.getReceiverPublicKey.withArgs(mail.to[0].address).yieldsAsync(null, receiverKey);
keychainStub.getReceiverPublicKey.withArgs(mail.to[1].address).yieldsAsync(); 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({ emailDaoStub.encrypt.withArgs({
mail: mail, mail: mail,
publicKeysArmored: [senderKey.publicKey, receiverKey.publicKey] publicKeysArmored: [senderKey.publicKey, receiverKey.publicKey, receiverKey.publicKey]
}).yieldsAsync(); }).yieldsAsync();
devicestorageStub.storeList.withArgs([mail]).yieldsAsync(); devicestorageStub.storeList.withArgs([mail]).yieldsAsync();
@ -85,8 +125,9 @@ define(function(require) {
outbox.put(mail, function(error) { outbox.put(mail, function(error) {
expect(error).to.not.exist; expect(error).to.not.exist;
expect(mail.publicKeysArmored.length).to.equal(2); expect(mail.publicKeysArmored.length).to.equal(3);
expect(mail.unregisteredUsers.length).to.equal(1); expect(emailDaoStub.encrypt.calledOnce).to.be.true;
expect(devicestorageStub.storeList.calledOnce).to.be.true;
done(); done();
}); });
@ -162,28 +203,8 @@ define(function(require) {
keychainStub.getReceiverPublicKey.withArgs(notinvited.unregisteredUsers[0].address).yieldsAsync(); keychainStub.getReceiverPublicKey.withArgs(notinvited.unregisteredUsers[0].address).yieldsAsync();
keychainStub.getReceiverPublicKey.withArgs(newlyjoined.unregisteredUsers[0].address).yieldsAsync(null, newlyjoinedKey); 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.sendPlaintext.yieldsAsync();
emailDaoStub.reEncrypt.withArgs({
mail: newlyjoined,
publicKeysArmored: [newlyjoinedKey.publicKey]
}).yieldsAsync(null, newlyjoined);
emailDaoStub.sendEncrypted.withArgs({ emailDaoStub.sendEncrypted.withArgs({
email: newlyjoined email: newlyjoined
}).yieldsAsync(); }).yieldsAsync();