Skip to content
This repository was archived by the owner on Jul 10, 2019. It is now read-only.

Commit 9bc2bc7

Browse files
author
Tankred Hase
committed
Show invite dialog in writer when recipient has no public key
1 parent 9aebecd commit 9bc2bc7

File tree

10 files changed

+270
-25
lines changed

10 files changed

+270
-25
lines changed

src/js/app-config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module.exports = appCfg;
1212
* Global app configurations
1313
*/
1414
appCfg.config = {
15+
pgpComment: 'Whiteout Mail - https://whiteout.io',
1516
keyServerUrl: 'https://keys.whiteout.io',
1617
hkpUrl: 'http://keyserver.ubuntu.com',
1718
privkeyServerUrl: 'https://keychain.whiteout.io',

src/js/controller/app/read.js

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
var ReadCtrl = function($scope, $location, $q, email, invitation, outbox, pgp, keychain, appConfig, download, auth, dialog, status) {
88

9-
var str = appConfig.string;
10-
119
//
1210
// scope state
1311
//
@@ -158,18 +156,10 @@ var ReadCtrl = function($scope, $location, $q, email, invitation, outbox, pgp, k
158156
});
159157

160158
}).then(function() {
161-
var invitationMail = {
162-
from: [{
163-
address: sender
164-
}],
165-
to: [{
166-
address: recipient
167-
}],
168-
cc: [],
169-
bcc: [],
170-
subject: str.invitationSubject,
171-
body: str.invitationMessage
172-
};
159+
var invitationMail = invitation.createMail({
160+
sender: sender,
161+
recipient: recipient
162+
});
173163
// send invitation mail
174164
return outbox.put(invitationMail);
175165

src/js/controller/app/write.js

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ var util = require('crypto-lib').util;
66
// Controller
77
//
88

9-
var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain, pgp, email, outbox, dialog, axe, status) {
9+
var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain, pgp, email, outbox, dialog, axe, status, invitation) {
1010

1111
var str = appConfig.string;
1212
var cfg = appConfig.config;
@@ -52,6 +52,8 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain
5252
$scope.body = '';
5353
$scope.attachments = [];
5454
$scope.addressBookCache = undefined;
55+
$scope.showInvite = undefined;
56+
$scope.invited = [];
5557
}
5658

5759
function reportBug() {
@@ -248,6 +250,9 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain
248250
recipient.key = key;
249251
recipient.secure = true;
250252
}
253+
} else {
254+
// show invite dialog if no key found
255+
$scope.showInvite = true;
251256
}
252257
$scope.checkSendStatus();
253258

@@ -286,6 +291,7 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain
286291

287292
// only allow sending if receviers exist
288293
if (numReceivers < 1) {
294+
$scope.showInvite = false;
289295
return;
290296
}
291297

@@ -299,6 +305,7 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain
299305
$scope.okToSend = true;
300306
$scope.sendBtnText = str.sendBtnSecure;
301307
$scope.sendBtnSecure = true;
308+
$scope.showInvite = false;
302309
} else {
303310
// send plaintext
304311
$scope.okToSend = true;
@@ -315,6 +322,56 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain
315322
$scope.attachments.splice($scope.attachments.indexOf(attachment), 1);
316323
};
317324

325+
/**
326+
* Invite all users without a public key
327+
*/
328+
$scope.invite = function() {
329+
var sender = auth.emailAddress,
330+
sendJobs = [],
331+
invitees = [];
332+
333+
$scope.showInvite = false;
334+
335+
// get recipients with no keys
336+
$scope.to.forEach(check);
337+
$scope.cc.forEach(check);
338+
$scope.bcc.forEach(check);
339+
340+
function check(recipient) {
341+
if (util.validateEmailAddress(recipient.address) && !recipient.secure && $scope.invited.indexOf(recipient.address) === -1) {
342+
invitees.push(recipient.address);
343+
}
344+
}
345+
346+
return $q(function(resolve) {
347+
resolve();
348+
349+
}).then(function() {
350+
invitees.forEach(function(recipientAddress) {
351+
var invitationMail = invitation.createMail({
352+
sender: sender,
353+
recipient: recipientAddress
354+
});
355+
// send invitation mail
356+
var promise = outbox.put(invitationMail).then(function() {
357+
return invitation.invite({
358+
recipient: recipientAddress,
359+
sender: sender
360+
});
361+
});
362+
sendJobs.push(promise);
363+
// remember already invited users to prevent spamming
364+
$scope.invited.push(recipientAddress);
365+
});
366+
367+
return Promise.all(sendJobs);
368+
369+
}).catch(function(err) {
370+
$scope.showInvite = true;
371+
return dialog.error(err);
372+
});
373+
};
374+
318375
//
319376
// Editing email body
320377
//

