admin.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. jQuery(function($){
  2. // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
  3. var entityMap = {
  4. '&': '&',
  5. '<': '&lt;',
  6. '>': '&gt;',
  7. '"': '&quot;',
  8. "'": '&#39;',
  9. '/': '&#x2F;',
  10. '`': '&#x60;',
  11. '=': '&#x3D;'
  12. };
  13. function escapeHtml(string) {
  14. return String(string).replace(/[&<>"'`=\/]/g, function (s) {
  15. return entityMap[s];
  16. });
  17. }
  18. function unix_time_format(tm) {
  19. var date = new Date(tm ? tm * 1000 : 0);
  20. return date.toLocaleString();
  21. }
  22. function humanFileSize(bytes) {
  23. if(Math.abs(bytes) < 1024) {
  24. return bytes + ' B';
  25. }
  26. var units = ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
  27. var u = -1;
  28. do {
  29. bytes /= 1024;
  30. ++u;
  31. } while(Math.abs(bytes) >= 1024 && u < units.length - 1);
  32. return bytes.toFixed(1)+' '+units[u];
  33. }
  34. $("#refresh_postfix_log").on('click', function(e) {
  35. e.preventDefault();
  36. draw_postfix_logs();
  37. });
  38. $("#refresh_dovecot_log").on('click', function(e) {
  39. e.preventDefault();
  40. draw_dovecot_logs();
  41. });
  42. $("#refresh_sogo_log").on('click', function(e) {
  43. e.preventDefault();
  44. draw_sogo_logs();
  45. });
  46. $("#refresh_fail2ban_log").on('click', function(e) {
  47. e.preventDefault();
  48. draw_fail2ban_logs();
  49. });
  50. $("#refresh_rspamd_history").on('click', function(e) {
  51. e.preventDefault();
  52. draw_rspamd_history();
  53. });
  54. function draw_postfix_logs() {
  55. ft_postfix_logs = FooTable.init('#postfix_log', {
  56. "columns": [
  57. {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
  58. {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
  59. {"name":"message","title":lang.message},
  60. ],
  61. "rows": $.ajax({
  62. dataType: 'json',
  63. url: '/api/v1/get/logs/postfix/1000',
  64. jsonp: false,
  65. error: function () {
  66. console.log('Cannot draw postfix log table');
  67. },
  68. success: function (data) {
  69. $.each(data, function (i, item) {
  70. item.message = escapeHtml(item.message);
  71. var danger_class = ["emerg", "alert", "crit", "err"];
  72. var warning_class = ["warning"];
  73. var info_class = ["notice", "info", "debug"];
  74. if (jQuery.inArray(item.priority, danger_class) !== -1) {
  75. item.priority = '<span class="label label-danger">' + item.priority + '</span>';
  76. }
  77. else if (jQuery.inArray(item.priority, warning_class) !== -1) {
  78. item.priority = '<span class="label label-warning">' + item.priority + '</span>';
  79. }
  80. else if (jQuery.inArray(item.priority, info_class) !== -1) {
  81. item.priority = '<span class="label label-info">' + item.priority + '</span>';
  82. }
  83. });
  84. }
  85. }),
  86. "empty": lang.empty,
  87. "paging": {
  88. "enabled": true,
  89. "limit": 5,
  90. "size": log_pagination_size
  91. },
  92. "filtering": {
  93. "enabled": true,
  94. "position": "left",
  95. "placeholder": lang.filter_table
  96. },
  97. "sorting": {
  98. "enabled": true
  99. }
  100. });
  101. }
  102. function draw_fail2ban_logs() {
  103. ft_fail2ban_logs = FooTable.init('#fail2ban_log', {
  104. "columns": [
  105. {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
  106. {"name":"message","title":lang.message},
  107. ],
  108. "rows": $.ajax({
  109. dataType: 'json',
  110. url: '/api/v1/get/logs/fail2ban/1000',
  111. jsonp: false,
  112. error: function () {
  113. console.log('Cannot draw fail2ban log table');
  114. },
  115. success: function (data) {
  116. $.each(data, function (i, item) {
  117. item.message = escapeHtml(item.message);
  118. });
  119. }
  120. }),
  121. "empty": lang.empty,
  122. "paging": {
  123. "enabled": true,
  124. "limit": 5,
  125. "size": log_pagination_size
  126. },
  127. "filtering": {
  128. "enabled": true,
  129. "position": "left",
  130. "placeholder": lang.filter_table
  131. },
  132. "sorting": {
  133. "enabled": true
  134. }
  135. });
  136. }
  137. function draw_sogo_logs() {
  138. ft_sogo_logs = FooTable.init('#sogo_log', {
  139. "columns": [
  140. {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
  141. {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
  142. {"name":"message","title":lang.message},
  143. ],
  144. "rows": $.ajax({
  145. dataType: 'json',
  146. url: '/api/v1/get/logs/sogo/1000',
  147. jsonp: false,
  148. error: function () {
  149. console.log('Cannot draw sogo log table');
  150. },
  151. success: function (data) {
  152. $.each(data, function (i, item) {
  153. var danger_class = ["emerg", "alert", "crit", "err"];
  154. var warning_class = ["warning"];
  155. var info_class = ["notice", "info", "debug"];
  156. item.message = escapeHtml(item.message);
  157. if (jQuery.inArray(item.priority, danger_class) !== -1) {
  158. item.priority = '<span class="label label-danger">' + item.priority + '</span>';
  159. }
  160. else if (jQuery.inArray(item.priority, warning_class) !== -1) {
  161. item.priority = '<span class="label label-warning">' + item.priority + '</span>';
  162. }
  163. else if (jQuery.inArray(item.priority, info_class) !== -1) {
  164. item.priority = '<span class="label label-info">' + item.priority + '</span>';
  165. }
  166. });
  167. }
  168. }),
  169. "empty": lang.empty,
  170. "paging": {
  171. "enabled": true,
  172. "limit": 5,
  173. "size": log_pagination_size
  174. },
  175. "filtering": {
  176. "enabled": true,
  177. "position": "left",
  178. "placeholder": lang.filter_table
  179. },
  180. "sorting": {
  181. "enabled": true
  182. }
  183. });
  184. }
  185. function draw_dovecot_logs() {
  186. ft_postfix_logs = FooTable.init('#dovecot_log', {
  187. "columns": [
  188. {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
  189. {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
  190. {"name":"message","title":lang.message},
  191. ],
  192. "rows": $.ajax({
  193. dataType: 'json',
  194. url: '/api/v1/get/logs/dovecot/1000',
  195. jsonp: false,
  196. error: function () {
  197. console.log('Cannot draw dovecot log table');
  198. },
  199. success: function (data) {
  200. $.each(data, function (i, item) {
  201. var danger_class = ["emerg", "alert", "crit", "err"];
  202. var warning_class = ["warning"];
  203. var info_class = ["notice", "info", "debug"];
  204. item.message = escapeHtml(item.message);
  205. if (jQuery.inArray(item.priority, danger_class) !== -1) {
  206. item.priority = '<span class="label label-danger">' + item.priority + '</span>';
  207. }
  208. else if (jQuery.inArray(item.priority, warning_class) !== -1) {
  209. item.priority = '<span class="label label-warning">' + item.priority + '</span>';
  210. }
  211. else if (jQuery.inArray(item.priority, info_class) !== -1) {
  212. item.priority = '<span class="label label-info">' + item.priority + '</span>';
  213. }
  214. });
  215. }
  216. }),
  217. "empty": lang.empty,
  218. "paging": {
  219. "enabled": true,
  220. "limit": 5,
  221. "size": log_pagination_size
  222. },
  223. "filtering": {
  224. "enabled": true,
  225. "position": "left",
  226. "placeholder": lang.filter_table
  227. },
  228. "sorting": {
  229. "enabled": true
  230. }
  231. });
  232. }
  233. function draw_domain_admins() {
  234. ft_domainadmins = FooTable.init('#domainadminstable', {
  235. "columns": [
  236. {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
  237. {"sorted": true,"name":"username","title":lang.username,"style":{"width":"250px"}},
  238. {"name":"selected_domains","title":lang.admin_domains,"breakpoints":"xs sm"},
  239. {"name":"tfa_active","title":"TFA", "filterable": false,"style":{"maxWidth":"80px","width":"80px"}},
  240. {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
  241. {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
  242. ],
  243. "rows": $.ajax({
  244. dataType: 'json',
  245. url: '/api/v1/get/domain-admin/all',
  246. jsonp: false,
  247. error: function () {
  248. console.log('Cannot draw domain admin table');
  249. },
  250. success: function (data) {
  251. $.each(data, function (i, item) {
  252. item.chkbox = '<input type="checkbox" data-id="domain_admins" name="multi_select" value="' + item.username + '" />';
  253. item.action = '<div class="btn-group">' +
  254. '<a href="/edit.php?domainadmin=' + encodeURI(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
  255. '<a href="#" id="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
  256. '</div>';
  257. });
  258. }
  259. }),
  260. "empty": lang.empty,
  261. "paging": {
  262. "enabled": true,
  263. "limit": 5,
  264. "size": log_pagination_size
  265. },
  266. "filtering": {
  267. "enabled": true,
  268. "position": "left",
  269. "placeholder": lang.filter_table
  270. },
  271. "sorting": {
  272. "enabled": true
  273. }
  274. });
  275. }
  276. function draw_fwd_hosts() {
  277. ft_forwardinghoststable = FooTable.init('#forwardinghoststable', {
  278. "columns": [
  279. {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
  280. {"name":"host","type":"text","title":lang.host,"style":{"width":"250px"}},
  281. {"name":"source","title":lang.source,"breakpoints":"xs sm"},
  282. {"name":"keep_spam","title":lang.spamfilter, "type": "text","style":{"maxWidth":"80px","width":"80px"}},
  283. {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
  284. ],
  285. "rows": $.ajax({
  286. dataType: 'json',
  287. url: '/api/v1/get/fwdhost/all',
  288. jsonp: false,
  289. error: function () {
  290. console.log('Cannot draw forwarding hosts table');
  291. },
  292. success: function (data) {
  293. $.each(data, function (i, item) {
  294. item.action = '<div class="btn-group">' +
  295. '<a href="#" id="delete_selected" data-id="single-domain-admin" data-api-url="delete/fwdhost" data-item="' + encodeURI(item.host) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
  296. '</div>';
  297. if (item.keep_spam == "yes") {
  298. item.keep_spam = lang.no;
  299. }
  300. else {
  301. item.keep_spam = lang.yes;
  302. }
  303. item.chkbox = '<input type="checkbox" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />';
  304. });
  305. }
  306. }),
  307. "empty": lang.empty,
  308. "paging": {
  309. "enabled": true,
  310. "limit": 5,
  311. "size": log_pagination_size
  312. },
  313. "sorting": {
  314. "enabled": true
  315. }
  316. });
  317. }
  318. function draw_rspamd_history() {
  319. ft_postfix_logs = FooTable.init('#rspamd_history', {
  320. "columns": [{
  321. "name": "message-id",
  322. "title": "ID",
  323. "breakpoints": "all",
  324. "style": {
  325. "minWidth": 130,
  326. "overflow": "hidden",
  327. "textOverflow": "ellipsis",
  328. "wordBreak": "break-all",
  329. "whiteSpace": "normal"
  330. }
  331. }, {
  332. "name": "ip",
  333. "title": "IP address",
  334. "breakpoints": "all",
  335. "style": {
  336. "minWidth": 88
  337. }
  338. }, {
  339. "name": "sender_mime",
  340. "title": "From",
  341. "breakpoints": "xs sm md",
  342. "style": {
  343. "minWidth": 100
  344. }
  345. }, {
  346. "name": "rcpt_mime",
  347. "title": "To",
  348. "breakpoints": "xs sm md",
  349. "style": {
  350. "minWidth": 100
  351. }
  352. }, {
  353. "name": "subject",
  354. "title": "Subject",
  355. "breakpoints": "all",
  356. "style": {
  357. "word-break": "break-all",
  358. "minWidth": 150
  359. }
  360. }, {
  361. "name": "action",
  362. "title": "Action",
  363. "style": {
  364. "minwidth": 82
  365. }
  366. }, {
  367. "name": "score",
  368. "title": "Score",
  369. "style": {
  370. "maxWidth": 110
  371. },
  372. }, {
  373. "name": "symbols",
  374. "title": "Symbols",
  375. "breakpoints": "all",
  376. }, {
  377. "name": "size",
  378. "title": "Msg size",
  379. "breakpoints": "all",
  380. "style": {
  381. "minwidth": 50,
  382. },
  383. "formatter": function(value) { return humanFileSize(value); }
  384. }, {
  385. "name": "scan_time",
  386. "title": "Scan time",
  387. "breakpoints": "all",
  388. "style": {
  389. "maxWidth": 72
  390. },
  391. }, {
  392. "sorted": true,
  393. "breakpoints": "all",
  394. "direction": "DESC",
  395. "name": "time",
  396. "title": "Time",
  397. }, {
  398. "name": "user",
  399. "title": "Authenticated user",
  400. "breakpoints": "xs sm md",
  401. "style": {
  402. "minWidth": 100
  403. }
  404. }],
  405. "rows": $.ajax({
  406. dataType: 'json',
  407. url: '/api/v1/get/logs/rspamd-history',
  408. jsonp: false,
  409. error: function () {
  410. console.log('Cannot draw rspamd history table');
  411. },
  412. success: function (data) {
  413. $.each(data, function (i, item) {
  414. item.rcpt_mime = item.rcpt_mime.join(",&#8203;");
  415. Object.keys(item.symbols).map(function(key) {
  416. var sym = item.symbols[key];
  417. if (sym.score <= 0) {
  418. sym.score_formatted = '(<span class="text-success"><b>' + sym.score + '</b></span>)'
  419. }
  420. else {
  421. sym.score_formatted = '(<span class="text-danger"><b>' + sym.score + '</b></span>)'
  422. }
  423. var str = '<strong>' + key + '</strong> ' + sym.score_formatted;
  424. if (sym.options) {
  425. str += ' [' + sym.options.join(",") + "]";
  426. }
  427. item.symbols[key].str = str;
  428. });
  429. item.symbols = Object.keys(item.symbols).
  430. map(function(key) {
  431. return item.symbols[key];
  432. }).sort(function(e1, e2) {
  433. return Math.abs(e1.score) < Math.abs(e2.score);
  434. }).map(function(e) {
  435. return e.str;
  436. }).join("<br>\n");
  437. item.time = {
  438. "value": unix_time_format(item.unix_time),
  439. "options": {
  440. "sortValue": item.unix_time
  441. }
  442. };
  443. var scan_time = item.time_real.toFixed(3) + ' / ' + item.time_virtual.toFixed(3);
  444. item.scan_time = {
  445. "options": {
  446. "sortValue": item.time_real
  447. },
  448. "value": scan_time
  449. };
  450. if (item.action === 'clean' || item.action === 'no action') {
  451. item.action = "<div class='label label-success'>" + item.action + "</div>";
  452. } else if (item.action === 'rewrite subject' || item.action === 'add header' || item.action === 'probable spam') {
  453. item.action = "<div class='label label-warning'>" + item.action + "</div>";
  454. } else if (item.action === 'spam' || item.action === 'reject') {
  455. item.action = "<div class='label label-danger'>" + item.action + "</div>";
  456. } else {
  457. item.action = "<div class='label label-info'>" + item.action + "</div>";
  458. }
  459. var score_content;
  460. if (item.score < item.required_score) {
  461. score_content = "[ <span class='text-success'>" + item.score.toFixed(2) + " / " + item.required_score + "</span> ]";
  462. } else {
  463. score_content = "[ <span class='text-danger'>" + item.score.toFixed(2) + " / " + item.required_score + "</span> ]";
  464. }
  465. item.score = {
  466. "options": {
  467. "sortValue": item.score
  468. },
  469. "value": score_content
  470. };
  471. if (item.user == null) {
  472. item.user = "none";
  473. }
  474. });
  475. }
  476. }),
  477. "empty": lang.empty,
  478. "paging": {
  479. "enabled": true,
  480. "limit": 5,
  481. "size": log_pagination_size
  482. },
  483. "filtering": {
  484. "enabled": true,
  485. "position": "left",
  486. "placeholder": lang.filter_table
  487. },
  488. "sorting": {
  489. "enabled": true
  490. }
  491. });
  492. }
  493. draw_postfix_logs();
  494. draw_dovecot_logs();
  495. draw_sogo_logs();
  496. draw_fail2ban_logs();
  497. draw_domain_admins();
  498. draw_fwd_hosts();
  499. draw_rspamd_history();
  500. });