diff --git a/autoinstall/autoinstall.sh b/autoinstall/autoinstall.sh
index 5869b4d..321a24a 100755
--- a/autoinstall/autoinstall.sh
+++ b/autoinstall/autoinstall.sh
@@ -11,8 +11,8 @@ LUCI_APP=1
OWRT_VERSION="19.07"
RUAB_VERSION="0.9.0-2"
RUAB_MOD_LUA_VERSION="0.9.0-2"
-RUAB_LUCI_APP_VERSION="0.9.0-6"
-BASE_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_openwrt/master"
+RUAB_LUCI_APP_VERSION="0.9.0-7"
+BASE_URL="https://github.com/gSpotx2f/ruantiblock_openwrt/raw/master"
PKG_DIR="/tmp"
if [ -n "$1" ]; then
@@ -29,8 +29,8 @@ URL_LUCI_APP_RU_PKG="${BASE_URL}/packages/${OWRT_VERSION}/luci-i18n-ruantiblock-
### tor
URL_TORRC="${BASE_URL}/tor/etc/tor/torrc"
### ruantiblock-mod-lua
-URL_LUA_IPTOOL="https://raw.githubusercontent.com/gSpotx2f/iptool-lua/master/5.1/iptool.lua"
-URL_LUA_IDN="https://raw.githubusercontent.com/haste/lua-idn/master/idn.lua"
+URL_LUA_IPTOOL="https://github.com/gSpotx2f/iptool-lua/raw/master/5.1/iptool.lua"
+URL_LUA_IDN="https://github.com/haste/lua-idn/raw/master/idn.lua"
### Local files
diff --git a/images/01.jpg b/images/01.jpg
deleted file mode 100644
index e96e480..0000000
Binary files a/images/01.jpg and /dev/null differ
diff --git a/images/02.jpg b/images/02.jpg
deleted file mode 100644
index 3dff941..0000000
Binary files a/images/02.jpg and /dev/null differ
diff --git a/images/03.jpg b/images/03.jpg
deleted file mode 100644
index b7ed136..0000000
Binary files a/images/03.jpg and /dev/null differ
diff --git a/luci-app-ruantiblock/Makefile b/luci-app-ruantiblock/Makefile
index 5a6ed70..527dd81 100644
--- a/luci-app-ruantiblock/Makefile
+++ b/luci-app-ruantiblock/Makefile
@@ -5,11 +5,12 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=0.9.0
-PKG_RELEASE:=6
+PKG_RELEASE:=7
LUCI_TITLE:=LuCI support for ruantiblock
-LUCI_DEPENDS:=+ruantiblock +luci-mod-admin-full
+LUCI_DEPENDS:=+ruantiblock
LUCI_PKGARCH:=all
-include ../../luci.mk
+#include ../../luci.mk
+include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature
diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/abstract-log.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/abstract-log.js
index 1c0e098..cf2fb8f 100644
--- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/abstract-log.js
+++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/abstract-log.js
@@ -139,15 +139,15 @@ return L.Class.extend({
* View name (for local storage and downloads).
* Must be overridden by a subclass!
*/
- viewName: null,
+ viewName : null,
/**
* Page title.
* Must be overridden by a subclass!
*/
- title: null,
+ title : null,
- logLevels: {
+ logLevels : {
'emerg': E('span', { 'class': 'zonebadge log-emerg' }, E('strong', _('Emergency'))),
'alert': E('span', { 'class': 'zonebadge log-alert' }, E('strong', _('Alert'))),
'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'))),
},
- 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,
- totalLogLines: 0,
+ totalLogLines : 0,
- htmlEntities: function(str) {
+ htmlEntities : function(str) {
return String(str).replace(
/&/g, '&').replace(
/ {
@@ -455,27 +455,27 @@ return L.Class.extend({
'style': 'max-width:4em !important',
});
- let logHostsDropdownElem = '';
+ let logHostsDropdownElem = '';
let logLevelsDropdownElem = '';
if(this.isLevels) {
logLevelsDropdownElem = this.makeLogLevelsDropdownSection();
};
if(this.isHosts) {
- logHostsDropdownElem = this.makeLogHostsDropdownSection();
+ logHostsDropdownElem = this.makeLogHostsDropdownSection();
};
let logFilter = E('input', {
- 'id': 'logFilter',
- 'name': 'logFilter',
- 'type': 'text',
- 'form': 'logForm',
- 'class': 'cbi-input-text',
+ 'id' : 'logFilter',
+ 'name' : 'logFilter',
+ 'type' : 'text',
+ 'form' : 'logForm',
+ 'class' : 'cbi-input-text',
'placeholder': _('Type an expression...'),
});
let logFormSubmitBtn = E('input', {
- 'type': 'submit',
- 'form': 'logForm',
+ 'type' : 'submit',
+ 'form' : 'logForm',
'class': 'cbi-button btn cbi-button-action',
'value': _('Apply'),
'click': ev => ev.target.blur(),
@@ -483,9 +483,9 @@ return L.Class.extend({
});
let logSorting = E('select', {
- 'id': 'logSorting',
- 'name': 'logSorting',
- 'form': 'logForm',
+ 'id' : 'logSorting',
+ 'name' : 'logSorting',
+ 'form' : 'logForm',
'class': "cbi-input-select",
}, [
E('option', { 'value': 'asc' }, _('ascending')),
@@ -494,8 +494,8 @@ return L.Class.extend({
logSorting.value = this.logSortingValue;
let logDownloadBtn = E('button', {
- 'id': 'logDownloadBtn',
- 'name': 'logDownloadBtn',
+ 'id' : 'logDownloadBtn',
+ 'name' : 'logDownloadBtn',
'class': 'cbi-button btn',
'click': ui.createHandlerFn(this, this.downloadLog),
}, _('Download log'));
@@ -509,7 +509,7 @@ return L.Class.extend({
E('div', { 'id': 'tailInputSection', 'class': 'cbi-value' }, [
E('label', {
'class': 'cbi-value-title',
- 'for': 'tailInput',
+ 'for' : 'tailInput',
}, _('Last entries')),
E('div', { 'class': 'cbi-value-field' }, [
tailInput,
@@ -523,7 +523,7 @@ return L.Class.extend({
E('div', { 'class': 'cbi-value' }, [
E('label', {
'class': 'cbi-value-title',
- 'for': 'logFilter',
+ 'for' : 'logFilter',
}, _('Message filter')),
E('div', { 'class': 'cbi-value-field' }, logFilter),
]),
@@ -531,7 +531,7 @@ return L.Class.extend({
E('div', { 'class': 'cbi-value' }, [
E('label', {
'class': 'cbi-value-title',
- 'for': 'logSorting',
+ 'for' : 'logSorting',
}, _('Sorting entries')),
E('div', { 'class': 'cbi-value-field' }, logSorting,),
]),
@@ -539,14 +539,14 @@ return L.Class.extend({
E('div', { 'class': 'cbi-value' }, [
E('label', {
'class': 'cbi-value-title',
- 'for': 'logFilter',
+ 'for' : 'logFilter',
}, _('Refresh log')),
E('div', { 'class': 'cbi-value-field' }, [
logFormSubmitBtn,
E('form', {
- 'id': 'logForm',
- 'name': 'logForm',
- 'style': 'display:inline-block; margin-top:0.5em',
+ 'id' : 'logForm',
+ 'name' : 'logForm',
+ 'style' : 'display:inline-block; margin-top:0.5em',
'submit': ui.createHandlerFn(this, function(ev) {
ev.preventDefault();
let formElems = Array.from(document.forms.logForm.elements);
@@ -633,8 +633,8 @@ return L.Class.extend({
]);
},
+ handleSave : null,
handleSaveApply: null,
- handleSave: null,
- handleReset: null,
+ handleReset : null,
}),
})
diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/cron.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/cron.js
index 7652f8f..7484db6 100644
--- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/cron.js
+++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/cron.js
@@ -3,221 +3,234 @@
'require ui';
'require view.ruantiblock.tools as tools';
-let crontab_regexp = new RegExp(`^(\\*?\\/?(\\d){0,2}\\s){5}${tools.exec_path} update(\n)?`, 'gm');
-let current_crontab_content;
-
-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
[ %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
[ %s ]'.format(e.message, '/etc/init.d/cron')));
- });
- }).catch(e => {
- ui.addNotification(null, E('p', _('Unable to save the changes')
- + ': %s
[ %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({
- load: function() {
- return fs.read(tools.crontab_file).catch(e => {
- ui.addNotification(null, E('p', _('Unable to read the contents')
- + ': %s
[ %s ]'.format(
- e.message, tools.crontab_file
- )));
- });
- },
+ crontabRegexp: new RegExp(
+ `^(\\*?\\/?(\\d){0,2}\\s){5}${tools.execPath} update(\n)?`, 'gm'),
- render: function(content) {
- current_crontab_content = content;
- let current_task = pick_cron_task(content);
+ currentCrontabContent: null,
- 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,
- }, cron_status_string(current_task));
+ toDD: function(n){
+ return String(n).replace(/^(\d)$/, "0$1");
+ },
- let btn_cron_del = E('button', {
- 'class': 'cbi-button btn cbi-button-reset',
- 'id': 'btn_cron_del',
- 'name': 'btn_cron_del',
- }, _('Reset'));
- btn_cron_del.onclick = ui.createHandlerFn(this, del_cron_schedule);
- btn_cron_del.style.visibility = (current_task) ? 'visible' : 'hidden';
+ cronStatusString: function(s) {
+ return s || _('No Shedule');
+ },
- 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),
- ])
- ]);
+ pickCronTask: function(content) {
+ if(!content){
+ return;
+ };
+ let current_tasks = content.match(this.crontabRegexp) || [];
+ return current_tasks.join('');
+ },
- 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) {
- 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 ]),
- ])
- )
- };
+ writeCronFile: function() {
+ let btn_cron_add = document.getElementById('btn_cron_add');
+ let btn_cron_del = document.getElementById('btn_cron_del');
- 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',
- { '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 = onchange_hour_interval;
+ return fs.write(tools.crontabFile, this.currentCrontabContent).then(rc => {
+ ui.addNotification(null, E('p',_('Changes have been saved.')), 'info');
+ this.setCronStatus(this.pickCronTask(this.currentCrontabContent));
+ }).then(() => {
+ return tools.getInitStatus('cron').then(res => {
+ if(!res) {
+ return tools.handleServiceAction('cron', 'enable');
+ };
+ });
+ }).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',
- { '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'));
+ delCronSchedule: function(ev) {
+ if(this.currentCrontabContent) {
+ this.currentCrontabContent = this.currentCrontabContent.replace(
+ this.crontabRegexp, "");
+ };
+ return this.writeCronFile();
+ },
- 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',
- { 'id': 'cron_hour', 'style': 'width:60px !important; min-width:60px !important' });
- for(let i = 0; i < 24 ; i++) {
- cron_hour.append(E('option', { 'value': String(i) }, to_dd(i)));
- };
- layout_append(cron_hour, _('Hour'));
+ onchangeHourInterval: function(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;
- let cron_min = E('select',
- { 'id': 'cron_min', 'style': 'width:60px !important; min-width:60px !important' });
- for(let i = 0; i < 60 ; i++) {
- cron_min.append(E('option', { 'value': String(i) }, to_dd(i)));
- };
- layout_append(cron_min, _('Minute'));
+ // For luci-theme-material
+ 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%';
+ };
+ },
- 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, set_cron_schedule);
- layout_append(btn_cron_add);
+ load: function() {
+ return fs.read(tools.crontabFile).catch(e => {
+ ui.addNotification(null, E('p', _('Unable to read the contents')
+ + ': %s [ %s ]'.format(
+ e.message, tools.crontabFile
+ )));
+ });
+ },
- 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),
- ]);
+ render: function(content) {
+ this.currentCrontabContent = content;
+ let current_task = this.pickCronTask(content);
- },
+ 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,
- handleSaveApply: null,
- handleReset: null,
+ let btn_cron_del = E('button', {
+ 'class': 'cbi-button btn cbi-button-reset',
+ 'id': 'btn_cron_del',
+ 'name': 'btn_cron_del',
+ }, _('Reset'));
+ btn_cron_del.onclick = ui.createHandlerFn(this, 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,
});
diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/info.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/info.js
index 2e3b047..f209831 100644
--- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/info.js
+++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/info.js
@@ -4,230 +4,238 @@
'require view.ruantiblock.tools as tools';
return L.view.extend({
- poll_info: function() {
- return fs.exec_direct(tools.exec_path, [ 'html-info' ], 'json').catch(e => {
- ui.addNotification(null, E('p', _('Unable to execute or read contents')
- + ': %s
[ %s ]'.format(e.message, tools.exec_path)
- ));
- L.Poll.stop();
- }).then(data => {
- if(!data) {
- return;
- };
+ infoPoll: function() {
+ return fs.exec_direct(tools.execPath, [ 'html-info' ], 'json').catch(e => {
+ ui.addNotification(null, E('p', _('Unable to execute or read contents')
+ + ': %s [ %s ]'.format(e.message, tools.execPath)
+ ));
+ L.Poll.stop();
+ }).then(data => {
+ if(!data) {
+ return;
+ };
- try {
- data = JSON.parse(data);
- } catch(err) {};
+ try {
+ data = JSON.parse(data);
+ } catch(err) {};
- if(data.status === 'enabled') {
- let date = document.getElementById('last_blacklist_update.date');
+ if(data.status === 'enabled') {
+ let date = document.getElementById('last_blacklist_update.date');
- if(data.last_blacklist_update.status) {
- if(date) {
- date.textContent = data.last_blacklist_update.date;
- };
+ if(data.last_blacklist_update.status) {
+ if(date) {
+ date.textContent = data.last_blacklist_update.date;
+ };
- let ip = document.getElementById('last_blacklist_update.ip');
- if(ip) {
- ip.textContent = data.last_blacklist_update.ip;
- };
+ let ip = document.getElementById('last_blacklist_update.ip');
+ if(ip) {
+ ip.textContent = data.last_blacklist_update.ip;
+ };
- let cidr = document.getElementById('last_blacklist_update.cidr');
- if(cidr) {
- cidr.textContent = data.last_blacklist_update.cidr;
- };
+ let cidr = document.getElementById('last_blacklist_update.cidr');
+ if(cidr) {
+ cidr.textContent = data.last_blacklist_update.cidr;
+ };
- let fqdn = document.getElementById('last_blacklist_update.fqdn');
- if(fqdn) {
- fqdn.textContent = data.last_blacklist_update.fqdn;
- };
- } else {
- if(date) {
- date.textContent = _('No data');
- };
- };
+ let fqdn = document.getElementById('last_blacklist_update.fqdn');
+ if(fqdn) {
+ fqdn.textContent = data.last_blacklist_update.fqdn;
+ };
+ } else {
+ if(date) {
+ date.textContent = _('No data');
+ };
+ };
- if(data.iptables) {
- for(let [k, v] of Object.entries(data.iptables)) {
- if(k === '_dummy') continue;
+ if(data.iptables) {
+ for(let [k, v] of Object.entries(data.iptables)) {
+ if(k === '_dummy') continue;
- let elem = document.getElementById('iptables.' + k);
- if(elem) {
- elem.textContent = v;
- };
- };
- };
+ let elem = document.getElementById('iptables.' + k);
+ if(elem) {
+ elem.textContent = v;
+ };
+ };
+ };
- if(data.ipset) {
- for(let [k, v] of Object.entries(data.ipset)) {
- if(k === '_dummy') continue;
+ if(data.ipset) {
+ for(let [k, v] of Object.entries(data.ipset)) {
+ if(k === '_dummy') continue;
- let elem0 = document.getElementById('ipset.' + k + '.' + '0');
- let elem1 = document.getElementById('ipset.' + k + '.' + '1');
- if(elem0 && elem1) {
- elem0.textContent = v[0];
- elem1.textContent = v[1];
- };
- };
- };
- } else {
- if(L.Poll.active()) {
- L.Poll.stop();
- };
- };
- });
- },
+ let elem0 = document.getElementById('ipset.' + k + '.' + '0');
+ let elem1 = document.getElementById('ipset.' + k + '.' + '1');
+ if(elem0 && elem1) {
+ elem0.textContent = v[0];
+ elem1.textContent = v[1];
+ };
+ };
+ };
+ } else {
+ if(L.Poll.active()) {
+ L.Poll.stop();
+ };
+ };
+ });
+ },
- load: function() {
- return fs.exec_direct(tools.exec_path, [ 'html-info' ], 'json').catch(e => {
- ui.addNotification(null, E('p', _('Unable to execute or read contents')
- + ': %s
[ %s ]'.format(e.message, tools.exec_path)
- ));
- })
- },
+ load: function() {
+ return fs.exec_direct(tools.execPath, [ 'html-info' ], 'json').catch(e => {
+ ui.addNotification(null, E('p', _('Unable to execute or read contents')
+ + ': %s [ %s ]'.format(e.message, tools.execPath)
+ ));
+ })
+ },
- render: function(data) {
- if(!data) {
- return;
- };
+ render: function(data) {
+ if(!data) {
+ return;
+ };
- try {
- data = JSON.parse(data);
- } catch(err) {};
+ try {
+ data = JSON.parse(data);
+ } catch(err) {};
- let update_status = null,
- iptables = null,
- ipset = null;
- if(data) {
- if(data.status === 'enabled') {
- update_status = E('div', { 'class': 'table' });
+ let update_status = null,
+ iptables = null,
+ ipset = null;
+ if(data) {
+ if(data.status === 'enabled') {
+ update_status = E('div', { 'class': 'table' });
- if(data.last_blacklist_update.status) {
- update_status.append(
- E('div', { 'class': 'tr' }, [
- E('div', { 'class': 'td left', 'style': 'min-width:33%' },
- _('Last blacklist update') + ':'),
- E('div', { 'class': 'td left', 'id': 'last_blacklist_update.date' },
- data.last_blacklist_update.date),
- ]),
- E('div', { 'class': 'tr' }, [
- E('div', { 'class': 'td left' }, 'IP:'),
- E('div', { 'class': 'td left', 'id': 'last_blacklist_update.ip' },
- data.last_blacklist_update.ip),
- ]),
- E('div', { 'class': 'tr' }, [
- E('div', { 'class': 'td left' }, 'CIDR:'),
- E('div', { 'class': 'td left', 'id': 'last_blacklist_update.cidr' },
- data.last_blacklist_update.cidr),
- ]),
- E('div', { 'class': 'tr' }, [
- E('div', { 'class': 'td left' }, 'FQDN:'),
- E('div', { 'class': 'td left', 'id': 'last_blacklist_update.fqdn' },
- data.last_blacklist_update.fqdn),
- ])
- );
- } else {
- update_status.append(
- E('div', { 'class': 'tr' }, [
- E('div', { 'class': 'td left' },
- _('Last blacklist update')),
- E('div', { 'class': 'td left' }, _('No data')),
- ])
- );
- };
+ if(data.last_blacklist_update.status) {
+ update_status.append(
+ E('div', { 'class': 'tr' }, [
+ E('div', { 'class': 'td left', 'style': 'min-width:33%' },
+ _('Last blacklist update') + ':'),
+ E('div', { 'class': 'td left',
+ 'id': 'last_blacklist_update.date' },
+ data.last_blacklist_update.date),
+ ]),
+ E('div', { 'class': 'tr' }, [
+ E('div', { 'class': 'td left' }, 'IP:'),
+ E('div', { 'class': 'td left',
+ 'id': 'last_blacklist_update.ip' },
+ data.last_blacklist_update.ip),
+ ]),
+ E('div', { 'class': 'tr' }, [
+ E('div', { 'class': 'td left' }, 'CIDR:'),
+ E('div', { 'class': 'td left',
+ 'id': 'last_blacklist_update.cidr' },
+ data.last_blacklist_update.cidr),
+ ]),
+ E('div', { 'class': 'tr' }, [
+ E('div', { 'class': 'td left' }, 'FQDN:'),
+ E('div', { 'class': 'td left',
+ 'id': 'last_blacklist_update.fqdn' },
+ data.last_blacklist_update.fqdn),
+ ])
+ );
+ } else {
+ 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) {
- let table_iptables = E('div', { 'class': 'table' }, [
- E('div', { 'class': 'tr table-titles' }, [
- E('div', { 'class': 'th left', 'style': 'min-width:33%' },
- _('Match-set')),
- E('div', { 'class': 'th left' }, _('Bytes')),
- ]),
- ]);
+ if(data.iptables) {
+ let table_iptables = E('div', { 'class': 'table' }, [
+ E('div', { 'class': 'tr table-titles' }, [
+ E('div', { 'class': 'th left', 'style': 'min-width:33%' },
+ _('Match-set')),
+ E('div', { 'class': 'th left' }, _('Bytes')),
+ ]),
+ ]);
- for(let [k, v] of Object.entries(data.iptables)) {
- if(k === '_dummy') continue;
+ for(let [k, v] of Object.entries(data.iptables)) {
+ 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(
- 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),
- ])
- );
- };
+ iptables = E([
+ E('h3', {}, _('Iptables rules')),
+ table_iptables,
+ ]);
+ };
- iptables = E([
- E('h3', {}, _('Iptables rules')),
- table_iptables,
- ]);
- };
+ if(data.ipset) {
+ let table_ipset = E('div', { 'class': 'table' },
+ E('div', { 'class': 'tr table-titles' }, [
+ E('div', { 'class': 'th left', 'style': 'min-width:33%' },
+ _('Name')),
+ E('div', { 'class': 'th left' },
+ _('Size in memory')),
+ E('div', { 'class': 'th left' },
+ _('Number of entries')),
+ ])
+ );
- if(data.ipset) {
- let table_ipset = E('div', { 'class': 'table' },
- E('div', { 'class': 'tr table-titles' }, [
- E('div', { 'class': 'th left', 'style': 'min-width:33%' }, _('Name')),
- E('div', { 'class': 'th left' }, _('Size in memory')),
- E('div', { 'class': 'th left' }, _('Number of entries')),
- ])
- );
+ for(let [k, v] of Object.entries(data.ipset)) {
+ if(k === '_dummy') continue;
- for(let [k, v] of Object.entries(data.ipset)) {
- if(k === '_dummy') continue;
+ table_ipset.append(
+ 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(
- 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]),
- ])
- );
- };
+ ipset = E([
+ E('h3', {}, _('Ipset')),
+ table_ipset,
+ ]);
+ };
- ipset = E([
- E('h3', {}, _('Ipset')),
- table_ipset,
- ]);
- };
+ L.Poll.add(this.infoPoll);
+ } else {
+ 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);
- } else {
- 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)
- ),
- ]);
- },
-
- handleSave: null,
- handleSaveApply: null,
- handleReset: null,
+ handleSave : null,
+ handleSaveApply: null,
+ handleReset : null,
});
diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log.js
index a24e352..cc592d0 100644
--- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log.js
+++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log.js
@@ -8,13 +8,13 @@ return abc.view.extend({
title: _('Ruantiblock') + ' - ' + _('Log'),
- appRegexp: new RegExp(`^.*${tools.app_name}\[[0-9]+\].*$`, 'gm'),
+ appRegexp : new RegExp(`^.*${tools.appName}\[[0-9]+\].*$`, 'gm'),
- testRegexp: new RegExp(/([0-9]{2}:){2}[0-9]{2}/),
+ testRegexp : new RegExp(/([0-9]{2}:){2}[0-9]{2}/),
isLoggerChecked: false,
- entriesHandler: null,
+ entriesHandler : null,
// logd
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;
if(logger) {
- return fs.exec_direct(logger, [ '-e', tools.app_name ]).catch(err => {
- ui.addNotification(null, E('p', {}, _('Unable to load log data:') + ' ' + err.message));
+ return fs.exec_direct(logger, [ '-e', tools.appName ]).catch(err => {
+ ui.addNotification(
+ null, E('p', {}, _('Unable to load log data:') + ' ' + err.message));
return '';
});
};
diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/service.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/service.js
index 25730f2..08866df 100644
--- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/service.js
+++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/service.js
@@ -4,342 +4,349 @@
'require ui';
'require view.ruantiblock.tools as tools';
-const btn_style_neutral = 'btn'
-const btn_style_action = 'btn cbi-button-action';
-const btn_style_save = 'btn cbi-button-save important';
-const btn_style_reset = 'btn cbi-button-reset important';
-const btn_style_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
[ %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();
- });
- });
-}
+const btn_style_neutral = 'btn'
+const btn_style_action = 'btn cbi-button-action';
+const btn_style_positive = 'btn cbi-button-save important';
+const btn_style_negative = 'btn cbi-button-reset important';
+const btn_style_warning = 'btn cbi-button-negative important'
return L.view.extend({
- poll_status: function() {
- return fs.read(tools.token_file).then(v => {
- v = tools.normalize_value(v);
- if(v != status_token_value) {
- get_app_status().then(set_app_status);
- }
- status_token_value = v;
- }).catch(e => {
- status_token_value = 0;
- });
- },
+ statusTokenValue: null,
- dialog_destroy: function(ev) {
- ev.target.blur();
- let cancel_button = E('button', {
- 'class': btn_style_neutral,
- 'click': ui.hideModal,
- }, _('Cancel'));
+ disableButtons: function(bool, btn, elems=[]) {
+ let btn_start = elems[1] || document.getElementById("btn_start");
+ let btn_destroy = elems[5] || document.getElementById("btn_destroy");
+ let btn_enable = elems[2] || document.getElementById("btn_enable");
+ let btn_update = elems[4] || document.getElementById("btn_update");
+ let btn_tp = elems[3] || document.getElementById("btn_tp");
- let shutdown_btn = E('button', {
- 'class': btn_style_warning,
- }, _('Shutdown'));
- shutdown_btn.onclick = ui.createHandlerFn(this, function() {
- cancel_button.disabled = true;
- return button_action('destroy');
- });
+ 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;
+ };
+ },
- 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,
- ])
- ]);
- },
+ getAppStatus: function() {
+ return Promise.all([
+ fs.exec(tools.execPath, [ 'raw-status' ]),
+ fs.exec(tools.execPath, [ 'total-proxy-status' ]),
+ fs.exec(tools.execPath, [ 'vpn-route-status' ]),
+ tools.getInitStatus(tools.appName),
+ L.resolveDefault(fs.read(tools.tokenFile), 0),
+ uci.load(tools.appName),
+ ]).catch(e => {
+ ui.addNotification(null, E('p', _('Unable to execute or read contents')
+ + ': %s [ %s | %s | %s ]'.format(
+ e.message, tools.execPath, 'tools.getInitStatus', 'uci.ruantiblock'
+ )));
+ });
+ },
- load: function() {
- return get_app_status();
- },
+ setAppStatus: function(status_array, elems=[], force_app_code) {
+ let section = uci.get(tools.appName, 'config');
+ if(!status_array || typeof(section) !== 'object') {
+ (elems[0] || document.getElementById("status")).innerHTML = tools.makeStatusString(1);
+ ui.addNotification(null, E('p', _('Unable to read the contents')
+ + ': setAppStatus()'));
+ this.disableButtons(true, null, elems);
+ return;
+ };
- render: function(status_array) {
- if(!status_array) {
- 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];
+ 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 proxy_local_clients = (typeof(section) === 'object') ? section.proxy_local_clients : null;
- status_token_value = (Array.isArray(status_array)) ? tools.normalize_value(status_array[4]) : null;
+ let btn_enable = elems[2] || document.getElementById('btn_enable');
+ if(enabled_flag == true) {
+ btn_enable.onclick = ui.createHandlerFn(
+ this, this.serviceAction, 'disable', 'btn_enable');
+ btn_enable.textContent = _('Enabled');
+ btn_enable.className = btn_style_positive;
+ } else {
+ btn_enable.onclick = ui.createHandlerFn(
+ this, this.serviceAction, 'enable', 'btn_enable');
+ btn_enable.textContent = _('Disabled');
+ btn_enable.className = btn_style_negative;
+ };
- let status_string = E('div', {
- 'id': 'status',
- 'name': 'status',
- 'class': 'cbi-section-node',
- });
+ let btn_tp = elems[3] || document.getElementById('btn_tp');
+ if(btn_tp) {
+ if(tp_status_code == 0) {
+ 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) {
- 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 btnStartStateOn = () => {
+ btn_start.onclick = ui.createHandlerFn(
+ this, this.serviceAction, 'stop', 'btn_start');
+ btn_start.textContent = _('Enabled');
+ btn_start.className = btn_style_positive;
+ }
- let btn_start = E('button', {
- 'id': 'btn_start',
- 'name': 'btn_start',
- 'class': btn_style_action,
- }, _('Enable'));
- layout_append(btn_start, _('Service'));
+ let btnStartStateOff = () => {
+ btn_start.onclick = ui.createHandlerFn(
+ this, this.serviceAction,'start', 'btn_start');
+ btn_start.textContent = _('Disabled');
+ btn_start.className = btn_style_negative;
+ }
- let btn_enable = E('button', {
- 'id': 'btn_enable',
- 'name': 'btn_enable',
- 'class': btn_style_save,
- }, _('Enable'));
- layout_append(btn_enable, _('Run at startup'));
+ if(app_status_code == 0) {
+ this.disableButtons(false, null, elems);
+ btnStartStateOn();
+ btn_destroy.disabled = false;
+ btn_update.disabled = false;
+ 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', {
- 'id': 'btn_tp',
- 'name': 'btn_tp',
- 'class': btn_style_save,
- }, _('Enable'));
- if(proxy_local_clients == '0') {
- layout_append(btn_tp, _('Total-proxy'),
- _('All traffic goes through the proxy without applying rules'));
- };
+ (elems[0] || document.getElementById("status")).innerHTML = tools.makeStatusString(
+ app_status_code,
+ proxy_mode,
+ bllist_mode,
+ bllist_module,
+ bllist_source,
+ tp_status_code,
+ vpn_route_status_code);
- let btn_update = E('button', {
- 'id': 'btn_update',
- 'name': 'btn_update',
- 'class': btn_style_action,
- }, _('Update'));
- btn_update.onclick = ui.createHandlerFn(this, () => { button_action('update') });
- layout_append(btn_update, _('Update blacklist'));
+ if(!L.Poll.active()) {
+ L.Poll.start();
+ };
+ },
- let btn_destroy = E('button', {
- 'id': 'btn_destroy',
- 'name': 'btn_destroy',
- 'class': btn_style_reset,
- }, _('Shutdown'));
- btn_destroy.onclick = this.dialog_destroy;
+ serviceAction: function(action, button) {
+ if(button) {
+ let elem = document.getElementById(button);
+ this.disableButtons(true, elem);
+ };
- layout_append(btn_destroy, _('Shutdown'),
- _('Complete service shutdown, as well as deleting ipsets and blacklist data'));
+ L.Poll.stop();
- set_app_status(status_array, [
- status_string,
- btn_start,
- btn_enable,
- btn_tp,
- btn_update,
- btn_destroy,
- ]);
+ return tools.handleServiceAction(tools.appName, action).then(() => {
+ return this.getAppStatus().then(
+ (status_array) => {
+ this.setAppStatus(status_array);
+ }
+ );
+ });
+ },
- L.Poll.add(this.poll_status);
+ appAction: function(action, button) {
+ if(button) {
+ let elem = document.getElementById(button);
+ this.disableButtons(true, elem);
+ };
- 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
- ),
- ]);
- },
+ L.Poll.stop();
- handleSave: null,
- handleSaveApply: null,
- handleReset: null,
+ if(action === 'update') {
+ this.getAppStatus().then(status_array => {
+ this.setAppStatus(status_array, [], 4);
+ });
+ };
+
+ return fs.exec_direct(tools.execPath, [ action ]).then(res => {
+ return this.getAppStatus().then(
+ (status_array) => {
+ this.setAppStatus(status_array);
+ ui.hideModal();
+ }
+ );
+ });
+ },
+
+ statusPoll: function() {
+ return fs.read(tools.tokenFile).then(v => {
+ v = tools.normalizeValue(v);
+ if(v != this.statusTokenValue) {
+ this.getAppStatus().then(
+ L.bind(this.setAppStatus, this)
+ );
+ }
+ this.statusTokenValue = v;
+ }).catch(e => {
+ this.statusTokenValue = 0;
+ });
+ },
+
+ dialogDestroy: function(ev) {
+ ev.target.blur();
+ let cancel_button = E('button', {
+ 'class': btn_style_neutral,
+ '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,
});
diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/settings.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/settings.js
index c278fe3..3ffd645 100644
--- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/settings.js
+++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/settings.js
@@ -6,393 +6,354 @@
'require tools.widgets as widgets';
'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 # in the first position of the line - comments on the line.
Examples (dot is a special character):') + '128[.]199[.]0[.]0/16'
-);
-
-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
34[.]217[.]90[.]52
162[.]13[.]190[.]# in the first position of the line - comments on the line.
Examples:') + 'poker'
-);
-
-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 (
[ck]?a[sz]ino?
[vw]ulkan
slots?# is the first character of a line).
Examples:') + '#comment'
-);
-
-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
domain.net
sub.domain.com 8.8.8.8
sub.domain.com 8.8.8.8#53
74.125.131.19
74.125.0.0/16
[ %s ]'.format(e.message, '/etc/init.d/tor')));
- });
- }
-);
-
return L.view.extend({
- app_status_code: null,
+ availableParsers: {},
- load: function() {
- 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
[ %s ]'.format(
- e.message, tools.parsers_dir
- )));
- });
- },
+ appStatusCode : null,
- render: function(data) {
- if(!data) {
- return;
- };
- this.app_status_code = 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';
+ depends: function(elem, key, array, empty=true) {
+ if(empty && array.length === 0) {
+ elem.depends(key, '_dummy');
+ } else {
+ array.forEach(e => elem.depends(key, e));
+ };
+ },
- if(p_dir_arr) {
- p_dir_arr.forEach(e => {
- let fname = e.name;
- if(fname.startsWith('ruab_parser')) {
- available_parsers.push(tools.parsers_dir + '/' + fname);
- };
- });
- };
+ dependsBllistModule: function(elem) {
+ this.depends(elem, 'bllist_module', Object.values(this.availableParsers));
+ },
- 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');
- s.anonymous = true;
- s.addremove = false;
+ 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)
+ ),
+ ]);
+ },
+ }),
- /* 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(this.app_status_code == 1 || this.app_status_code == 2) {
- o = s.taboption('main_settings', form.ListValue, 'proxy_mode',
- _('Proxy mode'));
- o.value('1', 'Tor');
- o.value('2', 'VPN');
- };
+ if(p_dir_arr) {
+ p_dir_arr.forEach(e => {
+ let fname = e.name;
+ if(fname.startsWith('ruab_parser')) {
+ this.availableParsers[fname] = tools.parsersDir + '/' + fname;
+ };
+ });
+ };
- // 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;
- proxy_local_clients.default = proxy_local_clients.enabled;
+ let ip_filter_edit = new tools.fileEditDialog(
+ tools.ipFilterFile,
+ _('IP filter'),
+ _('Patterns can be strings or regular expressions. Each pattern in a separate line, the symbol # in the first position of the line - comments on the line.
Examples (dot is a special character):') +
+ '128[.]199[.]0[.]0/16'
+ );
- // USE_LOGGER
- o = s.taboption('main_settings', form.Flag, 'use_logger',
- _('Logging events'));
- o.rmempty = false;
- o.default = 1;
+ let fqdn_filter_edit = new tools.fileEditDialog(
+ tools.fqdnFilterFile,
+ _('FQDN filter'),
+ _('Patterns can be strings or regular expressions. Each pattern in a separate line, the symbol
34[.]217[.]90[.]52
162[.]13[.]190[.]# in the first position of the line - comments on the line.
Examples:') +
+ 'poker'
+ );
- // 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');
+ let user_entries_edit = new tools.fileEditDialog(
+ tools.userEntriesFile,
+ _('User entries'),
+ _('One entry (IP, CIDR or FQDN) per line. In the FQDN records, you can specify the DNS server for resolving this domain (separated by a space). You can also comment on lines (
[ck]?a[sz]ino?
[vw]ulkan
slots?# is the first character of a line).
Examples:') +
+ '#comment'
+ );
- // 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;
- o.default = 0;
+ let torrc_edit = new tools.fileEditDialog(
+ tools.torrcFile,
+ _('Tor configuration file'),
+ null,
+ function(rc) {
+ return tools.getInitStatus('tor').then(res => {
+ if(res) {
+ return tools.handleServiceAction('tor', 'restart');
+ };
+ });
+ }
+ );
+
+ let m, s, o;
+
+ m = new form.Map(tools.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) {
- /* Tor tab */
+ if(this.appStatusCode == 1 || this.appStatusCode == 2) {
+ /* Tor tab */
- s.tab('tor_settings', _('Tor mode'));
+ s.tab('tor_settings', _('Tor mode'));
- // IF_LAN
- o = s.taboption('tor_settings', widgets.DeviceSelect, 'if_lan',
- _('LAN interface'));
- o.multiple = false;
- o.noaliases = true;
- o.rmempty = false;
- o.default = lan_iface;
+ // IF_LAN
+ o = s.taboption('tor_settings', widgets.DeviceSelect, 'if_lan',
+ _('LAN interface'));
+ o.multiple = false;
+ o.noaliases = true;
+ o.rmempty = false;
+ o.default = lan_iface;
- // TOR_TRANS_PORT
- o = s.taboption('tor_settings', form.Value, 'tor_trans_port',
- _('Transparent proxy port for iptables rules'));
- o.rmempty = false;
- o.datatype = "port";
- o.default = '9040';
+ // TOR_TRANS_PORT
+ o = s.taboption('tor_settings', form.Value, 'tor_trans_port',
+ _('Transparent proxy port for iptables rules'));
+ o.rmempty = false;
+ o.datatype = "port";
- // ONION_DNS_ADDR
- o = s.taboption('tor_settings', form.Value, 'onion_dns_addr',
- _("Optional DNS resolver for '.onion' zone"), '
domain.net
sub.domain.com 8.8.8.8
sub.domain.com 8.8.8.8#53
74.125.131.19
74.125.0.0/16ipaddress#port');
- o.rmempty = false;
- o.default = '127.0.0.1#9053';
- o.validate = validate_ip_port;
+ // ONION_DNS_ADDR
+ o = s.taboption('tor_settings', form.Value, 'onion_dns_addr',
+ _("Optional DNS resolver for '.onion' zone"), 'ipaddress#port');
+ o.rmempty = false;
+ o.validate = this.validateIpPort;
- // Torrc edit dialog
- o = s.taboption('tor_settings', form.Button, '_torrc_btn',
- _('Tor configuration file'));
- o.onclick = () => torrc_edit.show();
- o.inputtitle = _('Edit');
- o.inputstyle = 'edit btn';
+ // Torrc edit dialog
+ o = s.taboption('tor_settings', form.Button, '_torrc_btn',
+ _('Tor configuration file'));
+ o.onclick = () => torrc_edit.show();
+ o.inputtitle = _('Edit');
+ o.inputstyle = 'edit btn';
- /* VPN tab */
+ /* VPN tab */
- s.tab('vpn_settings', _('VPN mode'));
+ s.tab('vpn_settings', _('VPN mode'));
- // IF_VPN
- o = s.taboption('vpn_settings', widgets.DeviceSelect, 'if_vpn',
- _('VPN interface'));
- o.multiple = false;
- o.noaliases = true;
- o.rmempty = false;
- o.default = vpn_iface;
- };
+ // IF_VPN
+ o = s.taboption('vpn_settings', widgets.DeviceSelect, 'if_vpn',
+ _('VPN interface'));
+ o.multiple = false;
+ o.noaliases = true;
+ o.rmempty = false;
+ o.default = vpn_iface;
+ };
- /* Parser settings tab */
+ /* Parser settings tab */
- s.tab('parser_settings', _('Blacklist settings'));
+ s.tab('parser_settings', _('Blacklist settings'));
- // BLLIST_MODULE
- let bllist_module = s.taboption('parser_settings', form.ListValue,
- 'bllist_module', _('Blacklist module'));
- bllist_module.value("", _("user entries only"));
- available_parsers.forEach(e => bllist_module.value(e));
+ // BLLIST_MODULE
+ let bllist_module = s.taboption('parser_settings', form.ListValue,
+ 'bllist_module', _('Blacklist module'));
+ bllist_module.value('', _('none (user entries only)'));
+ Object.entries(this.availableParsers).forEach(
+ e => bllist_module.value(e[1], e[0]));
- // BLLIST_MODE
- let bllist_mode = s.taboption('parser_settings', form.ListValue,
- 'bllist_mode', _('Module operation mode'));
- bllist_mode.value('ip');
- bllist_mode.value('fqdn');
- depends_bllist_module(bllist_mode);
+ // BLLIST_MODE
+ let bllist_mode = s.taboption('parser_settings', form.ListValue,
+ 'bllist_mode', _('Module operation mode'));
+ bllist_mode.value('ip');
+ bllist_mode.value('fqdn');
- // BLLIST_SOURCE
- let bllist_source = s.taboption('parser_settings', form.ListValue,
- 'bllist_source', _('Blacklist source'));
- bllist_source.description = _("Options") + ':';
- for(let [k, v] of Object.entries(tools.blacklist_sources)) {
- bllist_source.value(k);
- bllist_source.description += `
${k} - ${v}`;
- };
- depends_bllist_module(bllist_source);
+ // BLLIST_SOURCE
+ let bllist_source = s.taboption('parser_settings', form.ListValue,
+ 'bllist_source', _('Blacklist source'));
+ bllist_source.description = _("Options") + ':';
+ for(let [k, v] of Object.entries(tools.blacklistSources)) {
+ bllist_source.value(k);
+ bllist_source.description += `
${k} - ${v}`;
+ };
- o = s.taboption('parser_settings', CBIBlockTitle, '_dummy_ip');
- o.string = _('IP configuration') + ':';
- depends_bllist_module(o);
+ o = s.taboption('parser_settings', this.CBIBlockTitle, '_dummy_ip');
+ o.string = _('IP configuration') + ':';
- // 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.datatype = 'uinteger';
- o.default = '0';
- depends_bllist_module(o);
+ // IP_LIMIT
+ o = s.taboption('parser_settings', form.Value, 'ip_limit', _("IP limit"));
+ o.description = _("The number of IP addresses in the subnet, upon reaching which the entire '/24' subnet is added to the list");
+ o.rmempty = false;
+ o.datatype = 'uinteger';
- // OPT_EXCLUDE_NETS
- o = s.taboption('parser_settings', form.DynamicList, 'opt_exclude_nets');
- o.title = _('IP subnet patterns (/24) that are excluded from optimization');
- o.description = _('e.g:') + ' 192.168.1.';
- o.placeholder = _('e.g:') + ' 192.168.1.';
- o.default = '';
+ // OPT_EXCLUDE_NETS
+ o = s.taboption('parser_settings', form.DynamicList, 'opt_exclude_nets');
+ o.title = _('IP subnet patterns (/24) that are excluded from optimization');
+ o.description = _('e.g:') + ' 192.168.1.';
+ o.placeholder = _('e.g:') + ' 192.168.1.';
+ 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
- o = s.taboption('parser_settings', form.Flag, 'summarize_ip',
- _("Summarize IP ranges"));
- o.rmempty = false;
- o.default = 0;
- depends_bllist_module(o);
+ // SUMMARIZE_CIDR
+ o = s.taboption('parser_settings', form.Flag, 'summarize_cidr',
+ _("Summarize '/24' networks"));
+ o.rmempty = false;
- // SUMMARIZE_CIDR
- o = s.taboption('parser_settings', form.Flag, 'summarize_cidr',
- _("Summarize '/24' networks"));
- o.rmempty = false;
- o.default = 0;
- depends_bllist_module(o);
+ o = s.taboption('parser_settings', this.CBIBlockTitle, '_dummy_fqdn');
+ o.string = _('FQDN configuration') + ':';
- o = s.taboption('parser_settings', CBIBlockTitle, '_dummy_fqdn');
- o.string = _('FQDN configuration') + ':';
- depends_bllist_module(o);
+ // SD_LIMIT
+ o = s.taboption('parser_settings', form.Value, 'sd_limit',
+ _("Subdomains limit"));
+ o.description = _('The number of subdomains in the domain, upon reaching which the entire 2nd level domain is added to the list');
+ o.rmempty = false;
+ o.datatype = 'uinteger';
- // SD_LIMIT
- o = s.taboption('parser_settings', form.Value, 'sd_limit',
- _("Subdomains limit"));
- o.description = _('The number of subdomains in the domain, upon reaching which the entire 2nd level domain is added to the list');
- o.datatype = 'uinteger';
- o.default = '16';
- depends_bllist_module(o);
+ // OPT_EXCLUDE_SLD
+ o = s.taboption('parser_settings', form.DynamicList, 'opt_exclude_sld',
+ _('2nd level domains that are excluded from optimization'));
+ o.description = _('e.g:') + ' livejournal.com';
+ o.placeholder = _('e.g:') + ' livejournal.com';
+ o.datatype = "hostname";
- // OPT_EXCLUDE_SLD
- o = s.taboption('parser_settings', form.DynamicList, 'opt_exclude_sld',
- _('2nd level domains that are excluded from optimization'));
- o.datatype = "hostname";
- o.default = [
- 'livejournal.com',
- 'facebook.com',
- 'vk.com',
- 'blog.jp',
- 'msk.ru',
- 'net.ru',
- 'org.ru',
- 'net.ua',
- 'com.ua',
- 'org.ua',
- 'co.uk',
- 'amazonaws.com',
- ];
- depends_bllist_module(o);
+ // USE_IDN
+ o = s.taboption('parser_settings', form.Flag, 'use_idn',
+ _("Convert cyrillic domains to punycode"));
+ o.rmempty = false;
- // USE_IDN
- o = s.taboption('parser_settings', form.Flag, 'use_idn',
- _("Convert cyrillic domains to punycode"));
- o.rmempty = false;
- o.default = 0;
- depends_bllist_module(o);
+ // ALT_NSLOOKUP
+ o = s.taboption('parser_settings', form.Flag, 'alt_nslookup',
+ _('Use optional DNS resolver'));
+ o.rmempty = false;
- // ALT_NSLOOKUP
- o = s.taboption('parser_settings', form.Flag, 'alt_nslookup',
- _('Use optional DNS resolver'));
- o.rmempty = false;
- o.default = 0;
- depends_bllist_module(o);
-
- // ALT_DNS_ADDR
- o = s.taboption('parser_settings', form.Value, 'alt_dns_addr',
- _("Optional DNS resolver"), 'ipaddress[#port]');
- o.rmempty = false;
- o.depends('alt_nslookup', '1');
- o.validate = validate_ip_port;
- o.default = '8.8.8.8';
+ // ALT_DNS_ADDR
+ o = s.taboption('parser_settings', form.Value, 'alt_dns_addr',
+ _("Optional DNS resolver"), 'ipaddress[#port]');
+ o.rmempty = false;
+ o.validate = this.validateIpPort;
- /* Entries filters tab */
+ /* Blacklist entry filters tab */
- s.tab('entries_filter_tab', _('Entries filters'));
+ s.tab('entries_filter_tab', _('Blacklist entry filters'));
- // IP_FILTER
- o = s.taboption('entries_filter_tab', form.Flag, 'ip_filter',
- _("Enable IP filter"));
- o.description = _('Exclude IP addresses from blacklist by IP filter patterns');
- o.rmempty = false;
- o.default = 0;
- depends_bllist_module(o);
+ // IP_FILTER
+ o = s.taboption('entries_filter_tab', form.Flag, 'ip_filter',
+ _("Enable IP filter"));
+ o.description = _('Exclude IP addresses from blacklist by IP filter patterns');
+ o.rmempty = false;
- // IP_FILTER edit dialog
- o = s.taboption('entries_filter_tab', form.Button, '_ip_filter_btn',
- _("IP filter"));
- o.onclick = () => ip_filter_edit.show();
- o.inputtitle = _('Edit');
- o.inputstyle = 'edit btn';
- depends_bllist_module(o);
+ // IP_FILTER edit dialog
+ o = s.taboption('entries_filter_tab', form.Button, '_ip_filter_btn',
+ _("IP filter"));
+ o.onclick = () => ip_filter_edit.show();
+ o.inputtitle = _('Edit');
+ o.inputstyle = 'edit btn';
- // FQDN_FILTER
- o = s.taboption('entries_filter_tab', form.Flag, 'fqdn_filter',
- _("Enable FQDN filter"));
- o.description = _('Exclude domains from blacklist by FQDN filter patterns');
- o.rmempty = false;
- o.default = 0;
- depends_bllist_module(o);
+ // FQDN_FILTER
+ o = s.taboption('entries_filter_tab', form.Flag, 'fqdn_filter',
+ _("Enable FQDN filter"));
+ o.description = _('Exclude domains from blacklist by FQDN filter patterns');
+ o.rmempty = false;
- // FQDN_FILTER edit dialog
- o = s.taboption('entries_filter_tab', form.Button, '_fqdn_filter_btn',
- _("FQDN filter"));
- o.onclick = () => fqdn_filter_edit.show();
- o.inputtitle = _('Edit');
- o.inputstyle = 'edit btn';
- depends_bllist_module(o);
+ // FQDN_FILTER edit dialog
+ o = s.taboption('entries_filter_tab', form.Button, '_fqdn_filter_btn',
+ _("FQDN filter"));
+ o.onclick = () => fqdn_filter_edit.show();
+ o.inputtitle = _('Edit');
+ o.inputstyle = 'edit btn';
- /* User entries tab */
+ /* User entries tab */
- s.tab('user_entries_tab', _('User entries'));
+ s.tab('user_entries_tab', _('User entries'));
- // ADD_USER_ENTRIES
- o = s.taboption('user_entries_tab', form.Flag, 'add_user_entries',
- _('Enable'), _("Add user entries to the blacklist when updating"));
- o.rmempty = false;
- o.default = 0;
- depends_bllist_module(o);
+ // ADD_USER_ENTRIES
+ o = s.taboption('user_entries_tab', form.Flag, 'add_user_entries',
+ _('Enable'), _("Add user entries to the blacklist when updating"));
+ o.rmempty = false;
+ o.default = 0;
+ this.dependsBllistModule(o);
- // USER_ENTRIES_DNS
- o = s.taboption('user_entries_tab', form.Value, 'user_entries_dns',
- _("DNS server that is used for FQDN entries"), 'ipaddress[#port]');
- o.validate = validate_ip_port;
+ // USER_ENTRIES_DNS
+ o = s.taboption('user_entries_tab', form.Value, 'user_entries_dns',
+ _("DNS server that is used for FQDN entries"), 'ipaddress[#port]');
+ o.validate = this.validateIpPort;
- // USER_ENTRIES edit dialog
- o = s.taboption('user_entries_tab', form.Button, '_user_entries_btn',
- _('User entries'));
- o.onclick = () => user_entries_edit.show();
- o.inputtitle = _('Edit');
- o.inputstyle = 'edit btn';
+ // USER_ENTRIES edit dialog
+ o = s.taboption('user_entries_tab', form.Button, '_user_entries_btn',
+ _('User entries'));
+ o.onclick = () => user_entries_edit.show();
+ o.inputtitle = _('Edit');
+ 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();
- map_promise.then(node => node.classList.add('fade-in'));
+ handleSaveApply: function(ev, mode) {
+ return this.handleSave(ev).then(() => {
+ ui.changes.apply(mode == '0');
- return map_promise;
- },
-
- 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);
- };
- });
- },
+ if(this.appStatusCode != 1 && this.appStatusCode != 2) {
+ window.setTimeout(() => tools.handleServiceAction(
+ tools.appName, 'restart'), 3000);
+ };
+ });
+ },
});
diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/tools.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/tools.js
index 48444c4..bc5896c 100644
--- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/tools.js
+++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/tools.js
@@ -1,252 +1,291 @@
'use strict';
'require fs';
+'require rpc';
'require ui';
document.head.append(E('style', {'type': 'text/css'},
`
.label-status {
- display: inline;
- margin: 0px 2px 0px 0 !important;
- padding: 1px 4px 2px 4px;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
- font-weight: bold;
- color: #fff !important;
+ display: inline;
+ margin: 0px 2px 0px 0 !important;
+ padding: 1px 4px 2px 4px;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ font-weight: bold;
+ color: #fff !important;
}
.starting {
- background-color: #a7b668 !important;
+ background-color: #a7b668 !important;
}
.running {
- background-color: #2ea256 !important;
+ background-color: #2ea256 !important;
}
.updating {
- background-color: #1e82ff !important;
+ background-color: #1e82ff !important;
}
.stopped {
- background-color: #acacac !important;
+ background-color: #acacac !important;
}
.error {
- background-color: #ff4e54 !important;
+ background-color: #ff4e54 !important;
}
.total-proxy {
- background-color: #ffb937 !important;
+ background-color: #ffb937 !important;
}
`));
return L.Class.extend({
- app_name: 'ruantiblock',
- exec_path: '/usr/bin/ruantiblock',
- init_path: '/etc/init.d/ruantiblock',
- token_file: '/var/run/ruantiblock.token',
- parsers_dir: '/usr/bin',
- torrc_file: '/etc/tor/torrc',
- user_entries_file: '/etc/ruantiblock/user_entries',
- fqdn_filter_file: '/etc/ruantiblock/fqdn_filter',
- ip_filter_file: '/etc/ruantiblock/ip_filter',
- crontab_file: '/etc/crontabs/root',
- info_label_starting: '' + _('Starting') + '',
- info_label_running: '' + _('Enabled') + '',
- info_label_updating: '' + _('Updating') + '',
- info_label_stopped: '' + _('Disabled') + '',
- info_label_error: '' + _('Error') + '',
+ appName : 'ruantiblock',
+ execPath : '/usr/bin/ruantiblock',
+ tokenFile : '/var/run/ruantiblock.token',
+ parsersDir : '/usr/bin',
+ torrcFile : '/etc/tor/torrc',
+ userEntriesFile : '/etc/ruantiblock/user_entries',
+ fqdnFilterFile : '/etc/ruantiblock/fqdn_filter',
+ ipFilterFile : '/etc/ruantiblock/ip_filter',
+ crontabFile : '/etc/crontabs/root',
+ infoLabelStarting: '' + _('Starting') + '',
+ infoLabelRunning : '' + _('Enabled') + '',
+ infoLabelUpdating: '' + _('Updating') + '',
+ infoLabelStopped : '' + _('Disabled') + '',
+ infoLabelError : '' + _('Error') + '',
- blacklist_sources: {
- 'rublacklist': 'https://rublacklist.net',
- 'zapret-info': 'https://github.com/zapret-info/z-i',
- 'antifilter': 'https://antifilter.download',
- },
+ blacklistSources: {
+ 'rublacklist': 'https://rublacklist.net',
+ 'zapret-info': 'https://github.com/zapret-info/z-i',
+ 'antifilter' : 'https://antifilter.download',
+ },
- normalize_value: function(v) {
- return (v && typeof(v) === 'string') ? v.trim().replace(/\r?\n/g, '') : v;
- },
+ callInitStatus: rpc.declare({
+ object: 'luci',
+ method: 'getInitList',
+ params: [ 'name' ],
+ expect: { '': {} }
+ }),
- make_status_string: function(
- app_status_code,
- proxy_mode,
- bllist_mode,
- bllist_module,
- bllist_source,
- tp_status_code,
- vpn_route_status_code) {
- let app_status_label;
- let spinning = '';
+ callInitAction: rpc.declare({
+ object: 'luci',
+ method: 'setInitAction',
+ params: [ 'name', 'action' ],
+ expect: { result: false }
+ }),
- switch(app_status_code) {
- case 0:
- app_status_label = this.info_label_running;
- break;
- case 2:
- app_status_label = this.info_label_stopped;
- break;
- case 3:
- app_status_label = this.info_label_starting;
- spinning = ' spinning';
- break;
- case 4:
- app_status_label = this.info_label_updating;
- spinning = ' spinning';
- break;
- default:
- app_status_label = this.info_label_error;
- return `