blob: 80da6416788cdcb247d8cda9ee2f56644b42908e [file] [log] [blame]
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01001// Base64 functions
2var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(r){var t,e,o,a,h,n,c,d="",C=0;for(r=Base64._utf8_encode(r);C<r.length;)a=(t=r.charCodeAt(C++))>>2,h=(3&t)<<4|(e=r.charCodeAt(C++))>>4,n=(15&e)<<2|(o=r.charCodeAt(C++))>>6,c=63&o,isNaN(e)?n=c=64:isNaN(o)&&(c=64),d=d+this._keyStr.charAt(a)+this._keyStr.charAt(h)+this._keyStr.charAt(n)+this._keyStr.charAt(c);return d},decode:function(r){var t,e,o,a,h,n,c="",d=0;for(r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");d<r.length;)t=this._keyStr.indexOf(r.charAt(d++))<<2|(a=this._keyStr.indexOf(r.charAt(d++)))>>4,e=(15&a)<<4|(h=this._keyStr.indexOf(r.charAt(d++)))>>2,o=(3&h)<<6|(n=this._keyStr.indexOf(r.charAt(d++))),c+=String.fromCharCode(t),64!=h&&(c+=String.fromCharCode(e)),64!=n&&(c+=String.fromCharCode(o));return c=Base64._utf8_decode(c)},_utf8_encode:function(r){r=r.replace(/\r\n/g,"\n");for(var t="",e=0;e<r.length;e++){var o=r.charCodeAt(e);o<128?t+=String.fromCharCode(o):o>127&&o<2048?(t+=String.fromCharCode(o>>6|192),t+=String.fromCharCode(63&o|128)):(t+=String.fromCharCode(o>>12|224),t+=String.fromCharCode(o>>6&63|128),t+=String.fromCharCode(63&o|128))}return t},_utf8_decode:function(r){for(var t="",e=0,o=c1=c2=0;e<r.length;)(o=r.charCodeAt(e))<128?(t+=String.fromCharCode(o),e++):o>191&&o<224?(c2=r.charCodeAt(e+1),t+=String.fromCharCode((31&o)<<6|63&c2),e+=2):(c2=r.charCodeAt(e+1),c3=r.charCodeAt(e+2),t+=String.fromCharCode((15&o)<<12|(63&c2)<<6|63&c3),e+=3);return t}};
3jQuery(function($){
4 // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
5 var entityMap={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};
6 function jq(myid) {return "#" + myid.replace( /(:|\.|\[|\]|,|=|@)/g, "\\$1" );}
7 function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
8 function validateRegex(e){var t=e.split("/"),n=e,r="";t.length>1&&(n=t[1],r=t[2]);try{return new RegExp(n,r),!0}catch(e){return!1}}
9 function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
10 function hashCode(t){for(var n=0,r=0;r<t.length;r++)n=t.charCodeAt(r)+((n<<5)-n);return n}
11 function intToRGB(t){var n=(16777215&t).toString(16).toUpperCase();return"00000".substring(0,6-n.length)+n}
12 $("#dkim_missing_keys").on('click', function(e) {
13 e.preventDefault();
14 var domains = [];
15 $('.dkim_missing').each(function() {
16 domains.push($(this).val());
17 });
18 $('#dkim_add_domains').val(domains);
19 });
20 $(".arrow-toggle").on('click', function(e) { e.preventDefault(); $(this).find('.arrow').toggleClass("animation"); });
21 $("#mass_exclude").change(function(){ $("#mass_include").selectpicker('deselectAll'); });
22 $("#mass_include").change(function(){ $("#mass_exclude").selectpicker('deselectAll'); });
23 $("#mass_disarm").click(function() { $("#mass_send").attr("disabled", !this.checked); });
24 $(".admin-ays-dialog").click(function() { return confirm(lang.ays); });
25 $(".validate_rspamd_regex").click(function( event ) {
26 event.preventDefault();
27 var regex_map_id = $(this).data('regex-map');
28 var regex_data = $(jq(regex_map_id)).val().split(/\r?\n/);
29 var regex_valid = true;
30 for(var i = 0;i < regex_data.length;i++){
31 if(regex_data[i].startsWith('#') || !regex_data[i]){
32 continue;
33 }
34 if(!validateRegex(regex_data[i])) {
35 mailcow_alert_box('Cannot build regex from line ' + (i+1), 'danger');
36 var regex_valid = false;
37 break;
38 }
39 if(!regex_data[i].startsWith('/') || !/\/[ims]?$/.test(regex_data[i])){
40 mailcow_alert_box('Line ' + (i+1) + ' is invalid', 'danger');
41 var regex_valid = false;
42 break;
43 }
44 }
45 if (regex_valid) {
46 mailcow_alert_box('Regex OK', 'success');
47 $('button[data-id="' + regex_map_id + '"]').attr({"disabled": false});
48 }
49 });
50 $('.textarea-code').on('keyup', function() {
51 $('.submit_rspamd_regex').attr({"disabled": true});
52 });
53 $("#show_rspamd_global_filters").click(function() {
54 $.get("inc/ajax/show_rspamd_global_filters.php");
55 $("#confirm_show_rspamd_global_filters").hide();
56 $("#rspamd_global_filters").removeClass("d-none");
57 });
58 $("#super_delete").click(function() { return confirm(lang.queue_ays); });
59
60 $(".refresh_table").on('click', function(e) {
61 e.preventDefault();
62 var table_name = $(this).data('table');
63 $('#' + table_name).DataTable().ajax.reload();
64 });
65 function draw_domain_admins() {
66 // just recalc width if instance already exists
67 if ($.fn.DataTable.isDataTable('#domainadminstable') ) {
68 $('#domainadminstable').DataTable().columns.adjust().responsive.recalc();
69 return;
70 }
71
72 $('#domainadminstable').DataTable({
73 responsive: true,
74 processing: true,
75 serverSide: false,
76 stateSave: true,
77 pageLength: pagination_size,
78 dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
79 "tr" +
80 "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
81 language: lang_datatables,
82 ajax: {
83 type: "GET",
84 url: "/api/v1/get/domain-admin/all",
85 dataSrc: function(data){
86 return process_table_data(data, 'domainadminstable');
87 }
88 },
89 columns: [
90 {
91 // placeholder, so checkbox will not block child row toggle
92 title: '',
93 data: null,
94 searchable: false,
95 orderable: false,
96 defaultContent: ''
97 },
98 {
99 title: '',
100 data: 'chkbox',
101 searchable: false,
102 orderable: false,
103 defaultContent: ''
104 },
105 {
106 title: lang.username,
107 data: 'username',
108 defaultContent: ''
109 },
110 {
111 title: lang.admin_domains,
112 data: 'selected_domains',
113 defaultContent: '',
114 },
115 {
116 title: "TFA",
117 data: 'tfa_active',
118 defaultContent: '',
119 render: function (data, type) {
120 if(data == 1) return '<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>';
121 else return '<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
122 }
123 },
124 {
125 title: lang.active,
126 data: 'active',
127 defaultContent: '',
128 render: function (data, type) {
129 if(data == 1) return '<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>';
130 else return '<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
131 }
132 },
133 {
134 title: lang.action,
135 data: 'action',
136 className: 'dt-sm-head-hidden dt-text-right',
137 defaultContent: ''
138 },
139 ],
140 initComplete: function(settings, json){
141 }
142 });
143 }
144 function draw_oauth2_clients() {
145 // just recalc width if instance already exists
146 if ($.fn.DataTable.isDataTable('#oauth2clientstable') ) {
147 $('#oauth2clientstable').DataTable().columns.adjust().responsive.recalc();
148 return;
149 }
150
151 $('#oauth2clientstable').DataTable({
152 responsive: true,
153 processing: true,
154 serverSide: false,
155 stateSave: true,
156 pageLength: pagination_size,
157 dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
158 "tr" +
159 "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
160 language: lang_datatables,
161 ajax: {
162 type: "GET",
163 url: "/api/v1/get/oauth2-client/all",
164 dataSrc: function(data){
165 return process_table_data(data, 'oauth2clientstable');
166 }
167 },
168 columns: [
169 {
170 // placeholder, so checkbox will not block child row toggle
171 title: '',
172 data: null,
173 searchable: false,
174 orderable: false,
175 defaultContent: ''
176 },
177 {
178 title: '',
179 data: 'chkbox',
180 searchable: false,
181 orderable: false,
182 defaultContent: ''
183 },
184 {
185 title: 'ID',
186 data: 'id',
187 defaultContent: ''
188 },
189 {
190 title: lang.oauth2_client_id,
191 data: 'client_id',
192 defaultContent: ''
193 },
194 {
195 title: lang.oauth2_client_secret,
196 data: 'client_secret',
197 defaultContent: ''
198 },
199 {
200 title: lang.oauth2_redirect_uri,
201 data: 'redirect_uri',
202 defaultContent: ''
203 },
204 {
205 title: lang.action,
206 data: 'action',
207 className: 'dt-sm-head-hidden dt-text-right',
208 defaultContent: ''
209 },
210 ]
211 });
212 }
213 function draw_admins() {
214 // just recalc width if instance already exists
215 if ($.fn.DataTable.isDataTable('#adminstable') ) {
216 $('#adminstable').DataTable().columns.adjust().responsive.recalc();
217 return;
218 }
219
220 $('#adminstable').DataTable({
221 responsive: true,
222 processing: true,
223 serverSide: false,
224 stateSave: true,
225 pageLength: pagination_size,
226 dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
227 "tr" +
228 "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
229 language: lang_datatables,
230 ajax: {
231 type: "GET",
232 url: "/api/v1/get/admin/all",
233 dataSrc: function(data){
234 return process_table_data(data, 'adminstable');
235 }
236 },
237 columns: [
238 {
239 // placeholder, so checkbox will not block child row toggle
240 title: '',
241 data: null,
242 searchable: false,
243 orderable: false,
244 defaultContent: ''
245 },
246 {
247 title: '',
248 data: 'chkbox',
249 searchable: false,
250 orderable: false,
251 defaultContent: ''
252 },
253 {
254 title: lang.username,
255 data: 'username',
256 defaultContent: ''
257 },
258 {
259 title: "TFA",
260 data: 'tfa_active',
261 defaultContent: '',
262 render: function (data, type) {
263 if(data == 1) return '<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>';
264 else return '<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
265 }
266 },
267 {
268 title: lang.active,
269 data: 'active',
270 defaultContent: '',
271 render: function (data, type) {
272 if(data == 1) return '<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>';
273 else return '<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
274 }
275 },
276 {
277 title: lang.action,
278 data: 'action',
279 defaultContent: '',
280 className: 'dt-sm-head-hidden dt-text-right'
281 },
282 ]
283 });
284 }
285 function draw_fwd_hosts() {
286 // just recalc width if instance already exists
287 if ($.fn.DataTable.isDataTable('#forwardinghoststable') ) {
288 $('#forwardinghoststable').DataTable().columns.adjust().responsive.recalc();
289 return;
290 }
291
292 $('#forwardinghoststable').DataTable({
293 responsive: true,
294 processing: true,
295 serverSide: false,
296 stateSave: true,
297 pageLength: pagination_size,
298 dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
299 "tr" +
300 "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
301 language: lang_datatables,
302 ajax: {
303 type: "GET",
304 url: "/api/v1/get/fwdhost/all",
305 dataSrc: function(data){
306 return process_table_data(data, 'forwardinghoststable');
307 }
308 },
309 columns: [
310 {
311 // placeholder, so checkbox will not block child row toggle
312 title: '',
313 data: null,
314 searchable: false,
315 orderable: false,
316 defaultContent: ''
317 },
318 {
319 title: '',
320 data: 'chkbox',
321 searchable: false,
322 orderable: false,
323 defaultContent: ''
324 },
325 {
326 title: lang.host,
327 data: 'host',
328 defaultContent: ''
329 },
330 {
331 title: lang.source,
332 data: 'source',
333 defaultContent: ''
334 },
335 {
336 title: lang.spamfilter,
337 data: 'keep_spam',
338 defaultContent: '',
339 render: function(data, type){
340 return 'yes'==data?'<i class="bi bi-x-lg"><span class="sorting-value">yes</span></i>':'no'==data&&'<i class="bi bi-check-lg"><span class="sorting-value">no</span></i>';
341 }
342 },
343 {
344 title: lang.action,
345 data: 'action',
346 className: 'dt-sm-head-hidden dt-text-right',
347 defaultContent: ''
348 },
349 ]
350 });
351 }
352 function draw_relayhosts() {
353 // just recalc width if instance already exists
354 if ($.fn.DataTable.isDataTable('#relayhoststable') ) {
355 $('#relayhoststable').DataTable().columns.adjust().responsive.recalc();
356 return;
357 }
358
359 $('#relayhoststable').DataTable({
360 responsive: true,
361 processing: true,
362 serverSide: false,
363 stateSave: true,
364 pageLength: pagination_size,
365 dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
366 "tr" +
367 "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
368 language: lang_datatables,
369 ajax: {
370 type: "GET",
371 url: "/api/v1/get/relayhost/all",
372 dataSrc: function(data){
373 return process_table_data(data, 'relayhoststable');
374 }
375 },
376 columns: [
377 {
378 // placeholder, so checkbox will not block child row toggle
379 title: '',
380 data: null,
381 searchable: false,
382 orderable: false,
383 defaultContent: ''
384 },
385 {
386 title: '',
387 data: 'chkbox',
388 searchable: false,
389 orderable: false,
390 defaultContent: ''
391 },
392 {
393 title: 'ID',
394 data: 'id',
395 defaultContent: ''
396 },
397 {
398 title: lang.host,
399 data: 'hostname',
400 defaultContent: ''
401 },
402 {
403 title: lang.username,
404 data: 'username',
405 defaultContent: ''
406 },
407 {
408 title: lang.in_use_by,
409 data: 'in_use_by',
410 defaultContent: ''
411 },
412 {
413 title: lang.active,
414 data: 'active',
415 defaultContent: '',
416 render: function (data, type) {
417 if(data == 1) return '<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>';
418 else return '<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
419 }
420 },
421 {
422 title: lang.action,
423 data: 'action',
424 className: 'dt-sm-head-hidden dt-text-right',
425 defaultContent: ''
426 },
427 ]
428 });
429 }
430 function draw_transport_maps() {
431 // just recalc width if instance already exists
432 if ($.fn.DataTable.isDataTable('#transportstable') ) {
433 $('#transportstable').DataTable().columns.adjust().responsive.recalc();
434 return;
435 }
436
437 $('#transportstable').DataTable({
438 responsive: true,
439 processing: true,
440 serverSide: false,
441 stateSave: true,
442 pageLength: pagination_size,
443 dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
444 "tr" +
445 "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
446 language: lang_datatables,
447 ajax: {
448 type: "GET",
449 url: "/api/v1/get/transport/all",
450 dataSrc: function(data){
451 return process_table_data(data, 'transportstable');
452 }
453 },
454 columns: [
455 {
456 // placeholder, so checkbox will not block child row toggle
457 title: '',
458 data: null,
459 searchable: false,
460 orderable: false,
461 defaultContent: ''
462 },
463 {
464 title: '',
465 data: 'chkbox',
466 searchable: false,
467 orderable: false,
468 defaultContent: ''
469 },
470 {
471 title: 'ID',
472 data: 'id',
473 defaultContent: ''
474 },
475 {
476 title: lang.destination,
477 data: 'destination',
478 defaultContent: ''
479 },
480 {
481 title: lang.nexthop,
482 data: 'nexthop',
483 defaultContent: ''
484 },
485 {
486 title: lang.username,
487 data: 'username',
488 defaultContent: ''
489 },
490 {
491 title: lang.active,
492 data: 'active',
493 defaultContent: '',
494 render: function (data, type) {
495 if(data == 1) return '<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>';
496 else return '<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
497 }
498 },
499 {
500 title: lang.action,
501 data: 'action',
502 className: 'dt-sm-head-hidden dt-text-right',
503 defaultContent: ''
504 },
505 ]
506 });
507 }
508
509 function process_table_data(data, table) {
510 if (table == 'relayhoststable') {
511 $.each(data, function (i, item) {
512 item.action = '<div class="btn-group">' +
513 '<a href="#" data-bs-toggle="modal" data-bs-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="sender-dependent" class="btn btn-xs btn-xs-lg btn-xs-third btn-secondary"><i class="bi bi-caret-right-fill"></i> Test</a>' +
514 '<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
515 '<a href="#" data-action="delete_selected" data-id="single-rlyhost" data-api-url="delete/relayhost" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
516 '</div>';
517 if (item.used_by_mailboxes == '') { item.in_use_by = item.used_by_domains; }
518 else if (item.used_by_domains == '') { item.in_use_by = item.used_by_mailboxes; }
519 else { item.in_use_by = item.used_by_mailboxes + '<hr style="margin:5px 0px 5px 0px;">' + item.used_by_domains; }
520 item.chkbox = '<input type="checkbox" class="form-check-input" data-id="rlyhosts" name="multi_select" value="' + item.id + '" />';
521 });
522 } else if (table == 'transportstable') {
523 $.each(data, function (i, item) {
524 if (item.is_mx_based) {
525 item.destination = '<i class="bi bi-info-circle-fill text-info mx-info" data-bs-toggle="tooltip" title="' + lang.is_mx_based + '"></i> <code>' + item.destination + '</code>';
526 }
527 if (item.username) {
528 item.username = '<i style="color:#' + intToRGB(hashCode(item.nexthop)) + ';" class="bi bi-square-fill"></i> ' + item.username;
529 }
530 item.action = '<div class="btn-group">' +
531 '<a href="#" data-bs-toggle="modal" data-bs-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="transport-map" class="btn btn-xs btn-xs-lg btn-xs-third btn-secondary"><i class="bi bi-caret-right-fill"></i> Test</a>' +
532 '<a href="/edit/transport/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
533 '<a href="#" data-action="delete_selected" data-id="single-transport" data-api-url="delete/transport" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
534 '</div>';
535 item.chkbox = '<input type="checkbox" class="form-check-input" data-id="transports" name="multi_select" value="' + item.id + '" />';
536 });
537 } else if (table == 'queuetable') {
538 $.each(data, function (i, item) {
539 item.chkbox = '<input type="checkbox" class="form-check-input" data-id="mailqitems" name="multi_select" value="' + item.queue_id + '" />';
540 rcpts = $.map(item.recipients, function(i) {
541 return escapeHtml(i);
542 });
543 item.recipients = rcpts.join('<hr style="margin:1px!important">');
544 item.action = '<div class="btn-group">' +
545 '<a href="#" data-bs-toggle="modal" data-bs-target="#showQueuedMsg" data-queue-id="' + encodeURI(item.queue_id) + '" class="btn btn-xs btn-xs-lg btn-secondary">' + lang.queue_show_message + '</a>' +
546 '</div>';
547 });
548 } else if (table == 'forwardinghoststable') {
549 $.each(data, function (i, item) {
550 item.action = '<div class="btn-group">' +
551 '<a href="#" data-action="delete_selected" data-id="single-fwdhost" data-api-url="delete/fwdhost" data-item="' + encodeURI(item.host) + '" class="btn btn-xs btn-xs-lg btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
552 '</div>';
553 item.chkbox = '<input type="checkbox" class="form-check-input" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />';
554 });
555 } else if (table == 'oauth2clientstable') {
556 $.each(data, function (i, item) {
557 item.action = '<div class="btn-group">' +
558 '<a href="/edit.php?oauth2client=' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
559 '<a href="#" data-action="delete_selected" data-id="single-oauth2-client" data-api-url="delete/oauth2-client" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
560 '</div>';
561 item.scope = "profile";
562 item.grant_types = 'refresh_token password authorization_code';
563 item.chkbox = '<input type="checkbox" class="form-check-input" data-id="oauth2_clients" name="multi_select" value="' + item.id + '" />';
564 });
565 } else if (table == 'domainadminstable') {
566 $.each(data, function (i, item) {
567 item.selected_domains = escapeHtml(item.selected_domains);
568 item.selected_domains = item.selected_domains.toString().replace(/,/g, "<br>");
569 item.chkbox = '<input type="checkbox" class="form-check-input" data-id="domain_admins" name="multi_select" value="' + item.username + '" />';
570 item.action = '<div class="btn-group">' +
571 '<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
572 '<a href="#" data-action="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
573 '<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-success"><i class="bi bi-person-fill"></i> Login</a>' +
574 '</div>';
575 });
576 } else if (table == 'adminstable') {
577 $.each(data, function (i, item) {
578 if (admin_username.toLowerCase() == item.username.toLowerCase()) {
579 item.usr = '<i class="bi bi-person-check"></i> ' + item.username;
580 } else {
581 item.usr = item.username;
582 }
583 item.chkbox = '<input type="checkbox" class="form-check-input" data-id="admins" name="multi_select" value="' + item.username + '" />';
584 item.action = '<div class="btn-group">' +
585 '<a href="/edit/admin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
586 '<a href="#" data-action="delete_selected" data-id="single-admin" data-api-url="delete/admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
587 '</div>';
588 });
589 }
590 return data
591 };
592
593 // detect element visibility changes
594 function onVisible(element, callback) {
595 $(document).ready(function() {
596 element_object = document.querySelector(element);
597 if (element_object === null) return;
598
599 new IntersectionObserver((entries, observer) => {
600 entries.forEach(entry => {
601 if(entry.intersectionRatio > 0) {
602 callback(element_object);
603 }
604 });
605 }).observe(element_object);
606 });
607 }
608 // Draw Table if tab is active
609 onVisible("[id^=adminstable]", () => draw_admins());
610 onVisible("[id^=domainadminstable]", () => draw_domain_admins());
611 onVisible("[id^=oauth2clientstable]", () => draw_oauth2_clients());
612 onVisible("[id^=forwardinghoststable]", () => draw_fwd_hosts());
613 onVisible("[id^=relayhoststable]", () => draw_relayhosts());
614 onVisible("[id^=transportstable]", () => draw_transport_maps());
615
616
617 $('body').on('click', 'span.footable-toggle', function () {
618 event.stopPropagation();
619 })
620
621 // API IP check toggle
622 $("#skip_ip_check_ro").click(function( event ) {
623 $("#skip_ip_check_ro").not(this).prop('checked', false);
624 if ($("#skip_ip_check_ro:checked").length > 0) {
625 $('#allow_from_ro').prop('disabled', true);
626 }
627 else {
628 $("#allow_from_ro").removeAttr('disabled');
629 }
630 });
631 $("#skip_ip_check_rw").click(function( event ) {
632 $("#skip_ip_check_rw").not(this).prop('checked', false);
633 if ($("#skip_ip_check_rw:checked").length > 0) {
634 $('#allow_from_rw').prop('disabled', true);
635 }
636 else {
637 $("#allow_from_rw").removeAttr('disabled');
638 }
639 });
640 // Relayhost
641 $('#testRelayhostModal').on('show.bs.modal', function (e) {
642 $('#test_relayhost_result').text("-");
643 button = $(e.relatedTarget)
644 if (button != null) {
645 $('#relayhost_id').val(button.data('relayhost-id'));
646 }
647 })
648 $('#test_relayhost').on('click', function (e) {
649 e.preventDefault();
650 prev = $('#test_relayhost').text();
651 $(this).prop("disabled",true);
652 $(this).html('<i class="bi bi-arrow-repeat icon-spin"></i> ');
653 $.ajax({
654 type: 'GET',
655 url: 'inc/ajax/relay_check.php',
656 dataType: 'text',
657 data: $('#test_relayhost_form').serialize(),
658 complete: function (data) {
659 $('#test_relayhost_result').html(data.responseText);
660 $('#test_relayhost').prop("disabled",false);
661 $('#test_relayhost').text(prev);
662 }
663 });
664 })
665 // Transport
666 $('#testTransportModal').on('show.bs.modal', function (e) {
667 $('#test_transport_result').text("-");
668 button = $(e.relatedTarget)
669 if (button != null) {
670 $('#transport_id').val(button.data('transport-id'));
671 $('#transport_type').val(button.data('transport-type'));
672 }
673 })
674 $('#test_transport').on('click', function (e) {
675 e.preventDefault();
676 prev = $('#test_transport').text();
677 $(this).prop("disabled",true);
678 $(this).html('<div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div> ');
679 $.ajax({
680 type: 'GET',
681 url: 'inc/ajax/transport_check.php',
682 dataType: 'text',
683 data: $('#test_transport_form').serialize(),
684 complete: function (data) {
685 $('#test_transport_result').html(data.responseText);
686 $('#test_transport').prop("disabled",false);
687 $('#test_transport').text(prev);
688 }
689 });
690 })
691 // DKIM private key modal
692 $('#showDKIMprivKey').on('show.bs.modal', function (e) {
693 $('#priv_key_pre').text("-");
694 p_related = $(e.relatedTarget)
695 if (p_related != null) {
696 var decoded_key = Base64.decode((p_related.data('priv-key')));
697 $('#priv_key_pre').text(decoded_key);
698 }
699 })
700 // FIDO2 friendly name modal
701 $('#fido2ChangeFn').on('show.bs.modal', function (e) {
702 rename_link = $(e.relatedTarget)
703 if (rename_link != null) {
704 $('#fido2_cid').val(rename_link.data('cid'));
705 $('#fido2_subject_desc').text(Base64.decode(rename_link.data('subject')));
706 }
707 })
708 // App links
709 function add_table_row(table_id, type) {
710 var row = $('<tr />');
711 if (type == "app_link") {
712 cols = '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="app" required></td>';
713 cols += '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="href" required></td>';
714 cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-secondary h-100 w-100" type="button">' + lang.remove_row + '</a></td>';
715 } else if (type == "f2b_regex") {
716 cols = '<td><input style="text-align:center" class="input-sm input-xs-lg form-control" data-id="f2b_regex" type="text" value="+" disabled></td>';
717 cols += '<td><input class="input-sm input-xs-lg form-control regex-input" data-id="f2b_regex" type="text" name="regex" required></td>';
718 cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-secondary h-100 w-100" type="button">' + lang.remove_row + '</a></td>';
719 }
720 row.append(cols);
721 table_id.append(row);
722 }
723 $('#app_link_table').on('click', 'tr a', function (e) {
724 e.preventDefault();
725 $(this).parents('tr').remove();
726 });
727 $('#f2b_regex_table').on('click', 'tr a', function (e) {
728 e.preventDefault();
729 $(this).parents('tr').remove();
730 });
731 $('#add_app_link_row').click(function() {
732 add_table_row($('#app_link_table'), "app_link");
733 });
734 $('#add_f2b_regex_row').click(function() {
735 add_table_row($('#f2b_regex_table'), "f2b_regex");
736 });
737});