src/js/crypto/pgp.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ var util = openpgp.util,
1111
* High level crypto api that handles all calls to OpenPGP.js
1212
*/
1313
function PGP() {
14-
openpgp.config.commentstring = 'Whiteout Mail - https://whiteout.io';
14+
openpgp.config.commentstring = config.pgpComment;
1515
openpgp.config.prefer_hash_algorithm = openpgp.enums.hash.sha256;
1616
openpgp.initWorker(config.workerPath + '/openpgp.worker.min.js');
1717
}

src/js/email/outbox.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ Outbox.prototype.put = function(mail) {
6262
var self = this,
6363
allReaders = mail.from.concat(mail.to.concat(mail.cc.concat(mail.bcc))); // all the users that should be able to read the mail
6464

65+
if (mail.to.concat(mail.cc.concat(mail.bcc)).length === 0) {
66+
return new Promise(function() {
67+
throw new Error('Message has no recipients!');
68+
});
69+
}
70+
6571
mail.publicKeysArmored = []; // gather the public keys
6672
mail.uid = mail.id = util.UUID(); // the mail needs a random id & uid for storage in the database
6773

src/js/service/invitation.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,33 @@ module.exports = Invitation;
88
* The Invitation is a high level Data Access Object that access the invitation service REST endpoint.
99
* @param {Object} restDao The REST Data Access Object abstraction
1010
*/
11-
function Invitation(invitationRestDao) {
11+
function Invitation(invitationRestDao, appConfig) {
1212
this._restDao = invitationRestDao;
13+
this._appConfig = appConfig;
1314
}
1415

15-
//
16-
// API
17-
//
16+
/**
17+
* Create the invitation mail object
18+
* @param {String} options.sender The sender's email address
19+
* @param {String} options.recipient The recipient's email address
20+
* @return {Object} The mail object
21+
*/
22+
Invitation.prototype.createMail = function(options) {
23+
var str = this._appConfig.string;
24+
25+
return {
26+
from: [{
27+
address: options.sender
28+
}],
29+
to: [{
30+
address: options.recipient
31+
}],
32+
cc: [],
33+
bcc: [],
34+
subject: str.invitationSubject,
35+
body: str.invitationMessage
36+
};
37+
};
1838

1939
/**
2040
* Notes an invite for the recipient by the sender in the invitation web service

src/sass/blocks/views/_write.scss

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,33 @@
2121
margin-top: 0.5em;
2222
}
2323
}
24+
&__invite {
25+
position: relative;
26+
margin-top: 1.3em;
27+
border: 1px solid $color-red-light;
28+
29+
p {
30+
color: $color-red-light;
31+
margin: 0.7em 1em;
32+
33+
svg {
34+
width: 1em;
35+
height: 1em;
36+
fill: $color-red-light;
37+
38+
// for better valignment
39+
position: relative;
40+
top: 0.15em;
41+
margin-right: 0.3em;
42+
}
43+
}
44+
45+
.btn {
46+
position: absolute;
47+
top: 5px;
48+
right: 5px;
49+
}
50+
}
2451
&__subject {
2552
position: relative;
2653
margin-top: 1.3em;

src/tpl/write.html

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ <h2>{{writerTitle}}</h2>
4141
</tags-input>
4242
</div>
4343

44+
<div class="write__invite" ng-show="showInvite">
45+
<p>
46+
<svg role="presentation"><use xlink:href="#icon-decrypted"/></svg>
47+
<strong>Key not found!</strong>
48+
<span class="u-hidden-sm">Invite user to encrypt.</span>
49+
</p>
50+
<button class="btn btn--light" wo-touch="invite()" title="Invite to Whiteout Mail">
51+
<svg role="presentation"><use xlink:href="#icon-add_contact"/></svg>
52+
Invite
53+
</button>
54+
</div>
55+
4456
<div class="write__subject">
4557
<input class="input-text" ng-model="subject" spellcheck="true" tabindex="2" placeholder="Subject" ng-change="updatePreview()">
4658
<input id="attachment-input" type="file" multiple attachment-input>
@@ -61,10 +73,10 @@ <h2>{{writerTitle}}</h2>
6173
</header>
6274

6375
<textarea class="write__body" ng-model="body" spellcheck="true" wo-focus-me="state.lightbox === 'write' && writerTitle === 'Reply'" tabindex="3"></textarea>
76+
</div><!--/write-->
6477

65-
</div>
6678
<footer class="lightbox__controls">
6779
<button wo-touch="sendToOutbox()" class="btn" ng-class="{'btn--invalid': sendBtnSecure === false}"
6880
ng-disabled="!okToSend" tabindex="4">{{sendBtnText || 'Send'}}</button>
6981
</footer>
70-
</div>
82+
</div><!--/lightbox__body-->

0 commit comments

Comments
 (0)