Merge pull request #6033 from dibdot/adblock
[project/luci.git] / applications / luci-app-adblock / htdocs / luci-static / resources / view / adblock / dnsreport.js
1 'use strict';
2 'require view';
3 'require fs';
4 'require ui';
5
6 /*
7 button handling
8 */
9 function handleAction(ev) {
10 if (ev.target && ev.target.getAttribute('name') === 'blacklist') {
11 L.ui.showModal(_('Add Blacklist Domain'), [
12 E('p', _('Add this (sub-)domain to your local blacklist.')),
13 E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
14 E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [
15 E('input', { 'class': 'cbi-input-text', 'style': 'width:300px', 'spellcheck': 'false', 'id': 'blacklist', 'value': ev.target.getAttribute('value') }, [])
16 ])
17 ]),
18 E('div', { 'class': 'right' }, [
19 E('button', {
20 'class': 'btn cbi-button',
21 'click': L.hideModal
22 }, _('Cancel')),
23 ' ',
24 E('button', {
25 'class': 'btn cbi-button-action',
26 'click': ui.createHandlerFn(this, function(ev) {
27 L.resolveDefault(fs.read_direct('/etc/adblock/adblock.blacklist'), '')
28 .then(function(res) {
29 var domain = document.getElementById('blacklist').value.trim().toLowerCase().replace(/[^a-z0-9\.\-]/g,'');
30 var pattern = new RegExp('^' + domain.replace(/[\.]/g,'\\.') + '$', 'm');
31 if (res.search(pattern) === -1) {
32 var blacklist = res + domain + '\n';
33 fs.write('/etc/adblock/adblock.blacklist', blacklist);
34 ui.addNotification(null, E('p', _('Blacklist changes have been saved. Refresh your adblock lists that changes take effect.')), 'info');
35 }
36 L.hideModal();
37 });
38 })
39 }, _('Save'))
40 ])
41 ]);
42 document.getElementById('blacklist').focus();
43 }
44
45 if (ev.target && ev.target.getAttribute('name') === 'whitelist') {
46 L.ui.showModal(_('Add Whitelist Domain'), [
47 E('p', _('Add this (sub-)domain to your local whitelist.')),
48 E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
49 E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [
50 E('input', { 'class': 'cbi-input-text', 'style': 'width:300px', 'spellcheck': 'false', 'id': 'whitelist', 'value': ev.target.getAttribute('value') }, [])
51 ])
52 ]),
53 E('div', { 'class': 'right' }, [
54 E('button', {
55 'class': 'btn cbi-button',
56 'click': L.hideModal
57 }, _('Cancel')),
58 ' ',
59 E('button', {
60 'class': 'btn cbi-button-action',
61 'click': ui.createHandlerFn(this, function(ev) {
62 L.resolveDefault(fs.read_direct('/etc/adblock/adblock.whitelist'), '')
63 .then(function(res) {
64 var domain = document.getElementById('whitelist').value.trim().toLowerCase().replace(/[^a-z0-9\.\-]/g,'');
65 var pattern = new RegExp('^' + domain.replace(/[\.]/g,'\\.') + '$', 'm');
66 if (res.search(pattern) === -1) {
67 var whitelist = res + domain + '\n';
68 fs.write('/etc/adblock/adblock.whitelist', whitelist);
69 ui.addNotification(null, E('p', _('Whitelist changes have been saved. Refresh your adblock lists that changes take effect.')), 'info');
70 }
71 L.hideModal();
72 });
73 })
74 }, _('Save'))
75 ])
76 ]);
77 document.getElementById('whitelist').focus();
78 }
79
80 if (ev === 'query') {
81 L.ui.showModal(_('Blocklist Query'), [
82 E('p', _('Query active blocklists and backups for a specific domain.')),
83 E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
84 E('label', { 'style': 'padding-top:.5em', 'id': 'run' }, [
85 E('input', {
86 'class': 'cbi-input-text',
87 'placeholder': 'google.com',
88 'style': 'width:300px',
89 'spellcheck': 'false',
90 'id': 'search'
91 })
92 ])
93 ]),
94 E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
95 '\xa0',
96 E('h5', _('Result')),
97 E('textarea', {
98 'id': 'result',
99 'style': 'width: 100% !important; padding: 5px; font-family: monospace',
100 'readonly': 'readonly',
101 'wrap': 'off',
102 'rows': 20
103 })
104 ]),
105 E('div', { 'class': 'right' }, [
106 E('button', {
107 'class': 'btn cbi-button',
108 'click': L.hideModal
109 }, _('Cancel')),
110 ' ',
111 E('button', {
112 'class': 'btn cbi-button-action',
113 'click': ui.createHandlerFn(this, function(ev) {
114 var domain = document.getElementById('search').value.trim().toLowerCase().replace(/[^a-z0-9\.\-]/g,'');
115 if (domain) {
116 document.getElementById('run').classList.add("spinning");
117 document.getElementById('search').value = domain;
118 document.getElementById('result').textContent = 'The query is running, please wait...';
119 L.resolveDefault(fs.exec_direct('/etc/init.d/adblock', ['query', domain])).then(function(res) {
120 var result = document.getElementById('result');
121 if (res) {
122 result.textContent = res.trim();
123 } else {
124 result.textContent = _('No Query results!');
125 }
126 document.getElementById('run').classList.remove("spinning");
127 document.getElementById('search').value = '';
128 })
129 }
130 document.getElementById('search').focus();
131 })
132 }, _('Query'))
133 ])
134 ]);
135 document.getElementById('search').focus();
136 }
137
138 if (ev === 'refresh') {
139 L.ui.showModal(_('Refresh DNS Report'), [
140 E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
141 E('label', { 'class': 'cbi-input-select', 'style': 'padding-top:.5em' }, [
142 E('select', { 'class': 'cbi-input-select', 'id': 'top_count' }, [
143 E('option', { 'value': '10' }, '10'),
144 E('option', { 'value': '20' }, '20'),
145 E('option', { 'value': '30' }, '30'),
146 E('option', { 'value': '40' }, '40'),
147 E('option', { 'value': '50' }, '50')
148 ]),
149 '\xa0\xa0\xa0',
150 _('max. top statistics')
151 ])
152 ]),
153 E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
154 E('label', { 'class': 'cbi-input-select', 'style': 'padding-top:.5em' }, [
155 E('select', { 'class': 'cbi-input-select', 'id': 'res_count' }, [
156 E('option', { 'value': '50' }, '50'),
157 E('option', { 'value': '100' }, '100'),
158 E('option', { 'value': '150' }, '150'),
159 E('option', { 'value': '250' }, '250'),
160 E('option', { 'value': '500' }, '500')
161 ]),
162 '\xa0\xa0\xa0',
163 _('max. result set size')
164 ])
165 ]),
166 E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [
167 E('input', { 'class': 'cbi-input-text', 'spellcheck': 'false', 'id': 'search' }, [
168 ]),
169 '\xa0\xa0\xa0',
170 _('Filter criteria like date, domain or client (optional)')
171 ]),
172 E('div', { 'class': 'right' }, [
173 E('button', {
174 'class': 'btn cbi-button',
175 'click': L.hideModal
176 }, _('Cancel')),
177 ' ',
178 E('button', {
179 'class': 'btn cbi-button-action',
180 'id': 'refresh',
181 'click': ui.createHandlerFn(this, async function(ev) {
182 var top_count = document.getElementById('top_count').value;
183 var res_count = document.getElementById('res_count').value;
184 var search = document.getElementById('search').value.trim().replace(/[^\w\.\-\:]/g,'') || '+';
185 L.resolveDefault(fs.exec_direct('/etc/init.d/adblock', ['report', 'gen', top_count, res_count, search]),'');
186 var running = 1;
187 while (running === 1) {
188 await new Promise(r => setTimeout(r, 1000));
189 L.resolveDefault(fs.read_direct('/var/run/adblock.pid')).then(function(res) {
190 if (!res) {
191 running = 0;
192 }
193 })
194 }
195 L.hideModal();
196 location.reload();
197 })
198 }, _('Refresh'))
199 ])
200 ]);
201 document.getElementById('refresh').focus();
202 }
203 }
204
205 return view.extend({
206 load: function() {
207 return L.resolveDefault(fs.exec_direct('/etc/init.d/adblock', ['report', 'json', '10', '50', '+']),'');
208 },
209
210 render: function(dnsreport) {
211 if (!dnsreport) {
212 dnsreport = '{}';
213 };
214 var content;
215 content = JSON.parse(dnsreport);
216
217 var rows_top = [];
218 var tbl_top = E('table', { 'class': 'table', 'id': 'top_10' }, [
219 E('tr', { 'class': 'tr table-titles' }, [
220 E('th', { 'class': 'th right' }, _('Count')),
221 E('th', { 'class': 'th' }, _('Clients')),
222 E('th', { 'class': 'th right' }, _('Count')),
223 E('th', { 'class': 'th' }, _('Domains')),
224 E('th', { 'class': 'th right' }, _('Count')),
225 E('th', { 'class': 'th' }, _('Blocked Domains'))
226 ])
227 ]);
228
229 var max = 0;
230 if (content.top_clients && content.top_domains && content.top_blocked) {
231 max = Math.max(content.top_clients.length, content.top_domains.length, content.top_blocked.length);
232 }
233 for (var i = 0; i < max; i++) {
234 var a_cnt = '\xa0', a_addr = '\xa0', b_cnt = '\xa0', b_addr = '\xa0', c_cnt = '\xa0', c_addr = '\xa0';
235 if (content.top_clients[i]) {
236 a_cnt = content.top_clients[i].count;
237 }
238 if (content.top_clients[i]) {
239 a_addr = content.top_clients[i].address;
240 }
241 if (content.top_domains[i]) {
242 b_cnt = content.top_domains[i].count;
243 }
244 if (content.top_domains[i]) {
245 b_addr = '<a href="https://duckduckgo.com/?q=' + encodeURIComponent(content.top_domains[i].address) + '&amp;k1=-1&amp;km=l&amp;kh=1" target="_blank" rel="noreferrer noopener" title="Domain Lookup">' + content.top_domains[i].address + '</a>';
246 }
247 if (content.top_blocked[i]) {
248 c_cnt = content.top_blocked[i].count;
249 }
250 if (content.top_blocked[i]) {
251 c_addr = '<a href="https://duckduckgo.com/?q=' + encodeURIComponent(content.top_blocked[i].address) + '&amp;k1=-1&amp;km=l&amp;kh=1" target="_blank" rel="noreferrer noopener" title="Domain Lookup">' + content.top_blocked[i].address + '</a>';
252 }
253 rows_top.push([
254 a_cnt,
255 a_addr,
256 b_cnt,
257 b_addr,
258 c_cnt,
259 c_addr
260 ]);
261 }
262 cbi_update_table(tbl_top, rows_top);
263
264 var rows_requests = [];
265 var tbl_requests = E('table', { 'class': 'table', 'id': 'requests' }, [
266 E('tr', { 'class': 'tr table-titles' }, [
267 E('th', { 'class': 'th' }, _('Date')),
268 E('th', { 'class': 'th' }, _('Time')),
269 E('th', { 'class': 'th' }, _('Client')),
270 E('th', { 'class': 'th' }, _('Domain')),
271 E('th', { 'class': 'th' }, _('Answer')),
272 E('th', { 'class': 'th' }, _('Action'))
273 ])
274 ]);
275
276 max = 0;
277 if (content.requests) {
278 var button;
279 max = content.requests.length;
280 for (var i = 0; i < max; i++) {
281 if (content.requests[i].rc === 'NX') {
282 button = E('button', {
283 'class': 'btn cbi-button cbi-button-positive',
284 'style': 'word-break: inherit',
285 'name': 'whitelist',
286 'value': content.requests[i].domain,
287 'click': handleAction
288 }, [ _('Whitelist...') ]);
289 } else {
290 button = E('button', {
291 'class': 'btn cbi-button cbi-button-negative',
292 'style': 'word-break: inherit',
293 'name': 'blacklist',
294 'value': content.requests[i].domain,
295 'click': handleAction
296 }, [ _('Blacklist...') ]);
297 }
298 rows_requests.push([
299 content.requests[i].date,
300 content.requests[i].time,
301 content.requests[i].client,
302 '<a href="https://duckduckgo.com/?q=' + encodeURIComponent(content.requests[i].domain) + '&amp;k1=-1&amp;km=l&amp;kh=1" target="_blank" rel="noreferrer noopener" title="Domain Lookup">' + content.requests[i].domain + '</a>',
303 content.requests[i].rc,
304 button
305 ]);
306 }
307 }
308 cbi_update_table(tbl_requests, rows_requests);
309
310 return E('div', { 'class': 'cbi-map', 'id': 'map' }, [
311 E('div', { 'class': 'cbi-section' }, [
312 E('p', _('This tab shows the last generated DNS Report, press the \'Refresh\' button to get a current one.')),
313 E('p', '\xa0'),
314 E('div', { 'class': 'cbi-value' }, [
315 E('div', { 'class': 'cbi-value-title', 'style': 'float:left;width:230px' }, _('Start Timestamp')),
316 E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'float:left;color:#37c' }, (content.start_date || '-') + ', ' + (content.start_time || '-'))
317 ]),
318 E('div', { 'class': 'cbi-value' }, [
319 E('div', { 'class': 'cbi-value-title', 'style': 'float:left;width:230px' }, _('End Timestamp')),
320 E('div', { 'class': 'cbi-value-title', 'id': 'end', 'style': 'float:left;color:#37c' }, (content.end_date || '-') + ', ' + (content.end_time || '-'))
321 ]),
322 E('div', { 'class': 'cbi-value' }, [
323 E('div', { 'class': 'cbi-value-title', 'style': 'float:left;width:230px' }, _('Total DNS Requests')),
324 E('div', { 'class': 'cbi-value-title', 'id': 'total', 'style': 'float:left;color:#37c' }, content.total || '-')
325 ]),
326 E('div', { 'class': 'cbi-value' }, [
327 E('div', { 'class': 'cbi-value-title', 'style': 'float:left;width:230px' }, _('Blocked DNS Requests')),
328 E('div', { 'class': 'cbi-value-title', 'id': 'blocked', 'style': 'float:left;color:#37c' }, (content.blocked || '-') + ' (' + (content.percent || '-') + ')')
329 ]),
330 E('div', { 'class': 'right' }, [
331 E('button', {
332 'class': 'btn cbi-button cbi-button-apply',
333 'click': ui.createHandlerFn(this, function() {
334 return handleAction('query');
335 })
336 }, [ _('Blocklist Query...') ]),
337 '\xa0\xa0\xa0',
338 E('button', {
339 'class': 'btn cbi-button cbi-button-positive',
340 'click': ui.createHandlerFn(this, function() {
341 return handleAction('refresh');
342 })
343 }, [ _('Refresh...') ])
344 ]),
345 ]),
346 E('div', { 'class': 'cbi-section' }, [
347 E('div', { 'class': 'left' }, [
348 E('h3', _('Top Statistics')),
349 tbl_top
350 ])
351 ]),
352 E('br'),
353 E('div', { 'class': 'cbi-section' }, [
354 E('div', { 'class': 'left' }, [
355 E('h3', _('Latest DNS Requests')),
356 tbl_requests
357 ])
358 ])
359 ]);
360 },
361 handleSaveApply: null,
362 handleSave: null,
363 handleReset: null
364 });