luci-app: Minor fixes and improvements
@@ -11,8 +11,8 @@ LUCI_APP=1
|
|||||||
OWRT_VERSION="19.07"
|
OWRT_VERSION="19.07"
|
||||||
RUAB_VERSION="0.9.0-2"
|
RUAB_VERSION="0.9.0-2"
|
||||||
RUAB_MOD_LUA_VERSION="0.9.0-2"
|
RUAB_MOD_LUA_VERSION="0.9.0-2"
|
||||||
RUAB_LUCI_APP_VERSION="0.9.0-6"
|
RUAB_LUCI_APP_VERSION="0.9.0-7"
|
||||||
BASE_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_openwrt/master"
|
BASE_URL="https://github.com/gSpotx2f/ruantiblock_openwrt/raw/master"
|
||||||
PKG_DIR="/tmp"
|
PKG_DIR="/tmp"
|
||||||
|
|
||||||
if [ -n "$1" ]; then
|
if [ -n "$1" ]; then
|
||||||
@@ -29,8 +29,8 @@ URL_LUCI_APP_RU_PKG="${BASE_URL}/packages/${OWRT_VERSION}/luci-i18n-ruantiblock-
|
|||||||
### tor
|
### tor
|
||||||
URL_TORRC="${BASE_URL}/tor/etc/tor/torrc"
|
URL_TORRC="${BASE_URL}/tor/etc/tor/torrc"
|
||||||
### ruantiblock-mod-lua
|
### ruantiblock-mod-lua
|
||||||
URL_LUA_IPTOOL="https://raw.githubusercontent.com/gSpotx2f/iptool-lua/master/5.1/iptool.lua"
|
URL_LUA_IPTOOL="https://github.com/gSpotx2f/iptool-lua/raw/master/5.1/iptool.lua"
|
||||||
URL_LUA_IDN="https://raw.githubusercontent.com/haste/lua-idn/master/idn.lua"
|
URL_LUA_IDN="https://github.com/haste/lua-idn/raw/master/idn.lua"
|
||||||
|
|
||||||
### Local files
|
### 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
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_VERSION:=0.9.0
|
PKG_VERSION:=0.9.0
|
||||||
PKG_RELEASE:=6
|
PKG_RELEASE:=7
|
||||||
LUCI_TITLE:=LuCI support for ruantiblock
|
LUCI_TITLE:=LuCI support for ruantiblock
|
||||||
LUCI_DEPENDS:=+ruantiblock +luci-mod-admin-full
|
LUCI_DEPENDS:=+ruantiblock
|
||||||
LUCI_PKGARCH:=all
|
LUCI_PKGARCH:=all
|
||||||
|
|
||||||
include ../../luci.mk
|
#include ../../luci.mk
|
||||||
|
include $(TOPDIR)/feeds/luci/luci.mk
|
||||||
|
|
||||||
# call BuildPackage - OpenWrt buildroot signature
|
# call BuildPackage - OpenWrt buildroot signature
|
||||||
|
|||||||
@@ -139,15 +139,15 @@ return L.Class.extend({
|
|||||||
* View name (for local storage and downloads).
|
* View name (for local storage and downloads).
|
||||||
* Must be overridden by a subclass!
|
* Must be overridden by a subclass!
|
||||||
*/
|
*/
|
||||||
viewName: null,
|
viewName : null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page title.
|
* Page title.
|
||||||
* Must be overridden by a subclass!
|
* Must be overridden by a subclass!
|
||||||
*/
|
*/
|
||||||
title: null,
|
title : null,
|
||||||
|
|
||||||
logLevels: {
|
logLevels : {
|
||||||
'emerg': E('span', { 'class': 'zonebadge log-emerg' }, E('strong', _('Emergency'))),
|
'emerg': E('span', { 'class': 'zonebadge log-emerg' }, E('strong', _('Emergency'))),
|
||||||
'alert': E('span', { 'class': 'zonebadge log-alert' }, E('strong', _('Alert'))),
|
'alert': E('span', { 'class': 'zonebadge log-alert' }, E('strong', _('Alert'))),
|
||||||
'crit': E('span', { 'class': 'zonebadge log-crit' }, E('strong', _('Critical'))),
|
'crit': E('span', { 'class': 'zonebadge log-crit' }, E('strong', _('Critical'))),
|
||||||
@@ -158,25 +158,25 @@ return L.Class.extend({
|
|||||||
'debug': E('span', { 'class': 'zonebadge log-debug' }, E('strong', _('Debug'))),
|
'debug': E('span', { 'class': 'zonebadge log-debug' }, E('strong', _('Debug'))),
|
||||||
},
|
},
|
||||||
|
|
||||||
tailValue: 25,
|
tailValue : 25,
|
||||||
|
|
||||||
logSortingValue: 'asc',
|
logSortingValue : 'asc',
|
||||||
|
|
||||||
isHosts: false,
|
isHosts : false,
|
||||||
|
|
||||||
isLevels: false,
|
isLevels : false,
|
||||||
|
|
||||||
logHosts: {},
|
logHosts : {},
|
||||||
|
|
||||||
logLevelsStat: {},
|
logLevelsStat : {},
|
||||||
|
|
||||||
logHostsDropdown: null,
|
logHostsDropdown : null,
|
||||||
|
|
||||||
logLevelsDropdown: null,
|
logLevelsDropdown: null,
|
||||||
|
|
||||||
totalLogLines: 0,
|
totalLogLines : 0,
|
||||||
|
|
||||||
htmlEntities: function(str) {
|
htmlEntities : function(str) {
|
||||||
return String(str).replace(
|
return String(str).replace(
|
||||||
/&/g, '&').replace(
|
/&/g, '&').replace(
|
||||||
/</g, '<').replace(
|
/</g, '<').replace(
|
||||||
@@ -426,15 +426,15 @@ return L.Class.extend({
|
|||||||
|
|
||||||
render: function(logdata) {
|
render: function(logdata) {
|
||||||
let logWrapper = E('div', {
|
let logWrapper = E('div', {
|
||||||
'id': 'logWrapper',
|
'id' : 'logWrapper',
|
||||||
'style': 'width:100%; min-height:20em; padding: 0 0 0 45px; font-size:0.9em !important'
|
'style': 'width:100%; min-height:20em; padding: 0 0 0 45px; font-size:0.9em !important'
|
||||||
}, this.makeLogArea(this.parseLogData(logdata, this.tailValue)));
|
}, this.makeLogArea(this.parseLogData(logdata, this.tailValue)));
|
||||||
|
|
||||||
let tailInput = E('input', {
|
let tailInput = E('input', {
|
||||||
'id': 'tailInput',
|
'id' : 'tailInput',
|
||||||
'name': 'tailInput',
|
'name' : 'tailInput',
|
||||||
'type': 'text',
|
'type' : 'text',
|
||||||
'form': 'logForm',
|
'form' : 'logForm',
|
||||||
'class': 'cbi-input-text',
|
'class': 'cbi-input-text',
|
||||||
'style': 'width:4em !important; min-width:4em !important',
|
'style': 'width:4em !important; min-width:4em !important',
|
||||||
'maxlength': 5,
|
'maxlength': 5,
|
||||||
@@ -443,8 +443,8 @@ return L.Class.extend({
|
|||||||
ui.addValidator(tailInput, 'uinteger', true);
|
ui.addValidator(tailInput, 'uinteger', true);
|
||||||
|
|
||||||
let tailReset = E('input', {
|
let tailReset = E('input', {
|
||||||
'type': 'button',
|
'type' : 'button',
|
||||||
'form': 'logForm',
|
'form' : 'logForm',
|
||||||
'class': 'cbi-button btn cbi-button-reset',
|
'class': 'cbi-button btn cbi-button-reset',
|
||||||
'value': 'Χ',
|
'value': 'Χ',
|
||||||
'click': ev => {
|
'click': ev => {
|
||||||
@@ -455,27 +455,27 @@ return L.Class.extend({
|
|||||||
'style': 'max-width:4em !important',
|
'style': 'max-width:4em !important',
|
||||||
});
|
});
|
||||||
|
|
||||||
let logHostsDropdownElem = '';
|
let logHostsDropdownElem = '';
|
||||||
let logLevelsDropdownElem = '';
|
let logLevelsDropdownElem = '';
|
||||||
if(this.isLevels) {
|
if(this.isLevels) {
|
||||||
logLevelsDropdownElem = this.makeLogLevelsDropdownSection();
|
logLevelsDropdownElem = this.makeLogLevelsDropdownSection();
|
||||||
};
|
};
|
||||||
if(this.isHosts) {
|
if(this.isHosts) {
|
||||||
logHostsDropdownElem = this.makeLogHostsDropdownSection();
|
logHostsDropdownElem = this.makeLogHostsDropdownSection();
|
||||||
};
|
};
|
||||||
|
|
||||||
let logFilter = E('input', {
|
let logFilter = E('input', {
|
||||||
'id': 'logFilter',
|
'id' : 'logFilter',
|
||||||
'name': 'logFilter',
|
'name' : 'logFilter',
|
||||||
'type': 'text',
|
'type' : 'text',
|
||||||
'form': 'logForm',
|
'form' : 'logForm',
|
||||||
'class': 'cbi-input-text',
|
'class' : 'cbi-input-text',
|
||||||
'placeholder': _('Type an expression...'),
|
'placeholder': _('Type an expression...'),
|
||||||
});
|
});
|
||||||
|
|
||||||
let logFormSubmitBtn = E('input', {
|
let logFormSubmitBtn = E('input', {
|
||||||
'type': 'submit',
|
'type' : 'submit',
|
||||||
'form': 'logForm',
|
'form' : 'logForm',
|
||||||
'class': 'cbi-button btn cbi-button-action',
|
'class': 'cbi-button btn cbi-button-action',
|
||||||
'value': _('Apply'),
|
'value': _('Apply'),
|
||||||
'click': ev => ev.target.blur(),
|
'click': ev => ev.target.blur(),
|
||||||
@@ -483,9 +483,9 @@ return L.Class.extend({
|
|||||||
});
|
});
|
||||||
|
|
||||||
let logSorting = E('select', {
|
let logSorting = E('select', {
|
||||||
'id': 'logSorting',
|
'id' : 'logSorting',
|
||||||
'name': 'logSorting',
|
'name' : 'logSorting',
|
||||||
'form': 'logForm',
|
'form' : 'logForm',
|
||||||
'class': "cbi-input-select",
|
'class': "cbi-input-select",
|
||||||
}, [
|
}, [
|
||||||
E('option', { 'value': 'asc' }, _('ascending')),
|
E('option', { 'value': 'asc' }, _('ascending')),
|
||||||
@@ -494,8 +494,8 @@ return L.Class.extend({
|
|||||||
logSorting.value = this.logSortingValue;
|
logSorting.value = this.logSortingValue;
|
||||||
|
|
||||||
let logDownloadBtn = E('button', {
|
let logDownloadBtn = E('button', {
|
||||||
'id': 'logDownloadBtn',
|
'id' : 'logDownloadBtn',
|
||||||
'name': 'logDownloadBtn',
|
'name' : 'logDownloadBtn',
|
||||||
'class': 'cbi-button btn',
|
'class': 'cbi-button btn',
|
||||||
'click': ui.createHandlerFn(this, this.downloadLog),
|
'click': ui.createHandlerFn(this, this.downloadLog),
|
||||||
}, _('Download log'));
|
}, _('Download log'));
|
||||||
@@ -509,7 +509,7 @@ return L.Class.extend({
|
|||||||
E('div', { 'id': 'tailInputSection', 'class': 'cbi-value' }, [
|
E('div', { 'id': 'tailInputSection', 'class': 'cbi-value' }, [
|
||||||
E('label', {
|
E('label', {
|
||||||
'class': 'cbi-value-title',
|
'class': 'cbi-value-title',
|
||||||
'for': 'tailInput',
|
'for' : 'tailInput',
|
||||||
}, _('Last entries')),
|
}, _('Last entries')),
|
||||||
E('div', { 'class': 'cbi-value-field' }, [
|
E('div', { 'class': 'cbi-value-field' }, [
|
||||||
tailInput,
|
tailInput,
|
||||||
@@ -523,7 +523,7 @@ return L.Class.extend({
|
|||||||
E('div', { 'class': 'cbi-value' }, [
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
E('label', {
|
E('label', {
|
||||||
'class': 'cbi-value-title',
|
'class': 'cbi-value-title',
|
||||||
'for': 'logFilter',
|
'for' : 'logFilter',
|
||||||
}, _('Message filter')),
|
}, _('Message filter')),
|
||||||
E('div', { 'class': 'cbi-value-field' }, logFilter),
|
E('div', { 'class': 'cbi-value-field' }, logFilter),
|
||||||
]),
|
]),
|
||||||
@@ -531,7 +531,7 @@ return L.Class.extend({
|
|||||||
E('div', { 'class': 'cbi-value' }, [
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
E('label', {
|
E('label', {
|
||||||
'class': 'cbi-value-title',
|
'class': 'cbi-value-title',
|
||||||
'for': 'logSorting',
|
'for' : 'logSorting',
|
||||||
}, _('Sorting entries')),
|
}, _('Sorting entries')),
|
||||||
E('div', { 'class': 'cbi-value-field' }, logSorting,),
|
E('div', { 'class': 'cbi-value-field' }, logSorting,),
|
||||||
]),
|
]),
|
||||||
@@ -539,14 +539,14 @@ return L.Class.extend({
|
|||||||
E('div', { 'class': 'cbi-value' }, [
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
E('label', {
|
E('label', {
|
||||||
'class': 'cbi-value-title',
|
'class': 'cbi-value-title',
|
||||||
'for': 'logFilter',
|
'for' : 'logFilter',
|
||||||
}, _('Refresh log')),
|
}, _('Refresh log')),
|
||||||
E('div', { 'class': 'cbi-value-field' }, [
|
E('div', { 'class': 'cbi-value-field' }, [
|
||||||
logFormSubmitBtn,
|
logFormSubmitBtn,
|
||||||
E('form', {
|
E('form', {
|
||||||
'id': 'logForm',
|
'id' : 'logForm',
|
||||||
'name': 'logForm',
|
'name' : 'logForm',
|
||||||
'style': 'display:inline-block; margin-top:0.5em',
|
'style' : 'display:inline-block; margin-top:0.5em',
|
||||||
'submit': ui.createHandlerFn(this, function(ev) {
|
'submit': ui.createHandlerFn(this, function(ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
let formElems = Array.from(document.forms.logForm.elements);
|
let formElems = Array.from(document.forms.logForm.elements);
|
||||||
@@ -633,8 +633,8 @@ return L.Class.extend({
|
|||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleSave : null,
|
||||||
handleSaveApply: null,
|
handleSaveApply: null,
|
||||||
handleSave: null,
|
handleReset : null,
|
||||||
handleReset: null,
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,221 +3,234 @@
|
|||||||
'require ui';
|
'require ui';
|
||||||
'require view.ruantiblock.tools as tools';
|
'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;
|
|
||||||
|
|
||||||
function to_dd(n){
|
|
||||||
return String(n).replace(/^(\d)$/, "0$1");
|
|
||||||
};
|
|
||||||
|
|
||||||
function cron_status_string(s) {
|
|
||||||
return s || _('No Shedule');
|
|
||||||
}
|
|
||||||
|
|
||||||
function pick_cron_task(content) {
|
|
||||||
if(!content){
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let current_tasks = content.match(crontab_regexp) || [];
|
|
||||||
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';
|
|
||||||
}
|
|
||||||
|
|
||||||
function write_cron_file() {
|
|
||||||
let btn_cron_add = document.getElementById('btn_cron_add');
|
|
||||||
let btn_cron_del = document.getElementById('btn_cron_del');
|
|
||||||
|
|
||||||
if(!current_crontab_content) {
|
|
||||||
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 => {
|
|
||||||
ui.addNotification(null, E('p',_('Changes have been saved.')), 'info');
|
|
||||||
set_cron_status(pick_cron_task(current_crontab_content));
|
|
||||||
}).then(() => {
|
|
||||||
return fs.exec('/etc/init.d/cron', [ 'enabled' ]).then(res => {
|
|
||||||
if(res.code !== 0) {
|
|
||||||
return fs.exec('/etc/init.d/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')));
|
|
||||||
});
|
|
||||||
}).catch(e => {
|
|
||||||
ui.addNotification(null, E('p', _('Unable to save the changes')
|
|
||||||
+ ': %s<br />[ %s ]'.format(
|
|
||||||
e.message, tools.crontab_file
|
|
||||||
)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function del_cron_schedule(ev) {
|
|
||||||
if(current_crontab_content) {
|
|
||||||
current_crontab_content = current_crontab_content.replace(crontab_regexp, "");
|
|
||||||
};
|
|
||||||
return write_cron_file();
|
|
||||||
};
|
|
||||||
|
|
||||||
function set_cron_schedule(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;
|
|
||||||
let min = document.getElementById('cron_min').value;
|
|
||||||
let task_string = '%s %s %s * * %s update\n'.format(
|
|
||||||
min,
|
|
||||||
(!hour_interval) ? hour : (hour_interval == "1") ? '*' : '*/' + hour_interval,
|
|
||||||
(hour_interval || day_interval == "1") ? '*' : '*/' + day_interval,
|
|
||||||
tools.exec_path
|
|
||||||
);
|
|
||||||
if(current_crontab_content) {
|
|
||||||
current_crontab_content = current_crontab_content.replace(crontab_regexp, "") + task_string;
|
|
||||||
};
|
|
||||||
return write_cron_file();
|
|
||||||
};
|
|
||||||
|
|
||||||
function onchange_hour_interval(e) {
|
|
||||||
let value = e.target.value;
|
|
||||||
let bool = (value != '');
|
|
||||||
let cron_hour = document.getElementById('cron_hour');
|
|
||||||
let cron_day_interval = document.getElementById('cron_day_interval');
|
|
||||||
cron_hour.disabled = bool;
|
|
||||||
cron_day_interval.disabled = bool;
|
|
||||||
|
|
||||||
if(bool) {
|
|
||||||
cron_hour.style.opacity = '50%';
|
|
||||||
cron_day_interval.style.opacity = '50%';
|
|
||||||
} else {
|
|
||||||
cron_hour.style.opacity = '100%';
|
|
||||||
cron_day_interval.style.opacity = '100%';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return L.view.extend({
|
return L.view.extend({
|
||||||
load: function() {
|
crontabRegexp: new RegExp(
|
||||||
return fs.read(tools.crontab_file).catch(e => {
|
`^(\\*?\\/?(\\d){0,2}\\s){5}${tools.execPath} update(\n)?`, 'gm'),
|
||||||
ui.addNotification(null, E('p', _('Unable to read the contents')
|
|
||||||
+ ': %s<br />[ %s ]'.format(
|
|
||||||
e.message, tools.crontab_file
|
|
||||||
)));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function(content) {
|
currentCrontabContent: null,
|
||||||
current_crontab_content = content;
|
|
||||||
let current_task = pick_cron_task(content);
|
|
||||||
|
|
||||||
let cron_status = E('textarea', {
|
toDD: function(n){
|
||||||
'id': 'cron_status',
|
return String(n).replace(/^(\d)$/, "0$1");
|
||||||
'name': 'cron_status',
|
},
|
||||||
'style': 'width:100% !important; padding:5px 10px 5px 10px !important; resize:none !important;',
|
|
||||||
'readonly': 'readonly',
|
|
||||||
'wrap': 'off',
|
|
||||||
'rows': 2,
|
|
||||||
}, cron_status_string(current_task));
|
|
||||||
|
|
||||||
let btn_cron_del = E('button', {
|
cronStatusString: function(s) {
|
||||||
'class': 'cbi-button btn cbi-button-reset',
|
return s || _('No Shedule');
|
||||||
'id': 'btn_cron_del',
|
},
|
||||||
'name': 'btn_cron_del',
|
|
||||||
}, _('Reset'));
|
|
||||||
btn_cron_del.onclick = ui.createHandlerFn(this, del_cron_schedule);
|
|
||||||
btn_cron_del.style.visibility = (current_task) ? 'visible' : 'hidden';
|
|
||||||
|
|
||||||
let status_header = E('div', { 'class': 'cbi-section-node' }, [
|
pickCronTask: function(content) {
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
if(!content){
|
||||||
E('label', { 'class': 'cbi-value-title', 'for': 'cron_status' },
|
return;
|
||||||
_('Current schedule')),
|
};
|
||||||
E('div', { 'class': 'cbi-value-field' }, cron_status),
|
let current_tasks = content.match(this.crontabRegexp) || [];
|
||||||
]),
|
return current_tasks.join('');
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
},
|
||||||
E('label', { 'class': 'cbi-value-title', 'for': 'btn_cron_del' }),
|
|
||||||
E('div', { 'class': 'cbi-value-field' }, btn_cron_del),
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
|
|
||||||
let layout = E('div', { 'class': 'cbi-section-node' });
|
setCronStatus: function(value) {
|
||||||
|
document.getElementById('cron_status').value = this.cronStatusString(value);
|
||||||
|
document.getElementById("btn_cron_del").style.visibility = (value) ?
|
||||||
|
'visible' : 'hidden';
|
||||||
|
},
|
||||||
|
|
||||||
function layout_append(elem, title, descr) {
|
writeCronFile: function() {
|
||||||
descr = (descr) ? E('div', { 'class': 'cbi-value-description' }, descr) : '';
|
let btn_cron_add = document.getElementById('btn_cron_add');
|
||||||
layout.append(
|
let btn_cron_del = document.getElementById('btn_cron_del');
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
|
||||||
E('label', { 'class': 'cbi-value-title', 'for': elem.id || null },
|
|
||||||
title),
|
|
||||||
E('div', { 'class': 'cbi-value-field' }, [ elem, descr ]),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
layout_append(E('b', {}, _('Interval')));
|
if(!this.currentCrontabContent) {
|
||||||
|
ui.addNotification(null, E('p', _('No changes to save.')));
|
||||||
|
btn_cron_add.disabled = false;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let cron_hour_interval = E('select',
|
return fs.write(tools.crontabFile, this.currentCrontabContent).then(rc => {
|
||||||
{ 'id': 'cron_hour_interval', 'style': 'width:60px !important; min-width:60px !important' }, [
|
ui.addNotification(null, E('p',_('Changes have been saved.')), 'info');
|
||||||
E('option', { 'value': '' }, ''),
|
this.setCronStatus(this.pickCronTask(this.currentCrontabContent));
|
||||||
E('option', { 'value': '1' }, '∗')
|
}).then(() => {
|
||||||
]);
|
return tools.getInitStatus('cron').then(res => {
|
||||||
for(let i = 2; i <= 12 ; i += 2) {
|
if(!res) {
|
||||||
cron_hour_interval.append(E('option', { 'value': String(i) }, '∗/' + i));
|
return tools.handleServiceAction('cron', 'enable');
|
||||||
};
|
};
|
||||||
layout_append(cron_hour_interval, _('Hour'));
|
});
|
||||||
cron_hour_interval.onchange = onchange_hour_interval;
|
}).finally(() => {
|
||||||
|
return tools.handleServiceAction('cron', 'restart');
|
||||||
|
}).catch(e => {
|
||||||
|
ui.addNotification(null, E('p', _('Unable to save the changes')
|
||||||
|
+ ': %s [ %s ]'.format(
|
||||||
|
e.message, tools.crontabFile
|
||||||
|
)));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
let cron_day_interval = E('select',
|
delCronSchedule: function(ev) {
|
||||||
{ 'id': 'cron_day_interval', 'style': 'width:60px !important; min-width:60px !important' },
|
if(this.currentCrontabContent) {
|
||||||
E('option', { 'value': '1' }, '∗')
|
this.currentCrontabContent = this.currentCrontabContent.replace(
|
||||||
);
|
this.crontabRegexp, "");
|
||||||
for(let i = 2; i < 8 ; i++) {
|
};
|
||||||
cron_day_interval.append(E('option', { 'value': String(i) }, '∗/' + i));
|
return this.writeCronFile();
|
||||||
};
|
},
|
||||||
cron_day_interval.append(E('option', { 'value': '14' }, '∗/14'));
|
|
||||||
cron_day_interval.append(E('option', { 'value': '28' }, '∗/28'));
|
|
||||||
layout_append(cron_day_interval, _('Day'));
|
|
||||||
|
|
||||||
layout_append(E('b', {}, _('Time')));
|
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;
|
||||||
|
let min = document.getElementById('cron_min').value;
|
||||||
|
let task_string = '%s %s %s * * %s update\n'.format(
|
||||||
|
min,
|
||||||
|
(!hour_interval) ? hour : (hour_interval == "1") ? '*' : '*/' + hour_interval,
|
||||||
|
(hour_interval || day_interval == "1") ? '*' : '*/' + day_interval,
|
||||||
|
tools.execPath
|
||||||
|
);
|
||||||
|
if(this.currentCrontabContent) {
|
||||||
|
this.currentCrontabContent = this.currentCrontabContent.replace(
|
||||||
|
this.crontabRegexp, "") + task_string;
|
||||||
|
};
|
||||||
|
return this.writeCronFile();
|
||||||
|
},
|
||||||
|
|
||||||
let cron_hour = E('select',
|
onchangeHourInterval: function(e) {
|
||||||
{ 'id': 'cron_hour', 'style': 'width:60px !important; min-width:60px !important' });
|
let value = e.target.value;
|
||||||
for(let i = 0; i < 24 ; i++) {
|
let bool = (value != '');
|
||||||
cron_hour.append(E('option', { 'value': String(i) }, to_dd(i)));
|
let cron_hour = document.getElementById('cron_hour');
|
||||||
};
|
let cron_day_interval = document.getElementById('cron_day_interval');
|
||||||
layout_append(cron_hour, _('Hour'));
|
cron_hour.disabled = bool;
|
||||||
|
cron_day_interval.disabled = bool;
|
||||||
|
|
||||||
let cron_min = E('select',
|
// For luci-theme-material
|
||||||
{ 'id': 'cron_min', 'style': 'width:60px !important; min-width:60px !important' });
|
if(bool) {
|
||||||
for(let i = 0; i < 60 ; i++) {
|
cron_hour.style.opacity = '50%';
|
||||||
cron_min.append(E('option', { 'value': String(i) }, to_dd(i)));
|
cron_day_interval.style.opacity = '50%';
|
||||||
};
|
} else {
|
||||||
layout_append(cron_min, _('Minute'));
|
cron_hour.style.opacity = '100%';
|
||||||
|
cron_day_interval.style.opacity = '100%';
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
let btn_cron_add = E('button', {
|
load: function() {
|
||||||
'class': 'btn cbi-button-save',
|
return fs.read(tools.crontabFile).catch(e => {
|
||||||
'id': 'btn_cron_add',
|
ui.addNotification(null, E('p', _('Unable to read the contents')
|
||||||
'name': 'btn_cron_add'
|
+ ': %s [ %s ]'.format(
|
||||||
}, _('Set'));
|
e.message, tools.crontabFile
|
||||||
btn_cron_add.onclick = ui.createHandlerFn(this, set_cron_schedule);
|
)));
|
||||||
layout_append(btn_cron_add);
|
});
|
||||||
|
},
|
||||||
|
|
||||||
return E([
|
render: function(content) {
|
||||||
E('h2',
|
this.currentCrontabContent = content;
|
||||||
{ 'class': 'fade-in' }, _('Ruantiblock') + ' - ' + _('Blacklist updates') + ' (cron)'),
|
let current_task = this.pickCronTask(content);
|
||||||
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),
|
|
||||||
]);
|
|
||||||
|
|
||||||
},
|
let cron_status = E('textarea', {
|
||||||
|
'id': 'cron_status',
|
||||||
|
'name': 'cron_status',
|
||||||
|
'style': 'width:100% !important; padding:5px 10px 5px 10px !important; resize:none !important;',
|
||||||
|
'readonly': 'readonly',
|
||||||
|
'wrap': 'off',
|
||||||
|
'rows': 2,
|
||||||
|
}, this.cronStatusString(current_task));
|
||||||
|
|
||||||
handleSave: null,
|
let btn_cron_del = E('button', {
|
||||||
handleSaveApply: null,
|
'class': 'cbi-button btn cbi-button-reset',
|
||||||
handleReset: null,
|
'id': 'btn_cron_del',
|
||||||
|
'name': 'btn_cron_del',
|
||||||
|
}, _('Reset'));
|
||||||
|
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' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title', 'for': 'btn_cron_del' }),
|
||||||
|
E('div', { 'class': 'cbi-value-field' },
|
||||||
|
btn_cron_del),
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
|
||||||
|
let layout = E('div', { 'class': 'cbi-section-node' });
|
||||||
|
|
||||||
|
function layout_append(elem, title, descr) {
|
||||||
|
descr = (descr) ? E('div', { 'class': 'cbi-value-description' }, descr) : '';
|
||||||
|
layout.append(
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title', 'for': elem.id || null },
|
||||||
|
title),
|
||||||
|
E('div', { 'class': 'cbi-value-field' },
|
||||||
|
[ elem, descr ]),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
layout_append(E('b', {}, _('Interval')));
|
||||||
|
|
||||||
|
let cron_hour_interval = E('select',
|
||||||
|
{ 'id': 'cron_hour_interval', 'style': 'width:60px !important; min-width:60px !important' }, [
|
||||||
|
E('option', { 'value': '' }, ''),
|
||||||
|
E('option', { 'value': '1' }, '∗')
|
||||||
|
]);
|
||||||
|
for(let i = 2; i <= 12 ; i += 2) {
|
||||||
|
cron_hour_interval.append(
|
||||||
|
E('option', { 'value': String(i) }, '∗/' + i)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
layout_append(cron_hour_interval, _('Hour'));
|
||||||
|
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': '14' }, '∗/14'));
|
||||||
|
cron_day_interval.append(E('option', { 'value': '28' }, '∗/28'));
|
||||||
|
layout_append(cron_day_interval, _('Day'));
|
||||||
|
|
||||||
|
layout_append(E('b', {}, _('Time')));
|
||||||
|
|
||||||
|
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) }, 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) }, this.toDD(i))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
layout_append(cron_min, _('Minute'));
|
||||||
|
|
||||||
|
let btn_cron_add = E('button', {
|
||||||
|
'class': 'btn cbi-button-save',
|
||||||
|
'id': 'btn_cron_add',
|
||||||
|
'name': 'btn_cron_add'
|
||||||
|
}, _('Set'));
|
||||||
|
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)'
|
||||||
|
),
|
||||||
|
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),
|
||||||
|
]);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSave : null,
|
||||||
|
handleSaveApply: null,
|
||||||
|
handleReset : null,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,230 +4,238 @@
|
|||||||
'require view.ruantiblock.tools as tools';
|
'require view.ruantiblock.tools as tools';
|
||||||
|
|
||||||
return L.view.extend({
|
return L.view.extend({
|
||||||
poll_info: function() {
|
infoPoll: 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')
|
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();
|
L.Poll.stop();
|
||||||
}).then(data => {
|
}).then(data => {
|
||||||
if(!data) {
|
if(!data) {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
} catch(err) {};
|
} catch(err) {};
|
||||||
|
|
||||||
if(data.status === 'enabled') {
|
if(data.status === 'enabled') {
|
||||||
let date = document.getElementById('last_blacklist_update.date');
|
let date = document.getElementById('last_blacklist_update.date');
|
||||||
|
|
||||||
if(data.last_blacklist_update.status) {
|
if(data.last_blacklist_update.status) {
|
||||||
if(date) {
|
if(date) {
|
||||||
date.textContent = data.last_blacklist_update.date;
|
date.textContent = data.last_blacklist_update.date;
|
||||||
};
|
};
|
||||||
|
|
||||||
let ip = document.getElementById('last_blacklist_update.ip');
|
let ip = document.getElementById('last_blacklist_update.ip');
|
||||||
if(ip) {
|
if(ip) {
|
||||||
ip.textContent = data.last_blacklist_update.ip;
|
ip.textContent = data.last_blacklist_update.ip;
|
||||||
};
|
};
|
||||||
|
|
||||||
let cidr = document.getElementById('last_blacklist_update.cidr');
|
let cidr = document.getElementById('last_blacklist_update.cidr');
|
||||||
if(cidr) {
|
if(cidr) {
|
||||||
cidr.textContent = data.last_blacklist_update.cidr;
|
cidr.textContent = data.last_blacklist_update.cidr;
|
||||||
};
|
};
|
||||||
|
|
||||||
let fqdn = document.getElementById('last_blacklist_update.fqdn');
|
let fqdn = document.getElementById('last_blacklist_update.fqdn');
|
||||||
if(fqdn) {
|
if(fqdn) {
|
||||||
fqdn.textContent = data.last_blacklist_update.fqdn;
|
fqdn.textContent = data.last_blacklist_update.fqdn;
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
if(date) {
|
if(date) {
|
||||||
date.textContent = _('No data');
|
date.textContent = _('No data');
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
if(data.iptables) {
|
if(data.iptables) {
|
||||||
for(let [k, v] of Object.entries(data.iptables)) {
|
for(let [k, v] of Object.entries(data.iptables)) {
|
||||||
if(k === '_dummy') continue;
|
if(k === '_dummy') continue;
|
||||||
|
|
||||||
let elem = document.getElementById('iptables.' + k);
|
let elem = document.getElementById('iptables.' + k);
|
||||||
if(elem) {
|
if(elem) {
|
||||||
elem.textContent = v;
|
elem.textContent = v;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
if(data.ipset) {
|
if(data.ipset) {
|
||||||
for(let [k, v] of Object.entries(data.ipset)) {
|
for(let [k, v] of Object.entries(data.ipset)) {
|
||||||
if(k === '_dummy') continue;
|
if(k === '_dummy') continue;
|
||||||
|
|
||||||
let elem0 = document.getElementById('ipset.' + k + '.' + '0');
|
let elem0 = document.getElementById('ipset.' + k + '.' + '0');
|
||||||
let elem1 = document.getElementById('ipset.' + k + '.' + '1');
|
let elem1 = document.getElementById('ipset.' + k + '.' + '1');
|
||||||
if(elem0 && elem1) {
|
if(elem0 && elem1) {
|
||||||
elem0.textContent = v[0];
|
elem0.textContent = v[0];
|
||||||
elem1.textContent = v[1];
|
elem1.textContent = v[1];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
if(L.Poll.active()) {
|
if(L.Poll.active()) {
|
||||||
L.Poll.stop();
|
L.Poll.stop();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
load: function() {
|
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')
|
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)
|
||||||
));
|
));
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function(data) {
|
render: function(data) {
|
||||||
if(!data) {
|
if(!data) {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
} catch(err) {};
|
} catch(err) {};
|
||||||
|
|
||||||
let update_status = null,
|
let update_status = null,
|
||||||
iptables = null,
|
iptables = null,
|
||||||
ipset = null;
|
ipset = null;
|
||||||
if(data) {
|
if(data) {
|
||||||
if(data.status === 'enabled') {
|
if(data.status === 'enabled') {
|
||||||
update_status = E('div', { 'class': 'table' });
|
update_status = E('div', { 'class': 'table' });
|
||||||
|
|
||||||
if(data.last_blacklist_update.status) {
|
if(data.last_blacklist_update.status) {
|
||||||
update_status.append(
|
update_status.append(
|
||||||
E('div', { 'class': 'tr' }, [
|
E('div', { 'class': 'tr' }, [
|
||||||
E('div', { 'class': 'td left', 'style': 'min-width:33%' },
|
E('div', { 'class': 'td left', 'style': 'min-width:33%' },
|
||||||
_('Last blacklist update') + ':'),
|
_('Last blacklist update') + ':'),
|
||||||
E('div', { 'class': 'td left', 'id': 'last_blacklist_update.date' },
|
E('div', { 'class': 'td left',
|
||||||
data.last_blacklist_update.date),
|
'id': 'last_blacklist_update.date' },
|
||||||
]),
|
data.last_blacklist_update.date),
|
||||||
E('div', { 'class': 'tr' }, [
|
]),
|
||||||
E('div', { 'class': 'td left' }, 'IP:'),
|
E('div', { 'class': 'tr' }, [
|
||||||
E('div', { 'class': 'td left', 'id': 'last_blacklist_update.ip' },
|
E('div', { 'class': 'td left' }, 'IP:'),
|
||||||
data.last_blacklist_update.ip),
|
E('div', { 'class': 'td left',
|
||||||
]),
|
'id': 'last_blacklist_update.ip' },
|
||||||
E('div', { 'class': 'tr' }, [
|
data.last_blacklist_update.ip),
|
||||||
E('div', { 'class': 'td left' }, 'CIDR:'),
|
]),
|
||||||
E('div', { 'class': 'td left', 'id': 'last_blacklist_update.cidr' },
|
E('div', { 'class': 'tr' }, [
|
||||||
data.last_blacklist_update.cidr),
|
E('div', { 'class': 'td left' }, 'CIDR:'),
|
||||||
]),
|
E('div', { 'class': 'td left',
|
||||||
E('div', { 'class': 'tr' }, [
|
'id': 'last_blacklist_update.cidr' },
|
||||||
E('div', { 'class': 'td left' }, 'FQDN:'),
|
data.last_blacklist_update.cidr),
|
||||||
E('div', { 'class': 'td left', 'id': 'last_blacklist_update.fqdn' },
|
]),
|
||||||
data.last_blacklist_update.fqdn),
|
E('div', { 'class': 'tr' }, [
|
||||||
])
|
E('div', { 'class': 'td left' }, 'FQDN:'),
|
||||||
);
|
E('div', { 'class': 'td left',
|
||||||
} else {
|
'id': 'last_blacklist_update.fqdn' },
|
||||||
update_status.append(
|
data.last_blacklist_update.fqdn),
|
||||||
E('div', { 'class': 'tr' }, [
|
])
|
||||||
E('div', { 'class': 'td left' },
|
);
|
||||||
_('Last blacklist update')),
|
} else {
|
||||||
E('div', { 'class': 'td left' }, _('No data')),
|
update_status.append(
|
||||||
])
|
E('div', { 'class': 'tr' }, [
|
||||||
);
|
E('div', { 'class': 'td left' },
|
||||||
};
|
_('Last blacklist update')),
|
||||||
|
E('div', { 'class': 'td left' }, _('No data')),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
if(data.iptables) {
|
if(data.iptables) {
|
||||||
let table_iptables = E('div', { 'class': 'table' }, [
|
let table_iptables = E('div', { 'class': 'table' }, [
|
||||||
E('div', { 'class': 'tr table-titles' }, [
|
E('div', { 'class': 'tr table-titles' }, [
|
||||||
E('div', { 'class': 'th left', 'style': 'min-width:33%' },
|
E('div', { 'class': 'th left', 'style': 'min-width:33%' },
|
||||||
_('Match-set')),
|
_('Match-set')),
|
||||||
E('div', { 'class': 'th left' }, _('Bytes')),
|
E('div', { 'class': 'th left' }, _('Bytes')),
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
for(let [k, v] of Object.entries(data.iptables)) {
|
for(let [k, v] of Object.entries(data.iptables)) {
|
||||||
if(k === '_dummy') continue;
|
if(k === '_dummy') continue;
|
||||||
|
table_iptables.append(
|
||||||
|
E('div', { 'class': 'tr' }, [
|
||||||
|
E('div', {
|
||||||
|
'class' : 'td left',
|
||||||
|
'data-title': _('Match-set'),
|
||||||
|
}, k),
|
||||||
|
E('div', {
|
||||||
|
'class' : 'td left',
|
||||||
|
'id' : 'iptables.' + k,
|
||||||
|
'data-title': _('Bytes'),
|
||||||
|
}, v),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
table_iptables.append(
|
iptables = E([
|
||||||
E('div', { 'class': 'tr' }, [
|
E('h3', {}, _('Iptables rules')),
|
||||||
E('div', {
|
table_iptables,
|
||||||
'class': 'td left',
|
]);
|
||||||
'data-title': _('Match-set'),
|
};
|
||||||
}, k),
|
|
||||||
E('div', {
|
|
||||||
'class': 'td left',
|
|
||||||
'id': 'iptables.' + k,
|
|
||||||
'data-title': _('Bytes'),
|
|
||||||
}, v),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
iptables = E([
|
if(data.ipset) {
|
||||||
E('h3', {}, _('Iptables rules')),
|
let table_ipset = E('div', { 'class': 'table' },
|
||||||
table_iptables,
|
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')),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
if(data.ipset) {
|
for(let [k, v] of Object.entries(data.ipset)) {
|
||||||
let table_ipset = E('div', { 'class': 'table' },
|
if(k === '_dummy') continue;
|
||||||
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')),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
|
|
||||||
for(let [k, v] of Object.entries(data.ipset)) {
|
table_ipset.append(
|
||||||
if(k === '_dummy') continue;
|
E('div', { 'class': 'tr' }, [
|
||||||
|
E('div', {
|
||||||
|
'class' : 'td left',
|
||||||
|
'data-title': _('Name'),
|
||||||
|
}, k),
|
||||||
|
E('div', {
|
||||||
|
'class' : 'td left',
|
||||||
|
'id' : 'ipset.' + k + '.' + '0',
|
||||||
|
'data-title': _('Size in memory'),
|
||||||
|
}, v[0]),
|
||||||
|
E('div', {
|
||||||
|
'class' : 'td left',
|
||||||
|
'id' : 'ipset.' + k + '.' + '1',
|
||||||
|
'data-title': _('Number of entries'),
|
||||||
|
}, v[1]),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
table_ipset.append(
|
ipset = E([
|
||||||
E('div', { 'class': 'tr' }, [
|
E('h3', {}, _('Ipset')),
|
||||||
E('div', {
|
table_ipset,
|
||||||
'class': 'td left',
|
]);
|
||||||
'data-title': _('Name'),
|
};
|
||||||
}, k),
|
|
||||||
E('div', {
|
|
||||||
'class': 'td left',
|
|
||||||
'id': 'ipset.' + k + '.' + '0',
|
|
||||||
'data-title': _('Size in memory'),
|
|
||||||
}, v[0]),
|
|
||||||
E('div', {
|
|
||||||
'class': 'td left',
|
|
||||||
'id': 'ipset.' + k + '.' + '1',
|
|
||||||
'data-title': _('Number of entries'),
|
|
||||||
}, v[1]),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
ipset = E([
|
L.Poll.add(this.infoPoll);
|
||||||
E('h3', {}, _('Ipset')),
|
} else {
|
||||||
table_ipset,
|
update_status = E('em', {}, _('Status') + ' : ' + _('disabled'));
|
||||||
]);
|
};
|
||||||
};
|
};
|
||||||
|
return E([
|
||||||
|
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)
|
||||||
|
),
|
||||||
|
E('div', { 'class': 'cbi-section fade-in' },
|
||||||
|
E('div', { 'class': 'cbi-section-node' }, iptables)
|
||||||
|
),
|
||||||
|
E('div', { 'class': 'cbi-section fade-in' },
|
||||||
|
E('div', { 'class': 'cbi-section-node' }, ipset)
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
L.Poll.add(this.poll_info);
|
handleSave : null,
|
||||||
} else {
|
handleSaveApply: null,
|
||||||
update_status = E('em', {}, _('Status') + ' : ' + _('disabled'));
|
handleReset : null,
|
||||||
};
|
|
||||||
};
|
|
||||||
return E([
|
|
||||||
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)
|
|
||||||
),
|
|
||||||
E('div', { 'class': 'cbi-section fade-in' },
|
|
||||||
E('div', { 'class': 'cbi-section-node' }, iptables)
|
|
||||||
),
|
|
||||||
E('div', { 'class': 'cbi-section fade-in' },
|
|
||||||
E('div', { 'class': 'cbi-section-node' }, ipset)
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSave: null,
|
|
||||||
handleSaveApply: null,
|
|
||||||
handleReset: null,
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ return abc.view.extend({
|
|||||||
|
|
||||||
title: _('Ruantiblock') + ' - ' + _('Log'),
|
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}/),
|
testRegexp : new RegExp(/([0-9]{2}:){2}[0-9]{2}/),
|
||||||
|
|
||||||
isLoggerChecked: false,
|
isLoggerChecked: false,
|
||||||
|
|
||||||
entriesHandler: null,
|
entriesHandler : null,
|
||||||
|
|
||||||
// logd
|
// logd
|
||||||
logdHandler: function(strArray, lineNum) {
|
logdHandler: function(strArray, lineNum) {
|
||||||
@@ -53,8 +53,9 @@ return abc.view.extend({
|
|||||||
let logger = (stat[0]) ? stat[0].path : (stat[1]) ? stat[1].path : null;
|
let logger = (stat[0]) ? stat[0].path : (stat[1]) ? stat[1].path : null;
|
||||||
|
|
||||||
if(logger) {
|
if(logger) {
|
||||||
return fs.exec_direct(logger, [ '-e', tools.app_name ]).catch(err => {
|
return fs.exec_direct(logger, [ '-e', tools.appName ]).catch(err => {
|
||||||
ui.addNotification(null, E('p', {}, _('Unable to load log data:') + ' ' + err.message));
|
ui.addNotification(
|
||||||
|
null, E('p', {}, _('Unable to load log data:') + ' ' + err.message));
|
||||||
return '';
|
return '';
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,342 +4,349 @@
|
|||||||
'require ui';
|
'require ui';
|
||||||
'require view.ruantiblock.tools as tools';
|
'require view.ruantiblock.tools as tools';
|
||||||
|
|
||||||
const btn_style_neutral = 'btn'
|
const btn_style_neutral = 'btn'
|
||||||
const btn_style_action = 'btn cbi-button-action';
|
const btn_style_action = 'btn cbi-button-action';
|
||||||
const btn_style_save = 'btn cbi-button-save important';
|
const btn_style_positive = 'btn cbi-button-save important';
|
||||||
const btn_style_reset = 'btn cbi-button-reset important';
|
const btn_style_negative = 'btn cbi-button-reset important';
|
||||||
const btn_style_warning = 'btn cbi-button-negative important'
|
const btn_style_warning = 'btn cbi-button-negative important'
|
||||||
let status_token_value;
|
|
||||||
|
|
||||||
function disable_buttons(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");
|
|
||||||
let btn_update = elems[4] || document.getElementById("btn_update");
|
|
||||||
let btn_tp = elems[3] || document.getElementById("btn_tp");
|
|
||||||
|
|
||||||
btn_start.disabled = bool;
|
|
||||||
btn_update.disabled = bool;
|
|
||||||
btn_destroy.disabled = bool;
|
|
||||||
if(btn === btn_update) {
|
|
||||||
btn_enable.disabled = false;
|
|
||||||
} else {
|
|
||||||
btn_enable.disabled = bool;
|
|
||||||
};
|
|
||||||
if(btn_tp) {
|
|
||||||
btn_tp.disabled = bool
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_app_status() {
|
|
||||||
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),
|
|
||||||
]).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'
|
|
||||||
)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function set_app_status(status_array, elems=[], force_app_code) {
|
|
||||||
let section = uci.get(tools.app_name, 'config');
|
|
||||||
if(!status_array || typeof(section) !== 'object') {
|
|
||||||
(elems[0] || document.getElementById("status")).innerHTML = tools.make_status_string(1);
|
|
||||||
ui.addNotification(null, E('p', _('Unable to read the contents')
|
|
||||||
+ ': set_app_status()'));
|
|
||||||
disable_buttons(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 proxy_local_clients = section.proxy_local_clients;
|
|
||||||
let proxy_mode = section.proxy_mode;
|
|
||||||
let bllist_mode = section.bllist_mode;
|
|
||||||
let bllist_module = section.bllist_module;
|
|
||||||
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;
|
|
||||||
} else {
|
|
||||||
btn_enable.onclick = ui.createHandlerFn(this, button_action, 'enable');
|
|
||||||
btn_enable.textContent = _('Enable');
|
|
||||||
btn_enable.className = btn_style_save;
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
} else {
|
|
||||||
btn_tp.onclick = ui.createHandlerFn(this, button_action, 'total-proxy-on');
|
|
||||||
btn_tp.textContent = _('Enable');
|
|
||||||
btn_tp.className = btn_style_save;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
function btn_start_state_off() {
|
|
||||||
btn_start.onclick = ui.createHandlerFn(this, button_action, 'start');
|
|
||||||
btn_start.textContent = _('Enable');
|
|
||||||
btn_start.className = btn_style_action;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(app_status_code == 0) {
|
|
||||||
disable_buttons(false, null, elems);
|
|
||||||
btn_start_state_on();
|
|
||||||
btn_destroy.disabled = false;
|
|
||||||
btn_update.disabled = false;
|
|
||||||
if(btn_tp) {
|
|
||||||
btn_tp.disabled = false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if(app_status_code == 2) {
|
|
||||||
disable_buttons(false, null, elems);
|
|
||||||
btn_start_state_off();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
else if(app_status_code == 4) {
|
|
||||||
btn_start_state_on();
|
|
||||||
disable_buttons(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);
|
|
||||||
};
|
|
||||||
|
|
||||||
(elems[0] || document.getElementById("status")).innerHTML = tools.make_status_string(
|
|
||||||
app_status_code,
|
|
||||||
proxy_mode,
|
|
||||||
bllist_mode,
|
|
||||||
bllist_module,
|
|
||||||
bllist_source,
|
|
||||||
tp_status_code,
|
|
||||||
vpn_route_status_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);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return fs.exec_direct(cmd, [ action ]).then(res => {
|
|
||||||
return get_app_status().then(
|
|
||||||
(status_array) => {
|
|
||||||
set_app_status(status_array);
|
|
||||||
ui.hideModal();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return L.view.extend({
|
return L.view.extend({
|
||||||
poll_status: function() {
|
statusTokenValue: null,
|
||||||
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);
|
|
||||||
}
|
|
||||||
status_token_value = v;
|
|
||||||
}).catch(e => {
|
|
||||||
status_token_value = 0;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
dialog_destroy: function(ev) {
|
disableButtons: function(bool, btn, elems=[]) {
|
||||||
ev.target.blur();
|
let btn_start = elems[1] || document.getElementById("btn_start");
|
||||||
let cancel_button = E('button', {
|
let btn_destroy = elems[5] || document.getElementById("btn_destroy");
|
||||||
'class': btn_style_neutral,
|
let btn_enable = elems[2] || document.getElementById("btn_enable");
|
||||||
'click': ui.hideModal,
|
let btn_update = elems[4] || document.getElementById("btn_update");
|
||||||
}, _('Cancel'));
|
let btn_tp = elems[3] || document.getElementById("btn_tp");
|
||||||
|
|
||||||
let shutdown_btn = E('button', {
|
btn_start.disabled = bool;
|
||||||
'class': btn_style_warning,
|
btn_update.disabled = bool;
|
||||||
}, _('Shutdown'));
|
btn_destroy.disabled = bool;
|
||||||
shutdown_btn.onclick = ui.createHandlerFn(this, function() {
|
if(btn === btn_update) {
|
||||||
cancel_button.disabled = true;
|
btn_enable.disabled = false;
|
||||||
return button_action('destroy');
|
} else {
|
||||||
});
|
btn_enable.disabled = bool;
|
||||||
|
};
|
||||||
|
if(btn_tp) {
|
||||||
|
btn_tp.disabled = bool;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
ui.showModal(_('Shutdown'), [
|
getAppStatus: function() {
|
||||||
E('div', { 'class': 'cbi-section' }, [
|
return Promise.all([
|
||||||
E('p', _('The service will be disabled and all blacklist data will be deleted. Continue?')),
|
fs.exec(tools.execPath, [ 'raw-status' ]),
|
||||||
]),
|
fs.exec(tools.execPath, [ 'total-proxy-status' ]),
|
||||||
E('div', { 'class': 'right' }, [
|
fs.exec(tools.execPath, [ 'vpn-route-status' ]),
|
||||||
shutdown_btn,
|
tools.getInitStatus(tools.appName),
|
||||||
' ',
|
L.resolveDefault(fs.read(tools.tokenFile), 0),
|
||||||
cancel_button,
|
uci.load(tools.appName),
|
||||||
])
|
]).catch(e => {
|
||||||
]);
|
ui.addNotification(null, E('p', _('Unable to execute or read contents')
|
||||||
},
|
+ ': %s [ %s | %s | %s ]'.format(
|
||||||
|
e.message, tools.execPath, 'tools.getInitStatus', 'uci.ruantiblock'
|
||||||
|
)));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
load: function() {
|
setAppStatus: function(status_array, elems=[], force_app_code) {
|
||||||
return get_app_status();
|
let section = uci.get(tools.appName, 'config');
|
||||||
},
|
if(!status_array || typeof(section) !== 'object') {
|
||||||
|
(elems[0] || document.getElementById("status")).innerHTML = tools.makeStatusString(1);
|
||||||
|
ui.addNotification(null, E('p', _('Unable to read the contents')
|
||||||
|
+ ': setAppStatus()'));
|
||||||
|
this.disableButtons(true, null, elems);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
render: function(status_array) {
|
let app_status_code = (force_app_code) ? force_app_code : status_array[0].code;
|
||||||
if(!status_array) {
|
let tp_status_code = status_array[1].code;
|
||||||
return;
|
let vpn_route_status_code = status_array[2].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;
|
||||||
|
let bllist_module = section.bllist_module;
|
||||||
|
let bllist_source = section.bllist_source;
|
||||||
|
|
||||||
let section = uci.get(tools.app_name, 'config');
|
let btn_enable = elems[2] || document.getElementById('btn_enable');
|
||||||
let proxy_local_clients = (typeof(section) === 'object') ? section.proxy_local_clients : null;
|
if(enabled_flag == true) {
|
||||||
status_token_value = (Array.isArray(status_array)) ? tools.normalize_value(status_array[4]) : null;
|
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, this.serviceAction, 'enable', 'btn_enable');
|
||||||
|
btn_enable.textContent = _('Disabled');
|
||||||
|
btn_enable.className = btn_style_negative;
|
||||||
|
};
|
||||||
|
|
||||||
let status_string = E('div', {
|
let btn_tp = elems[3] || document.getElementById('btn_tp');
|
||||||
'id': 'status',
|
if(btn_tp) {
|
||||||
'name': 'status',
|
if(tp_status_code == 0) {
|
||||||
'class': 'cbi-section-node',
|
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, this.appAction, 'total-proxy-on', 'btn_tp');
|
||||||
|
btn_tp.textContent = _('Disabled');
|
||||||
|
btn_tp.className = btn_style_negative;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
let layout = E('div', { 'class': 'cbi-section-node' });
|
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 layout_append(elem, title, descr) {
|
let btnStartStateOn = () => {
|
||||||
descr = (descr) ? E('div', { 'class': 'cbi-value-description' }, descr) : '';
|
btn_start.onclick = ui.createHandlerFn(
|
||||||
layout.append(
|
this, this.serviceAction, 'stop', 'btn_start');
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
btn_start.textContent = _('Enabled');
|
||||||
E('label', { 'class': 'cbi-value-title' }, title),
|
btn_start.className = btn_style_positive;
|
||||||
E('div', { 'class': 'cbi-value-field' }, [ elem, descr ]),
|
}
|
||||||
])
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let btn_start = E('button', {
|
let btnStartStateOff = () => {
|
||||||
'id': 'btn_start',
|
btn_start.onclick = ui.createHandlerFn(
|
||||||
'name': 'btn_start',
|
this, this.serviceAction,'start', 'btn_start');
|
||||||
'class': btn_style_action,
|
btn_start.textContent = _('Disabled');
|
||||||
}, _('Enable'));
|
btn_start.className = btn_style_negative;
|
||||||
layout_append(btn_start, _('Service'));
|
}
|
||||||
|
|
||||||
let btn_enable = E('button', {
|
if(app_status_code == 0) {
|
||||||
'id': 'btn_enable',
|
this.disableButtons(false, null, elems);
|
||||||
'name': 'btn_enable',
|
btnStartStateOn();
|
||||||
'class': btn_style_save,
|
btn_destroy.disabled = false;
|
||||||
}, _('Enable'));
|
btn_update.disabled = false;
|
||||||
layout_append(btn_enable, _('Run at startup'));
|
if(btn_tp) {
|
||||||
|
btn_tp.disabled = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if(app_status_code == 2) {
|
||||||
|
this.disableButtons(false, null, elems);
|
||||||
|
btnStartStateOff();
|
||||||
|
btn_update.disabled = true;
|
||||||
|
if(btn_tp) {
|
||||||
|
btn_tp.disabled = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if(app_status_code == 3) {
|
||||||
|
btnStartStateOff();
|
||||||
|
this.disableButtons(true, btn_start, elems);
|
||||||
|
}
|
||||||
|
else if(app_status_code == 4) {
|
||||||
|
btnStartStateOn();
|
||||||
|
this.disableButtons(true, btn_update, elems);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ui.addNotification(null, E('p', _('Error')
|
||||||
|
+ ' %s: return code = %s'.format(tools.execPath, app_status_code)));
|
||||||
|
this.disableButtons(true, null, elems);
|
||||||
|
};
|
||||||
|
|
||||||
let btn_tp = E('button', {
|
(elems[0] || document.getElementById("status")).innerHTML = tools.makeStatusString(
|
||||||
'id': 'btn_tp',
|
app_status_code,
|
||||||
'name': 'btn_tp',
|
proxy_mode,
|
||||||
'class': btn_style_save,
|
bllist_mode,
|
||||||
}, _('Enable'));
|
bllist_module,
|
||||||
if(proxy_local_clients == '0') {
|
bllist_source,
|
||||||
layout_append(btn_tp, _('Total-proxy'),
|
tp_status_code,
|
||||||
_('All traffic goes through the proxy without applying rules'));
|
vpn_route_status_code);
|
||||||
};
|
|
||||||
|
|
||||||
let btn_update = E('button', {
|
if(!L.Poll.active()) {
|
||||||
'id': 'btn_update',
|
L.Poll.start();
|
||||||
'name': 'btn_update',
|
};
|
||||||
'class': btn_style_action,
|
},
|
||||||
}, _('Update'));
|
|
||||||
btn_update.onclick = ui.createHandlerFn(this, () => { button_action('update') });
|
|
||||||
layout_append(btn_update, _('Update blacklist'));
|
|
||||||
|
|
||||||
let btn_destroy = E('button', {
|
serviceAction: function(action, button) {
|
||||||
'id': 'btn_destroy',
|
if(button) {
|
||||||
'name': 'btn_destroy',
|
let elem = document.getElementById(button);
|
||||||
'class': btn_style_reset,
|
this.disableButtons(true, elem);
|
||||||
}, _('Shutdown'));
|
};
|
||||||
btn_destroy.onclick = this.dialog_destroy;
|
|
||||||
|
|
||||||
layout_append(btn_destroy, _('Shutdown'),
|
L.Poll.stop();
|
||||||
_('Complete service shutdown, as well as deleting ipsets and blacklist data'));
|
|
||||||
|
|
||||||
set_app_status(status_array, [
|
return tools.handleServiceAction(tools.appName, action).then(() => {
|
||||||
status_string,
|
return this.getAppStatus().then(
|
||||||
btn_start,
|
(status_array) => {
|
||||||
btn_enable,
|
this.setAppStatus(status_array);
|
||||||
btn_tp,
|
}
|
||||||
btn_update,
|
);
|
||||||
btn_destroy,
|
});
|
||||||
]);
|
},
|
||||||
|
|
||||||
L.Poll.add(this.poll_status);
|
appAction: function(action, button) {
|
||||||
|
if(button) {
|
||||||
|
let elem = document.getElementById(button);
|
||||||
|
this.disableButtons(true, elem);
|
||||||
|
};
|
||||||
|
|
||||||
return E([
|
L.Poll.stop();
|
||||||
E('h2', { 'class': 'fade-in' }, _('Ruantiblock')),
|
|
||||||
E('div', { 'class': 'cbi-section-descr fade-in' },
|
|
||||||
E('a', {
|
|
||||||
'href': 'https://github.com/gSpotx2f/ruantiblock_openwrt/wiki',
|
|
||||||
'target': '_blank' },
|
|
||||||
'https://github.com/gSpotx2f/ruantiblock_openwrt/wiki')
|
|
||||||
),
|
|
||||||
E('div', { 'class': 'cbi-section fade-in' }, [
|
|
||||||
status_string,
|
|
||||||
E('hr'),
|
|
||||||
]),
|
|
||||||
E('div', { 'class': 'cbi-section fade-in' },
|
|
||||||
layout
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSave: null,
|
if(action === 'update') {
|
||||||
handleSaveApply: null,
|
this.getAppStatus().then(status_array => {
|
||||||
handleReset: null,
|
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,
|
||||||
|
'click': ui.hideModal,
|
||||||
|
}, _('Cancel'));
|
||||||
|
|
||||||
|
let shutdown_btn = E('button', {
|
||||||
|
'class': btn_style_warning,
|
||||||
|
}, _('Shutdown'));
|
||||||
|
shutdown_btn.onclick = ui.createHandlerFn(this, () => {
|
||||||
|
cancel_button.disabled = true;
|
||||||
|
return this.appAction('destroy');
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.showModal(_('Shutdown'), [
|
||||||
|
E('div', { 'class': 'cbi-section' }, [
|
||||||
|
E('p', _('The service will be disabled and all blacklist data will be deleted. Continue?')),
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'right' }, [
|
||||||
|
shutdown_btn,
|
||||||
|
' ',
|
||||||
|
cancel_button,
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
|
load: function() {
|
||||||
|
return this.getAppStatus();
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function(status_array) {
|
||||||
|
if(!status_array) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
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',
|
||||||
|
'name' : 'status',
|
||||||
|
'class': 'cbi-section-node',
|
||||||
|
});
|
||||||
|
|
||||||
|
let layout = E('div', { 'class': 'cbi-section-node' });
|
||||||
|
|
||||||
|
function layout_append(elem, title, descr) {
|
||||||
|
descr = (descr) ? E('div', { 'class': 'cbi-value-description' }, descr) : '';
|
||||||
|
layout.append(
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, title),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, [ elem, descr ]),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let btn_start = E('button', {
|
||||||
|
'id' : 'btn_start',
|
||||||
|
'name' : 'btn_start',
|
||||||
|
'class': btn_style_action,
|
||||||
|
}, _('Enable'));
|
||||||
|
layout_append(btn_start, _('Service'));
|
||||||
|
|
||||||
|
let btn_enable = E('button', {
|
||||||
|
'id' : 'btn_enable',
|
||||||
|
'name' : 'btn_enable',
|
||||||
|
'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_positive,
|
||||||
|
}, _('Enable'));
|
||||||
|
if(proxy_local_clients == '0') {
|
||||||
|
layout_append(btn_tp, _('Total-proxy'),
|
||||||
|
_('All traffic goes through the proxy without applying rules'));
|
||||||
|
};
|
||||||
|
|
||||||
|
let btn_update = E('button', {
|
||||||
|
'id' : 'btn_update',
|
||||||
|
'name' : 'btn_update',
|
||||||
|
'class': btn_style_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_negative,
|
||||||
|
}, _('Shutdown'));
|
||||||
|
btn_destroy.onclick = L.bind(this.dialogDestroy, this);
|
||||||
|
|
||||||
|
layout_append(btn_destroy, _('Shutdown'),
|
||||||
|
_('Complete service shutdown, as well as deleting ipsets and blacklist data'));
|
||||||
|
|
||||||
|
this.setAppStatus(status_array, [
|
||||||
|
status_string,
|
||||||
|
btn_start,
|
||||||
|
btn_enable,
|
||||||
|
btn_tp,
|
||||||
|
btn_update,
|
||||||
|
btn_destroy,
|
||||||
|
]);
|
||||||
|
|
||||||
|
L.Poll.add(L.bind(this.statusPoll, this));
|
||||||
|
|
||||||
|
return E([
|
||||||
|
E('h2', { 'class': 'fade-in' }, _('Ruantiblock')),
|
||||||
|
E('div', { 'class': 'cbi-section-descr fade-in' },
|
||||||
|
E('a', {
|
||||||
|
'href': 'https://github.com/gSpotx2f/ruantiblock_openwrt/wiki',
|
||||||
|
'target': '_blank' },
|
||||||
|
'https://github.com/gSpotx2f/ruantiblock_openwrt/wiki')
|
||||||
|
),
|
||||||
|
E('div', { 'class': 'cbi-section fade-in' }, [
|
||||||
|
status_string,
|
||||||
|
E('hr'),
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'cbi-section fade-in' },
|
||||||
|
layout
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSave : null,
|
||||||
|
handleSaveApply: null,
|
||||||
|
handleReset : null,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,393 +6,354 @@
|
|||||||
'require tools.widgets as widgets';
|
'require tools.widgets as widgets';
|
||||||
'require view.ruantiblock.tools as tools';
|
'require view.ruantiblock.tools as tools';
|
||||||
|
|
||||||
let available_parsers = [];
|
|
||||||
|
|
||||||
function depends(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);
|
|
||||||
};
|
|
||||||
|
|
||||||
function validate_ip_port(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({
|
|
||||||
string: null,
|
|
||||||
|
|
||||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
|
||||||
this.title = this.description = null;
|
|
||||||
return E([
|
|
||||||
E('label', { 'class': 'cbi-value-title' }),
|
|
||||||
E('div', { 'class': 'cbi-value-field' },
|
|
||||||
E('b', {}, this.string)
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
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({
|
return L.view.extend({
|
||||||
app_status_code: null,
|
availableParsers: {},
|
||||||
|
|
||||||
load: function() {
|
appStatusCode : null,
|
||||||
return Promise.all([
|
|
||||||
L.resolveDefault(fs.exec(tools.exec_path, [ 'raw-status' ]), 1),
|
|
||||||
fs.list(tools.parsers_dir),
|
|
||||||
uci.load('network'),
|
|
||||||
]).catch(e => {
|
|
||||||
ui.addNotification(null, E('p', _('Unable to read the contents')
|
|
||||||
+ ': %s<br />[ %s ]'.format(
|
|
||||||
e.message, tools.parsers_dir
|
|
||||||
)));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function(data) {
|
depends: function(elem, key, array, empty=true) {
|
||||||
if(!data) {
|
if(empty && array.length === 0) {
|
||||||
return;
|
elem.depends(key, '_dummy');
|
||||||
};
|
} else {
|
||||||
this.app_status_code = data[0].code;
|
array.forEach(e => elem.depends(key, e));
|
||||||
let p_dir_arr = data[1];
|
};
|
||||||
let lan_iface = uci.get('network', 'lan', 'ifname') || 'eth0';
|
},
|
||||||
let vpn_iface = uci.get('network', 'VPN', 'ifname') || 'tun0';
|
|
||||||
|
|
||||||
if(p_dir_arr) {
|
dependsBllistModule: function(elem) {
|
||||||
p_dir_arr.forEach(e => {
|
this.depends(elem, 'bllist_module', Object.values(this.availableParsers));
|
||||||
let fname = e.name;
|
},
|
||||||
if(fname.startsWith('ruab_parser')) {
|
|
||||||
available_parsers.push(tools.parsers_dir + '/' + fname);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
let m, s, o;
|
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`;
|
||||||
|
},
|
||||||
|
|
||||||
m = new form.Map(tools.app_name, _('Ruantiblock') + ' - ' + _('Settings'));
|
CBIBlockTitle: form.DummyValue.extend({
|
||||||
|
string: null,
|
||||||
|
|
||||||
s = m.section(form.NamedSection, 'config');
|
renderWidget: function(section_id, option_index, cfgvalue) {
|
||||||
s.anonymous = true;
|
this.title = this.description = null;
|
||||||
s.addremove = false;
|
return E([
|
||||||
|
E('label', { 'class': 'cbi-value-title' }),
|
||||||
|
E('div', { 'class': 'cbi-value-field' },
|
||||||
|
E('b', {}, this.string)
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
/* Main settings tab */
|
load: function() {
|
||||||
|
return Promise.all([
|
||||||
|
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 [ %s ]'.format(
|
||||||
|
e.message, tools.parsersDir
|
||||||
|
)));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
s.tab('main_settings', _('Main settings'));
|
render: function(data) {
|
||||||
|
if(!data) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
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';
|
||||||
|
|
||||||
// PROXY_MODE
|
if(p_dir_arr) {
|
||||||
if(this.app_status_code == 1 || this.app_status_code == 2) {
|
p_dir_arr.forEach(e => {
|
||||||
o = s.taboption('main_settings', form.ListValue, 'proxy_mode',
|
let fname = e.name;
|
||||||
_('Proxy mode'));
|
if(fname.startsWith('ruab_parser')) {
|
||||||
o.value('1', 'Tor');
|
this.availableParsers[fname] = tools.parsersDir + '/' + fname;
|
||||||
o.value('2', 'VPN');
|
};
|
||||||
};
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// PROXY_LOCAL_CLIENTS
|
let ip_filter_edit = new tools.fileEditDialog(
|
||||||
let proxy_local_clients = s.taboption('main_settings', form.Flag, 'proxy_local_clients',
|
tools.ipFilterFile,
|
||||||
_("Apply proxy rules to router application traffic"));
|
_('IP filter'),
|
||||||
proxy_local_clients.rmempty = false;
|
_('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):') +
|
||||||
proxy_local_clients.default = proxy_local_clients.enabled;
|
'<br /><code>128[.]199[.]0[.]0/16<br />34[.]217[.]90[.]52<br />162[.]13[.]190[.]</code>'
|
||||||
|
);
|
||||||
|
|
||||||
// USE_LOGGER
|
let fqdn_filter_edit = new tools.fileEditDialog(
|
||||||
o = s.taboption('main_settings', form.Flag, 'use_logger',
|
tools.fqdnFilterFile,
|
||||||
_('Logging events'));
|
_('FQDN filter'),
|
||||||
o.rmempty = false;
|
_('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:') +
|
||||||
o.default = 1;
|
'<br /><code>poker<br />[ck]?a[sz]ino?<br />[vw]ulkan<br />slots?</code>'
|
||||||
|
);
|
||||||
|
|
||||||
// DEF_TOTAL_PROXY
|
let user_entries_edit = new tools.fileEditDialog(
|
||||||
o = s.taboption('main_settings', form.Flag, 'def_total_proxy',
|
tools.userEntriesFile,
|
||||||
_("Enable the 'total-proxy' option at startup"));
|
_('User entries'),
|
||||||
o.rmempty = false;
|
_('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:') +
|
||||||
o.default = 0;
|
'<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>'
|
||||||
o.depends('proxy_local_clients', '0');
|
);
|
||||||
|
|
||||||
// IPSET_CLEAR_SETS
|
let torrc_edit = new tools.fileEditDialog(
|
||||||
o = s.taboption('main_settings', form.Flag, 'ipset_clear_sets',
|
tools.torrcFile,
|
||||||
_('Clean up ipsets before updating blacklist'));
|
_('Tor configuration file'),
|
||||||
o.description = _('Reduces RAM consumption during update');
|
null,
|
||||||
o.rmempty = false;
|
function(rc) {
|
||||||
o.default = 0;
|
return tools.getInitStatus('tor').then(res => {
|
||||||
|
if(res) {
|
||||||
|
return tools.handleServiceAction('tor', 'restart');
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let m, s, o;
|
||||||
|
|
||||||
|
m = new form.Map(tools.appName, _('Ruantiblock') + ' - ' + _('Settings'));
|
||||||
|
|
||||||
|
s = m.section(form.NamedSection, 'config');
|
||||||
|
s.anonymous = true;
|
||||||
|
s.addremove = false;
|
||||||
|
|
||||||
|
/* Main settings tab */
|
||||||
|
|
||||||
|
s.tab('main_settings', _('Main settings'));
|
||||||
|
|
||||||
|
// PROXY_MODE
|
||||||
|
if(this.appStatusCode == 1 || this.appStatusCode == 2) {
|
||||||
|
o = s.taboption('main_settings', form.ListValue, 'proxy_mode',
|
||||||
|
_('Proxy mode'));
|
||||||
|
o.value('1', 'Tor');
|
||||||
|
o.value('2', 'VPN');
|
||||||
|
};
|
||||||
|
|
||||||
|
// PROXY_LOCAL_CLIENTS
|
||||||
|
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;
|
||||||
|
|
||||||
|
// USE_LOGGER
|
||||||
|
o = s.taboption('main_settings', form.Flag, 'use_logger',
|
||||||
|
_('Logging events'));
|
||||||
|
o.rmempty = false;
|
||||||
|
|
||||||
|
// DEF_TOTAL_PROXY
|
||||||
|
o = s.taboption('main_settings', form.Flag, 'def_total_proxy',
|
||||||
|
_("Enable the 'total-proxy' option at startup"));
|
||||||
|
o.rmempty = false;
|
||||||
|
o.default = 0;
|
||||||
|
o.depends('proxy_local_clients', '0');
|
||||||
|
|
||||||
|
// IPSET_CLEAR_SETS
|
||||||
|
o = s.taboption('main_settings', form.Flag, 'ipset_clear_sets',
|
||||||
|
_('Clean up ipsets before updating blacklist'));
|
||||||
|
o.description = _('Reduces RAM consumption during update');
|
||||||
|
o.rmempty = false;
|
||||||
|
|
||||||
|
|
||||||
if(this.app_status_code == 1 || this.app_status_code == 2) {
|
if(this.appStatusCode == 1 || this.appStatusCode == 2) {
|
||||||
/* Tor tab */
|
/* Tor tab */
|
||||||
|
|
||||||
s.tab('tor_settings', _('Tor mode'));
|
s.tab('tor_settings', _('Tor mode'));
|
||||||
|
|
||||||
// IF_LAN
|
// IF_LAN
|
||||||
o = s.taboption('tor_settings', widgets.DeviceSelect, 'if_lan',
|
o = s.taboption('tor_settings', widgets.DeviceSelect, 'if_lan',
|
||||||
_('LAN interface'));
|
_('LAN interface'));
|
||||||
o.multiple = false;
|
o.multiple = false;
|
||||||
o.noaliases = true;
|
o.noaliases = true;
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.default = lan_iface;
|
o.default = lan_iface;
|
||||||
|
|
||||||
// TOR_TRANS_PORT
|
// TOR_TRANS_PORT
|
||||||
o = s.taboption('tor_settings', form.Value, 'tor_trans_port',
|
o = s.taboption('tor_settings', form.Value, 'tor_trans_port',
|
||||||
_('Transparent proxy port for iptables rules'));
|
_('Transparent proxy port for iptables rules'));
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.datatype = "port";
|
o.datatype = "port";
|
||||||
o.default = '9040';
|
|
||||||
|
|
||||||
// ONION_DNS_ADDR
|
// ONION_DNS_ADDR
|
||||||
o = s.taboption('tor_settings', form.Value, 'onion_dns_addr',
|
o = s.taboption('tor_settings', form.Value, 'onion_dns_addr',
|
||||||
_("Optional DNS resolver for '.onion' zone"), '<code>ipaddress#port</code>');
|
_("Optional DNS resolver for '.onion' zone"), '<code>ipaddress#port</code>');
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.default = '127.0.0.1#9053';
|
o.validate = this.validateIpPort;
|
||||||
o.validate = validate_ip_port;
|
|
||||||
|
|
||||||
// Torrc edit dialog
|
// Torrc edit dialog
|
||||||
o = s.taboption('tor_settings', form.Button, '_torrc_btn',
|
o = s.taboption('tor_settings', form.Button, '_torrc_btn',
|
||||||
_('Tor configuration file'));
|
_('Tor configuration file'));
|
||||||
o.onclick = () => torrc_edit.show();
|
o.onclick = () => torrc_edit.show();
|
||||||
o.inputtitle = _('Edit');
|
o.inputtitle = _('Edit');
|
||||||
o.inputstyle = 'edit btn';
|
o.inputstyle = 'edit btn';
|
||||||
|
|
||||||
|
|
||||||
/* VPN tab */
|
/* VPN tab */
|
||||||
|
|
||||||
s.tab('vpn_settings', _('VPN mode'));
|
s.tab('vpn_settings', _('VPN mode'));
|
||||||
|
|
||||||
// IF_VPN
|
// IF_VPN
|
||||||
o = s.taboption('vpn_settings', widgets.DeviceSelect, 'if_vpn',
|
o = s.taboption('vpn_settings', widgets.DeviceSelect, 'if_vpn',
|
||||||
_('VPN interface'));
|
_('VPN interface'));
|
||||||
o.multiple = false;
|
o.multiple = false;
|
||||||
o.noaliases = true;
|
o.noaliases = true;
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.default = vpn_iface;
|
o.default = vpn_iface;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Parser settings tab */
|
/* Parser settings tab */
|
||||||
|
|
||||||
s.tab('parser_settings', _('Blacklist settings'));
|
s.tab('parser_settings', _('Blacklist settings'));
|
||||||
|
|
||||||
// BLLIST_MODULE
|
// BLLIST_MODULE
|
||||||
let bllist_module = s.taboption('parser_settings', form.ListValue,
|
let bllist_module = s.taboption('parser_settings', form.ListValue,
|
||||||
'bllist_module', _('Blacklist module'));
|
'bllist_module', _('Blacklist module'));
|
||||||
bllist_module.value("", _("user entries only"));
|
bllist_module.value('', _('none (user entries only)'));
|
||||||
available_parsers.forEach(e => bllist_module.value(e));
|
Object.entries(this.availableParsers).forEach(
|
||||||
|
e => bllist_module.value(e[1], e[0]));
|
||||||
|
|
||||||
// BLLIST_MODE
|
// BLLIST_MODE
|
||||||
let bllist_mode = s.taboption('parser_settings', form.ListValue,
|
let bllist_mode = s.taboption('parser_settings', form.ListValue,
|
||||||
'bllist_mode', _('Module operation mode'));
|
'bllist_mode', _('Module operation mode'));
|
||||||
bllist_mode.value('ip');
|
bllist_mode.value('ip');
|
||||||
bllist_mode.value('fqdn');
|
bllist_mode.value('fqdn');
|
||||||
depends_bllist_module(bllist_mode);
|
|
||||||
|
|
||||||
// BLLIST_SOURCE
|
// BLLIST_SOURCE
|
||||||
let bllist_source = s.taboption('parser_settings', form.ListValue,
|
let bllist_source = s.taboption('parser_settings', form.ListValue,
|
||||||
'bllist_source', _('Blacklist source'));
|
'bllist_source', _('Blacklist source'));
|
||||||
bllist_source.description = _("Options") + ':';
|
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.value(k);
|
||||||
bllist_source.description += `<br />${k} - <a href="${v}" target="_blank">${v}</a>`;
|
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') + ':';
|
o.string = _('IP configuration') + ':';
|
||||||
depends_bllist_module(o);
|
|
||||||
|
|
||||||
// IP_LIMIT
|
// IP_LIMIT
|
||||||
o = s.taboption('parser_settings', form.Value, 'ip_limit', _("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.description = _("The number of IP addresses in the subnet, upon reaching which the entire '/24' subnet is added to the list");
|
||||||
o.datatype = 'uinteger';
|
o.rmempty = false;
|
||||||
o.default = '0';
|
o.datatype = 'uinteger';
|
||||||
depends_bllist_module(o);
|
|
||||||
|
|
||||||
// OPT_EXCLUDE_NETS
|
// OPT_EXCLUDE_NETS
|
||||||
o = s.taboption('parser_settings', form.DynamicList, '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.title = _('IP subnet patterns (/24) that are excluded from optimization');
|
||||||
o.description = _('e.g:') + ' <code>192.168.1.</code>';
|
o.description = _('e.g:') + ' <code>192.168.1.</code>';
|
||||||
o.placeholder = _('e.g:') + ' 192.168.1.';
|
o.placeholder = _('e.g:') + ' 192.168.1.';
|
||||||
o.default = '';
|
o.validate = (section, value) => {
|
||||||
|
return (/^$|^([0-9]{1,3}[.]){3}$/.test(value)) ? true : _('Expecting:')
|
||||||
|
+ ' ' + _('net pattern') + ' (' + _('e.g:') + ' 192.168.3.)\n';
|
||||||
|
};
|
||||||
|
|
||||||
depends_bllist_module(o);
|
// SUMMARIZE_IP
|
||||||
|
o = s.taboption('parser_settings', form.Flag, 'summarize_ip',
|
||||||
|
_("Summarize IP ranges"));
|
||||||
|
o.rmempty = false;
|
||||||
|
|
||||||
// SUMMARIZE_IP
|
// SUMMARIZE_CIDR
|
||||||
o = s.taboption('parser_settings', form.Flag, 'summarize_ip',
|
o = s.taboption('parser_settings', form.Flag, 'summarize_cidr',
|
||||||
_("Summarize IP ranges"));
|
_("Summarize '/24' networks"));
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.default = 0;
|
|
||||||
depends_bllist_module(o);
|
|
||||||
|
|
||||||
// SUMMARIZE_CIDR
|
o = s.taboption('parser_settings', this.CBIBlockTitle, '_dummy_fqdn');
|
||||||
o = s.taboption('parser_settings', form.Flag, 'summarize_cidr',
|
o.string = _('FQDN configuration') + ':';
|
||||||
_("Summarize '/24' networks"));
|
|
||||||
o.rmempty = false;
|
|
||||||
o.default = 0;
|
|
||||||
depends_bllist_module(o);
|
|
||||||
|
|
||||||
o = s.taboption('parser_settings', CBIBlockTitle, '_dummy_fqdn');
|
// SD_LIMIT
|
||||||
o.string = _('FQDN configuration') + ':';
|
o = s.taboption('parser_settings', form.Value, 'sd_limit',
|
||||||
depends_bllist_module(o);
|
_("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';
|
||||||
|
|
||||||
// SD_LIMIT
|
// OPT_EXCLUDE_SLD
|
||||||
o = s.taboption('parser_settings', form.Value, 'sd_limit',
|
o = s.taboption('parser_settings', form.DynamicList, 'opt_exclude_sld',
|
||||||
_("Subdomains limit"));
|
_('2nd level domains that are excluded from optimization'));
|
||||||
o.description = _('The number of subdomains in the domain, upon reaching which the entire 2nd level domain is added to the list');
|
o.description = _('e.g:') + ' <code>livejournal.com</code>';
|
||||||
o.datatype = 'uinteger';
|
o.placeholder = _('e.g:') + ' livejournal.com';
|
||||||
o.default = '16';
|
o.datatype = "hostname";
|
||||||
depends_bllist_module(o);
|
|
||||||
|
|
||||||
// OPT_EXCLUDE_SLD
|
// USE_IDN
|
||||||
o = s.taboption('parser_settings', form.DynamicList, 'opt_exclude_sld',
|
o = s.taboption('parser_settings', form.Flag, 'use_idn',
|
||||||
_('2nd level domains that are excluded from optimization'));
|
_("Convert cyrillic domains to punycode"));
|
||||||
o.datatype = "hostname";
|
o.rmempty = false;
|
||||||
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
|
// ALT_NSLOOKUP
|
||||||
o = s.taboption('parser_settings', form.Flag, 'use_idn',
|
o = s.taboption('parser_settings', form.Flag, 'alt_nslookup',
|
||||||
_("Convert cyrillic domains to punycode"));
|
_('Use optional DNS resolver'));
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.default = 0;
|
|
||||||
depends_bllist_module(o);
|
|
||||||
|
|
||||||
// ALT_NSLOOKUP
|
// ALT_DNS_ADDR
|
||||||
o = s.taboption('parser_settings', form.Flag, 'alt_nslookup',
|
o = s.taboption('parser_settings', form.Value, 'alt_dns_addr',
|
||||||
_('Use optional DNS resolver'));
|
_("Optional DNS resolver"), '<code>ipaddress[#port]</code>');
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.default = 0;
|
o.validate = this.validateIpPort;
|
||||||
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';
|
|
||||||
|
|
||||||
|
|
||||||
/* Entries filters tab */
|
/* Blacklist entry filters tab */
|
||||||
|
|
||||||
s.tab('entries_filter_tab', _('Entries filters'));
|
s.tab('entries_filter_tab', _('Blacklist entry filters'));
|
||||||
|
|
||||||
// IP_FILTER
|
// IP_FILTER
|
||||||
o = s.taboption('entries_filter_tab', form.Flag, 'ip_filter',
|
o = s.taboption('entries_filter_tab', form.Flag, 'ip_filter',
|
||||||
_("Enable IP filter"));
|
_("Enable IP filter"));
|
||||||
o.description = _('Exclude IP addresses from blacklist by IP filter patterns');
|
o.description = _('Exclude IP addresses from blacklist by IP filter patterns');
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.default = 0;
|
|
||||||
depends_bllist_module(o);
|
|
||||||
|
|
||||||
// IP_FILTER edit dialog
|
// IP_FILTER edit dialog
|
||||||
o = s.taboption('entries_filter_tab', form.Button, '_ip_filter_btn',
|
o = s.taboption('entries_filter_tab', form.Button, '_ip_filter_btn',
|
||||||
_("IP filter"));
|
_("IP filter"));
|
||||||
o.onclick = () => ip_filter_edit.show();
|
o.onclick = () => ip_filter_edit.show();
|
||||||
o.inputtitle = _('Edit');
|
o.inputtitle = _('Edit');
|
||||||
o.inputstyle = 'edit btn';
|
o.inputstyle = 'edit btn';
|
||||||
depends_bllist_module(o);
|
|
||||||
|
|
||||||
// FQDN_FILTER
|
// FQDN_FILTER
|
||||||
o = s.taboption('entries_filter_tab', form.Flag, 'fqdn_filter',
|
o = s.taboption('entries_filter_tab', form.Flag, 'fqdn_filter',
|
||||||
_("Enable FQDN filter"));
|
_("Enable FQDN filter"));
|
||||||
o.description = _('Exclude domains from blacklist by FQDN filter patterns');
|
o.description = _('Exclude domains from blacklist by FQDN filter patterns');
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.default = 0;
|
|
||||||
depends_bllist_module(o);
|
|
||||||
|
|
||||||
// FQDN_FILTER edit dialog
|
// FQDN_FILTER edit dialog
|
||||||
o = s.taboption('entries_filter_tab', form.Button, '_fqdn_filter_btn',
|
o = s.taboption('entries_filter_tab', form.Button, '_fqdn_filter_btn',
|
||||||
_("FQDN filter"));
|
_("FQDN filter"));
|
||||||
o.onclick = () => fqdn_filter_edit.show();
|
o.onclick = () => fqdn_filter_edit.show();
|
||||||
o.inputtitle = _('Edit');
|
o.inputtitle = _('Edit');
|
||||||
o.inputstyle = 'edit btn';
|
o.inputstyle = 'edit btn';
|
||||||
depends_bllist_module(o);
|
|
||||||
|
|
||||||
|
|
||||||
/* User entries tab */
|
/* User entries tab */
|
||||||
|
|
||||||
s.tab('user_entries_tab', _('User entries'));
|
s.tab('user_entries_tab', _('User entries'));
|
||||||
|
|
||||||
// ADD_USER_ENTRIES
|
// ADD_USER_ENTRIES
|
||||||
o = s.taboption('user_entries_tab', form.Flag, 'add_user_entries',
|
o = s.taboption('user_entries_tab', form.Flag, 'add_user_entries',
|
||||||
_('Enable'), _("Add user entries to the blacklist when updating"));
|
_('Enable'), _("Add user entries to the blacklist when updating"));
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.default = 0;
|
o.default = 0;
|
||||||
depends_bllist_module(o);
|
this.dependsBllistModule(o);
|
||||||
|
|
||||||
// USER_ENTRIES_DNS
|
// USER_ENTRIES_DNS
|
||||||
o = s.taboption('user_entries_tab', form.Value, '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>');
|
_("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
|
// USER_ENTRIES edit dialog
|
||||||
o = s.taboption('user_entries_tab', form.Button, '_user_entries_btn',
|
o = s.taboption('user_entries_tab', form.Button, '_user_entries_btn',
|
||||||
_('User entries'));
|
_('User entries'));
|
||||||
o.onclick = () => user_entries_edit.show();
|
o.onclick = () => user_entries_edit.show();
|
||||||
o.inputtitle = _('Edit');
|
o.inputtitle = _('Edit');
|
||||||
o.inputstyle = 'edit btn';
|
o.inputstyle = 'edit btn';
|
||||||
|
|
||||||
|
let map_promise = m.render();
|
||||||
|
map_promise.then(node => node.classList.add('fade-in'));
|
||||||
|
return map_promise;
|
||||||
|
},
|
||||||
|
|
||||||
let map_promise = m.render();
|
handleSaveApply: function(ev, mode) {
|
||||||
map_promise.then(node => node.classList.add('fade-in'));
|
return this.handleSave(ev).then(() => {
|
||||||
|
ui.changes.apply(mode == '0');
|
||||||
|
|
||||||
return map_promise;
|
if(this.appStatusCode != 1 && this.appStatusCode != 2) {
|
||||||
},
|
window.setTimeout(() => tools.handleServiceAction(
|
||||||
|
tools.appName, 'restart'), 3000);
|
||||||
handleSaveApply: function(ev, mode) {
|
};
|
||||||
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);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,252 +1,291 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
'require fs';
|
'require fs';
|
||||||
|
'require rpc';
|
||||||
'require ui';
|
'require ui';
|
||||||
|
|
||||||
document.head.append(E('style', {'type': 'text/css'},
|
document.head.append(E('style', {'type': 'text/css'},
|
||||||
`
|
`
|
||||||
.label-status {
|
.label-status {
|
||||||
display: inline;
|
display: inline;
|
||||||
margin: 0px 2px 0px 0 !important;
|
margin: 0px 2px 0px 0 !important;
|
||||||
padding: 1px 4px 2px 4px;
|
padding: 1px 4px 2px 4px;
|
||||||
-webkit-border-radius: 3px;
|
-webkit-border-radius: 3px;
|
||||||
-moz-border-radius: 3px;
|
-moz-border-radius: 3px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
}
|
}
|
||||||
.starting {
|
.starting {
|
||||||
background-color: #a7b668 !important;
|
background-color: #a7b668 !important;
|
||||||
}
|
}
|
||||||
.running {
|
.running {
|
||||||
background-color: #2ea256 !important;
|
background-color: #2ea256 !important;
|
||||||
}
|
}
|
||||||
.updating {
|
.updating {
|
||||||
background-color: #1e82ff !important;
|
background-color: #1e82ff !important;
|
||||||
}
|
}
|
||||||
.stopped {
|
.stopped {
|
||||||
background-color: #acacac !important;
|
background-color: #acacac !important;
|
||||||
}
|
}
|
||||||
.error {
|
.error {
|
||||||
background-color: #ff4e54 !important;
|
background-color: #ff4e54 !important;
|
||||||
}
|
}
|
||||||
.total-proxy {
|
.total-proxy {
|
||||||
background-color: #ffb937 !important;
|
background-color: #ffb937 !important;
|
||||||
}
|
}
|
||||||
`));
|
`));
|
||||||
|
|
||||||
return L.Class.extend({
|
return L.Class.extend({
|
||||||
app_name: 'ruantiblock',
|
appName : 'ruantiblock',
|
||||||
exec_path: '/usr/bin/ruantiblock',
|
execPath : '/usr/bin/ruantiblock',
|
||||||
init_path: '/etc/init.d/ruantiblock',
|
tokenFile : '/var/run/ruantiblock.token',
|
||||||
token_file: '/var/run/ruantiblock.token',
|
parsersDir : '/usr/bin',
|
||||||
parsers_dir: '/usr/bin',
|
torrcFile : '/etc/tor/torrc',
|
||||||
torrc_file: '/etc/tor/torrc',
|
userEntriesFile : '/etc/ruantiblock/user_entries',
|
||||||
user_entries_file: '/etc/ruantiblock/user_entries',
|
fqdnFilterFile : '/etc/ruantiblock/fqdn_filter',
|
||||||
fqdn_filter_file: '/etc/ruantiblock/fqdn_filter',
|
ipFilterFile : '/etc/ruantiblock/ip_filter',
|
||||||
ip_filter_file: '/etc/ruantiblock/ip_filter',
|
crontabFile : '/etc/crontabs/root',
|
||||||
crontab_file: '/etc/crontabs/root',
|
infoLabelStarting: '<span class="label-status starting">' + _('Starting') + '</span>',
|
||||||
info_label_starting: '<span class="label-status starting">' + _('Starting') + '</span>',
|
infoLabelRunning : '<span class="label-status running">' + _('Enabled') + '</span>',
|
||||||
info_label_running: '<span class="label-status running">' + _('Enabled') + '</span>',
|
infoLabelUpdating: '<span class="label-status updating">' + _('Updating') + '</span>',
|
||||||
info_label_updating: '<span class="label-status updating">' + _('Updating') + '</span>',
|
infoLabelStopped : '<span class="label-status stopped">' + _('Disabled') + '</span>',
|
||||||
info_label_stopped: '<span class="label-status stopped">' + _('Disabled') + '</span>',
|
infoLabelError : '<span class="label-status error">' + _('Error') + '</span>',
|
||||||
info_label_error: '<span class="label-status error">' + _('Error') + '</span>',
|
|
||||||
|
|
||||||
blacklist_sources: {
|
blacklistSources: {
|
||||||
'rublacklist': 'https://rublacklist.net',
|
'rublacklist': 'https://rublacklist.net',
|
||||||
'zapret-info': 'https://github.com/zapret-info/z-i',
|
'zapret-info': 'https://github.com/zapret-info/z-i',
|
||||||
'antifilter': 'https://antifilter.download',
|
'antifilter' : 'https://antifilter.download',
|
||||||
},
|
},
|
||||||
|
|
||||||
normalize_value: function(v) {
|
callInitStatus: rpc.declare({
|
||||||
return (v && typeof(v) === 'string') ? v.trim().replace(/\r?\n/g, '') : v;
|
object: 'luci',
|
||||||
},
|
method: 'getInitList',
|
||||||
|
params: [ 'name' ],
|
||||||
|
expect: { '': {} }
|
||||||
|
}),
|
||||||
|
|
||||||
make_status_string: function(
|
callInitAction: rpc.declare({
|
||||||
app_status_code,
|
object: 'luci',
|
||||||
proxy_mode,
|
method: 'setInitAction',
|
||||||
bllist_mode,
|
params: [ 'name', 'action' ],
|
||||||
bllist_module,
|
expect: { result: false }
|
||||||
bllist_source,
|
}),
|
||||||
tp_status_code,
|
|
||||||
vpn_route_status_code) {
|
|
||||||
let app_status_label;
|
|
||||||
let spinning = '';
|
|
||||||
|
|
||||||
switch(app_status_code) {
|
getInitStatus: function(name) {
|
||||||
case 0:
|
return this.callInitStatus(name).then(res => {
|
||||||
app_status_label = this.info_label_running;
|
if(res) {
|
||||||
break;
|
return res[name].enabled;
|
||||||
case 2:
|
} else {
|
||||||
app_status_label = this.info_label_stopped;
|
throw _('Command failed');
|
||||||
break;
|
}
|
||||||
case 3:
|
}).catch(e => {
|
||||||
app_status_label = this.info_label_starting;
|
ui.addNotification(null,
|
||||||
spinning = ' spinning';
|
E('p', _('Failed to get %s init status: %s').format(name, e)));
|
||||||
break;
|
});
|
||||||
case 4:
|
},
|
||||||
app_status_label = this.info_label_updating;
|
|
||||||
spinning = ' spinning';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
app_status_label = this.info_label_error;
|
|
||||||
return `<div class="table">
|
|
||||||
<div class="tr">
|
|
||||||
<div class="td left" style="min-width:33%%">
|
|
||||||
${_('Status')}:
|
|
||||||
</div>
|
|
||||||
<div class="td left">
|
|
||||||
${app_status_label}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`
|
|
||||||
};
|
|
||||||
|
|
||||||
return `<div class="table">
|
handleServiceAction: function(name, action) {
|
||||||
<div class="tr">
|
return this.callInitAction(name, action).then(success => {
|
||||||
<div class="td left" style="min-width:33%%">
|
if(!success) {
|
||||||
${_('Status')}:
|
throw _('Command failed');
|
||||||
</div>
|
};
|
||||||
<div class="td left%s">
|
return true;
|
||||||
%s %s %s
|
}).catch(e => {
|
||||||
</div>
|
ui.addNotification(null,
|
||||||
</div>
|
E('p', _('Service action failed "%s %s": %s').format(name, action, e)));
|
||||||
<div class="tr">
|
});
|
||||||
<div class="td left">
|
},
|
||||||
${_('Proxy mode')}:
|
|
||||||
</div>
|
|
||||||
<div class="td left">
|
|
||||||
%s
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="tr">
|
|
||||||
<div class="td left">
|
|
||||||
${_('Blacklist update mode')}:
|
|
||||||
</div>
|
|
||||||
<div class="td left">
|
|
||||||
%s
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
%s
|
|
||||||
</div>
|
|
||||||
`.format(
|
|
||||||
spinning,
|
|
||||||
app_status_label,
|
|
||||||
(tp_status_code == 0) ? '<span class="label-status total-proxy">'
|
|
||||||
+ _('Total-proxy is on') + '</span>' : '',
|
|
||||||
(app_status_code != 2 && proxy_mode == 2 && vpn_route_status_code != 0)
|
|
||||||
? '<span class="label-status error">'
|
|
||||||
+ _('VPN routing error! Need restart') + '</span>' : '',
|
|
||||||
(proxy_mode == 1) ? 'Tor' : 'VPN',
|
|
||||||
(!bllist_module || bllist_module === '') ? _('user entries only') : bllist_mode,
|
|
||||||
(!bllist_module || bllist_module === '') ? '' :
|
|
||||||
`<div class="tr">
|
|
||||||
<div class="td left">
|
|
||||||
${_('Blacklist source')}:
|
|
||||||
</div>
|
|
||||||
<div class="td left">
|
|
||||||
<span style="cursor:help; border-bottom:1px dotted" data-tooltip="${this.blacklist_sources[bllist_source]}">
|
|
||||||
${bllist_source}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>`
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
file_edit_dialog: L.Class.extend({
|
normalizeValue: function(v) {
|
||||||
__init__: function(file, title, description, callback, file_exists=false) {
|
return (v && typeof(v) === 'string') ? v.trim().replace(/\r?\n/g, '') : v;
|
||||||
this.file = file;
|
},
|
||||||
this.title = title;
|
|
||||||
this.description = description;
|
|
||||||
this.callback = callback;
|
|
||||||
this.file_exists = file_exists;
|
|
||||||
},
|
|
||||||
|
|
||||||
load: function() {
|
makeStatusString: function(
|
||||||
return fs.read(this.file);
|
app_status_code,
|
||||||
},
|
proxy_mode,
|
||||||
|
bllist_mode,
|
||||||
|
bllist_module,
|
||||||
|
bllist_source,
|
||||||
|
tp_status_code,
|
||||||
|
vpn_route_status_code) {
|
||||||
|
let app_status_label;
|
||||||
|
let spinning = '';
|
||||||
|
|
||||||
render: function(content) {
|
switch(app_status_code) {
|
||||||
ui.showModal(this.title, [
|
case 0:
|
||||||
E('div', { 'class': 'cbi-section' }, [
|
app_status_label = this.infoLabelRunning;
|
||||||
E('div', { 'class': 'cbi-section-descr' }, this.description),
|
break;
|
||||||
E('div', { 'class': 'cbi-section' },
|
case 2:
|
||||||
E('p', {},
|
app_status_label = this.infoLabelStopped;
|
||||||
E('textarea', {
|
break;
|
||||||
'id': 'widget.modal_content',
|
case 3:
|
||||||
'class': 'cbi-input-textarea',
|
app_status_label = this.infoLabelStarting;
|
||||||
'style': 'width:100% !important',
|
spinning = ' spinning';
|
||||||
'rows': 10,
|
break;
|
||||||
'wrap': 'off',
|
case 4:
|
||||||
'spellcheck': 'false',
|
app_status_label = this.infoLabelUpdating;
|
||||||
},
|
spinning = ' spinning';
|
||||||
content || '')
|
break;
|
||||||
)
|
default:
|
||||||
),
|
app_status_label = this.infoLabelError;
|
||||||
]),
|
return `<div class="table">
|
||||||
E('div', { 'class': 'right' }, [
|
<div class="tr">
|
||||||
E('button', {
|
<div class="td left" style="min-width:33%%">
|
||||||
'class': 'btn',
|
${_('Status')}:
|
||||||
'click': ui.hideModal,
|
</div>
|
||||||
}, _('Dismiss')),
|
<div class="td left">
|
||||||
' ',
|
${app_status_label}
|
||||||
E('button', {
|
</div>
|
||||||
'id': 'btn_save',
|
</div>
|
||||||
'class': 'btn cbi-button-positive important',
|
</div>`
|
||||||
'click': ui.createHandlerFn(this, this.handleSave),
|
};
|
||||||
}, _('Save')),
|
|
||||||
]),
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSave: function(ev) {
|
return `<div class="table">
|
||||||
let textarea = document.getElementById('widget.modal_content');
|
<div class="tr">
|
||||||
let value = textarea.value.trim().replace(/\r\n/g, '\n') + '\n';
|
<div class="td left" style="min-width:33%%">
|
||||||
|
${_('Status')}:
|
||||||
|
</div>
|
||||||
|
<div class="td left%s">
|
||||||
|
%s %s %s
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tr">
|
||||||
|
<div class="td left">
|
||||||
|
${_('Proxy mode')}:
|
||||||
|
</div>
|
||||||
|
<div class="td left">
|
||||||
|
%s
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tr">
|
||||||
|
<div class="td left">
|
||||||
|
${_('Blacklist update mode')}:
|
||||||
|
</div>
|
||||||
|
<div class="td left">
|
||||||
|
%s
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
%s
|
||||||
|
</div>
|
||||||
|
`.format(
|
||||||
|
spinning,
|
||||||
|
app_status_label,
|
||||||
|
(tp_status_code == 0) ? '<span class="label-status total-proxy">'
|
||||||
|
+ _('Total-proxy is on') + '</span>' : '',
|
||||||
|
(app_status_code != 2 && proxy_mode == 2 && vpn_route_status_code != 0)
|
||||||
|
? '<span class="label-status error">'
|
||||||
|
+ _('VPN routing error! Need restart') + '</span>' : '',
|
||||||
|
(proxy_mode == 1) ? 'Tor' : 'VPN',
|
||||||
|
(!bllist_module || bllist_module === '') ? _('user entries only') : bllist_mode,
|
||||||
|
(!bllist_module || bllist_module === '') ? '' :
|
||||||
|
`<div class="tr">
|
||||||
|
<div class="td left">
|
||||||
|
${_('Blacklist source')}:
|
||||||
|
</div>
|
||||||
|
<div class="td left">
|
||||||
|
<span style="cursor:help; border-bottom:1px dotted" data-tooltip="${this.blacklistSources[bllist_source]}">
|
||||||
|
${bllist_source}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
return fs.write(this.file, value).then(async rc => {
|
fileEditDialog: L.Class.extend({
|
||||||
textarea.value = value;
|
__init__: function(file, title, description, callback, file_exists=false) {
|
||||||
ui.addNotification(null, E('p', _('Contents have been saved.')),
|
this.file = file;
|
||||||
'info');
|
this.title = title;
|
||||||
if(this.callback) {
|
this.description = description;
|
||||||
return this.callback(rc);
|
this.callback = callback;
|
||||||
};
|
this.file_exists = file_exists;
|
||||||
}).catch(e => {
|
},
|
||||||
ui.addNotification(null, E('p', _('Unable to save the contents')
|
|
||||||
+ ': %s'.format(e.message)));
|
|
||||||
}).finally(() => {
|
|
||||||
ui.hideModal();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
error: function(e) {
|
load: function() {
|
||||||
if(!this.file_exists && e instanceof Error && e.name === 'NotFoundError') {
|
return fs.read(this.file);
|
||||||
return this.render();
|
},
|
||||||
} else {
|
|
||||||
ui.showModal(this.title, [
|
|
||||||
E('div', { 'class': 'cbi-section' },
|
|
||||||
E('p', {}, _('Unable to read the contents')
|
|
||||||
+ ': %s'.format(e.message))
|
|
||||||
),
|
|
||||||
E('div', { 'class': 'right' },
|
|
||||||
E('button', {
|
|
||||||
'class': 'btn',
|
|
||||||
'click': ui.hideModal,
|
|
||||||
}, _('Dismiss'))
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
show: function() {
|
render: function(content) {
|
||||||
ui.showModal(null,
|
ui.showModal(this.title, [
|
||||||
E('p', { 'class': 'spinning' }, _('Loading'))
|
E('div', { 'class': 'cbi-section' }, [
|
||||||
);
|
E('div', { 'class': 'cbi-section-descr' }, this.description),
|
||||||
this.load().then(content => {
|
E('div', { 'class': 'cbi-section' },
|
||||||
ui.hideModal();
|
E('p', {},
|
||||||
return this.render(content);
|
E('textarea', {
|
||||||
}).catch(e => {
|
'id': 'widget.modal_content',
|
||||||
ui.hideModal();
|
'class': 'cbi-input-textarea',
|
||||||
return this.error(e);
|
'style': 'width:100% !important',
|
||||||
})
|
'rows': 10,
|
||||||
},
|
'wrap': 'off',
|
||||||
}),
|
'spellcheck': 'false',
|
||||||
|
},
|
||||||
|
content || '')
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'right' }, [
|
||||||
|
E('button', {
|
||||||
|
'class': 'btn',
|
||||||
|
'click': ui.hideModal,
|
||||||
|
}, _('Dismiss')),
|
||||||
|
' ',
|
||||||
|
E('button', {
|
||||||
|
'id': 'btn_save',
|
||||||
|
'class': 'btn cbi-button-positive important',
|
||||||
|
'click': ui.createHandlerFn(this, this.handleSave),
|
||||||
|
}, _('Save')),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSave: function(ev) {
|
||||||
|
let textarea = document.getElementById('widget.modal_content');
|
||||||
|
let value = textarea.value.trim().replace(/\r\n/g, '\n') + '\n';
|
||||||
|
|
||||||
|
return fs.write(this.file, value).then(async rc => {
|
||||||
|
textarea.value = value;
|
||||||
|
ui.addNotification(null, E('p', _('Contents have been saved.')),
|
||||||
|
'info');
|
||||||
|
if(this.callback) {
|
||||||
|
return this.callback(rc);
|
||||||
|
};
|
||||||
|
}).catch(e => {
|
||||||
|
ui.addNotification(null, E('p', _('Unable to save the contents')
|
||||||
|
+ ': %s'.format(e.message)));
|
||||||
|
}).finally(() => {
|
||||||
|
ui.hideModal();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
error: function(e) {
|
||||||
|
if(!this.file_exists && e instanceof Error && e.name === 'NotFoundError') {
|
||||||
|
return this.render();
|
||||||
|
} else {
|
||||||
|
ui.showModal(this.title, [
|
||||||
|
E('div', { 'class': 'cbi-section' },
|
||||||
|
E('p', {}, _('Unable to read the contents')
|
||||||
|
+ ': %s'.format(e.message))
|
||||||
|
),
|
||||||
|
E('div', { 'class': 'right' },
|
||||||
|
E('button', {
|
||||||
|
'class': 'btn',
|
||||||
|
'click': ui.hideModal,
|
||||||
|
}, _('Dismiss'))
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function() {
|
||||||
|
ui.showModal(null,
|
||||||
|
E('p', { 'class': 'spinning' }, _('Loading'))
|
||||||
|
);
|
||||||
|
this.load().then(content => {
|
||||||
|
ui.hideModal();
|
||||||
|
return this.render(content);
|
||||||
|
}).catch(e => {
|
||||||
|
ui.hideModal();
|
||||||
|
return this.error(e);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ msgstr "Домены 2-го уровня не подлежащие оптими
|
|||||||
msgid "Add user entries to the blacklist when updating"
|
msgid "Add user entries to the blacklist when updating"
|
||||||
msgstr "Добавлять записи пользователя в блэклист при обновлении"
|
msgstr "Добавлять записи пользователя в блэклист при обновлении"
|
||||||
|
|
||||||
|
msgid "Alert"
|
||||||
|
msgstr "Тревога"
|
||||||
|
|
||||||
|
msgid "All"
|
||||||
|
msgstr "Все"
|
||||||
|
|
||||||
msgid "All traffic goes through the proxy without applying rules"
|
msgid "All traffic goes through the proxy without applying rules"
|
||||||
msgstr "Весь трафик отправляется в прокси, без применения правил"
|
msgstr "Весь трафик отправляется в прокси, без применения правил"
|
||||||
|
|
||||||
@@ -28,6 +34,9 @@ msgstr "Применить"
|
|||||||
msgid "Apply proxy rules to router application traffic"
|
msgid "Apply proxy rules to router application traffic"
|
||||||
msgstr "Применять правила прокси к трафику приложений роутера"
|
msgstr "Применять правила прокси к трафику приложений роутера"
|
||||||
|
|
||||||
|
msgid "Blacklist entry filters"
|
||||||
|
msgstr "Фильтры записей блэклиста"
|
||||||
|
|
||||||
msgid "Blacklist module"
|
msgid "Blacklist module"
|
||||||
msgstr "Модуль блэклиста"
|
msgstr "Модуль блэклиста"
|
||||||
|
|
||||||
@@ -55,10 +64,12 @@ msgstr "Изменения сохранены."
|
|||||||
msgid "Clean up ipsets before updating blacklist"
|
msgid "Clean up ipsets before updating blacklist"
|
||||||
msgstr "Очищать ipset'ы перед обновлением блэклиста"
|
msgstr "Очищать ipset'ы перед обновлением блэклиста"
|
||||||
|
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr "Команда не выполнена"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Complete service shutdown, as well as deleting ipsets and blacklist data"
|
"Complete service shutdown, as well as deleting ipsets and blacklist data"
|
||||||
msgstr ""
|
msgstr "Полное выключение службы, а также удаление ipset'ов и данных блэклиста"
|
||||||
"Полное выключение службы, а также удаление ipset'ов и данных блэклиста"
|
|
||||||
|
|
||||||
msgid "Contents have been saved."
|
msgid "Contents have been saved."
|
||||||
msgstr "Содержимое сохранено."
|
msgstr "Содержимое сохранено."
|
||||||
@@ -66,6 +77,9 @@ msgstr "Содержимое сохранено."
|
|||||||
msgid "Convert cyrillic domains to punycode"
|
msgid "Convert cyrillic domains to punycode"
|
||||||
msgstr "Конвертировать кириллические домены в punycode"
|
msgstr "Конвертировать кириллические домены в punycode"
|
||||||
|
|
||||||
|
msgid "Critical"
|
||||||
|
msgstr "Критическая ситуация"
|
||||||
|
|
||||||
msgid "Current schedule"
|
msgid "Current schedule"
|
||||||
msgstr "Текущее расписание"
|
msgstr "Текущее расписание"
|
||||||
|
|
||||||
@@ -75,18 +89,27 @@ msgstr "DNS сервер для FQDN записей"
|
|||||||
msgid "Day"
|
msgid "Day"
|
||||||
msgstr "День"
|
msgstr "День"
|
||||||
|
|
||||||
msgid "Disable"
|
msgid "Debug"
|
||||||
msgstr "Отключить"
|
msgstr "Отладка"
|
||||||
|
|
||||||
msgid "Disabled"
|
msgid "Disabled"
|
||||||
msgstr "Отключено"
|
msgstr "Отключено"
|
||||||
|
|
||||||
msgid "Dismiss"
|
msgid "Dismiss"
|
||||||
msgstr "Закрыть"
|
msgstr "Отмена"
|
||||||
|
|
||||||
|
msgid "Download error"
|
||||||
|
msgstr "Ошибка загрузки"
|
||||||
|
|
||||||
|
msgid "Download log"
|
||||||
|
msgstr "Скачать лог"
|
||||||
|
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "Изменить"
|
msgstr "Изменить"
|
||||||
|
|
||||||
|
msgid "Emergency"
|
||||||
|
msgstr "Чрезвычайная ситуация"
|
||||||
|
|
||||||
msgid "Enable"
|
msgid "Enable"
|
||||||
msgstr "Включить"
|
msgstr "Включить"
|
||||||
|
|
||||||
@@ -102,18 +125,18 @@ msgstr "Включать 'total-proxy' при старте"
|
|||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Включено"
|
msgstr "Включено"
|
||||||
|
|
||||||
msgid "Entries filters"
|
msgid "Entries"
|
||||||
msgstr "Фильтры записей"
|
msgstr "Записи"
|
||||||
|
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Ошибка"
|
msgstr "Ошибка"
|
||||||
|
|
||||||
msgid "Exclude domains from blacklist by FQDN filter patterns"
|
|
||||||
msgstr "Исключение доменов из блэклиста по шаблонам фильтра FQDN"
|
|
||||||
|
|
||||||
msgid "Exclude IP addresses from blacklist by IP filter patterns"
|
msgid "Exclude IP addresses from blacklist by IP filter patterns"
|
||||||
msgstr "Исключение IP адресов из блэклиста по шаблонам фильтра IP"
|
msgstr "Исключение IP адресов из блэклиста по шаблонам фильтра IP"
|
||||||
|
|
||||||
|
msgid "Exclude domains from blacklist by FQDN filter patterns"
|
||||||
|
msgstr "Исключение доменов из блэклиста по шаблонам фильтра FQDN"
|
||||||
|
|
||||||
msgid "Expecting:"
|
msgid "Expecting:"
|
||||||
msgstr "Ожидается:"
|
msgstr "Ожидается:"
|
||||||
|
|
||||||
@@ -123,12 +146,24 @@ msgstr "Конфигурация FQDN"
|
|||||||
msgid "FQDN filter"
|
msgid "FQDN filter"
|
||||||
msgstr "Фильтр FQDN"
|
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"
|
msgid "Hour"
|
||||||
msgstr "Час"
|
msgstr "Час"
|
||||||
|
|
||||||
msgid "Interval"
|
|
||||||
msgstr "Интервал"
|
|
||||||
|
|
||||||
msgid "IP configuration"
|
msgid "IP configuration"
|
||||||
msgstr "Конфигурация IP"
|
msgstr "Конфигурация IP"
|
||||||
|
|
||||||
@@ -141,6 +176,15 @@ msgstr "Лимит IP адресов"
|
|||||||
msgid "IP subnet patterns (/24) that are excluded from optimization"
|
msgid "IP subnet patterns (/24) that are excluded from optimization"
|
||||||
msgstr "Шаблоны IP подсетей (/24) не подлежащих оптимизации"
|
msgstr "Шаблоны IP подсетей (/24) не подлежащих оптимизации"
|
||||||
|
|
||||||
|
msgid "Info"
|
||||||
|
msgstr "Информация"
|
||||||
|
|
||||||
|
msgid "Interval"
|
||||||
|
msgstr "Интервал"
|
||||||
|
|
||||||
|
msgid "Invalid regular expression"
|
||||||
|
msgstr "Неправильное регулярное выражение"
|
||||||
|
|
||||||
msgid "Ipset"
|
msgid "Ipset"
|
||||||
msgstr "Ipset"
|
msgstr "Ipset"
|
||||||
|
|
||||||
@@ -153,6 +197,12 @@ msgstr "LAN интерфейс"
|
|||||||
msgid "Last blacklist update"
|
msgid "Last blacklist update"
|
||||||
msgstr "Последнее обновление блэклиста"
|
msgstr "Последнее обновление блэклиста"
|
||||||
|
|
||||||
|
msgid "Last entries"
|
||||||
|
msgstr "Последние записи"
|
||||||
|
|
||||||
|
msgid "Level"
|
||||||
|
msgstr "Уровень"
|
||||||
|
|
||||||
msgid "Loading"
|
msgid "Loading"
|
||||||
msgstr "Загрузка"
|
msgstr "Загрузка"
|
||||||
|
|
||||||
@@ -162,12 +212,21 @@ msgstr "Лог"
|
|||||||
msgid "Logging events"
|
msgid "Logging events"
|
||||||
msgstr "Записывать события в лог"
|
msgstr "Записывать события в лог"
|
||||||
|
|
||||||
|
msgid "Logging levels"
|
||||||
|
msgstr "Уровни логирования"
|
||||||
|
|
||||||
msgid "Main settings"
|
msgid "Main settings"
|
||||||
msgstr "Основные настройки"
|
msgstr "Основные настройки"
|
||||||
|
|
||||||
msgid "Match-set"
|
msgid "Match-set"
|
||||||
msgstr "Правило"
|
msgstr "Правило"
|
||||||
|
|
||||||
|
msgid "Message"
|
||||||
|
msgstr "Сообщение"
|
||||||
|
|
||||||
|
msgid "Message filter"
|
||||||
|
msgstr "Фильтр сообщений"
|
||||||
|
|
||||||
msgid "Minute"
|
msgid "Minute"
|
||||||
msgstr "Минута"
|
msgstr "Минута"
|
||||||
|
|
||||||
@@ -177,14 +236,20 @@ msgstr "Режим работы модуля"
|
|||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Имя"
|
msgstr "Имя"
|
||||||
|
|
||||||
|
msgid "No Shedule"
|
||||||
|
msgstr "Нет расписания"
|
||||||
|
|
||||||
msgid "No changes to save."
|
msgid "No changes to save."
|
||||||
msgstr "Нет изменений для сохранения."
|
msgstr "Нет изменений для сохранения."
|
||||||
|
|
||||||
msgid "No data"
|
msgid "No data"
|
||||||
msgstr "Нет данных"
|
msgstr "Нет данных"
|
||||||
|
|
||||||
msgid "No Shedule"
|
msgid "No entries available..."
|
||||||
msgstr "Нет расписания"
|
msgstr "Нет доступных записей..."
|
||||||
|
|
||||||
|
msgid "Notice"
|
||||||
|
msgstr "Сообщение"
|
||||||
|
|
||||||
msgid "Number of entries"
|
msgid "Number of entries"
|
||||||
msgstr "Кол-во записей"
|
msgstr "Кол-во записей"
|
||||||
@@ -202,15 +267,12 @@ msgstr ""
|
|||||||
msgid "One of the following:"
|
msgid "One of the following:"
|
||||||
msgstr "Одно из следующих значений:"
|
msgstr "Одно из следующих значений:"
|
||||||
|
|
||||||
msgid "Only messages that include the specified string will be displayed"
|
msgid "Optional DNS resolver"
|
||||||
msgstr "Будут показаны только сообщения включающие указанную строку"
|
msgstr "Альтернативный DNS резолвер"
|
||||||
|
|
||||||
msgid "Optional DNS resolver for '.onion' zone"
|
msgid "Optional DNS resolver for '.onion' zone"
|
||||||
msgstr "Дополнительный DNS резолвер для '.onion' зоны"
|
msgstr "Дополнительный DNS резолвер для '.onion' зоны"
|
||||||
|
|
||||||
msgid "Optional DNS resolver"
|
|
||||||
msgstr "Альтернативный DNS резолвер"
|
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr "Опции"
|
msgstr "Опции"
|
||||||
|
|
||||||
@@ -238,15 +300,27 @@ msgstr "Режим прокси"
|
|||||||
msgid "Reduces RAM consumption during update"
|
msgid "Reduces RAM consumption during update"
|
||||||
msgstr "Уменьшает потребление оперативной памяти при обновлении"
|
msgstr "Уменьшает потребление оперативной памяти при обновлении"
|
||||||
|
|
||||||
|
msgid "Refresh log"
|
||||||
|
msgstr "Обновить лог"
|
||||||
|
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr "Сбросить"
|
msgstr "Сбросить"
|
||||||
|
|
||||||
|
msgid "Ruantiblock"
|
||||||
|
msgstr "Ruantiblock"
|
||||||
|
|
||||||
msgid "Run at startup"
|
msgid "Run at startup"
|
||||||
msgstr "Запуск при старте системы"
|
msgstr "Запуск при старте системы"
|
||||||
|
|
||||||
|
msgid "Save"
|
||||||
|
msgstr "Сохранить"
|
||||||
|
|
||||||
msgid "Service"
|
msgid "Service"
|
||||||
msgstr "Служба"
|
msgstr "Служба"
|
||||||
|
|
||||||
|
msgid "Service action failed \"%s %s\": %s"
|
||||||
|
msgstr "Не удалось выполнить действие службы \"%s %s\": %s"
|
||||||
|
|
||||||
msgid "Set"
|
msgid "Set"
|
||||||
msgstr "Установить"
|
msgstr "Установить"
|
||||||
|
|
||||||
@@ -259,6 +333,9 @@ msgstr "Выключение"
|
|||||||
msgid "Size in memory"
|
msgid "Size in memory"
|
||||||
msgstr "Размер в памяти"
|
msgstr "Размер в памяти"
|
||||||
|
|
||||||
|
msgid "Sorting entries"
|
||||||
|
msgstr "Сортировка записей"
|
||||||
|
|
||||||
msgid "Starting"
|
msgid "Starting"
|
||||||
msgstr "Запускается"
|
msgstr "Запускается"
|
||||||
|
|
||||||
@@ -300,21 +377,33 @@ msgstr ""
|
|||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr "Время"
|
msgstr "Время"
|
||||||
|
|
||||||
|
msgid "Timestamp"
|
||||||
|
msgstr "Время"
|
||||||
|
|
||||||
msgid "Tor configuration file"
|
msgid "Tor configuration file"
|
||||||
msgstr "Конфигурационный файл Tor"
|
msgstr "Конфигурационный файл Tor"
|
||||||
|
|
||||||
msgid "Tor mode"
|
msgid "Tor mode"
|
||||||
msgstr "Режим Tor"
|
msgstr "Режим Tor"
|
||||||
|
|
||||||
|
msgid "Total-proxy"
|
||||||
|
msgstr "Total-proxy"
|
||||||
|
|
||||||
msgid "Total-proxy is on"
|
msgid "Total-proxy is on"
|
||||||
msgstr "Total-proxy включен"
|
msgstr "Total-proxy включен"
|
||||||
|
|
||||||
msgid "Transparent proxy port for iptables rules"
|
msgid "Transparent proxy port for iptables rules"
|
||||||
msgstr "Порт прозрачного прокси для правил iptables"
|
msgstr "Порт прозрачного прокси для правил iptables"
|
||||||
|
|
||||||
|
msgid "Type an expression..."
|
||||||
|
msgstr "Введите выражение..."
|
||||||
|
|
||||||
msgid "Unable to execute or read contents"
|
msgid "Unable to execute or read contents"
|
||||||
msgstr "Невозможно выполнить или прочитать содержимое"
|
msgstr "Невозможно выполнить или прочитать содержимое"
|
||||||
|
|
||||||
|
msgid "Unable to load log data:"
|
||||||
|
msgstr "Невозможно загрузить данные лога:"
|
||||||
|
|
||||||
msgid "Unable to read the contents"
|
msgid "Unable to read the contents"
|
||||||
msgstr "Невозможно прочитать содержимое"
|
msgstr "Невозможно прочитать содержимое"
|
||||||
|
|
||||||
@@ -348,9 +437,27 @@ msgstr "Режим VPN"
|
|||||||
msgid "VPN routing error! Need restart"
|
msgid "VPN routing error! Need restart"
|
||||||
msgstr "Ошибка маршрутизации VPN! Необходим перезапуск"
|
msgstr "Ошибка маршрутизации VPN! Необходим перезапуск"
|
||||||
|
|
||||||
|
msgid "Warning"
|
||||||
|
msgstr "Внимание"
|
||||||
|
|
||||||
|
msgid "ascending"
|
||||||
|
msgstr "по возрастанию"
|
||||||
|
|
||||||
|
msgid "descending"
|
||||||
|
msgstr "по убыванию"
|
||||||
|
|
||||||
|
msgid "disabled"
|
||||||
|
msgstr "отключен"
|
||||||
|
|
||||||
msgid "e.g:"
|
msgid "e.g:"
|
||||||
msgstr "прим:"
|
msgstr "прим:"
|
||||||
|
|
||||||
|
msgid "net pattern"
|
||||||
|
msgstr "шаблон сети"
|
||||||
|
|
||||||
|
msgid "none (user entries only)"
|
||||||
|
msgstr "нет (только записи пользователя)"
|
||||||
|
|
||||||
msgid "user entries only"
|
msgid "user entries only"
|
||||||
msgstr "только записи пользователя"
|
msgstr "только записи пользователя"
|
||||||
|
|
||||||
@@ -359,86 +466,3 @@ msgstr "верный IP-адрес"
|
|||||||
|
|
||||||
msgid "valid address#port"
|
msgid "valid address#port"
|
||||||
msgstr "верный IP-адрес#порт"
|
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"
|
msgid "Add user entries to the blacklist when updating"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Alert"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "All"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "All traffic goes through the proxy without applying rules"
|
msgid "All traffic goes through the proxy without applying rules"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -16,6 +22,9 @@ msgstr ""
|
|||||||
msgid "Apply proxy rules to router application traffic"
|
msgid "Apply proxy rules to router application traffic"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Blacklist entry filters"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Blacklist module"
|
msgid "Blacklist module"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -43,6 +52,9 @@ msgstr ""
|
|||||||
msgid "Clean up ipsets before updating blacklist"
|
msgid "Clean up ipsets before updating blacklist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Complete service shutdown, as well as deleting ipsets and blacklist data"
|
"Complete service shutdown, as well as deleting ipsets and blacklist data"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -53,6 +65,9 @@ msgstr ""
|
|||||||
msgid "Convert cyrillic domains to punycode"
|
msgid "Convert cyrillic domains to punycode"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Critical"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Current schedule"
|
msgid "Current schedule"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -62,43 +77,47 @@ msgstr ""
|
|||||||
msgid "Day"
|
msgid "Day"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Disable"
|
msgid "Debug"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Disabled"
|
msgid "Disabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Dismiss"
|
msgid "Dismiss"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Download error"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Download log"
|
||||||
|
msgstr ""
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Emergency"
|
||||||
|
msgstr ""
|
||||||
msgid "Enable"
|
msgid "Enable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Enable FQDN filter"
|
msgid "Enable FQDN filter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Enable ip filter"
|
msgid "Enable IP filter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Enable the 'total-proxy' option at startup"
|
msgid "Enable the 'total-proxy' option at startup"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Entries filters"
|
msgid "Entries"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Exclude domains from blacklist by FQDN filter patterns"
|
msgid "Exclude IP addresses from blacklist by IP filter patterns"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Exclude IP addresses from blacklist by IP filter patterns"
|
msgid "Exclude domains from blacklist by FQDN filter patterns"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Expecting:"
|
msgid "Expecting:"
|
||||||
@@ -110,15 +129,24 @@ msgstr ""
|
|||||||
msgid "FQDN filter"
|
msgid "FQDN filter"
|
||||||
msgstr ""
|
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 ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Hour"
|
msgid "Hour"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Interval"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "IP configuration"
|
msgid "IP configuration"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -131,6 +159,15 @@ msgstr ""
|
|||||||
msgid "IP subnet patterns (/24) that are excluded from optimization"
|
msgid "IP subnet patterns (/24) that are excluded from optimization"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Info"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Interval"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Invalid regular expression"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Ipset"
|
msgid "Ipset"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -143,6 +180,12 @@ msgstr ""
|
|||||||
msgid "Last blacklist update"
|
msgid "Last blacklist update"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Last entries"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Level"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Loading"
|
msgid "Loading"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -152,12 +195,21 @@ msgstr ""
|
|||||||
msgid "Logging events"
|
msgid "Logging events"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Logging levels"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Main settings"
|
msgid "Main settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Match-set"
|
msgid "Match-set"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Message"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Message filter"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Minute"
|
msgid "Minute"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -167,13 +219,19 @@ msgstr ""
|
|||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "No Shedule"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "No changes to save."
|
msgid "No changes to save."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "No data"
|
msgid "No data"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "No Shedule"
|
msgid "No entries available..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Notice"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Number of entries"
|
msgid "Number of entries"
|
||||||
@@ -189,10 +247,10 @@ msgstr ""
|
|||||||
msgid "One of the following:"
|
msgid "One of the following:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Optional DNS resolver for '.onion' zone"
|
msgid "Optional DNS resolver"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Optional DNS resolver"
|
msgid "Optional DNS resolver for '.onion' zone"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
@@ -216,33 +274,46 @@ msgstr ""
|
|||||||
msgid "Reduces RAM consumption during update"
|
msgid "Reduces RAM consumption during update"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Refresh log"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Ruantiblock"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Run at startup"
|
msgid "Run at startup"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Save"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Service"
|
msgid "Service"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Service action failed \"%s %s\": %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Set"
|
msgid "Set"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Shutdown"
|
msgid "Shutdown"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Size in memory"
|
msgid "Size in memory"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Sorting entries"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Starting"
|
msgid "Starting"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Statistics"
|
msgid "Statistics"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -273,21 +344,31 @@ msgstr ""
|
|||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Timestamp"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Tor configuration file"
|
msgid "Tor configuration file"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Tor mode"
|
msgid "Tor mode"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Total-proxy"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Total-proxy is on"
|
msgid "Total-proxy is on"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Transparent proxy port for iptables rules"
|
msgid "Transparent proxy port for iptables rules"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Type an expression..."
|
||||||
|
msgstr ""
|
||||||
msgid "Unable to execute or read contents"
|
msgid "Unable to execute or read contents"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Unable to load log data:"
|
||||||
|
msgstr ""
|
||||||
msgid "Unable to read the contents"
|
msgid "Unable to read the contents"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -308,7 +389,6 @@ msgstr ""
|
|||||||
|
|
||||||
msgid "Use optional DNS resolver"
|
msgid "Use optional DNS resolver"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "User entries"
|
msgid "User entries"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -321,9 +401,27 @@ msgstr ""
|
|||||||
msgid "VPN routing error! Need restart"
|
msgid "VPN routing error! Need restart"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Warning"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ascending"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "descending"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "disabled"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "e.g:"
|
msgid "e.g:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "net pattern"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "none (user entries only)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "user entries only"
|
msgid "user entries only"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -332,86 +430,3 @@ msgstr ""
|
|||||||
|
|
||||||
msgid "valid address#port"
|
msgid "valid address#port"
|
||||||
msgstr ""
|
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 ""
|
|
||||||
|
|||||||
@@ -1,37 +1,34 @@
|
|||||||
{
|
{
|
||||||
"luci-app-ruantiblock": {
|
"luci-app-ruantiblock": {
|
||||||
"description": "Grant access to ruantiblock procedures",
|
"description": "Grant access to ruantiblock procedures",
|
||||||
"read": {
|
"read": {
|
||||||
"cgi-io": [ "exec" ],
|
"cgi-io": [ "exec" ],
|
||||||
"file": {
|
"file": {
|
||||||
"/usr/bin": [ "list" ],
|
"/usr/bin": [ "list" ],
|
||||||
"/etc/ruantiblock/fqdn_filter": [ "read" ],
|
"/etc/ruantiblock/fqdn_filter": [ "read" ],
|
||||||
"/etc/ruantiblock/ip_filter": [ "read" ],
|
"/etc/ruantiblock/ip_filter": [ "read" ],
|
||||||
"/etc/ruantiblock/user_entries": [ "read" ],
|
"/etc/ruantiblock/user_entries": [ "read" ],
|
||||||
"/var/run/ruantiblock.token": [ "read" ],
|
"/var/run/ruantiblock.token": [ "read" ],
|
||||||
"/etc/tor/torrc": [ "read" ],
|
"/etc/tor/torrc": [ "read" ],
|
||||||
"/etc/crontabs/root": [ "read" ],
|
"/etc/crontabs/root": [ "read" ],
|
||||||
"/usr/bin/ruantiblock": [ "exec" ],
|
"/usr/bin/ruantiblock": [ "exec" ],
|
||||||
"/etc/init.d/ruantiblock": [ "exec" ],
|
"/sbin/logread -e ruantiblock": [ "exec" ],
|
||||||
"/etc/init.d/tor enabled": [ "exec" ],
|
"/usr/sbin/logread -e ruantiblock": [ "exec" ]
|
||||||
"/etc/init.d/tor restart": [ "exec" ],
|
},
|
||||||
"/etc/init.d/cron enabled": [ "exec" ],
|
"uci": [ "network", "ruantiblock" ],
|
||||||
"/etc/init.d/cron enable": [ "exec" ],
|
"ubus": {
|
||||||
"/etc/init.d/cron restart": [ "exec" ],
|
"luci": [ "getInitList", "setInitAction" ]
|
||||||
"/sbin/logread -e ruantiblock": [ "exec" ],
|
}
|
||||||
"/usr/sbin/logread -e ruantiblock": [ "exec" ]
|
},
|
||||||
},
|
"write": {
|
||||||
"uci": [ "network", "ruantiblock" ]
|
"file": {
|
||||||
},
|
"/etc/ruantiblock/fqdn_filter": [ "write" ],
|
||||||
"write": {
|
"/etc/ruantiblock/ip_filter": [ "write" ],
|
||||||
"file": {
|
"/etc/ruantiblock/user_entries": [ "write" ],
|
||||||
"/etc/ruantiblock/fqdn_filter": [ "write" ],
|
"/etc/tor/torrc": [ "write" ],
|
||||||
"/etc/ruantiblock/ip_filter": [ "write" ],
|
"/etc/crontabs/root": [ "write" ]
|
||||||
"/etc/ruantiblock/user_entries": [ "write" ],
|
},
|
||||||
"/etc/tor/torrc": [ "write" ],
|
"uci": [ "ruantiblock" ]
|
||||||
"/etc/crontabs/root": [ "write" ]
|
}
|
||||||
},
|
}
|
||||||
"uci": [ "ruantiblock" ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
|
|
||||||
config main 'config'
|
config main 'config'
|
||||||
option proxy_mode '1'
|
option proxy_mode '1'
|
||||||
option proxy_local_clients '1'
|
option proxy_local_clients '1'
|
||||||
option ipset_clear_sets '0'
|
option ipset_clear_sets '0'
|
||||||
option if_lan 'eth0'
|
option if_lan 'eth0'
|
||||||
option if_vpn 'tun0'
|
option if_vpn 'tun0'
|
||||||
option tor_trans_port '9040'
|
option tor_trans_port '9040'
|
||||||
option onion_dns_addr '127.0.0.1#9053'
|
option onion_dns_addr '127.0.0.1#9053'
|
||||||
option add_user_entries '0'
|
option add_user_entries '0'
|
||||||
option use_logger '1'
|
option use_logger '1'
|
||||||
option def_total_proxy '0'
|
option def_total_proxy '0'
|
||||||
option bllist_source 'zapret-info'
|
option bllist_source 'zapret-info'
|
||||||
option bllist_mode 'ip'
|
option bllist_mode 'ip'
|
||||||
option ip_limit '0'
|
option ip_limit '0'
|
||||||
option summarize_ip '0'
|
option summarize_ip '0'
|
||||||
option summarize_cidr '0'
|
option summarize_cidr '0'
|
||||||
option ip_filter '0'
|
option ip_filter '0'
|
||||||
option sd_limit '16'
|
option sd_limit '16'
|
||||||
list opt_exclude_sld 'livejournal.com'
|
list opt_exclude_sld 'livejournal.com'
|
||||||
list opt_exclude_sld 'facebook.com'
|
list opt_exclude_sld 'facebook.com'
|
||||||
list opt_exclude_sld 'vk.com'
|
list opt_exclude_sld 'vk.com'
|
||||||
list opt_exclude_sld 'blog.jp'
|
list opt_exclude_sld 'blog.jp'
|
||||||
list opt_exclude_sld 'msk.ru'
|
list opt_exclude_sld 'msk.ru'
|
||||||
list opt_exclude_sld 'net.ru'
|
list opt_exclude_sld 'net.ru'
|
||||||
list opt_exclude_sld 'org.ru'
|
list opt_exclude_sld 'org.ru'
|
||||||
list opt_exclude_sld 'net.ua'
|
list opt_exclude_sld 'net.ua'
|
||||||
list opt_exclude_sld 'com.ua'
|
list opt_exclude_sld 'com.ua'
|
||||||
list opt_exclude_sld 'org.ua'
|
list opt_exclude_sld 'org.ua'
|
||||||
list opt_exclude_sld 'co.uk'
|
list opt_exclude_sld 'co.uk'
|
||||||
list opt_exclude_sld 'amazonaws.com'
|
list opt_exclude_sld 'amazonaws.com'
|
||||||
option fqdn_filter '0'
|
option fqdn_filter '0'
|
||||||
option use_idn '0'
|
option use_idn '0'
|
||||||
option alt_nslookup '0'
|
option alt_nslookup '0'
|
||||||
option alt_dns_addr '8.8.8.8'
|
option alt_dns_addr '8.8.8.8'
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ IF_VPN=`uci get ruantiblock.config.if_vpn`
|
|||||||
PROXY_MODE=`uci get ruantiblock.config.proxy_mode`
|
PROXY_MODE=`uci get ruantiblock.config.proxy_mode`
|
||||||
|
|
||||||
if [ "$ACTION" = "ifup" ] && [ "$PROXY_MODE" = "2" ] && [ "$DEVICE" = "$IF_VPN" ]; then
|
if [ "$ACTION" = "ifup" ] && [ "$PROXY_MODE" = "2" ] && [ "$DEVICE" = "$IF_VPN" ]; then
|
||||||
[ `/usr/bin/ruantiblock raw-status` -ne 2 ] && /usr/bin/ruantiblock reload
|
[ `/usr/bin/ruantiblock raw-status` -ne 2 ] && /usr/bin/ruantiblock reload
|
||||||
fi
|
fi
|
||||||
|
|||||||
|
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 |