comparison plugins/enigma/enigma.js @ 0:1e000243b222

vanilla 1.3.3 distro, I hope
author Charlie Root
date Thu, 04 Jan 2018 15:50:29 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e000243b222
1 /* Enigma Plugin */
2
3 window.rcmail && rcmail.addEventListener('init', function(evt) {
4 if (rcmail.env.task == 'settings') {
5 if (rcmail.gui_objects.keyslist) {
6 rcmail.keys_list = new rcube_list_widget(rcmail.gui_objects.keyslist,
7 {multiselect:true, draggable:false, keyboard:false});
8 rcmail.keys_list
9 .addEventListener('select', function(o) { rcmail.enigma_keylist_select(o); })
10 .addEventListener('keypress', function(o) { rcmail.enigma_keylist_keypress(o); })
11 .init()
12 .focus();
13
14 rcmail.enigma_list();
15
16 rcmail.register_command('firstpage', function(props) { return rcmail.enigma_list_page('first'); });
17 rcmail.register_command('previouspage', function(props) { return rcmail.enigma_list_page('previous'); });
18 rcmail.register_command('nextpage', function(props) { return rcmail.enigma_list_page('next'); });
19 rcmail.register_command('lastpage', function(props) { return rcmail.enigma_list_page('last'); });
20 }
21
22 if (rcmail.env.action == 'plugin.enigmakeys') {
23 rcmail.register_command('search', function(props) {return rcmail.enigma_search(props); }, true);
24 rcmail.register_command('reset-search', function(props) {return rcmail.enigma_search_reset(props); }, true);
25 rcmail.register_command('plugin.enigma-import', function() { rcmail.enigma_import(); }, true);
26 rcmail.register_command('plugin.enigma-import-search', function() { rcmail.enigma_import_search(); }, true);
27 rcmail.register_command('plugin.enigma-key-export', function() { rcmail.enigma_export(); });
28 rcmail.register_command('plugin.enigma-key-export-selected', function() { rcmail.enigma_export(true); });
29 rcmail.register_command('plugin.enigma-key-import', function() { rcmail.enigma_key_import(); }, true);
30 rcmail.register_command('plugin.enigma-key-delete', function(props) { return rcmail.enigma_delete(); });
31 rcmail.register_command('plugin.enigma-key-create', function(props) { return rcmail.enigma_key_create(); }, true);
32 rcmail.register_command('plugin.enigma-key-save', function(props) { return rcmail.enigma_key_create_save(); }, true);
33
34 rcmail.addEventListener('responseafterplugin.enigmakeys', function() {
35 rcmail.enable_command('plugin.enigma-key-export', rcmail.env.rowcount > 0);
36 });
37
38 if (rcmail.gui_objects.importform) {
39 // make sure Enter key in search input starts searching
40 // instead of submitting the form
41 $('#rcmimportsearch').keydown(function(e) {
42 if (e.which == 13) {
43 rcmail.enigma_import_search();
44 return false;
45 }
46 });
47
48 $('input[type="button"]:first').focus();
49 }
50 }
51 }
52 else if (rcmail.env.task == 'mail') {
53 if (rcmail.env.action == 'compose') {
54 rcmail.addEventListener('beforesend', function(props) { rcmail.enigma_beforesend_handler(props); })
55 .addEventListener('beforesavedraft', function(props) { rcmail.enigma_beforesavedraft_handler(props); });
56
57 $('input,label', $('#enigmamenu')).mouseup(function(e) {
58 // don't close the menu on mouse click inside
59 e.stopPropagation();
60 });
61
62 $('a.button.enigma').prop('tabindex', $('#messagetoolbar > a:first').prop('tabindex'));
63 }
64
65 $.each(['encrypt', 'sign'], function() {
66 if (rcmail.env['enigma_force_' + this])
67 $('[name="_enigma_' + this + '"]').prop('checked', true);
68 });
69
70 if (rcmail.env.enigma_password_request) {
71 rcmail.enigma_password_request(rcmail.env.enigma_password_request);
72 }
73 }
74 });
75
76
77 /*********************************************************/
78 /********* Enigma Settings/Keys/Certs UI *********/
79 /*********************************************************/
80
81 // Display key(s) import form
82 rcube_webmail.prototype.enigma_key_import = function()
83 {
84 this.enigma_loadframe('&_action=plugin.enigmakeys&_a=import');
85 };
86
87 // Display key(s) generation form
88 rcube_webmail.prototype.enigma_key_create = function()
89 {
90 this.enigma_loadframe('&_action=plugin.enigmakeys&_a=create');
91 };
92
93 // Generate key(s) and submit them
94 rcube_webmail.prototype.enigma_key_create_save = function()
95 {
96 var options, lock, users = [],
97 password = $('#key-pass').val(),
98 confirm = $('#key-pass-confirm').val(),
99 size = $('#key-size').val();
100
101 $('[name="identity[]"]:checked').each(function() {
102 users.push(this.value);
103 });
104
105 // validate the form
106 if (!password || !confirm)
107 return alert(this.get_label('enigma.formerror'));
108
109 if (password != confirm)
110 return alert(this.get_label('enigma.passwordsdiffer'));
111
112 if (!users.length)
113 return alert(this.get_label('enigma.noidentselected'));
114
115 // generate keys
116 // use OpenPGP.js if browser supports required features
117 if (window.openpgp && window.crypto && (window.crypto.getRandomValues || window.crypto.subtle)) {
118 lock = this.set_busy(true, 'enigma.keygenerating');
119 options = {
120 numBits: size,
121 userId: users,
122 passphrase: password
123 };
124
125 openpgp.generateKeyPair(options).then(function(keypair) {
126 // success
127 var post = {_a: 'import', _keys: keypair.privateKeyArmored, _generated: 1,
128 _passwd: password, _keyid: keypair.key.primaryKey.fingerprint};
129
130 // send request to server
131 rcmail.http_post('plugin.enigmakeys', post, lock);
132 }, function(error) {
133 // failure
134 rcmail.set_busy(false, null, lock);
135 rcmail.display_message(rcmail.get_label('enigma.keygenerateerror'), 'error');
136 });
137 }
138 else {
139 rcmail.display_message(rcmail.get_label('enigma.keygennosupport'), 'error');
140 }
141 };
142
143 // Action executed after successful key generation and import
144 rcube_webmail.prototype.enigma_key_create_success = function()
145 {
146 parent.rcmail.enigma_list(1);
147 };
148
149 // Delete key(s)
150 rcube_webmail.prototype.enigma_delete = function()
151 {
152 var keys = this.keys_list.get_selection();
153
154 if (!keys.length || !confirm(this.get_label('enigma.keyremoveconfirm')))
155 return;
156
157 var lock = this.display_message(this.get_label('enigma.keyremoving'), 'loading'),
158 post = {_a: 'delete', _keys: keys};
159
160 // send request to server
161 this.http_post('plugin.enigmakeys', post, lock);
162 };
163
164 // Export key(s)
165 rcube_webmail.prototype.enigma_export = function(selected)
166 {
167 var priv = false,
168 list = this.keys_list,
169 keys = selected ? list.get_selection().join(',') : '*',
170 args = {_keys: keys};
171
172 if (!keys.length)
173 return;
174
175 // find out whether selected keys are private
176 if (keys == '*')
177 priv = true;
178 else
179 $.each(list.get_selection(), function() {
180 flags = $(list.rows[this].obj).data('flags');
181 if (flags && flags.indexOf('p') >= 0) {
182 priv = true;
183 return false;
184 }
185 });
186
187 // ask the user about including private key in the export
188 if (priv)
189 return this.show_popup_dialog(
190 this.get_label('enigma.keyexportprompt'),
191 this.get_label('enigma.exportkeys'),
192 [{
193 text: this.get_label('enigma.onlypubkeys'),
194 click: function(e) {
195 rcmail.enigma_export_submit(args);
196 $(this).remove();
197 }
198 },
199 {
200 text: this.get_label('enigma.withprivkeys'),
201 click: function(e) {
202 args._priv = 1;
203 rcmail.enigma_export_submit(args);
204 $(this).remove();
205 }
206 }],
207 {width: 400}
208 );
209
210 this.enigma_export_submit(args);
211 };
212
213 // Sumbitting request for key(s) export
214 // Done this way to handle password input
215 rcube_webmail.prototype.enigma_export_submit = function(data)
216 {
217 var id = 'keyexport-' + new Date().getTime(),
218 form = $('<form>').attr({target: id, method: 'post', style: 'display:none',
219 action: '?_action=plugin.enigmakeys&_task=settings&_a=export'}),
220 iframe = $('<iframe>').attr({name: id, style: 'display:none'})
221
222 form.append($('<input>').attr({name: '_token', value: this.env.request_token}));
223 $.each(data, function(i, v) {
224 form.append($('<input>').attr({name: i, value: v}));
225 });
226
227 iframe.appendTo(document.body);
228 form.appendTo(document.body).submit();
229 };
230
231 // Submit key(s) import form
232 rcube_webmail.prototype.enigma_import = function()
233 {
234 var form, file, lock,
235 id = 'keyexport-' + new Date().getTime(),
236 iframe = $('<iframe>').attr({name: id, style: 'display:none'});
237
238 if (form = this.gui_objects.importform) {
239 file = document.getElementById('rcmimportfile');
240 if (file && !file.value) {
241 alert(this.get_label('selectimportfile'));
242 return;
243 }
244
245 lock = this.set_busy(true, 'importwait');
246 iframe.appendTo(document.body);
247 $(form).attr({target: id, action: this.add_url(form.action, '_unlock', lock)})
248 .submit();
249 }
250 };
251
252 // Ssearch for key(s) for import
253 rcube_webmail.prototype.enigma_import_search = function()
254 {
255 var form, search;
256
257 if (form = this.gui_objects.importform) {
258 search = $('#rcmimportsearch').val();
259 if (!search) {
260 return;
261 }
262
263 this.enigma_find_publickey(search);
264 }
265 };
266
267 // list row selection handler
268 rcube_webmail.prototype.enigma_keylist_select = function(list)
269 {
270 var id = list.get_single_selection(), url;
271
272 if (id)
273 url = '&_action=plugin.enigmakeys&_a=info&_id=' + id;
274
275 this.enigma_loadframe(url);
276 this.enable_command('plugin.enigma-key-delete', 'plugin.enigma-key-export-selected', list.selection.length > 0);
277 };
278
279 rcube_webmail.prototype.enigma_keylist_keypress = function(list)
280 {
281 if (list.modkey == CONTROL_KEY)
282 return;
283
284 if (list.key_pressed == list.DELETE_KEY || list.key_pressed == list.BACKSPACE_KEY)
285 this.command('plugin.enigma-key-delete');
286 else if (list.key_pressed == 33)
287 this.command('previouspage');
288 else if (list.key_pressed == 34)
289 this.command('nextpage');
290 };
291
292 // load key frame
293 rcube_webmail.prototype.enigma_loadframe = function(url)
294 {
295 var win;
296
297 if (win = this.get_frame_window(this.env.contentframe)) {
298 if (!url) {
299 if (win.location && win.location.href.indexOf(this.env.blankpage) < 0)
300 win.location.href = this.env.blankpage;
301 if (this.env.frame_lock)
302 this.set_busy(false, null, this.env.frame_lock);
303 return;
304 }
305
306 this.env.frame_lock = this.set_busy(true, 'loading');
307 win.location.href = this.env.comm_path + '&_framed=1' + url;
308 }
309 };
310
311 // Search keys/certs
312 rcube_webmail.prototype.enigma_search = function(props)
313 {
314 if (!props && this.gui_objects.qsearchbox)
315 props = this.gui_objects.qsearchbox.value;
316
317 if (props || this.env.search_request) {
318 var params = {'_a': 'search', '_q': props},
319 lock = this.set_busy(true, 'searching');
320 // if (this.gui_objects.search_filter)
321 // addurl += '&_filter=' + this.gui_objects.search_filter.value;
322 this.env.current_page = 1;
323 this.enigma_loadframe();
324 this.enigma_clear_list();
325 this.http_post('plugin.enigmakeys', params, lock);
326 }
327
328 return false;
329 };
330
331 // Reset search filter and the list
332 rcube_webmail.prototype.enigma_search_reset = function(props)
333 {
334 var s = this.env.search_request;
335 this.reset_qsearch();
336
337 if (s) {
338 this.enigma_loadframe();
339 this.enigma_clear_list();
340
341 // refresh the list
342 this.enigma_list();
343 }
344
345 return false;
346 };
347
348 // Keys/certs listing
349 rcube_webmail.prototype.enigma_list = function(page, reset_frame)
350 {
351 if (this.is_framed())
352 return parent.rcmail.enigma_list(page, reset_frame);
353
354 var params = {'_a': 'list'},
355 lock = this.set_busy(true, 'loading');
356
357 this.env.current_page = page ? page : 1;
358
359 if (this.env.search_request)
360 params._q = this.env.search_request;
361 if (page)
362 params._p = page;
363
364 this.enigma_clear_list(reset_frame);
365 this.http_post('plugin.enigmakeys', params, lock);
366 };
367
368 // Change list page
369 rcube_webmail.prototype.enigma_list_page = function(page)
370 {
371 if (page == 'next')
372 page = this.env.current_page + 1;
373 else if (page == 'last')
374 page = this.env.pagecount;
375 else if (page == 'prev' && this.env.current_page > 1)
376 page = this.env.current_page - 1;
377 else if (page == 'first' && this.env.current_page > 1)
378 page = 1;
379
380 this.enigma_list(page);
381 };
382
383 // Remove list rows
384 rcube_webmail.prototype.enigma_clear_list = function(reset_frame)
385 {
386 if (reset_frame !== false)
387 this.enigma_loadframe();
388
389 if (this.keys_list)
390 this.keys_list.clear(true);
391
392 this.enable_command('plugin.enigma-key-delete', 'plugin.enigma-key-delete-selected', false);
393 };
394
395 // Adds a row to the list
396 rcube_webmail.prototype.enigma_add_list_row = function(r)
397 {
398 if (!this.gui_objects.keyslist || !this.keys_list)
399 return false;
400
401 var list = this.keys_list,
402 tbody = this.gui_objects.keyslist.tBodies[0],
403 rowcount = tbody.rows.length,
404 even = rowcount%2,
405 css_class = 'message'
406 + (even ? ' even' : ' odd'),
407 // for performance use DOM instead of jQuery here
408 row = document.createElement('tr'),
409 col = document.createElement('td');
410
411 row.id = 'rcmrow' + r.id;
412 row.className = css_class;
413 if (r.flags) $(row).data('flags', r.flags);
414
415 col.innerHTML = r.name;
416 row.appendChild(col);
417 list.insert_row(row);
418 };
419
420
421 /*********************************************************/
422 /********* Enigma Message methods *********/
423 /*********************************************************/
424
425 // handle message send/save action
426 rcube_webmail.prototype.enigma_beforesend_handler = function(props)
427 {
428 this.env.last_action = 'send';
429 this.enigma_compose_handler(props);
430 };
431
432 rcube_webmail.prototype.enigma_beforesavedraft_handler = function(props)
433 {
434 this.env.last_action = 'savedraft';
435 this.enigma_compose_handler(props);
436 };
437
438 rcube_webmail.prototype.enigma_compose_handler = function(props)
439 {
440 var form = this.gui_objects.messageform;
441
442 // copy inputs from enigma menu to the form
443 $('#enigmamenu input').each(function() {
444 var id = this.id + '_cpy', input = $('#' + id);
445
446 if (!input.length) {
447 input = $(this).clone();
448 input.prop({id: id, type: 'hidden'}).appendTo(form);
449 }
450
451 input.val(this.checked ? '1' : '');
452 });
453
454 // disable signing when saving drafts
455 if (this.env.last_action == 'savedraft') {
456 $('input[name="_enigma_sign"]', form).val(0);
457 }
458 };
459
460 // Import attached keys/certs file
461 rcube_webmail.prototype.enigma_import_attachment = function(mime_id)
462 {
463 var lock = this.set_busy(true, 'loading'),
464 post = {_uid: this.env.uid, _mbox: this.env.mailbox, _part: mime_id};
465
466 this.http_post('plugin.enigmaimport', post, lock);
467
468 return false;
469 };
470
471 // password request popup
472 rcube_webmail.prototype.enigma_password_request = function(data)
473 {
474 if (!data || !data.keyid) {
475 return;
476 }
477
478 var ref = this,
479 msg = this.get_label('enigma.enterkeypass'),
480 myprompt = $('<div class="prompt">'),
481 myprompt_content = $('<div class="message">')
482 .appendTo(myprompt),
483 myprompt_input = $('<input>').attr({type: 'password', size: 30})
484 .keypress(function(e) {
485 if (e.which == 13)
486 (ref.is_framed() ? window.parent.$ : $)('.ui-dialog-buttonpane button.mainaction:visible').click();
487 })
488 .appendTo(myprompt);
489
490 data.key = data.keyid;
491 if (data.keyid.length > 8)
492 data.keyid = data.keyid.substr(data.keyid.length - 8);
493
494 $.each(['keyid', 'user'], function() {
495 msg = msg.replace('$' + this, data[this]);
496 });
497
498 myprompt_content.text(msg);
499
500 this.show_popup_dialog(myprompt, this.get_label('enigma.enterkeypasstitle'),
501 [{
502 text: this.get_label('save'),
503 'class': 'mainaction',
504 click: function(e) {
505 e.stopPropagation();
506
507 var jq = ref.is_framed() ? window.parent.$ : $;
508
509 data.password = myprompt_input.val();
510
511 if (!data.password) {
512 myprompt_input.focus();
513 return;
514 }
515
516 ref.enigma_password_submit(data);
517 jq(this).remove();
518 }
519 },
520 {
521 text: this.get_label('cancel'),
522 click: function(e) {
523 var jq = ref.is_framed() ? window.parent.$ : $;
524 e.stopPropagation();
525 jq(this).remove();
526 }
527 }], {width: 400});
528
529 if (this.is_framed() && parent.rcmail.message_list) {
530 // this fixes bug when pressing Enter on "Save" button in the dialog
531 parent.rcmail.message_list.blur();
532 }
533 };
534
535 // submit entered password
536 rcube_webmail.prototype.enigma_password_submit = function(data)
537 {
538 var lock, form;
539
540 if (this.env.action == 'compose' && !data['compose-init']) {
541 return this.enigma_password_compose_submit(data);
542 }
543 else if (this.env.action == 'plugin.enigmakeys' && (form = this.gui_objects.importform)) {
544 if (!$('input[name="_keyid"]', form).length) {
545 $(form).append($('<input>').attr({type: 'hidden', name: '_keyid', value: data.key}))
546 .append($('<input>').attr({type: 'hidden', name: '_passwd', value: data.password}))
547 }
548
549 return this.enigma_import();
550 }
551
552 lock = data.nolock ? null : this.set_busy(true, 'loading');
553 form = $('<form>')
554 .attr({method: 'post', action: data.action || location.href, style: 'display:none'})
555 .append($('<input>').attr({type: 'hidden', name: '_keyid', value: data.key}))
556 .append($('<input>').attr({type: 'hidden', name: '_passwd', value: data.password}))
557 .append($('<input>').attr({type: 'hidden', name: '_token', value: this.env.request_token}))
558 .append($('<input>').attr({type: 'hidden', name: '_unlock', value: lock}));
559
560 // Additional form fields for request parameters
561 $.each(data, function(i, v) {
562 if (i.indexOf('input') == 0)
563 form.append($('<input>').attr({type: 'hidden', name: i.substring(5), value: v}))
564 });
565
566 if (data.iframe) {
567 var name = 'enigma_frame_' + (new Date()).getTime(),
568 frame = $('<iframe>').attr({style: 'display:none', name: name}).appendTo(document.body);
569 form.attr('target', name);
570 }
571
572 form.appendTo(document.body).submit();
573 };
574
575 // submit entered password - in mail compose page
576 rcube_webmail.prototype.enigma_password_compose_submit = function(data)
577 {
578 var form = this.gui_objects.messageform;
579
580 if (!$('input[name="_keyid"]', form).length) {
581 $(form).append($('<input>').attr({type: 'hidden', name: '_keyid', value: data.key}))
582 .append($('<input>').attr({type: 'hidden', name: '_passwd', value: data.password}));
583 }
584 else {
585 $('input[name="_keyid"]', form).val(data.key);
586 $('input[name="_passwd"]', form).val(data.password);
587 }
588
589 this.submit_messageform(this.env.last_action == 'savedraft');
590 };
591
592 // Display no-key error with key search button
593 rcube_webmail.prototype.enigma_key_not_found = function(data)
594 {
595 return this.show_popup_dialog(
596 data.text,
597 data.title,
598 [{
599 text: data.button,
600 click: function(e) {
601 $(this).remove();
602 rcmail.enigma_find_publickey(data.email);
603 }
604 }],
605 {width: 400, dialogClass: 'error'}
606 );
607 };
608
609 // Search for a public key on the key server
610 rcube_webmail.prototype.enigma_find_publickey = function(email)
611 {
612 this.mailvelope_search_pubkeys([email],
613 function(status) {},
614 function(key) {
615 var lock = rcmail.set_busy(true, 'enigma.importwait'),
616 post = {_a: 'import', _keys: key};
617
618 if (rcmail.env.action == 'plugin.enigmakeys')
619 post._refresh = 1;
620
621 // send request to server
622 rcmail.http_post('plugin.enigmakeys', post, lock);
623 }
624 );
625 };