luci-app: Minor fixes and improvements
@@ -11,8 +11,8 @@ LUCI_APP=1
|
||||
OWRT_VERSION="19.07"
|
||||
RUAB_VERSION="0.9.0-2"
|
||||
RUAB_MOD_LUA_VERSION="0.9.0-2"
|
||||
RUAB_LUCI_APP_VERSION="0.9.0-6"
|
||||
BASE_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_openwrt/master"
|
||||
RUAB_LUCI_APP_VERSION="0.9.0-7"
|
||||
BASE_URL="https://github.com/gSpotx2f/ruantiblock_openwrt/raw/master"
|
||||
PKG_DIR="/tmp"
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
@@ -29,8 +29,8 @@ URL_LUCI_APP_RU_PKG="${BASE_URL}/packages/${OWRT_VERSION}/luci-i18n-ruantiblock-
|
||||
### tor
|
||||
URL_TORRC="${BASE_URL}/tor/etc/tor/torrc"
|
||||
### ruantiblock-mod-lua
|
||||
URL_LUA_IPTOOL="https://raw.githubusercontent.com/gSpotx2f/iptool-lua/master/5.1/iptool.lua"
|
||||
URL_LUA_IDN="https://raw.githubusercontent.com/haste/lua-idn/master/idn.lua"
|
||||
URL_LUA_IPTOOL="https://github.com/gSpotx2f/iptool-lua/raw/master/5.1/iptool.lua"
|
||||
URL_LUA_IDN="https://github.com/haste/lua-idn/raw/master/idn.lua"
|
||||
|
||||
### Local files
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 81 KiB |
@@ -5,11 +5,12 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_VERSION:=0.9.0
|
||||
PKG_RELEASE:=6
|
||||
PKG_RELEASE:=7
|
||||
LUCI_TITLE:=LuCI support for ruantiblock
|
||||
LUCI_DEPENDS:=+ruantiblock +luci-mod-admin-full
|
||||
LUCI_DEPENDS:=+ruantiblock
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
include ../../luci.mk
|
||||
#include ../../luci.mk
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
@@ -633,8 +633,8 @@ return L.Class.extend({
|
||||
]);
|
||||
},
|
||||
|
||||
handleSaveApply: null,
|
||||
handleSave : null,
|
||||
handleSaveApply: null,
|
||||
handleReset : null,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -3,73 +3,72 @@
|
||||
'require ui';
|
||||
'require view.ruantiblock.tools as tools';
|
||||
|
||||
let crontab_regexp = new RegExp(`^(\\*?\\/?(\\d){0,2}\\s){5}${tools.exec_path} update(\n)?`, 'gm');
|
||||
let current_crontab_content;
|
||||
return L.view.extend({
|
||||
crontabRegexp: new RegExp(
|
||||
`^(\\*?\\/?(\\d){0,2}\\s){5}${tools.execPath} update(\n)?`, 'gm'),
|
||||
|
||||
function to_dd(n){
|
||||
currentCrontabContent: null,
|
||||
|
||||
toDD: function(n){
|
||||
return String(n).replace(/^(\d)$/, "0$1");
|
||||
};
|
||||
},
|
||||
|
||||
function cron_status_string(s) {
|
||||
cronStatusString: function(s) {
|
||||
return s || _('No Shedule');
|
||||
}
|
||||
},
|
||||
|
||||
function pick_cron_task(content) {
|
||||
pickCronTask: function(content) {
|
||||
if(!content){
|
||||
return;
|
||||
};
|
||||
let current_tasks = content.match(crontab_regexp) || [];
|
||||
let current_tasks = content.match(this.crontabRegexp) || [];
|
||||
return current_tasks.join('');
|
||||
};
|
||||
},
|
||||
|
||||
function set_cron_status(value) {
|
||||
document.getElementById('cron_status').value = cron_status_string(value);
|
||||
document.getElementById("btn_cron_del").style.visibility = (value) ? 'visible' : 'hidden';
|
||||
}
|
||||
setCronStatus: function(value) {
|
||||
document.getElementById('cron_status').value = this.cronStatusString(value);
|
||||
document.getElementById("btn_cron_del").style.visibility = (value) ?
|
||||
'visible' : 'hidden';
|
||||
},
|
||||
|
||||
function write_cron_file() {
|
||||
writeCronFile: function() {
|
||||
let btn_cron_add = document.getElementById('btn_cron_add');
|
||||
let btn_cron_del = document.getElementById('btn_cron_del');
|
||||
|
||||
if(!current_crontab_content) {
|
||||
if(!this.currentCrontabContent) {
|
||||
ui.addNotification(null, E('p', _('No changes to save.')));
|
||||
btn_cron_add.disabled = false;
|
||||
return;
|
||||
};
|
||||
|
||||
return fs.write(tools.crontab_file, current_crontab_content).then(rc => {
|
||||
return fs.write(tools.crontabFile, this.currentCrontabContent).then(rc => {
|
||||
ui.addNotification(null, E('p',_('Changes have been saved.')), 'info');
|
||||
set_cron_status(pick_cron_task(current_crontab_content));
|
||||
this.setCronStatus(this.pickCronTask(this.currentCrontabContent));
|
||||
}).then(() => {
|
||||
return fs.exec('/etc/init.d/cron', [ 'enabled' ]).then(res => {
|
||||
if(res.code !== 0) {
|
||||
return fs.exec('/etc/init.d/cron', [ 'enable' ]);
|
||||
return tools.getInitStatus('cron').then(res => {
|
||||
if(!res) {
|
||||
return tools.handleServiceAction('cron', 'enable');
|
||||
};
|
||||
}).catch(e => {
|
||||
ui.addNotification(null, E('p', _('Unable to execute or read contents')
|
||||
+ ': %s<br />[ %s ]'.format(e.message, '/etc/init.d/cron')));
|
||||
});
|
||||
}).finally(() => {
|
||||
return fs.exec('/etc/init.d/cron', [ 'restart' ]).catch(e => {
|
||||
ui.addNotification(null, E('p', _('Unable to execute or read contents')
|
||||
+ ': %s<br />[ %s ]'.format(e.message, '/etc/init.d/cron')));
|
||||
});
|
||||
return tools.handleServiceAction('cron', 'restart');
|
||||
}).catch(e => {
|
||||
ui.addNotification(null, E('p', _('Unable to save the changes')
|
||||
+ ': %s<br />[ %s ]'.format(
|
||||
e.message, tools.crontab_file
|
||||
+ ': %s [ %s ]'.format(
|
||||
e.message, tools.crontabFile
|
||||
)));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
function del_cron_schedule(ev) {
|
||||
if(current_crontab_content) {
|
||||
current_crontab_content = current_crontab_content.replace(crontab_regexp, "");
|
||||
};
|
||||
return write_cron_file();
|
||||
delCronSchedule: function(ev) {
|
||||
if(this.currentCrontabContent) {
|
||||
this.currentCrontabContent = this.currentCrontabContent.replace(
|
||||
this.crontabRegexp, "");
|
||||
};
|
||||
return this.writeCronFile();
|
||||
},
|
||||
|
||||
function set_cron_schedule(ev) {
|
||||
setCronSchedule: function(ev) {
|
||||
let hour_interval = document.getElementById('cron_hour_interval').value;
|
||||
let day_interval = document.getElementById('cron_day_interval').value;
|
||||
let hour = document.getElementById('cron_hour').value;
|
||||
@@ -78,15 +77,16 @@ function set_cron_schedule(ev) {
|
||||
min,
|
||||
(!hour_interval) ? hour : (hour_interval == "1") ? '*' : '*/' + hour_interval,
|
||||
(hour_interval || day_interval == "1") ? '*' : '*/' + day_interval,
|
||||
tools.exec_path
|
||||
tools.execPath
|
||||
);
|
||||
if(current_crontab_content) {
|
||||
current_crontab_content = current_crontab_content.replace(crontab_regexp, "") + task_string;
|
||||
};
|
||||
return write_cron_file();
|
||||
if(this.currentCrontabContent) {
|
||||
this.currentCrontabContent = this.currentCrontabContent.replace(
|
||||
this.crontabRegexp, "") + task_string;
|
||||
};
|
||||
return this.writeCronFile();
|
||||
},
|
||||
|
||||
function onchange_hour_interval(e) {
|
||||
onchangeHourInterval: function(e) {
|
||||
let value = e.target.value;
|
||||
let bool = (value != '');
|
||||
let cron_hour = document.getElementById('cron_hour');
|
||||
@@ -94,6 +94,7 @@ function onchange_hour_interval(e) {
|
||||
cron_hour.disabled = bool;
|
||||
cron_day_interval.disabled = bool;
|
||||
|
||||
// For luci-theme-material
|
||||
if(bool) {
|
||||
cron_hour.style.opacity = '50%';
|
||||
cron_day_interval.style.opacity = '50%';
|
||||
@@ -101,21 +102,20 @@ function onchange_hour_interval(e) {
|
||||
cron_hour.style.opacity = '100%';
|
||||
cron_day_interval.style.opacity = '100%';
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
return L.view.extend({
|
||||
load: function() {
|
||||
return fs.read(tools.crontab_file).catch(e => {
|
||||
return fs.read(tools.crontabFile).catch(e => {
|
||||
ui.addNotification(null, E('p', _('Unable to read the contents')
|
||||
+ ': %s<br />[ %s ]'.format(
|
||||
e.message, tools.crontab_file
|
||||
+ ': %s [ %s ]'.format(
|
||||
e.message, tools.crontabFile
|
||||
)));
|
||||
});
|
||||
},
|
||||
|
||||
render: function(content) {
|
||||
current_crontab_content = content;
|
||||
let current_task = pick_cron_task(content);
|
||||
this.currentCrontabContent = content;
|
||||
let current_task = this.pickCronTask(content);
|
||||
|
||||
let cron_status = E('textarea', {
|
||||
'id': 'cron_status',
|
||||
@@ -124,25 +124,27 @@ return L.view.extend({
|
||||
'readonly': 'readonly',
|
||||
'wrap': 'off',
|
||||
'rows': 2,
|
||||
}, cron_status_string(current_task));
|
||||
}, this.cronStatusString(current_task));
|
||||
|
||||
let btn_cron_del = E('button', {
|
||||
'class': 'cbi-button btn cbi-button-reset',
|
||||
'id': 'btn_cron_del',
|
||||
'name': 'btn_cron_del',
|
||||
}, _('Reset'));
|
||||
btn_cron_del.onclick = ui.createHandlerFn(this, del_cron_schedule);
|
||||
btn_cron_del.onclick = ui.createHandlerFn(this, this.delCronSchedule);
|
||||
btn_cron_del.style.visibility = (current_task) ? 'visible' : 'hidden';
|
||||
|
||||
let status_header = E('div', { 'class': 'cbi-section-node' }, [
|
||||
E('div', { 'class': 'cbi-value' }, [
|
||||
E('label', { 'class': 'cbi-value-title', 'for': 'cron_status' },
|
||||
_('Current schedule')),
|
||||
E('div', { 'class': 'cbi-value-field' }, cron_status),
|
||||
E('div', { 'class': 'cbi-value-field' },
|
||||
cron_status),
|
||||
]),
|
||||
E('div', { 'class': 'cbi-value' }, [
|
||||
E('label', { 'class': 'cbi-value-title', 'for': 'btn_cron_del' }),
|
||||
E('div', { 'class': 'cbi-value-field' }, btn_cron_del),
|
||||
E('div', { 'class': 'cbi-value-field' },
|
||||
btn_cron_del),
|
||||
])
|
||||
]);
|
||||
|
||||
@@ -154,7 +156,8 @@ return L.view.extend({
|
||||
E('div', { 'class': 'cbi-value' }, [
|
||||
E('label', { 'class': 'cbi-value-title', 'for': elem.id || null },
|
||||
title),
|
||||
E('div', { 'class': 'cbi-value-field' }, [ elem, descr ]),
|
||||
E('div', { 'class': 'cbi-value-field' },
|
||||
[ elem, descr ]),
|
||||
])
|
||||
)
|
||||
};
|
||||
@@ -167,17 +170,21 @@ return L.view.extend({
|
||||
E('option', { 'value': '1' }, '∗')
|
||||
]);
|
||||
for(let i = 2; i <= 12 ; i += 2) {
|
||||
cron_hour_interval.append(E('option', { 'value': String(i) }, '∗/' + i));
|
||||
cron_hour_interval.append(
|
||||
E('option', { 'value': String(i) }, '∗/' + i)
|
||||
);
|
||||
};
|
||||
layout_append(cron_hour_interval, _('Hour'));
|
||||
cron_hour_interval.onchange = onchange_hour_interval;
|
||||
cron_hour_interval.onchange = this.onchangeHourInterval;
|
||||
|
||||
let cron_day_interval = E('select',
|
||||
{ 'id': 'cron_day_interval', 'style': 'width:60px !important; min-width:60px !important' },
|
||||
E('option', { 'value': '1' }, '∗')
|
||||
);
|
||||
for(let i = 2; i < 8 ; i++) {
|
||||
cron_day_interval.append(E('option', { 'value': String(i) }, '∗/' + i));
|
||||
cron_day_interval.append(
|
||||
E('option', { 'value': String(i) }, '∗/' + i)
|
||||
);
|
||||
};
|
||||
cron_day_interval.append(E('option', { 'value': '14' }, '∗/14'));
|
||||
cron_day_interval.append(E('option', { 'value': '28' }, '∗/28'));
|
||||
@@ -188,14 +195,18 @@ return L.view.extend({
|
||||
let cron_hour = E('select',
|
||||
{ 'id': 'cron_hour', 'style': 'width:60px !important; min-width:60px !important' });
|
||||
for(let i = 0; i < 24 ; i++) {
|
||||
cron_hour.append(E('option', { 'value': String(i) }, to_dd(i)));
|
||||
cron_hour.append(
|
||||
E('option', { 'value': String(i) }, this.toDD(i))
|
||||
);
|
||||
};
|
||||
layout_append(cron_hour, _('Hour'));
|
||||
|
||||
let cron_min = E('select',
|
||||
{ 'id': 'cron_min', 'style': 'width:60px !important; min-width:60px !important' });
|
||||
for(let i = 0; i < 60 ; i++) {
|
||||
cron_min.append(E('option', { 'value': String(i) }, to_dd(i)));
|
||||
cron_min.append(
|
||||
E('option', { 'value': String(i) }, this.toDD(i))
|
||||
);
|
||||
};
|
||||
layout_append(cron_min, _('Minute'));
|
||||
|
||||
@@ -204,12 +215,14 @@ return L.view.extend({
|
||||
'id': 'btn_cron_add',
|
||||
'name': 'btn_cron_add'
|
||||
}, _('Set'));
|
||||
btn_cron_add.onclick = ui.createHandlerFn(this, set_cron_schedule);
|
||||
btn_cron_add.onclick = ui.createHandlerFn(this, this.setCronSchedule);
|
||||
layout_append(btn_cron_add);
|
||||
|
||||
return E([
|
||||
E('h2',
|
||||
{ 'class': 'fade-in' }, _('Ruantiblock') + ' - ' + _('Blacklist updates') + ' (cron)'),
|
||||
{ 'class': 'fade-in' },
|
||||
_('Ruantiblock') + ' - ' + _('Blacklist updates') + ' (cron)'
|
||||
),
|
||||
E('div', { 'class': 'cbi-section-descr fade-in' }),
|
||||
E('div', { 'class': 'cbi-section fade-in' }, status_header),
|
||||
E('div', { 'class': 'cbi-section fade-in' }, layout),
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
'require view.ruantiblock.tools as tools';
|
||||
|
||||
return L.view.extend({
|
||||
poll_info: function() {
|
||||
return fs.exec_direct(tools.exec_path, [ 'html-info' ], 'json').catch(e => {
|
||||
infoPoll: function() {
|
||||
return fs.exec_direct(tools.execPath, [ 'html-info' ], 'json').catch(e => {
|
||||
ui.addNotification(null, E('p', _('Unable to execute or read contents')
|
||||
+ ': %s<br />[ %s ]'.format(e.message, tools.exec_path)
|
||||
+ ': %s [ %s ]'.format(e.message, tools.execPath)
|
||||
));
|
||||
L.Poll.stop();
|
||||
}).then(data => {
|
||||
@@ -79,9 +79,9 @@ return L.view.extend({
|
||||
},
|
||||
|
||||
load: function() {
|
||||
return fs.exec_direct(tools.exec_path, [ 'html-info' ], 'json').catch(e => {
|
||||
return fs.exec_direct(tools.execPath, [ 'html-info' ], 'json').catch(e => {
|
||||
ui.addNotification(null, E('p', _('Unable to execute or read contents')
|
||||
+ ': %s<br />[ %s ]'.format(e.message, tools.exec_path)
|
||||
+ ': %s [ %s ]'.format(e.message, tools.execPath)
|
||||
));
|
||||
})
|
||||
},
|
||||
@@ -107,22 +107,26 @@ return L.view.extend({
|
||||
E('div', { 'class': 'tr' }, [
|
||||
E('div', { 'class': 'td left', 'style': 'min-width:33%' },
|
||||
_('Last blacklist update') + ':'),
|
||||
E('div', { 'class': 'td left', 'id': 'last_blacklist_update.date' },
|
||||
E('div', { 'class': 'td left',
|
||||
'id': 'last_blacklist_update.date' },
|
||||
data.last_blacklist_update.date),
|
||||
]),
|
||||
E('div', { 'class': 'tr' }, [
|
||||
E('div', { 'class': 'td left' }, 'IP:'),
|
||||
E('div', { 'class': 'td left', 'id': 'last_blacklist_update.ip' },
|
||||
E('div', { 'class': 'td left',
|
||||
'id': 'last_blacklist_update.ip' },
|
||||
data.last_blacklist_update.ip),
|
||||
]),
|
||||
E('div', { 'class': 'tr' }, [
|
||||
E('div', { 'class': 'td left' }, 'CIDR:'),
|
||||
E('div', { 'class': 'td left', 'id': 'last_blacklist_update.cidr' },
|
||||
E('div', { 'class': 'td left',
|
||||
'id': 'last_blacklist_update.cidr' },
|
||||
data.last_blacklist_update.cidr),
|
||||
]),
|
||||
E('div', { 'class': 'tr' }, [
|
||||
E('div', { 'class': 'td left' }, 'FQDN:'),
|
||||
E('div', { 'class': 'td left', 'id': 'last_blacklist_update.fqdn' },
|
||||
E('div', { 'class': 'td left',
|
||||
'id': 'last_blacklist_update.fqdn' },
|
||||
data.last_blacklist_update.fqdn),
|
||||
])
|
||||
);
|
||||
@@ -147,7 +151,6 @@ return L.view.extend({
|
||||
|
||||
for(let [k, v] of Object.entries(data.iptables)) {
|
||||
if(k === '_dummy') continue;
|
||||
|
||||
table_iptables.append(
|
||||
E('div', { 'class': 'tr' }, [
|
||||
E('div', {
|
||||
@@ -172,9 +175,12 @@ return L.view.extend({
|
||||
if(data.ipset) {
|
||||
let table_ipset = E('div', { 'class': 'table' },
|
||||
E('div', { 'class': 'tr table-titles' }, [
|
||||
E('div', { 'class': 'th left', 'style': 'min-width:33%' }, _('Name')),
|
||||
E('div', { 'class': 'th left' }, _('Size in memory')),
|
||||
E('div', { 'class': 'th left' }, _('Number of entries')),
|
||||
E('div', { 'class': 'th left', 'style': 'min-width:33%' },
|
||||
_('Name')),
|
||||
E('div', { 'class': 'th left' },
|
||||
_('Size in memory')),
|
||||
E('div', { 'class': 'th left' },
|
||||
_('Number of entries')),
|
||||
])
|
||||
);
|
||||
|
||||
@@ -207,13 +213,15 @@ return L.view.extend({
|
||||
]);
|
||||
};
|
||||
|
||||
L.Poll.add(this.poll_info);
|
||||
L.Poll.add(this.infoPoll);
|
||||
} else {
|
||||
update_status = E('em', {}, _('Status') + ' : ' + _('disabled'));
|
||||
};
|
||||
};
|
||||
return E([
|
||||
E('h2', { 'class': 'fade-in' }, _('Ruantiblock') + ' - ' + _('Statistics')),
|
||||
E('h2', { 'class': 'fade-in' },
|
||||
_('Ruantiblock') + ' - ' + _('Statistics')
|
||||
),
|
||||
E('div', { 'class': 'cbi-section-descr fade-in' }),
|
||||
E('div', { 'class': 'cbi-section fade-in' },
|
||||
E('div', { 'class': 'cbi-section-node' }, update_status)
|
||||
|
||||
@@ -8,7 +8,7 @@ return abc.view.extend({
|
||||
|
||||
title: _('Ruantiblock') + ' - ' + _('Log'),
|
||||
|
||||
appRegexp: new RegExp(`^.*${tools.app_name}\[[0-9]+\].*$`, 'gm'),
|
||||
appRegexp : new RegExp(`^.*${tools.appName}\[[0-9]+\].*$`, 'gm'),
|
||||
|
||||
testRegexp : new RegExp(/([0-9]{2}:){2}[0-9]{2}/),
|
||||
|
||||
@@ -53,8 +53,9 @@ return abc.view.extend({
|
||||
let logger = (stat[0]) ? stat[0].path : (stat[1]) ? stat[1].path : null;
|
||||
|
||||
if(logger) {
|
||||
return fs.exec_direct(logger, [ '-e', tools.app_name ]).catch(err => {
|
||||
ui.addNotification(null, E('p', {}, _('Unable to load log data:') + ' ' + err.message));
|
||||
return fs.exec_direct(logger, [ '-e', tools.appName ]).catch(err => {
|
||||
ui.addNotification(
|
||||
null, E('p', {}, _('Unable to load log data:') + ' ' + err.message));
|
||||
return '';
|
||||
});
|
||||
};
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
|
||||
const btn_style_neutral = 'btn'
|
||||
const btn_style_action = 'btn cbi-button-action';
|
||||
const btn_style_save = 'btn cbi-button-save important';
|
||||
const btn_style_reset = 'btn cbi-button-reset important';
|
||||
const btn_style_positive = 'btn cbi-button-save important';
|
||||
const btn_style_negative = 'btn cbi-button-reset important';
|
||||
const btn_style_warning = 'btn cbi-button-negative important'
|
||||
let status_token_value;
|
||||
|
||||
function disable_buttons(bool, btn, elems=[]) {
|
||||
return L.view.extend({
|
||||
statusTokenValue: null,
|
||||
|
||||
disableButtons: function(bool, btn, elems=[]) {
|
||||
let btn_start = elems[1] || document.getElementById("btn_start");
|
||||
let btn_destroy = elems[5] || document.getElementById("btn_destroy");
|
||||
let btn_enable = elems[2] || document.getElementById("btn_enable");
|
||||
@@ -27,41 +29,40 @@ function disable_buttons(bool, btn, elems=[]) {
|
||||
btn_enable.disabled = bool;
|
||||
};
|
||||
if(btn_tp) {
|
||||
btn_tp.disabled = bool
|
||||
btn_tp.disabled = bool;
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
function get_app_status() {
|
||||
getAppStatus: function() {
|
||||
return Promise.all([
|
||||
fs.exec(tools.exec_path, [ 'raw-status' ]),
|
||||
fs.exec(tools.exec_path, [ 'total-proxy-status' ]),
|
||||
fs.exec(tools.exec_path, [ 'vpn-route-status' ]),
|
||||
fs.exec(tools.init_path, [ 'enabled' ]),
|
||||
L.resolveDefault(fs.read(tools.token_file), 0),
|
||||
uci.load(tools.app_name),
|
||||
fs.exec(tools.execPath, [ 'raw-status' ]),
|
||||
fs.exec(tools.execPath, [ 'total-proxy-status' ]),
|
||||
fs.exec(tools.execPath, [ 'vpn-route-status' ]),
|
||||
tools.getInitStatus(tools.appName),
|
||||
L.resolveDefault(fs.read(tools.tokenFile), 0),
|
||||
uci.load(tools.appName),
|
||||
]).catch(e => {
|
||||
ui.addNotification(null, E('p', _('Unable to execute or read contents')
|
||||
+ ': %s<br />[ %s | %s | %s ]'.format(
|
||||
e.message, tools.exec_path, tools.init_path, 'uci.ruantiblock'
|
||||
+ ': %s [ %s | %s | %s ]'.format(
|
||||
e.message, tools.execPath, 'tools.getInitStatus', 'uci.ruantiblock'
|
||||
)));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
function set_app_status(status_array, elems=[], force_app_code) {
|
||||
let section = uci.get(tools.app_name, 'config');
|
||||
setAppStatus: function(status_array, elems=[], force_app_code) {
|
||||
let section = uci.get(tools.appName, 'config');
|
||||
if(!status_array || typeof(section) !== 'object') {
|
||||
(elems[0] || document.getElementById("status")).innerHTML = tools.make_status_string(1);
|
||||
(elems[0] || document.getElementById("status")).innerHTML = tools.makeStatusString(1);
|
||||
ui.addNotification(null, E('p', _('Unable to read the contents')
|
||||
+ ': set_app_status()'));
|
||||
disable_buttons(true, null, elems);
|
||||
+ ': setAppStatus()'));
|
||||
this.disableButtons(true, null, elems);
|
||||
return;
|
||||
};
|
||||
|
||||
let app_status_code = (force_app_code) ? force_app_code : status_array[0].code;
|
||||
let tp_status_code = status_array[1].code;
|
||||
let vpn_route_status_code = status_array[2].code;
|
||||
let enabled_flag = status_array[3].code;
|
||||
|
||||
let enabled_flag = status_array[3];
|
||||
let proxy_local_clients = section.proxy_local_clients;
|
||||
let proxy_mode = section.proxy_mode;
|
||||
let bllist_mode = section.bllist_mode;
|
||||
@@ -69,48 +70,54 @@ function set_app_status(status_array, elems=[], force_app_code) {
|
||||
let bllist_source = section.bllist_source;
|
||||
|
||||
let btn_enable = elems[2] || document.getElementById('btn_enable');
|
||||
if(enabled_flag == 0) {
|
||||
btn_enable.onclick = ui.createHandlerFn(this, button_action, 'disable');
|
||||
btn_enable.textContent = _('Disable');
|
||||
btn_enable.className = btn_style_reset;
|
||||
if(enabled_flag == true) {
|
||||
btn_enable.onclick = ui.createHandlerFn(
|
||||
this, this.serviceAction, 'disable', 'btn_enable');
|
||||
btn_enable.textContent = _('Enabled');
|
||||
btn_enable.className = btn_style_positive;
|
||||
} else {
|
||||
btn_enable.onclick = ui.createHandlerFn(this, button_action, 'enable');
|
||||
btn_enable.textContent = _('Enable');
|
||||
btn_enable.className = btn_style_save;
|
||||
btn_enable.onclick = ui.createHandlerFn(
|
||||
this, this.serviceAction, 'enable', 'btn_enable');
|
||||
btn_enable.textContent = _('Disabled');
|
||||
btn_enable.className = btn_style_negative;
|
||||
};
|
||||
|
||||
let btn_tp = elems[3] || document.getElementById('btn_tp');
|
||||
if(btn_tp) {
|
||||
if(tp_status_code == 0) {
|
||||
btn_tp.onclick = ui.createHandlerFn(this, button_action, 'total-proxy-off');
|
||||
btn_tp.textContent = _('Disable');
|
||||
btn_tp.className = btn_style_reset;
|
||||
btn_tp.onclick = ui.createHandlerFn(
|
||||
this, this.appAction, 'total-proxy-off', 'btn_tp');
|
||||
btn_tp.textContent = _('Enabled');
|
||||
btn_tp.className = btn_style_positive;
|
||||
} else {
|
||||
btn_tp.onclick = ui.createHandlerFn(this, button_action, 'total-proxy-on');
|
||||
btn_tp.textContent = _('Enable');
|
||||
btn_tp.className = btn_style_save;
|
||||
btn_tp.onclick = ui.createHandlerFn(
|
||||
this, this.appAction, 'total-proxy-on', 'btn_tp');
|
||||
btn_tp.textContent = _('Disabled');
|
||||
btn_tp.className = btn_style_negative;
|
||||
};
|
||||
};
|
||||
|
||||
let btn_start = elems[1] || document.getElementById("btn_start");
|
||||
let btn_update = elems[4] || document.getElementById("btn_update");
|
||||
let btn_destroy = elems[5] || document.getElementById("btn_destroy");
|
||||
let btn_start = elems[1] || document.getElementById('btn_start');
|
||||
let btn_update = elems[4] || document.getElementById('btn_update');
|
||||
let btn_destroy = elems[5] || document.getElementById('btn_destroy');
|
||||
|
||||
function btn_start_state_on() {
|
||||
btn_start.onclick = ui.createHandlerFn(this, button_action, 'stop');
|
||||
btn_start.textContent = _('Disable');
|
||||
btn_start.className = btn_style_reset;
|
||||
let btnStartStateOn = () => {
|
||||
btn_start.onclick = ui.createHandlerFn(
|
||||
this, this.serviceAction, 'stop', 'btn_start');
|
||||
btn_start.textContent = _('Enabled');
|
||||
btn_start.className = btn_style_positive;
|
||||
}
|
||||
|
||||
function btn_start_state_off() {
|
||||
btn_start.onclick = ui.createHandlerFn(this, button_action, 'start');
|
||||
btn_start.textContent = _('Enable');
|
||||
btn_start.className = btn_style_action;
|
||||
let btnStartStateOff = () => {
|
||||
btn_start.onclick = ui.createHandlerFn(
|
||||
this, this.serviceAction,'start', 'btn_start');
|
||||
btn_start.textContent = _('Disabled');
|
||||
btn_start.className = btn_style_negative;
|
||||
}
|
||||
|
||||
if(app_status_code == 0) {
|
||||
disable_buttons(false, null, elems);
|
||||
btn_start_state_on();
|
||||
this.disableButtons(false, null, elems);
|
||||
btnStartStateOn();
|
||||
btn_destroy.disabled = false;
|
||||
btn_update.disabled = false;
|
||||
if(btn_tp) {
|
||||
@@ -118,28 +125,28 @@ function set_app_status(status_array, elems=[], force_app_code) {
|
||||
};
|
||||
}
|
||||
else if(app_status_code == 2) {
|
||||
disable_buttons(false, null, elems);
|
||||
btn_start_state_off();
|
||||
this.disableButtons(false, null, elems);
|
||||
btnStartStateOff();
|
||||
btn_update.disabled = true;
|
||||
if(btn_tp) {
|
||||
btn_tp.disabled = true;
|
||||
};
|
||||
}
|
||||
else if(app_status_code == 3) {
|
||||
btn_start_state_off();
|
||||
disable_buttons(true, btn_start, elems);
|
||||
btnStartStateOff();
|
||||
this.disableButtons(true, btn_start, elems);
|
||||
}
|
||||
else if(app_status_code == 4) {
|
||||
btn_start_state_on();
|
||||
disable_buttons(true, btn_update, elems);
|
||||
btnStartStateOn();
|
||||
this.disableButtons(true, btn_update, elems);
|
||||
}
|
||||
else {
|
||||
ui.addNotification(null, E('p', _('Error')
|
||||
+ ' %s: return code = %s'.format(tools.exec_path, app_status_code)));
|
||||
disable_buttons(true, null, elems);
|
||||
+ ' %s: return code = %s'.format(tools.execPath, app_status_code)));
|
||||
this.disableButtons(true, null, elems);
|
||||
};
|
||||
|
||||
(elems[0] || document.getElementById("status")).innerHTML = tools.make_status_string(
|
||||
(elems[0] || document.getElementById("status")).innerHTML = tools.makeStatusString(
|
||||
app_status_code,
|
||||
proxy_mode,
|
||||
bllist_mode,
|
||||
@@ -151,66 +158,64 @@ function set_app_status(status_array, elems=[], force_app_code) {
|
||||
if(!L.Poll.active()) {
|
||||
L.Poll.start();
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
function button_action(action) {
|
||||
let btn,
|
||||
cmd = tools.exec_path;
|
||||
|
||||
switch(action) {
|
||||
case 'start':
|
||||
case 'stop':
|
||||
btn = document.getElementById('btn_start');
|
||||
break;
|
||||
case 'destroy':
|
||||
btn = document.getElementById('btn_destroy');
|
||||
break;
|
||||
case 'update':
|
||||
btn = document.getElementById('btn_update');
|
||||
break;
|
||||
case 'enable':
|
||||
case 'disable':
|
||||
btn = document.getElementById('btn_enable');
|
||||
cmd = tools.init_path;
|
||||
break;
|
||||
case 'total-proxy-on':
|
||||
case 'total-proxy-off':
|
||||
btn = document.getElementById('btn_tp');
|
||||
break;
|
||||
}
|
||||
|
||||
disable_buttons(true, btn);
|
||||
L.Poll.stop();
|
||||
|
||||
if(action === 'update') {
|
||||
get_app_status().then(status_array => {
|
||||
set_app_status(status_array, [], 4);
|
||||
});
|
||||
serviceAction: function(action, button) {
|
||||
if(button) {
|
||||
let elem = document.getElementById(button);
|
||||
this.disableButtons(true, elem);
|
||||
};
|
||||
|
||||
return fs.exec_direct(cmd, [ action ]).then(res => {
|
||||
return get_app_status().then(
|
||||
(status_array) => {
|
||||
set_app_status(status_array);
|
||||
ui.hideModal();
|
||||
});
|
||||
});
|
||||
}
|
||||
L.Poll.stop();
|
||||
|
||||
return L.view.extend({
|
||||
poll_status: function() {
|
||||
return fs.read(tools.token_file).then(v => {
|
||||
v = tools.normalize_value(v);
|
||||
if(v != status_token_value) {
|
||||
get_app_status().then(set_app_status);
|
||||
return tools.handleServiceAction(tools.appName, action).then(() => {
|
||||
return this.getAppStatus().then(
|
||||
(status_array) => {
|
||||
this.setAppStatus(status_array);
|
||||
}
|
||||
status_token_value = v;
|
||||
}).catch(e => {
|
||||
status_token_value = 0;
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
dialog_destroy: function(ev) {
|
||||
appAction: function(action, button) {
|
||||
if(button) {
|
||||
let elem = document.getElementById(button);
|
||||
this.disableButtons(true, elem);
|
||||
};
|
||||
|
||||
L.Poll.stop();
|
||||
|
||||
if(action === 'update') {
|
||||
this.getAppStatus().then(status_array => {
|
||||
this.setAppStatus(status_array, [], 4);
|
||||
});
|
||||
};
|
||||
|
||||
return fs.exec_direct(tools.execPath, [ action ]).then(res => {
|
||||
return this.getAppStatus().then(
|
||||
(status_array) => {
|
||||
this.setAppStatus(status_array);
|
||||
ui.hideModal();
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
statusPoll: function() {
|
||||
return fs.read(tools.tokenFile).then(v => {
|
||||
v = tools.normalizeValue(v);
|
||||
if(v != this.statusTokenValue) {
|
||||
this.getAppStatus().then(
|
||||
L.bind(this.setAppStatus, this)
|
||||
);
|
||||
}
|
||||
this.statusTokenValue = v;
|
||||
}).catch(e => {
|
||||
this.statusTokenValue = 0;
|
||||
});
|
||||
},
|
||||
|
||||
dialogDestroy: function(ev) {
|
||||
ev.target.blur();
|
||||
let cancel_button = E('button', {
|
||||
'class': btn_style_neutral,
|
||||
@@ -220,9 +225,9 @@ return L.view.extend({
|
||||
let shutdown_btn = E('button', {
|
||||
'class': btn_style_warning,
|
||||
}, _('Shutdown'));
|
||||
shutdown_btn.onclick = ui.createHandlerFn(this, function() {
|
||||
shutdown_btn.onclick = ui.createHandlerFn(this, () => {
|
||||
cancel_button.disabled = true;
|
||||
return button_action('destroy');
|
||||
return this.appAction('destroy');
|
||||
});
|
||||
|
||||
ui.showModal(_('Shutdown'), [
|
||||
@@ -238,7 +243,7 @@ return L.view.extend({
|
||||
},
|
||||
|
||||
load: function() {
|
||||
return get_app_status();
|
||||
return this.getAppStatus();
|
||||
},
|
||||
|
||||
render: function(status_array) {
|
||||
@@ -246,9 +251,11 @@ return L.view.extend({
|
||||
return;
|
||||
};
|
||||
|
||||
let section = uci.get(tools.app_name, 'config');
|
||||
let proxy_local_clients = (typeof(section) === 'object') ? section.proxy_local_clients : null;
|
||||
status_token_value = (Array.isArray(status_array)) ? tools.normalize_value(status_array[4]) : null;
|
||||
let section = uci.get(tools.appName, 'config');
|
||||
let proxy_local_clients = (typeof(section) === 'object') ?
|
||||
section.proxy_local_clients : null;
|
||||
this.statusTokenValue = (Array.isArray(status_array)) ?
|
||||
tools.normalizeValue(status_array[4]) : null;
|
||||
|
||||
let status_string = E('div', {
|
||||
'id' : 'status',
|
||||
@@ -278,14 +285,14 @@ return L.view.extend({
|
||||
let btn_enable = E('button', {
|
||||
'id' : 'btn_enable',
|
||||
'name' : 'btn_enable',
|
||||
'class': btn_style_save,
|
||||
'class': btn_style_positive,
|
||||
}, _('Enable'));
|
||||
layout_append(btn_enable, _('Run at startup'));
|
||||
|
||||
let btn_tp = E('button', {
|
||||
'id' : 'btn_tp',
|
||||
'name' : 'btn_tp',
|
||||
'class': btn_style_save,
|
||||
'class': btn_style_positive,
|
||||
}, _('Enable'));
|
||||
if(proxy_local_clients == '0') {
|
||||
layout_append(btn_tp, _('Total-proxy'),
|
||||
@@ -297,20 +304,20 @@ return L.view.extend({
|
||||
'name' : 'btn_update',
|
||||
'class': btn_style_action,
|
||||
}, _('Update'));
|
||||
btn_update.onclick = ui.createHandlerFn(this, () => { button_action('update') });
|
||||
btn_update.onclick = ui.createHandlerFn(this, () => { this.appAction('update', 'btn_update') });
|
||||
layout_append(btn_update, _('Update blacklist'));
|
||||
|
||||
let btn_destroy = E('button', {
|
||||
'id' : 'btn_destroy',
|
||||
'name' : 'btn_destroy',
|
||||
'class': btn_style_reset,
|
||||
'class': btn_style_negative,
|
||||
}, _('Shutdown'));
|
||||
btn_destroy.onclick = this.dialog_destroy;
|
||||
btn_destroy.onclick = L.bind(this.dialogDestroy, this);
|
||||
|
||||
layout_append(btn_destroy, _('Shutdown'),
|
||||
_('Complete service shutdown, as well as deleting ipsets and blacklist data'));
|
||||
|
||||
set_app_status(status_array, [
|
||||
this.setAppStatus(status_array, [
|
||||
status_string,
|
||||
btn_start,
|
||||
btn_enable,
|
||||
@@ -319,7 +326,7 @@ return L.view.extend({
|
||||
btn_destroy,
|
||||
]);
|
||||
|
||||
L.Poll.add(this.poll_status);
|
||||
L.Poll.add(L.bind(this.statusPoll, this));
|
||||
|
||||
return E([
|
||||
E('h2', { 'class': 'fade-in' }, _('Ruantiblock')),
|
||||
|
||||
@@ -6,26 +6,29 @@
|
||||
'require tools.widgets as widgets';
|
||||
'require view.ruantiblock.tools as tools';
|
||||
|
||||
let available_parsers = [];
|
||||
return L.view.extend({
|
||||
availableParsers: {},
|
||||
|
||||
function depends(elem, key, array, empty=true) {
|
||||
appStatusCode : null,
|
||||
|
||||
depends: function(elem, key, array, empty=true) {
|
||||
if(empty && array.length === 0) {
|
||||
elem.depends(key, '_dummy');
|
||||
} else {
|
||||
array.forEach(e => elem.depends(key, e));
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
function depends_bllist_module(elem) {
|
||||
depends(elem, 'bllist_module', available_parsers);
|
||||
};
|
||||
dependsBllistModule: function(elem) {
|
||||
this.depends(elem, 'bllist_module', Object.values(this.availableParsers));
|
||||
},
|
||||
|
||||
function validate_ip_port(section, value) {
|
||||
validateIpPort: function(section, value) {
|
||||
return (/^$|^([0-9]{1,3}\.){3}[0-9]{1,3}(#[\d]{2,5})?$/.test(value)) ? true : _('Expecting:')
|
||||
+ ` ${_('One of the following:')}\n - ${_('valid IP address')}\n - ${_('valid address#port')}\n`;
|
||||
};
|
||||
},
|
||||
|
||||
let CBIBlockTitle = form.DummyValue.extend({
|
||||
CBIBlockTitle: form.DummyValue.extend({
|
||||
string: null,
|
||||
|
||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
||||
@@ -37,54 +40,17 @@ let CBIBlockTitle = form.DummyValue.extend({
|
||||
),
|
||||
]);
|
||||
},
|
||||
});
|
||||
|
||||
let ip_filter_edit = new tools.file_edit_dialog(
|
||||
tools.ip_filter_file,
|
||||
_('IP filter'),
|
||||
_('Patterns can be strings or regular expressions. Each pattern in a separate line, the symbol <code>#</code> in the first position of the line - comments on the line.<br />Examples (dot is a special character):') + '<br /><code>128[.]199[.]0[.]0/16<br />34[.]217[.]90[.]52<br />162[.]13[.]190[.]</code>'
|
||||
);
|
||||
|
||||
let fqdn_filter_edit = new tools.file_edit_dialog(
|
||||
tools.fqdn_filter_file,
|
||||
_('FQDN filter'),
|
||||
_('Patterns can be strings or regular expressions. Each pattern in a separate line, the symbol <code>#</code> in the first position of the line - comments on the line.<br />Examples:') + '<br /><code>poker<br />[ck]?a[sz]ino?<br />[vw]ulkan<br />slots?</code>'
|
||||
);
|
||||
|
||||
let user_entries_edit = new tools.file_edit_dialog(
|
||||
tools.user_entries_file,
|
||||
_('User entries'),
|
||||
_('One entry (IP, CIDR or FQDN) per line. In the FQDN records, you can specify the DNS server for resolving this domain (separated by a space). You can also comment on lines (<code>#</code> is the first character of a line).<br />Examples:') + '<br /><code>#comment<br />domain.net<br />sub.domain.com 8.8.8.8<br />sub.domain.com 8.8.8.8#53<br />74.125.131.19<br />74.125.0.0/16</code>'
|
||||
);
|
||||
|
||||
let torrc_edit = new tools.file_edit_dialog(
|
||||
tools.torrc_file,
|
||||
_('Tor configuration file'),
|
||||
null,
|
||||
function(rc) {
|
||||
return fs.exec('/etc/init.d/tor', [ 'enabled' ]).then(res => {
|
||||
if(res.code === 0) {
|
||||
return fs.exec('/etc/init.d/tor', [ 'restart' ]);
|
||||
};
|
||||
}).catch(e => {
|
||||
ui.addNotification(null, E('p', _('Unable to execute or read contents')
|
||||
+ ': %s<br />[ %s ]'.format(e.message, '/etc/init.d/tor')));
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return L.view.extend({
|
||||
app_status_code: null,
|
||||
}),
|
||||
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
L.resolveDefault(fs.exec(tools.exec_path, [ 'raw-status' ]), 1),
|
||||
fs.list(tools.parsers_dir),
|
||||
L.resolveDefault(fs.exec(tools.execPath, [ 'raw-status' ]), 1),
|
||||
fs.list(tools.parsersDir),
|
||||
uci.load('network'),
|
||||
]).catch(e => {
|
||||
ui.addNotification(null, E('p', _('Unable to read the contents')
|
||||
+ ': %s<br />[ %s ]'.format(
|
||||
e.message, tools.parsers_dir
|
||||
+ ': %s [ %s ]'.format(
|
||||
e.message, tools.parsersDir
|
||||
)));
|
||||
});
|
||||
},
|
||||
@@ -93,7 +59,7 @@ return L.view.extend({
|
||||
if(!data) {
|
||||
return;
|
||||
};
|
||||
this.app_status_code = data[0].code;
|
||||
this.appStatusCode = data[0].code;
|
||||
let p_dir_arr = data[1];
|
||||
let lan_iface = uci.get('network', 'lan', 'ifname') || 'eth0';
|
||||
let vpn_iface = uci.get('network', 'VPN', 'ifname') || 'tun0';
|
||||
@@ -102,14 +68,48 @@ return L.view.extend({
|
||||
p_dir_arr.forEach(e => {
|
||||
let fname = e.name;
|
||||
if(fname.startsWith('ruab_parser')) {
|
||||
available_parsers.push(tools.parsers_dir + '/' + fname);
|
||||
this.availableParsers[fname] = tools.parsersDir + '/' + fname;
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
let ip_filter_edit = new tools.fileEditDialog(
|
||||
tools.ipFilterFile,
|
||||
_('IP filter'),
|
||||
_('Patterns can be strings or regular expressions. Each pattern in a separate line, the symbol <code>#</code> in the first position of the line - comments on the line.<br />Examples (dot is a special character):') +
|
||||
'<br /><code>128[.]199[.]0[.]0/16<br />34[.]217[.]90[.]52<br />162[.]13[.]190[.]</code>'
|
||||
);
|
||||
|
||||
let fqdn_filter_edit = new tools.fileEditDialog(
|
||||
tools.fqdnFilterFile,
|
||||
_('FQDN filter'),
|
||||
_('Patterns can be strings or regular expressions. Each pattern in a separate line, the symbol <code>#</code> in the first position of the line - comments on the line.<br />Examples:') +
|
||||
'<br /><code>poker<br />[ck]?a[sz]ino?<br />[vw]ulkan<br />slots?</code>'
|
||||
);
|
||||
|
||||
let user_entries_edit = new tools.fileEditDialog(
|
||||
tools.userEntriesFile,
|
||||
_('User entries'),
|
||||
_('One entry (IP, CIDR or FQDN) per line. In the FQDN records, you can specify the DNS server for resolving this domain (separated by a space). You can also comment on lines (<code>#</code> is the first character of a line).<br />Examples:') +
|
||||
'<br /><code>#comment<br />domain.net<br />sub.domain.com 8.8.8.8<br />sub.domain.com 8.8.8.8#53<br />74.125.131.19<br />74.125.0.0/16</code>'
|
||||
);
|
||||
|
||||
let torrc_edit = new tools.fileEditDialog(
|
||||
tools.torrcFile,
|
||||
_('Tor configuration file'),
|
||||
null,
|
||||
function(rc) {
|
||||
return tools.getInitStatus('tor').then(res => {
|
||||
if(res) {
|
||||
return tools.handleServiceAction('tor', 'restart');
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
let m, s, o;
|
||||
|
||||
m = new form.Map(tools.app_name, _('Ruantiblock') + ' - ' + _('Settings'));
|
||||
m = new form.Map(tools.appName, _('Ruantiblock') + ' - ' + _('Settings'));
|
||||
|
||||
s = m.section(form.NamedSection, 'config');
|
||||
s.anonymous = true;
|
||||
@@ -120,7 +120,7 @@ return L.view.extend({
|
||||
s.tab('main_settings', _('Main settings'));
|
||||
|
||||
// PROXY_MODE
|
||||
if(this.app_status_code == 1 || this.app_status_code == 2) {
|
||||
if(this.appStatusCode == 1 || this.appStatusCode == 2) {
|
||||
o = s.taboption('main_settings', form.ListValue, 'proxy_mode',
|
||||
_('Proxy mode'));
|
||||
o.value('1', 'Tor');
|
||||
@@ -131,13 +131,11 @@ return L.view.extend({
|
||||
let proxy_local_clients = s.taboption('main_settings', form.Flag, 'proxy_local_clients',
|
||||
_("Apply proxy rules to router application traffic"));
|
||||
proxy_local_clients.rmempty = false;
|
||||
proxy_local_clients.default = proxy_local_clients.enabled;
|
||||
|
||||
// USE_LOGGER
|
||||
o = s.taboption('main_settings', form.Flag, 'use_logger',
|
||||
_('Logging events'));
|
||||
o.rmempty = false;
|
||||
o.default = 1;
|
||||
|
||||
// DEF_TOTAL_PROXY
|
||||
o = s.taboption('main_settings', form.Flag, 'def_total_proxy',
|
||||
@@ -151,10 +149,9 @@ return L.view.extend({
|
||||
_('Clean up ipsets before updating blacklist'));
|
||||
o.description = _('Reduces RAM consumption during update');
|
||||
o.rmempty = false;
|
||||
o.default = 0;
|
||||
|
||||
|
||||
if(this.app_status_code == 1 || this.app_status_code == 2) {
|
||||
if(this.appStatusCode == 1 || this.appStatusCode == 2) {
|
||||
/* Tor tab */
|
||||
|
||||
s.tab('tor_settings', _('Tor mode'));
|
||||
@@ -172,14 +169,12 @@ return L.view.extend({
|
||||
_('Transparent proxy port for iptables rules'));
|
||||
o.rmempty = false;
|
||||
o.datatype = "port";
|
||||
o.default = '9040';
|
||||
|
||||
// ONION_DNS_ADDR
|
||||
o = s.taboption('tor_settings', form.Value, 'onion_dns_addr',
|
||||
_("Optional DNS resolver for '.onion' zone"), '<code>ipaddress#port</code>');
|
||||
o.rmempty = false;
|
||||
o.default = '127.0.0.1#9053';
|
||||
o.validate = validate_ip_port;
|
||||
o.validate = this.validateIpPort;
|
||||
|
||||
// Torrc edit dialog
|
||||
o = s.taboption('tor_settings', form.Button, '_torrc_btn',
|
||||
@@ -210,126 +205,97 @@ return L.view.extend({
|
||||
// BLLIST_MODULE
|
||||
let bllist_module = s.taboption('parser_settings', form.ListValue,
|
||||
'bllist_module', _('Blacklist module'));
|
||||
bllist_module.value("", _("user entries only"));
|
||||
available_parsers.forEach(e => bllist_module.value(e));
|
||||
bllist_module.value('', _('none (user entries only)'));
|
||||
Object.entries(this.availableParsers).forEach(
|
||||
e => bllist_module.value(e[1], e[0]));
|
||||
|
||||
// BLLIST_MODE
|
||||
let bllist_mode = s.taboption('parser_settings', form.ListValue,
|
||||
'bllist_mode', _('Module operation mode'));
|
||||
bllist_mode.value('ip');
|
||||
bllist_mode.value('fqdn');
|
||||
depends_bllist_module(bllist_mode);
|
||||
|
||||
// BLLIST_SOURCE
|
||||
let bllist_source = s.taboption('parser_settings', form.ListValue,
|
||||
'bllist_source', _('Blacklist source'));
|
||||
bllist_source.description = _("Options") + ':';
|
||||
for(let [k, v] of Object.entries(tools.blacklist_sources)) {
|
||||
for(let [k, v] of Object.entries(tools.blacklistSources)) {
|
||||
bllist_source.value(k);
|
||||
bllist_source.description += `<br />${k} - <a href="${v}" target="_blank">${v}</a>`;
|
||||
};
|
||||
depends_bllist_module(bllist_source);
|
||||
|
||||
o = s.taboption('parser_settings', CBIBlockTitle, '_dummy_ip');
|
||||
o = s.taboption('parser_settings', this.CBIBlockTitle, '_dummy_ip');
|
||||
o.string = _('IP configuration') + ':';
|
||||
depends_bllist_module(o);
|
||||
|
||||
// IP_LIMIT
|
||||
o = s.taboption('parser_settings', form.Value, 'ip_limit', _("IP limit"));
|
||||
o.description = _("The number of IP addresses in the subnet, upon reaching which the entire '/24' subnet is added to the list");
|
||||
o.rmempty = false;
|
||||
o.datatype = 'uinteger';
|
||||
o.default = '0';
|
||||
depends_bllist_module(o);
|
||||
|
||||
// OPT_EXCLUDE_NETS
|
||||
o = s.taboption('parser_settings', form.DynamicList, 'opt_exclude_nets');
|
||||
o.title = _('IP subnet patterns (/24) that are excluded from optimization');
|
||||
o.description = _('e.g:') + ' <code>192.168.1.</code>';
|
||||
o.placeholder = _('e.g:') + ' 192.168.1.';
|
||||
o.default = '';
|
||||
|
||||
depends_bllist_module(o);
|
||||
o.validate = (section, value) => {
|
||||
return (/^$|^([0-9]{1,3}[.]){3}$/.test(value)) ? true : _('Expecting:')
|
||||
+ ' ' + _('net pattern') + ' (' + _('e.g:') + ' 192.168.3.)\n';
|
||||
};
|
||||
|
||||
// SUMMARIZE_IP
|
||||
o = s.taboption('parser_settings', form.Flag, 'summarize_ip',
|
||||
_("Summarize IP ranges"));
|
||||
o.rmempty = false;
|
||||
o.default = 0;
|
||||
depends_bllist_module(o);
|
||||
|
||||
// SUMMARIZE_CIDR
|
||||
o = s.taboption('parser_settings', form.Flag, 'summarize_cidr',
|
||||
_("Summarize '/24' networks"));
|
||||
o.rmempty = false;
|
||||
o.default = 0;
|
||||
depends_bllist_module(o);
|
||||
|
||||
o = s.taboption('parser_settings', CBIBlockTitle, '_dummy_fqdn');
|
||||
o = s.taboption('parser_settings', this.CBIBlockTitle, '_dummy_fqdn');
|
||||
o.string = _('FQDN configuration') + ':';
|
||||
depends_bllist_module(o);
|
||||
|
||||
// SD_LIMIT
|
||||
o = s.taboption('parser_settings', form.Value, 'sd_limit',
|
||||
_("Subdomains limit"));
|
||||
o.description = _('The number of subdomains in the domain, upon reaching which the entire 2nd level domain is added to the list');
|
||||
o.rmempty = false;
|
||||
o.datatype = 'uinteger';
|
||||
o.default = '16';
|
||||
depends_bllist_module(o);
|
||||
|
||||
// OPT_EXCLUDE_SLD
|
||||
o = s.taboption('parser_settings', form.DynamicList, 'opt_exclude_sld',
|
||||
_('2nd level domains that are excluded from optimization'));
|
||||
o.description = _('e.g:') + ' <code>livejournal.com</code>';
|
||||
o.placeholder = _('e.g:') + ' livejournal.com';
|
||||
o.datatype = "hostname";
|
||||
o.default = [
|
||||
'livejournal.com',
|
||||
'facebook.com',
|
||||
'vk.com',
|
||||
'blog.jp',
|
||||
'msk.ru',
|
||||
'net.ru',
|
||||
'org.ru',
|
||||
'net.ua',
|
||||
'com.ua',
|
||||
'org.ua',
|
||||
'co.uk',
|
||||
'amazonaws.com',
|
||||
];
|
||||
depends_bllist_module(o);
|
||||
|
||||
// USE_IDN
|
||||
o = s.taboption('parser_settings', form.Flag, 'use_idn',
|
||||
_("Convert cyrillic domains to punycode"));
|
||||
o.rmempty = false;
|
||||
o.default = 0;
|
||||
depends_bllist_module(o);
|
||||
|
||||
// ALT_NSLOOKUP
|
||||
o = s.taboption('parser_settings', form.Flag, 'alt_nslookup',
|
||||
_('Use optional DNS resolver'));
|
||||
o.rmempty = false;
|
||||
o.default = 0;
|
||||
depends_bllist_module(o);
|
||||
|
||||
// ALT_DNS_ADDR
|
||||
o = s.taboption('parser_settings', form.Value, 'alt_dns_addr',
|
||||
_("Optional DNS resolver"), '<code>ipaddress[#port]</code>');
|
||||
o.rmempty = false;
|
||||
o.depends('alt_nslookup', '1');
|
||||
o.validate = validate_ip_port;
|
||||
o.default = '8.8.8.8';
|
||||
o.validate = this.validateIpPort;
|
||||
|
||||
|
||||
/* Entries filters tab */
|
||||
/* Blacklist entry filters tab */
|
||||
|
||||
s.tab('entries_filter_tab', _('Entries filters'));
|
||||
s.tab('entries_filter_tab', _('Blacklist entry filters'));
|
||||
|
||||
// IP_FILTER
|
||||
o = s.taboption('entries_filter_tab', form.Flag, 'ip_filter',
|
||||
_("Enable IP filter"));
|
||||
o.description = _('Exclude IP addresses from blacklist by IP filter patterns');
|
||||
o.rmempty = false;
|
||||
o.default = 0;
|
||||
depends_bllist_module(o);
|
||||
|
||||
// IP_FILTER edit dialog
|
||||
o = s.taboption('entries_filter_tab', form.Button, '_ip_filter_btn',
|
||||
@@ -337,15 +303,12 @@ return L.view.extend({
|
||||
o.onclick = () => ip_filter_edit.show();
|
||||
o.inputtitle = _('Edit');
|
||||
o.inputstyle = 'edit btn';
|
||||
depends_bllist_module(o);
|
||||
|
||||
// FQDN_FILTER
|
||||
o = s.taboption('entries_filter_tab', form.Flag, 'fqdn_filter',
|
||||
_("Enable FQDN filter"));
|
||||
o.description = _('Exclude domains from blacklist by FQDN filter patterns');
|
||||
o.rmempty = false;
|
||||
o.default = 0;
|
||||
depends_bllist_module(o);
|
||||
|
||||
// FQDN_FILTER edit dialog
|
||||
o = s.taboption('entries_filter_tab', form.Button, '_fqdn_filter_btn',
|
||||
@@ -353,7 +316,6 @@ return L.view.extend({
|
||||
o.onclick = () => fqdn_filter_edit.show();
|
||||
o.inputtitle = _('Edit');
|
||||
o.inputstyle = 'edit btn';
|
||||
depends_bllist_module(o);
|
||||
|
||||
|
||||
/* User entries tab */
|
||||
@@ -365,12 +327,12 @@ return L.view.extend({
|
||||
_('Enable'), _("Add user entries to the blacklist when updating"));
|
||||
o.rmempty = false;
|
||||
o.default = 0;
|
||||
depends_bllist_module(o);
|
||||
this.dependsBllistModule(o);
|
||||
|
||||
// USER_ENTRIES_DNS
|
||||
o = s.taboption('user_entries_tab', form.Value, 'user_entries_dns',
|
||||
_("DNS server that is used for FQDN entries"), '<code>ipaddress[#port]</code>');
|
||||
o.validate = validate_ip_port;
|
||||
o.validate = this.validateIpPort;
|
||||
|
||||
// USER_ENTRIES edit dialog
|
||||
o = s.taboption('user_entries_tab', form.Button, '_user_entries_btn',
|
||||
@@ -379,10 +341,8 @@ return L.view.extend({
|
||||
o.inputtitle = _('Edit');
|
||||
o.inputstyle = 'edit btn';
|
||||
|
||||
|
||||
let map_promise = m.render();
|
||||
map_promise.then(node => node.classList.add('fade-in'));
|
||||
|
||||
return map_promise;
|
||||
},
|
||||
|
||||
@@ -390,8 +350,9 @@ return L.view.extend({
|
||||
return this.handleSave(ev).then(() => {
|
||||
ui.changes.apply(mode == '0');
|
||||
|
||||
if(this.app_status_code != 1 && this.app_status_code != 2) {
|
||||
window.setTimeout(() => fs.exec(tools.init_path, [ 'restart' ]), 3000);
|
||||
if(this.appStatusCode != 1 && this.appStatusCode != 2) {
|
||||
window.setTimeout(() => tools.handleServiceAction(
|
||||
tools.appName, 'restart'), 3000);
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use strict';
|
||||
'require fs';
|
||||
'require rpc';
|
||||
'require ui';
|
||||
|
||||
document.head.append(E('style', {'type': 'text/css'},
|
||||
@@ -35,33 +36,71 @@ document.head.append(E('style', {'type': 'text/css'},
|
||||
`));
|
||||
|
||||
return L.Class.extend({
|
||||
app_name: 'ruantiblock',
|
||||
exec_path: '/usr/bin/ruantiblock',
|
||||
init_path: '/etc/init.d/ruantiblock',
|
||||
token_file: '/var/run/ruantiblock.token',
|
||||
parsers_dir: '/usr/bin',
|
||||
torrc_file: '/etc/tor/torrc',
|
||||
user_entries_file: '/etc/ruantiblock/user_entries',
|
||||
fqdn_filter_file: '/etc/ruantiblock/fqdn_filter',
|
||||
ip_filter_file: '/etc/ruantiblock/ip_filter',
|
||||
crontab_file: '/etc/crontabs/root',
|
||||
info_label_starting: '<span class="label-status starting">' + _('Starting') + '</span>',
|
||||
info_label_running: '<span class="label-status running">' + _('Enabled') + '</span>',
|
||||
info_label_updating: '<span class="label-status updating">' + _('Updating') + '</span>',
|
||||
info_label_stopped: '<span class="label-status stopped">' + _('Disabled') + '</span>',
|
||||
info_label_error: '<span class="label-status error">' + _('Error') + '</span>',
|
||||
appName : 'ruantiblock',
|
||||
execPath : '/usr/bin/ruantiblock',
|
||||
tokenFile : '/var/run/ruantiblock.token',
|
||||
parsersDir : '/usr/bin',
|
||||
torrcFile : '/etc/tor/torrc',
|
||||
userEntriesFile : '/etc/ruantiblock/user_entries',
|
||||
fqdnFilterFile : '/etc/ruantiblock/fqdn_filter',
|
||||
ipFilterFile : '/etc/ruantiblock/ip_filter',
|
||||
crontabFile : '/etc/crontabs/root',
|
||||
infoLabelStarting: '<span class="label-status starting">' + _('Starting') + '</span>',
|
||||
infoLabelRunning : '<span class="label-status running">' + _('Enabled') + '</span>',
|
||||
infoLabelUpdating: '<span class="label-status updating">' + _('Updating') + '</span>',
|
||||
infoLabelStopped : '<span class="label-status stopped">' + _('Disabled') + '</span>',
|
||||
infoLabelError : '<span class="label-status error">' + _('Error') + '</span>',
|
||||
|
||||
blacklist_sources: {
|
||||
blacklistSources: {
|
||||
'rublacklist': 'https://rublacklist.net',
|
||||
'zapret-info': 'https://github.com/zapret-info/z-i',
|
||||
'antifilter' : 'https://antifilter.download',
|
||||
},
|
||||
|
||||
normalize_value: function(v) {
|
||||
callInitStatus: rpc.declare({
|
||||
object: 'luci',
|
||||
method: 'getInitList',
|
||||
params: [ 'name' ],
|
||||
expect: { '': {} }
|
||||
}),
|
||||
|
||||
callInitAction: rpc.declare({
|
||||
object: 'luci',
|
||||
method: 'setInitAction',
|
||||
params: [ 'name', 'action' ],
|
||||
expect: { result: false }
|
||||
}),
|
||||
|
||||
getInitStatus: function(name) {
|
||||
return this.callInitStatus(name).then(res => {
|
||||
if(res) {
|
||||
return res[name].enabled;
|
||||
} else {
|
||||
throw _('Command failed');
|
||||
}
|
||||
}).catch(e => {
|
||||
ui.addNotification(null,
|
||||
E('p', _('Failed to get %s init status: %s').format(name, e)));
|
||||
});
|
||||
},
|
||||
|
||||
handleServiceAction: function(name, action) {
|
||||
return this.callInitAction(name, action).then(success => {
|
||||
if(!success) {
|
||||
throw _('Command failed');
|
||||
};
|
||||
return true;
|
||||
}).catch(e => {
|
||||
ui.addNotification(null,
|
||||
E('p', _('Service action failed "%s %s": %s').format(name, action, e)));
|
||||
});
|
||||
},
|
||||
|
||||
normalizeValue: function(v) {
|
||||
return (v && typeof(v) === 'string') ? v.trim().replace(/\r?\n/g, '') : v;
|
||||
},
|
||||
|
||||
make_status_string: function(
|
||||
makeStatusString: function(
|
||||
app_status_code,
|
||||
proxy_mode,
|
||||
bllist_mode,
|
||||
@@ -74,21 +113,21 @@ return L.Class.extend({
|
||||
|
||||
switch(app_status_code) {
|
||||
case 0:
|
||||
app_status_label = this.info_label_running;
|
||||
app_status_label = this.infoLabelRunning;
|
||||
break;
|
||||
case 2:
|
||||
app_status_label = this.info_label_stopped;
|
||||
app_status_label = this.infoLabelStopped;
|
||||
break;
|
||||
case 3:
|
||||
app_status_label = this.info_label_starting;
|
||||
app_status_label = this.infoLabelStarting;
|
||||
spinning = ' spinning';
|
||||
break;
|
||||
case 4:
|
||||
app_status_label = this.info_label_updating;
|
||||
app_status_label = this.infoLabelUpdating;
|
||||
spinning = ' spinning';
|
||||
break;
|
||||
default:
|
||||
app_status_label = this.info_label_error;
|
||||
app_status_label = this.infoLabelError;
|
||||
return `<div class="table">
|
||||
<div class="tr">
|
||||
<div class="td left" style="min-width:33%%">
|
||||
@@ -144,7 +183,7 @@ return L.Class.extend({
|
||||
${_('Blacklist source')}:
|
||||
</div>
|
||||
<div class="td left">
|
||||
<span style="cursor:help; border-bottom:1px dotted" data-tooltip="${this.blacklist_sources[bllist_source]}">
|
||||
<span style="cursor:help; border-bottom:1px dotted" data-tooltip="${this.blacklistSources[bllist_source]}">
|
||||
${bllist_source}
|
||||
</span>
|
||||
</div>
|
||||
@@ -152,7 +191,7 @@ return L.Class.extend({
|
||||
);
|
||||
},
|
||||
|
||||
file_edit_dialog: L.Class.extend({
|
||||
fileEditDialog: L.Class.extend({
|
||||
__init__: function(file, title, description, callback, file_exists=false) {
|
||||
this.file = file;
|
||||
this.title = title;
|
||||
|
||||
@@ -19,6 +19,12 @@ msgstr "Домены 2-го уровня не подлежащие оптими
|
||||
msgid "Add user entries to the blacklist when updating"
|
||||
msgstr "Добавлять записи пользователя в блэклист при обновлении"
|
||||
|
||||
msgid "Alert"
|
||||
msgstr "Тревога"
|
||||
|
||||
msgid "All"
|
||||
msgstr "Все"
|
||||
|
||||
msgid "All traffic goes through the proxy without applying rules"
|
||||
msgstr "Весь трафик отправляется в прокси, без применения правил"
|
||||
|
||||
@@ -28,6 +34,9 @@ msgstr "Применить"
|
||||
msgid "Apply proxy rules to router application traffic"
|
||||
msgstr "Применять правила прокси к трафику приложений роутера"
|
||||
|
||||
msgid "Blacklist entry filters"
|
||||
msgstr "Фильтры записей блэклиста"
|
||||
|
||||
msgid "Blacklist module"
|
||||
msgstr "Модуль блэклиста"
|
||||
|
||||
@@ -55,10 +64,12 @@ msgstr "Изменения сохранены."
|
||||
msgid "Clean up ipsets before updating blacklist"
|
||||
msgstr "Очищать ipset'ы перед обновлением блэклиста"
|
||||
|
||||
msgid "Command failed"
|
||||
msgstr "Команда не выполнена"
|
||||
|
||||
msgid ""
|
||||
"Complete service shutdown, as well as deleting ipsets and blacklist data"
|
||||
msgstr ""
|
||||
"Полное выключение службы, а также удаление ipset'ов и данных блэклиста"
|
||||
msgstr "Полное выключение службы, а также удаление ipset'ов и данных блэклиста"
|
||||
|
||||
msgid "Contents have been saved."
|
||||
msgstr "Содержимое сохранено."
|
||||
@@ -66,6 +77,9 @@ msgstr "Содержимое сохранено."
|
||||
msgid "Convert cyrillic domains to punycode"
|
||||
msgstr "Конвертировать кириллические домены в punycode"
|
||||
|
||||
msgid "Critical"
|
||||
msgstr "Критическая ситуация"
|
||||
|
||||
msgid "Current schedule"
|
||||
msgstr "Текущее расписание"
|
||||
|
||||
@@ -75,18 +89,27 @@ msgstr "DNS сервер для FQDN записей"
|
||||
msgid "Day"
|
||||
msgstr "День"
|
||||
|
||||
msgid "Disable"
|
||||
msgstr "Отключить"
|
||||
msgid "Debug"
|
||||
msgstr "Отладка"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "Отключено"
|
||||
|
||||
msgid "Dismiss"
|
||||
msgstr "Закрыть"
|
||||
msgstr "Отмена"
|
||||
|
||||
msgid "Download error"
|
||||
msgstr "Ошибка загрузки"
|
||||
|
||||
msgid "Download log"
|
||||
msgstr "Скачать лог"
|
||||
|
||||
msgid "Edit"
|
||||
msgstr "Изменить"
|
||||
|
||||
msgid "Emergency"
|
||||
msgstr "Чрезвычайная ситуация"
|
||||
|
||||
msgid "Enable"
|
||||
msgstr "Включить"
|
||||
|
||||
@@ -102,18 +125,18 @@ msgstr "Включать 'total-proxy' при старте"
|
||||
msgid "Enabled"
|
||||
msgstr "Включено"
|
||||
|
||||
msgid "Entries filters"
|
||||
msgstr "Фильтры записей"
|
||||
msgid "Entries"
|
||||
msgstr "Записи"
|
||||
|
||||
msgid "Error"
|
||||
msgstr "Ошибка"
|
||||
|
||||
msgid "Exclude domains from blacklist by FQDN filter patterns"
|
||||
msgstr "Исключение доменов из блэклиста по шаблонам фильтра FQDN"
|
||||
|
||||
msgid "Exclude IP addresses from blacklist by IP filter patterns"
|
||||
msgstr "Исключение IP адресов из блэклиста по шаблонам фильтра IP"
|
||||
|
||||
msgid "Exclude domains from blacklist by FQDN filter patterns"
|
||||
msgstr "Исключение доменов из блэклиста по шаблонам фильтра FQDN"
|
||||
|
||||
msgid "Expecting:"
|
||||
msgstr "Ожидается:"
|
||||
|
||||
@@ -123,12 +146,24 @@ msgstr "Конфигурация FQDN"
|
||||
msgid "FQDN filter"
|
||||
msgstr "Фильтр FQDN"
|
||||
|
||||
msgid "Facility"
|
||||
msgstr "Категория"
|
||||
|
||||
msgid "Failed to get %s init status: %s"
|
||||
msgstr "Не удалось получить статус инициализации %s: %s"
|
||||
|
||||
msgid "HTML/XML error"
|
||||
msgstr "Ошибка HTML/XML"
|
||||
|
||||
msgid "Host"
|
||||
msgstr "Хост"
|
||||
|
||||
msgid "Hosts"
|
||||
msgstr "Хосты"
|
||||
|
||||
msgid "Hour"
|
||||
msgstr "Час"
|
||||
|
||||
msgid "Interval"
|
||||
msgstr "Интервал"
|
||||
|
||||
msgid "IP configuration"
|
||||
msgstr "Конфигурация IP"
|
||||
|
||||
@@ -141,6 +176,15 @@ msgstr "Лимит IP адресов"
|
||||
msgid "IP subnet patterns (/24) that are excluded from optimization"
|
||||
msgstr "Шаблоны IP подсетей (/24) не подлежащих оптимизации"
|
||||
|
||||
msgid "Info"
|
||||
msgstr "Информация"
|
||||
|
||||
msgid "Interval"
|
||||
msgstr "Интервал"
|
||||
|
||||
msgid "Invalid regular expression"
|
||||
msgstr "Неправильное регулярное выражение"
|
||||
|
||||
msgid "Ipset"
|
||||
msgstr "Ipset"
|
||||
|
||||
@@ -153,6 +197,12 @@ msgstr "LAN интерфейс"
|
||||
msgid "Last blacklist update"
|
||||
msgstr "Последнее обновление блэклиста"
|
||||
|
||||
msgid "Last entries"
|
||||
msgstr "Последние записи"
|
||||
|
||||
msgid "Level"
|
||||
msgstr "Уровень"
|
||||
|
||||
msgid "Loading"
|
||||
msgstr "Загрузка"
|
||||
|
||||
@@ -162,12 +212,21 @@ msgstr "Лог"
|
||||
msgid "Logging events"
|
||||
msgstr "Записывать события в лог"
|
||||
|
||||
msgid "Logging levels"
|
||||
msgstr "Уровни логирования"
|
||||
|
||||
msgid "Main settings"
|
||||
msgstr "Основные настройки"
|
||||
|
||||
msgid "Match-set"
|
||||
msgstr "Правило"
|
||||
|
||||
msgid "Message"
|
||||
msgstr "Сообщение"
|
||||
|
||||
msgid "Message filter"
|
||||
msgstr "Фильтр сообщений"
|
||||
|
||||
msgid "Minute"
|
||||
msgstr "Минута"
|
||||
|
||||
@@ -177,14 +236,20 @@ msgstr "Режим работы модуля"
|
||||
msgid "Name"
|
||||
msgstr "Имя"
|
||||
|
||||
msgid "No Shedule"
|
||||
msgstr "Нет расписания"
|
||||
|
||||
msgid "No changes to save."
|
||||
msgstr "Нет изменений для сохранения."
|
||||
|
||||
msgid "No data"
|
||||
msgstr "Нет данных"
|
||||
|
||||
msgid "No Shedule"
|
||||
msgstr "Нет расписания"
|
||||
msgid "No entries available..."
|
||||
msgstr "Нет доступных записей..."
|
||||
|
||||
msgid "Notice"
|
||||
msgstr "Сообщение"
|
||||
|
||||
msgid "Number of entries"
|
||||
msgstr "Кол-во записей"
|
||||
@@ -202,15 +267,12 @@ msgstr ""
|
||||
msgid "One of the following:"
|
||||
msgstr "Одно из следующих значений:"
|
||||
|
||||
msgid "Only messages that include the specified string will be displayed"
|
||||
msgstr "Будут показаны только сообщения включающие указанную строку"
|
||||
msgid "Optional DNS resolver"
|
||||
msgstr "Альтернативный DNS резолвер"
|
||||
|
||||
msgid "Optional DNS resolver for '.onion' zone"
|
||||
msgstr "Дополнительный DNS резолвер для '.onion' зоны"
|
||||
|
||||
msgid "Optional DNS resolver"
|
||||
msgstr "Альтернативный DNS резолвер"
|
||||
|
||||
msgid "Options"
|
||||
msgstr "Опции"
|
||||
|
||||
@@ -238,15 +300,27 @@ msgstr "Режим прокси"
|
||||
msgid "Reduces RAM consumption during update"
|
||||
msgstr "Уменьшает потребление оперативной памяти при обновлении"
|
||||
|
||||
msgid "Refresh log"
|
||||
msgstr "Обновить лог"
|
||||
|
||||
msgid "Reset"
|
||||
msgstr "Сбросить"
|
||||
|
||||
msgid "Ruantiblock"
|
||||
msgstr "Ruantiblock"
|
||||
|
||||
msgid "Run at startup"
|
||||
msgstr "Запуск при старте системы"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Сохранить"
|
||||
|
||||
msgid "Service"
|
||||
msgstr "Служба"
|
||||
|
||||
msgid "Service action failed \"%s %s\": %s"
|
||||
msgstr "Не удалось выполнить действие службы \"%s %s\": %s"
|
||||
|
||||
msgid "Set"
|
||||
msgstr "Установить"
|
||||
|
||||
@@ -259,6 +333,9 @@ msgstr "Выключение"
|
||||
msgid "Size in memory"
|
||||
msgstr "Размер в памяти"
|
||||
|
||||
msgid "Sorting entries"
|
||||
msgstr "Сортировка записей"
|
||||
|
||||
msgid "Starting"
|
||||
msgstr "Запускается"
|
||||
|
||||
@@ -300,21 +377,33 @@ msgstr ""
|
||||
msgid "Time"
|
||||
msgstr "Время"
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr "Время"
|
||||
|
||||
msgid "Tor configuration file"
|
||||
msgstr "Конфигурационный файл Tor"
|
||||
|
||||
msgid "Tor mode"
|
||||
msgstr "Режим Tor"
|
||||
|
||||
msgid "Total-proxy"
|
||||
msgstr "Total-proxy"
|
||||
|
||||
msgid "Total-proxy is on"
|
||||
msgstr "Total-proxy включен"
|
||||
|
||||
msgid "Transparent proxy port for iptables rules"
|
||||
msgstr "Порт прозрачного прокси для правил iptables"
|
||||
|
||||
msgid "Type an expression..."
|
||||
msgstr "Введите выражение..."
|
||||
|
||||
msgid "Unable to execute or read contents"
|
||||
msgstr "Невозможно выполнить или прочитать содержимое"
|
||||
|
||||
msgid "Unable to load log data:"
|
||||
msgstr "Невозможно загрузить данные лога:"
|
||||
|
||||
msgid "Unable to read the contents"
|
||||
msgstr "Невозможно прочитать содержимое"
|
||||
|
||||
@@ -348,9 +437,27 @@ msgstr "Режим VPN"
|
||||
msgid "VPN routing error! Need restart"
|
||||
msgstr "Ошибка маршрутизации VPN! Необходим перезапуск"
|
||||
|
||||
msgid "Warning"
|
||||
msgstr "Внимание"
|
||||
|
||||
msgid "ascending"
|
||||
msgstr "по возрастанию"
|
||||
|
||||
msgid "descending"
|
||||
msgstr "по убыванию"
|
||||
|
||||
msgid "disabled"
|
||||
msgstr "отключен"
|
||||
|
||||
msgid "e.g:"
|
||||
msgstr "прим:"
|
||||
|
||||
msgid "net pattern"
|
||||
msgstr "шаблон сети"
|
||||
|
||||
msgid "none (user entries only)"
|
||||
msgstr "нет (только записи пользователя)"
|
||||
|
||||
msgid "user entries only"
|
||||
msgstr "только записи пользователя"
|
||||
|
||||
@@ -359,86 +466,3 @@ msgstr "верный IP-адрес"
|
||||
|
||||
msgid "valid address#port"
|
||||
msgstr "верный IP-адрес#порт"
|
||||
|
||||
|
||||
|
||||
msgid "Alert"
|
||||
msgstr "Тревога"
|
||||
|
||||
msgid "All"
|
||||
msgstr "Все"
|
||||
|
||||
msgid "Critical"
|
||||
msgstr "Критическая ситуация"
|
||||
|
||||
msgid "Debug"
|
||||
msgstr "Отладка"
|
||||
|
||||
msgid "Download log"
|
||||
msgstr "Скачать лог"
|
||||
|
||||
msgid "Emergency"
|
||||
msgstr "Чрезвычайная ситуация"
|
||||
|
||||
msgid "Entries"
|
||||
msgstr "Записи"
|
||||
|
||||
msgid "Facility"
|
||||
msgstr "Категория"
|
||||
|
||||
msgid "Host"
|
||||
msgstr "Хост"
|
||||
|
||||
msgid "Hosts"
|
||||
msgstr "Хосты"
|
||||
|
||||
msgid "Info"
|
||||
msgstr "Информация"
|
||||
|
||||
msgid "Invalid regular expression"
|
||||
msgstr "Неправильное регулярное выражение"
|
||||
|
||||
msgid "Last entries"
|
||||
msgstr "Последние записи"
|
||||
|
||||
msgid "Level"
|
||||
msgstr "Уровень"
|
||||
|
||||
msgid "Logging levels"
|
||||
msgstr "Уровни логирования"
|
||||
|
||||
msgid "Message"
|
||||
msgstr "Сообщение"
|
||||
|
||||
msgid "Message filter"
|
||||
msgstr "Фильтр сообщений"
|
||||
|
||||
msgid "No entries available..."
|
||||
msgstr "Нет доступных записей..."
|
||||
|
||||
msgid "Notice"
|
||||
msgstr "Сообщение"
|
||||
|
||||
msgid "Refresh log"
|
||||
msgstr "Обновить лог"
|
||||
|
||||
msgid "Sorting entries"
|
||||
msgstr "Сортировка записей"
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr "Время"
|
||||
|
||||
msgid "Type an expression..."
|
||||
msgstr "Введите выражение..."
|
||||
|
||||
msgid "Unable to load log data:"
|
||||
msgstr "Невозможно загрузить данные лога:"
|
||||
|
||||
msgid "Warning"
|
||||
msgstr "Внимание"
|
||||
|
||||
msgid "ascending"
|
||||
msgstr "по возрастанию"
|
||||
|
||||
msgid "descending"
|
||||
msgstr "по убыванию"
|
||||
|
||||
@@ -7,6 +7,12 @@ msgstr ""
|
||||
msgid "Add user entries to the blacklist when updating"
|
||||
msgstr ""
|
||||
|
||||
msgid "Alert"
|
||||
msgstr ""
|
||||
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
msgid "All traffic goes through the proxy without applying rules"
|
||||
msgstr ""
|
||||
|
||||
@@ -16,6 +22,9 @@ msgstr ""
|
||||
msgid "Apply proxy rules to router application traffic"
|
||||
msgstr ""
|
||||
|
||||
msgid "Blacklist entry filters"
|
||||
msgstr ""
|
||||
|
||||
msgid "Blacklist module"
|
||||
msgstr ""
|
||||
|
||||
@@ -43,6 +52,9 @@ msgstr ""
|
||||
msgid "Clean up ipsets before updating blacklist"
|
||||
msgstr ""
|
||||
|
||||
msgid "Command failed"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Complete service shutdown, as well as deleting ipsets and blacklist data"
|
||||
msgstr ""
|
||||
@@ -53,6 +65,9 @@ msgstr ""
|
||||
msgid "Convert cyrillic domains to punycode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Critical"
|
||||
msgstr ""
|
||||
|
||||
msgid "Current schedule"
|
||||
msgstr ""
|
||||
|
||||
@@ -62,43 +77,47 @@ msgstr ""
|
||||
msgid "Day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Disable"
|
||||
msgid "Debug"
|
||||
msgstr ""
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dismiss"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download error"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download log"
|
||||
msgstr ""
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Emergency"
|
||||
msgstr ""
|
||||
msgid "Enable"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable FQDN filter"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable ip filter"
|
||||
msgid "Enable IP filter"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable the 'total-proxy' option at startup"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "Entries filters"
|
||||
msgid "Entries"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
|
||||
msgid "Exclude domains from blacklist by FQDN filter patterns"
|
||||
msgid "Exclude IP addresses from blacklist by IP filter patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "Exclude IP addresses from blacklist by IP filter patterns"
|
||||
msgid "Exclude domains from blacklist by FQDN filter patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "Expecting:"
|
||||
@@ -110,15 +129,24 @@ msgstr ""
|
||||
msgid "FQDN filter"
|
||||
msgstr ""
|
||||
|
||||
msgid "Hour"
|
||||
msgid "Facility"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to get %s init status: %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "HTML/XML error"
|
||||
msgstr ""
|
||||
|
||||
msgid "Host"
|
||||
msgstr ""
|
||||
|
||||
msgid "Hosts"
|
||||
msgstr ""
|
||||
|
||||
msgid "Hour"
|
||||
msgstr ""
|
||||
|
||||
msgid "Interval"
|
||||
msgstr ""
|
||||
|
||||
msgid "IP configuration"
|
||||
msgstr ""
|
||||
|
||||
@@ -131,6 +159,15 @@ msgstr ""
|
||||
msgid "IP subnet patterns (/24) that are excluded from optimization"
|
||||
msgstr ""
|
||||
|
||||
msgid "Info"
|
||||
msgstr ""
|
||||
|
||||
msgid "Interval"
|
||||
msgstr ""
|
||||
|
||||
msgid "Invalid regular expression"
|
||||
msgstr ""
|
||||
|
||||
msgid "Ipset"
|
||||
msgstr ""
|
||||
|
||||
@@ -143,6 +180,12 @@ msgstr ""
|
||||
msgid "Last blacklist update"
|
||||
msgstr ""
|
||||
|
||||
msgid "Last entries"
|
||||
msgstr ""
|
||||
|
||||
msgid "Level"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading"
|
||||
msgstr ""
|
||||
|
||||
@@ -152,12 +195,21 @@ msgstr ""
|
||||
msgid "Logging events"
|
||||
msgstr ""
|
||||
|
||||
msgid "Logging levels"
|
||||
msgstr ""
|
||||
|
||||
msgid "Main settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "Match-set"
|
||||
msgstr ""
|
||||
|
||||
msgid "Message"
|
||||
msgstr ""
|
||||
|
||||
msgid "Message filter"
|
||||
msgstr ""
|
||||
|
||||
msgid "Minute"
|
||||
msgstr ""
|
||||
|
||||
@@ -167,13 +219,19 @@ msgstr ""
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
msgid "No Shedule"
|
||||
msgstr ""
|
||||
|
||||
msgid "No changes to save."
|
||||
msgstr ""
|
||||
|
||||
msgid "No data"
|
||||
msgstr ""
|
||||
|
||||
msgid "No Shedule"
|
||||
msgid "No entries available..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Notice"
|
||||
msgstr ""
|
||||
|
||||
msgid "Number of entries"
|
||||
@@ -189,10 +247,10 @@ msgstr ""
|
||||
msgid "One of the following:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Optional DNS resolver for '.onion' zone"
|
||||
msgid "Optional DNS resolver"
|
||||
msgstr ""
|
||||
|
||||
msgid "Optional DNS resolver"
|
||||
msgid "Optional DNS resolver for '.onion' zone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Options"
|
||||
@@ -216,33 +274,46 @@ msgstr ""
|
||||
msgid "Reduces RAM consumption during update"
|
||||
msgstr ""
|
||||
|
||||
msgid "Refresh log"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset"
|
||||
msgstr ""
|
||||
|
||||
msgid "Ruantiblock"
|
||||
msgstr ""
|
||||
|
||||
msgid "Run at startup"
|
||||
msgstr ""
|
||||
|
||||
msgid "Save"
|
||||
msgstr ""
|
||||
|
||||
msgid "Service"
|
||||
msgstr ""
|
||||
|
||||
msgid "Service action failed \"%s %s\": %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set"
|
||||
msgstr ""
|
||||
|
||||
msgid "Settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "Shutdown"
|
||||
msgstr ""
|
||||
|
||||
msgid "Size in memory"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sorting entries"
|
||||
msgstr ""
|
||||
|
||||
msgid "Starting"
|
||||
msgstr ""
|
||||
|
||||
msgid "Statistics"
|
||||
msgstr ""
|
||||
|
||||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
@@ -273,21 +344,31 @@ msgstr ""
|
||||
msgid "Time"
|
||||
msgstr ""
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr ""
|
||||
|
||||
msgid "Tor configuration file"
|
||||
msgstr ""
|
||||
|
||||
msgid "Tor mode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Total-proxy"
|
||||
msgstr ""
|
||||
|
||||
msgid "Total-proxy is on"
|
||||
msgstr ""
|
||||
|
||||
msgid "Transparent proxy port for iptables rules"
|
||||
msgstr ""
|
||||
|
||||
msgid "Type an expression..."
|
||||
msgstr ""
|
||||
msgid "Unable to execute or read contents"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to load log data:"
|
||||
msgstr ""
|
||||
msgid "Unable to read the contents"
|
||||
msgstr ""
|
||||
|
||||
@@ -308,7 +389,6 @@ msgstr ""
|
||||
|
||||
msgid "Use optional DNS resolver"
|
||||
msgstr ""
|
||||
|
||||
msgid "User entries"
|
||||
msgstr ""
|
||||
|
||||
@@ -321,9 +401,27 @@ msgstr ""
|
||||
msgid "VPN routing error! Need restart"
|
||||
msgstr ""
|
||||
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
|
||||
msgid "ascending"
|
||||
msgstr ""
|
||||
|
||||
msgid "descending"
|
||||
msgstr ""
|
||||
|
||||
msgid "disabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "e.g:"
|
||||
msgstr ""
|
||||
|
||||
msgid "net pattern"
|
||||
msgstr ""
|
||||
|
||||
msgid "none (user entries only)"
|
||||
msgstr ""
|
||||
|
||||
msgid "user entries only"
|
||||
msgstr ""
|
||||
|
||||
@@ -332,86 +430,3 @@ msgstr ""
|
||||
|
||||
msgid "valid address#port"
|
||||
msgstr ""
|
||||
|
||||
|
||||
|
||||
msgid "Alert"
|
||||
msgstr ""
|
||||
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
msgid "Critical"
|
||||
msgstr ""
|
||||
|
||||
msgid "Debug"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download log"
|
||||
msgstr ""
|
||||
|
||||
msgid "Emergency"
|
||||
msgstr ""
|
||||
|
||||
msgid "Entries"
|
||||
msgstr ""
|
||||
|
||||
msgid "Facility"
|
||||
msgstr ""
|
||||
|
||||
msgid "Host"
|
||||
msgstr ""
|
||||
|
||||
msgid "Hosts"
|
||||
msgstr ""
|
||||
|
||||
msgid "Info"
|
||||
msgstr ""
|
||||
|
||||
msgid "Invalid regular expression"
|
||||
msgstr ""
|
||||
|
||||
msgid "Last entries"
|
||||
msgstr ""
|
||||
|
||||
msgid "Level"
|
||||
msgstr ""
|
||||
|
||||
msgid "Logging levels"
|
||||
msgstr ""
|
||||
|
||||
msgid "Message"
|
||||
msgstr ""
|
||||
|
||||
msgid "Message filter"
|
||||
msgstr ""
|
||||
|
||||
msgid "No entries available..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Notice"
|
||||
msgstr ""
|
||||
|
||||
msgid "Refresh log"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sorting entries"
|
||||
msgstr ""
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr ""
|
||||
|
||||
msgid "Type an expression..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to load log data:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
|
||||
msgid "ascending"
|
||||
msgstr ""
|
||||
|
||||
msgid "descending"
|
||||
msgstr ""
|
||||
|
||||
@@ -12,16 +12,13 @@
|
||||
"/etc/tor/torrc": [ "read" ],
|
||||
"/etc/crontabs/root": [ "read" ],
|
||||
"/usr/bin/ruantiblock": [ "exec" ],
|
||||
"/etc/init.d/ruantiblock": [ "exec" ],
|
||||
"/etc/init.d/tor enabled": [ "exec" ],
|
||||
"/etc/init.d/tor restart": [ "exec" ],
|
||||
"/etc/init.d/cron enabled": [ "exec" ],
|
||||
"/etc/init.d/cron enable": [ "exec" ],
|
||||
"/etc/init.d/cron restart": [ "exec" ],
|
||||
"/sbin/logread -e ruantiblock": [ "exec" ],
|
||||
"/usr/sbin/logread -e ruantiblock": [ "exec" ]
|
||||
},
|
||||
"uci": [ "network", "ruantiblock" ]
|
||||
"uci": [ "network", "ruantiblock" ],
|
||||
"ubus": {
|
||||
"luci": [ "getInitList", "setInitAction" ]
|
||||
}
|
||||
},
|
||||
"write": {
|
||||
"file": {
|
||||
|
||||
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 139 KiB |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 299 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 164 KiB |