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:
parent
badea7ab8a
commit
3d6a4698ce
@ -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;
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
@ -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) ? '' : ''}}" 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) ? '' : ''}}" 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) ? '' : ''}}" 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) ? '' : ''}}" 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) ? '' : ''}}" 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) ? '' : ''}}" 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-->
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user