commit | author | age
|
48e9c1
|
1 |
/* Enigma Plugin */ |
T |
2 |
|
0878c8
|
3 |
window.rcmail && rcmail.addEventListener('init', function(evt) { |
AM |
4 |
if (rcmail.env.task == 'settings') { |
|
5 |
rcmail.register_command('plugin.enigma', function() { rcmail.goto_url('plugin.enigma') }, true); |
48e9c1
|
6 |
|
0878c8
|
7 |
if (rcmail.gui_objects.keyslist) { |
AM |
8 |
rcmail.keys_list = new rcube_list_widget(rcmail.gui_objects.keyslist, |
211929
|
9 |
{multiselect:true, draggable:false, keyboard:false}); |
0878c8
|
10 |
rcmail.keys_list |
AM |
11 |
.addEventListener('select', function(o) { rcmail.enigma_keylist_select(o); }) |
|
12 |
.addEventListener('keypress', function(o) { rcmail.enigma_keylist_keypress(o); }) |
|
13 |
.init() |
|
14 |
.focus(); |
48e9c1
|
15 |
|
0878c8
|
16 |
rcmail.enigma_list(); |
48e9c1
|
17 |
|
0878c8
|
18 |
rcmail.register_command('firstpage', function(props) { return rcmail.enigma_list_page('first'); }); |
AM |
19 |
rcmail.register_command('previouspage', function(props) { return rcmail.enigma_list_page('previous'); }); |
|
20 |
rcmail.register_command('nextpage', function(props) { return rcmail.enigma_list_page('next'); }); |
|
21 |
rcmail.register_command('lastpage', function(props) { return rcmail.enigma_list_page('last'); }); |
|
22 |
} |
48e9c1
|
23 |
|
0878c8
|
24 |
if (rcmail.env.action == 'plugin.enigmakeys') { |
AM |
25 |
rcmail.register_command('search', function(props) {return rcmail.enigma_search(props); }, true); |
|
26 |
rcmail.register_command('reset-search', function(props) {return rcmail.enigma_search_reset(props); }, true); |
|
27 |
rcmail.register_command('plugin.enigma-import', function() { rcmail.enigma_import(); }, true); |
211929
|
28 |
rcmail.register_command('plugin.enigma-key-export', function() { rcmail.enigma_export(); }); |
AM |
29 |
rcmail.register_command('plugin.enigma-key-export-selected', function() { rcmail.enigma_export(true); }); |
|
30 |
rcmail.register_command('plugin.enigma-key-import', function() { rcmail.enigma_key_import(); }, true); |
|
31 |
rcmail.register_command('plugin.enigma-key-delete', function(props) { return rcmail.enigma_delete(); }); |
d5501a
|
32 |
rcmail.register_command('plugin.enigma-key-create', function(props) { return rcmail.enigma_key_create(); }, true); |
AM |
33 |
rcmail.register_command('plugin.enigma-key-save', function(props) { return rcmail.enigma_key_create_save(); }, true); |
211929
|
34 |
|
AM |
35 |
rcmail.addEventListener('responseafterplugin.enigmakeys', function() { |
|
36 |
rcmail.enable_command('plugin.enigma-key-export', rcmail.env.rowcount > 0); |
|
37 |
}); |
0878c8
|
38 |
} |
AM |
39 |
} |
|
40 |
else if (rcmail.env.task == 'mail') { |
|
41 |
if (rcmail.env.action == 'compose') { |
a99c34
|
42 |
rcmail.addEventListener('beforesend', function(props) { rcmail.enigma_beforesend_handler(props); }) |
AM |
43 |
.addEventListener('beforesavedraft', function(props) { rcmail.enigma_beforesavedraft_handler(props); }); |
|
44 |
|
0878c8
|
45 |
$('input,label', $('#enigmamenu')).mouseup(function(e) { |
AM |
46 |
// don't close the menu on mouse click inside |
|
47 |
e.stopPropagation(); |
|
48 |
}); |
|
49 |
} |
58c279
|
50 |
|
f04b56
|
51 |
$.each(['encrypt', 'sign'], function() { |
AM |
52 |
if (rcmail.env['enigma_force_' + this]) |
|
53 |
$('[name="_enigma_' + this + '"]').prop('checked', true); |
|
54 |
}); |
|
55 |
|
58c279
|
56 |
if (rcmail.env.enigma_password_request) { |
AM |
57 |
rcmail.enigma_password_request(rcmail.env.enigma_password_request); |
48e9c1
|
58 |
} |
0878c8
|
59 |
} |
AM |
60 |
}); |
|
61 |
|
48e9c1
|
62 |
|
T |
63 |
/*********************************************************/ |
|
64 |
/********* Enigma Settings/Keys/Certs UI *********/ |
|
65 |
/*********************************************************/ |
|
66 |
|
|
67 |
// Display key(s) import form |
|
68 |
rcube_webmail.prototype.enigma_key_import = function() |
|
69 |
{ |
0878c8
|
70 |
this.enigma_loadframe('&_action=plugin.enigmakeys&_a=import'); |
d5501a
|
71 |
}; |
AM |
72 |
|
|
73 |
// Display key(s) generation form |
|
74 |
rcube_webmail.prototype.enigma_key_create = function() |
|
75 |
{ |
|
76 |
this.enigma_loadframe('&_action=plugin.enigmakeys&_a=create'); |
|
77 |
}; |
|
78 |
|
|
79 |
// Generate key(s) and submit them |
|
80 |
rcube_webmail.prototype.enigma_key_create_save = function() |
|
81 |
{ |
|
82 |
var options, lock, |
|
83 |
user = $('#key-ident > option').filter(':selected').text(), |
|
84 |
password = $('#key-pass').val(), |
|
85 |
confirm = $('#key-pass-confirm').val(), |
|
86 |
size = $('#key-size').val(); |
|
87 |
|
|
88 |
// validate the form |
|
89 |
if (!password || !confirm) |
8f8bea
|
90 |
return alert(this.get_label('enigma.formerror')); |
d5501a
|
91 |
|
AM |
92 |
if (password != confirm) |
8f8bea
|
93 |
return alert(this.get_label('enigma.passwordsdiffer')); |
d5501a
|
94 |
|
AM |
95 |
if (user.match(/^<[^>]+>$/)) |
8f8bea
|
96 |
return alert(this.get_label('enigma.nonameident')); |
d5501a
|
97 |
|
AM |
98 |
// generate keys |
|
99 |
// use OpenPGP.js if browser supports required features |
|
100 |
if (window.openpgp && window.crypto && (window.crypto.getRandomValues || window.crypto.subtle)) { |
|
101 |
lock = this.set_busy(true, 'enigma.keygenerating'); |
|
102 |
options = { |
|
103 |
numBits: size, |
|
104 |
userId: user, |
|
105 |
passphrase: password |
|
106 |
}; |
|
107 |
|
|
108 |
openpgp.generateKeyPair(options).then(function(keypair) { |
|
109 |
// success |
a0dfcb
|
110 |
var post = {_a: 'import', _keys: keypair.privateKeyArmored}; |
d5501a
|
111 |
|
AM |
112 |
// send request to server |
|
113 |
rcmail.http_post('plugin.enigmakeys', post, lock); |
a8848b
|
114 |
}, function(error) { |
d5501a
|
115 |
// failure |
AM |
116 |
rcmail.set_busy(false, null, lock); |
8f8bea
|
117 |
rcmail.display_message(rcmail.get_label('enigma.keygenerateerror'), 'error'); |
d5501a
|
118 |
}); |
AM |
119 |
} |
|
120 |
// generate keys on the server |
a0dfcb
|
121 |
else if (rcmail.env.enigma_keygen_server) { |
AM |
122 |
lock = this.set_busy(true, 'enigma.keygenerating'); |
|
123 |
options = {_a: 'generate', _user: user, _password: password, _size: size}; |
|
124 |
rcmail.http_post('plugin.enigmakeys', options, lock); |
|
125 |
} |
d5501a
|
126 |
else { |
8f8bea
|
127 |
rcmail.display_message(rcmail.get_label('enigma.keygennosupport'), 'error'); |
d5501a
|
128 |
} |
AM |
129 |
}; |
|
130 |
|
|
131 |
// Action executed after successful key generation and import |
|
132 |
rcube_webmail.prototype.enigma_key_create_success = function() |
|
133 |
{ |
|
134 |
parent.rcmail.enigma_list(1); |
48e9c1
|
135 |
}; |
T |
136 |
|
0878c8
|
137 |
// Delete key(s) |
211929
|
138 |
rcube_webmail.prototype.enigma_delete = function() |
0878c8
|
139 |
{ |
AM |
140 |
var keys = this.keys_list.get_selection(); |
|
141 |
|
|
142 |
if (!keys.length || !confirm(this.get_label('enigma.keyremoveconfirm'))) |
|
143 |
return; |
|
144 |
|
|
145 |
var lock = this.display_message(this.get_label('enigma.keyremoving'), 'loading'), |
|
146 |
post = {_a: 'delete', _keys: keys}; |
|
147 |
|
|
148 |
// send request to server |
|
149 |
this.http_post('plugin.enigmakeys', post, lock); |
211929
|
150 |
}; |
AM |
151 |
|
|
152 |
// Export key(s) |
|
153 |
rcube_webmail.prototype.enigma_export = function(selected) |
|
154 |
{ |
|
155 |
var keys = selected ? this.keys_list.get_selection().join(',') : '*'; |
|
156 |
|
|
157 |
if (!keys.length) |
|
158 |
return; |
|
159 |
|
bd0551
|
160 |
this.goto_url('plugin.enigmakeys', {_a: 'export', _keys: keys}, false, true); |
0878c8
|
161 |
}; |
AM |
162 |
|
|
163 |
// Submit key(s) import form |
48e9c1
|
164 |
rcube_webmail.prototype.enigma_import = function() |
T |
165 |
{ |
|
166 |
var form, file; |
0878c8
|
167 |
|
48e9c1
|
168 |
if (form = this.gui_objects.importform) { |
T |
169 |
file = document.getElementById('rcmimportfile'); |
|
170 |
if (file && !file.value) { |
|
171 |
alert(this.get_label('selectimportfile')); |
|
172 |
return; |
|
173 |
} |
0878c8
|
174 |
|
AM |
175 |
var lock = this.set_busy(true, 'importwait'); |
|
176 |
|
|
177 |
form.action = this.add_url(form.action, '_unlock', lock); |
48e9c1
|
178 |
form.submit(); |
0878c8
|
179 |
|
48e9c1
|
180 |
this.lock_form(form, true); |
T |
181 |
} |
|
182 |
}; |
|
183 |
|
|
184 |
// list row selection handler |
0878c8
|
185 |
rcube_webmail.prototype.enigma_keylist_select = function(list) |
48e9c1
|
186 |
{ |
211929
|
187 |
var id = list.get_single_selection(), url; |
0878c8
|
188 |
|
211929
|
189 |
if (id) |
AM |
190 |
url = '&_action=plugin.enigmakeys&_a=info&_id=' + id; |
|
191 |
|
|
192 |
this.enigma_loadframe(url); |
|
193 |
this.enable_command('plugin.enigma-key-delete', 'plugin.enigma-key-export-selected', list.selection.length > 0); |
0878c8
|
194 |
}; |
AM |
195 |
|
|
196 |
rcube_webmail.prototype.enigma_keylist_keypress = function(list) |
|
197 |
{ |
|
198 |
if (list.modkey == CONTROL_KEY) |
|
199 |
return; |
|
200 |
|
|
201 |
if (list.key_pressed == list.DELETE_KEY || list.key_pressed == list.BACKSPACE_KEY) |
|
202 |
this.command('plugin.enigma-key-delete'); |
|
203 |
else if (list.key_pressed == 33) |
|
204 |
this.command('previouspage'); |
|
205 |
else if (list.key_pressed == 34) |
|
206 |
this.command('nextpage'); |
48e9c1
|
207 |
}; |
T |
208 |
|
|
209 |
// load key frame |
0878c8
|
210 |
rcube_webmail.prototype.enigma_loadframe = function(url) |
48e9c1
|
211 |
{ |
T |
212 |
var frm, win; |
0878c8
|
213 |
|
48e9c1
|
214 |
if (this.env.contentframe && window.frames && (frm = window.frames[this.env.contentframe])) { |
0878c8
|
215 |
if (!url && (win = window.frames[this.env.contentframe])) { |
AM |
216 |
if (win.location && win.location.href.indexOf(this.env.blankpage) < 0) |
48e9c1
|
217 |
win.location.href = this.env.blankpage; |
T |
218 |
return; |
|
219 |
} |
0878c8
|
220 |
|
d5501a
|
221 |
this.env.frame_lock = this.set_busy(true, 'loading'); |
AM |
222 |
frm.location.href = this.env.comm_path + '&_framed=1&' + url; |
48e9c1
|
223 |
} |
T |
224 |
}; |
|
225 |
|
|
226 |
// Search keys/certs |
|
227 |
rcube_webmail.prototype.enigma_search = function(props) |
|
228 |
{ |
|
229 |
if (!props && this.gui_objects.qsearchbox) |
|
230 |
props = this.gui_objects.qsearchbox.value; |
|
231 |
|
|
232 |
if (props || this.env.search_request) { |
0878c8
|
233 |
var params = {'_a': 'search', '_q': urlencode(props)}, |
48e9c1
|
234 |
lock = this.set_busy(true, 'searching'); |
T |
235 |
// if (this.gui_objects.search_filter) |
|
236 |
// addurl += '&_filter=' + this.gui_objects.search_filter.value; |
0878c8
|
237 |
this.env.current_page = 1; |
48e9c1
|
238 |
this.enigma_loadframe(); |
T |
239 |
this.enigma_clear_list(); |
0878c8
|
240 |
this.http_post('plugin.enigmakeys', params, lock); |
48e9c1
|
241 |
} |
T |
242 |
|
|
243 |
return false; |
|
244 |
} |
|
245 |
|
|
246 |
// Reset search filter and the list |
|
247 |
rcube_webmail.prototype.enigma_search_reset = function(props) |
|
248 |
{ |
|
249 |
var s = this.env.search_request; |
|
250 |
this.reset_qsearch(); |
|
251 |
|
|
252 |
if (s) { |
|
253 |
this.enigma_loadframe(); |
|
254 |
this.enigma_clear_list(); |
|
255 |
|
|
256 |
// refresh the list |
|
257 |
this.enigma_list(); |
|
258 |
} |
|
259 |
|
|
260 |
return false; |
|
261 |
} |
|
262 |
|
|
263 |
// Keys/certs listing |
|
264 |
rcube_webmail.prototype.enigma_list = function(page) |
|
265 |
{ |
0878c8
|
266 |
var params = {'_a': 'list'}, |
48e9c1
|
267 |
lock = this.set_busy(true, 'loading'); |
T |
268 |
|
|
269 |
this.env.current_page = page ? page : 1; |
|
270 |
|
|
271 |
if (this.env.search_request) |
|
272 |
params._q = this.env.search_request; |
|
273 |
if (page) |
|
274 |
params._p = page; |
|
275 |
|
|
276 |
this.enigma_clear_list(); |
0878c8
|
277 |
this.http_post('plugin.enigmakeys', params, lock); |
48e9c1
|
278 |
} |
T |
279 |
|
|
280 |
// Change list page |
|
281 |
rcube_webmail.prototype.enigma_list_page = function(page) |
|
282 |
{ |
|
283 |
if (page == 'next') |
|
284 |
page = this.env.current_page + 1; |
|
285 |
else if (page == 'last') |
|
286 |
page = this.env.pagecount; |
|
287 |
else if (page == 'prev' && this.env.current_page > 1) |
|
288 |
page = this.env.current_page - 1; |
|
289 |
else if (page == 'first' && this.env.current_page > 1) |
|
290 |
page = 1; |
|
291 |
|
|
292 |
this.enigma_list(page); |
|
293 |
} |
|
294 |
|
|
295 |
// Remove list rows |
|
296 |
rcube_webmail.prototype.enigma_clear_list = function() |
|
297 |
{ |
|
298 |
this.enigma_loadframe(); |
|
299 |
if (this.keys_list) |
|
300 |
this.keys_list.clear(true); |
211929
|
301 |
|
AM |
302 |
this.enable_command('plugin.enigma-key-delete', 'plugin.enigma-key-delete-selected', false); |
48e9c1
|
303 |
} |
T |
304 |
|
|
305 |
// Adds a row to the list |
|
306 |
rcube_webmail.prototype.enigma_add_list_row = function(r) |
|
307 |
{ |
|
308 |
if (!this.gui_objects.keyslist || !this.keys_list) |
|
309 |
return false; |
|
310 |
|
|
311 |
var list = this.keys_list, |
|
312 |
tbody = this.gui_objects.keyslist.tBodies[0], |
|
313 |
rowcount = tbody.rows.length, |
|
314 |
even = rowcount%2, |
|
315 |
css_class = 'message' |
|
316 |
+ (even ? ' even' : ' odd'), |
|
317 |
// for performance use DOM instead of jQuery here |
|
318 |
row = document.createElement('tr'), |
|
319 |
col = document.createElement('td'); |
|
320 |
|
|
321 |
row.id = 'rcmrow' + r.id; |
|
322 |
row.className = css_class; |
|
323 |
|
|
324 |
col.innerHTML = r.name; |
|
325 |
row.appendChild(col); |
|
326 |
list.insert_row(row); |
|
327 |
} |
|
328 |
|
a99c34
|
329 |
|
48e9c1
|
330 |
/*********************************************************/ |
T |
331 |
/********* Enigma Message methods *********/ |
|
332 |
/*********************************************************/ |
a99c34
|
333 |
|
AM |
334 |
// handle message send/save action |
|
335 |
rcube_webmail.prototype.enigma_beforesend_handler = function(props) |
|
336 |
{ |
|
337 |
this.env.last_action = 'send'; |
|
338 |
this.enigma_compose_handler(props); |
|
339 |
} |
|
340 |
|
|
341 |
rcube_webmail.prototype.enigma_beforesavedraft_handler = function(props) |
|
342 |
{ |
|
343 |
this.env.last_action = 'savedraft'; |
|
344 |
this.enigma_compose_handler(props); |
|
345 |
} |
|
346 |
|
|
347 |
rcube_webmail.prototype.enigma_compose_handler = function(props) |
|
348 |
{ |
|
349 |
var form = this.gui_objects.messageform; |
|
350 |
|
|
351 |
// copy inputs from enigma menu to the form |
|
352 |
$('#enigmamenu input').each(function() { |
|
353 |
var id = this.id + '_cpy', input = $('#' + id); |
|
354 |
|
|
355 |
if (!input.length) { |
|
356 |
input = $(this).clone(); |
|
357 |
input.prop({id: id, type: 'hidden'}).appendTo(form); |
|
358 |
} |
|
359 |
|
|
360 |
input.val(this.checked ? '1' : ''); |
|
361 |
}); |
|
362 |
|
|
363 |
// disable signing when saving drafts |
|
364 |
if (this.env.last_action == 'savedraft') { |
|
365 |
$('input[name="_enigma_sign"]', form).val(0); |
|
366 |
} |
|
367 |
} |
48e9c1
|
368 |
|
T |
369 |
// Import attached keys/certs file |
|
370 |
rcube_webmail.prototype.enigma_import_attachment = function(mime_id) |
|
371 |
{ |
0878c8
|
372 |
var lock = this.set_busy(true, 'loading'), |
AM |
373 |
post = {_uid: this.env.uid, _mbox: this.env.mailbox, _part: mime_id}; |
|
374 |
|
|
375 |
this.http_post('plugin.enigmaimport', post, lock); |
48e9c1
|
376 |
|
T |
377 |
return false; |
0878c8
|
378 |
} |
48e9c1
|
379 |
|
a99c34
|
380 |
// password request popup |
0878c8
|
381 |
rcube_webmail.prototype.enigma_password_request = function(data) |
AM |
382 |
{ |
|
383 |
if (!data || !data.keyid) { |
|
384 |
return; |
|
385 |
} |
|
386 |
|
|
387 |
var ref = this, |
|
388 |
msg = this.get_label('enigma.enterkeypass'), |
|
389 |
myprompt = $('<div class="prompt">'), |
|
390 |
myprompt_content = $('<div class="message">') |
|
391 |
.appendTo(myprompt), |
|
392 |
myprompt_input = $('<input>').attr({type: 'password', size: 30}) |
|
393 |
.keypress(function(e) { |
|
394 |
if (e.which == 13) |
|
395 |
(ref.is_framed() ? window.parent.$ : $)('.ui-dialog-buttonpane button.mainaction:visible').click(); |
|
396 |
}) |
|
397 |
.appendTo(myprompt); |
|
398 |
|
|
399 |
data.key = data.keyid; |
a99c34
|
400 |
if (data.keyid.length > 8) |
AM |
401 |
data.keyid = data.keyid.substr(data.keyid.length - 8); |
0878c8
|
402 |
|
AM |
403 |
$.each(['keyid', 'user'], function() { |
|
404 |
msg = msg.replace('$' + this, data[this]); |
|
405 |
}); |
|
406 |
|
|
407 |
myprompt_content.text(msg); |
|
408 |
|
|
409 |
this.show_popup_dialog(myprompt, this.get_label('enigma.enterkeypasstitle'), |
|
410 |
[{ |
|
411 |
text: this.get_label('save'), |
|
412 |
'class': 'mainaction', |
|
413 |
click: function(e) { |
|
414 |
e.stopPropagation(); |
|
415 |
|
58c279
|
416 |
var jq = ref.is_framed() ? window.parent.$ : $; |
0878c8
|
417 |
|
58c279
|
418 |
data.password = myprompt_input.val(); |
AM |
419 |
|
|
420 |
if (!data.password) { |
0878c8
|
421 |
myprompt_input.focus(); |
AM |
422 |
return; |
|
423 |
} |
|
424 |
|
58c279
|
425 |
ref.enigma_password_submit(data); |
0878c8
|
426 |
jq(this).remove(); |
AM |
427 |
} |
|
428 |
}, |
|
429 |
{ |
|
430 |
text: this.get_label('cancel'), |
|
431 |
click: function(e) { |
|
432 |
var jq = ref.is_framed() ? window.parent.$ : $; |
|
433 |
e.stopPropagation(); |
|
434 |
jq(this).remove(); |
|
435 |
} |
|
436 |
}], {width: 400}); |
|
437 |
|
|
438 |
if (this.is_framed() && parent.rcmail.message_list) { |
|
439 |
// this fixes bug when pressing Enter on "Save" button in the dialog |
|
440 |
parent.rcmail.message_list.blur(); |
|
441 |
} |
|
442 |
} |
|
443 |
|
a99c34
|
444 |
// submit entered password |
58c279
|
445 |
rcube_webmail.prototype.enigma_password_submit = function(data) |
0878c8
|
446 |
{ |
58c279
|
447 |
if (this.env.action == 'compose' && !data['compose-init']) { |
AM |
448 |
return this.enigma_password_compose_submit(data); |
a99c34
|
449 |
} |
58c279
|
450 |
|
AM |
451 |
var lock = this.set_busy(true, 'loading'); |
a99c34
|
452 |
|
AM |
453 |
// message preview |
0878c8
|
454 |
var form = $('<form>').attr({method: 'post', action: location.href, style: 'display:none'}) |
58c279
|
455 |
.append($('<input>').attr({type: 'hidden', name: '_keyid', value: data.key})) |
AM |
456 |
.append($('<input>').attr({type: 'hidden', name: '_passwd', value: data.password})) |
0878c8
|
457 |
.append($('<input>').attr({type: 'hidden', name: '_token', value: this.env.request_token})) |
58c279
|
458 |
.append($('<input>').attr({type: 'hidden', name: '_unlock', value: lock})) |
0878c8
|
459 |
.appendTo(document.body); |
AM |
460 |
|
|
461 |
form.submit(); |
|
462 |
} |
a99c34
|
463 |
|
AM |
464 |
// submit entered password - in mail compose page |
58c279
|
465 |
rcube_webmail.prototype.enigma_password_compose_submit = function(data) |
a99c34
|
466 |
{ |
AM |
467 |
var form = this.gui_objects.messageform; |
|
468 |
|
|
469 |
if (!$('input[name="_keyid"]', form).length) { |
58c279
|
470 |
$(form).append($('<input>').attr({type: 'hidden', name: '_keyid', value: data.key})) |
AM |
471 |
.append($('<input>').attr({type: 'hidden', name: '_passwd', value: data.password})); |
a99c34
|
472 |
} |
AM |
473 |
else { |
58c279
|
474 |
$('input[name="_keyid"]', form).val(data.key); |
AM |
475 |
$('input[name="_passwd"]', form).val(data.password); |
a99c34
|
476 |
} |
AM |
477 |
|
|
478 |
this.submit_messageform(this.env.last_action == 'savedraft'); |
|
479 |
} |