From 493cc103b86ac4f32f3db094afc038f3fac4b6ba Mon Sep 17 00:00:00 2001 From: gSpot Date: Thu, 4 Sep 2025 18:29:31 +0300 Subject: [PATCH] ruantiblock-mod-lua: added lua-idn. luci-app-ruantiblock: updated log. --- autoinstall/2.x/autoinstall.sh | 9 +- luci-app-ruantiblock/Makefile | 4 +- .../resources/view/ruantiblock/log-base.js | 315 ++++++++-------- .../resources/view/ruantiblock/log-system.js | 8 +- luci-app-ruantiblock/po/ru/ruantiblock.po | 33 +- .../po/templates/ruantiblock.pot | 30 +- ruantiblock-mod-lua/Makefile | 3 +- ruantiblock-mod-lua/files/usr/lib/lua/idn.lua | 337 ++++++++++++++++++ .../usr/libexec/ruantiblock/ruab_parser.lua | 2 +- ruantiblock-mod-py/Makefile | 2 +- ruantiblock/Makefile | 4 +- ruantiblock/files/etc/config/ruantiblock | 2 +- .../files/etc/ruantiblock/ruantiblock.conf | 2 +- 13 files changed, 547 insertions(+), 204 deletions(-) create mode 100644 ruantiblock-mod-lua/files/usr/lib/lua/idn.lua diff --git a/autoinstall/2.x/autoinstall.sh b/autoinstall/2.x/autoinstall.sh index 40b1f19..47ed1d1 100755 --- a/autoinstall/2.x/autoinstall.sh +++ b/autoinstall/2.x/autoinstall.sh @@ -10,9 +10,9 @@ LUCI_APP=1 HTTPS_DNS_PROXY=1 OWRT_VERSION="current" -RUAB_VERSION="2.1.6-r3" -RUAB_MOD_LUA_VERSION="2.1.6-r1" -RUAB_LUCI_APP_VERSION="2.1.6-r3" +RUAB_VERSION="2.1.7-r1" +RUAB_MOD_LUA_VERSION="2.1.7-r1" +RUAB_LUCI_APP_VERSION="2.1.7-r1" BASE_URL="https://raw.githubusercontent.com/gSpotx2f/packages-openwrt/master" PKG_DIR="/tmp" @@ -29,7 +29,6 @@ URL_LUCI_APP_PKG="${BASE_URL}/${OWRT_VERSION}/luci-app-ruantiblock_${RUAB_LUCI_A URL_LUCI_APP_RU_PKG="${BASE_URL}/${OWRT_VERSION}/luci-i18n-ruantiblock-ru_${RUAB_LUCI_APP_VERSION}_all.ipk" ### tor URL_TORRC="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_openwrt/master/tor/etc/tor/torrc" -URL_LUA_IDN="https://raw.githubusercontent.com/haste/lua-idn/master/idn.lua" ### Local files @@ -55,7 +54,6 @@ FILE_INIT_SCRIPT="${PREFIX}/etc/init.d/ruantiblock" FILE_MAIN_SCRIPT="${EXEC_DIR}/ruantiblock" ### tor FILE_TORRC="${PREFIX}/etc/tor/torrc" -FILE_LUA_IDN="${PREFIX}/usr/lib/lua/idn.lua" AWK_CMD="awk" WGET_CMD="$(which wget)" @@ -228,7 +226,6 @@ InstallLuaModule() { InstallPackages "lua" "luasocket" "luasec" "luabitop" RemoveFile "$FILE_MOD_LUA_PKG" > /dev/null DlFile "$URL_MOD_LUA_PKG" "$FILE_MOD_LUA_PKG" && $OPKG_CMD install "$FILE_MOD_LUA_PKG" - FileExists "$FILE_LUA_IDN" || DlFile "$URL_LUA_IDN" "$FILE_LUA_IDN" $UCI_CMD set ruantiblock.config.bllist_module="/usr/libexec/ruantiblock/ruab_parser.lua" $UCI_CMD commit ruantiblock } diff --git a/luci-app-ruantiblock/Makefile b/luci-app-ruantiblock/Makefile index a5b6d24..dc9ea07 100644 --- a/luci-app-ruantiblock/Makefile +++ b/luci-app-ruantiblock/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-ruantiblock -PKG_VERSION:=2.1.6 -PKG_RELEASE:=3 +PKG_VERSION:=2.1.7 +PKG_RELEASE:=1 LUCI_TITLE:=LuCI support for ruantiblock LUCI_DEPENDS:=+ruantiblock LUCI_PKGARCH:=all diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log-base.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log-base.js index 8890d4c..365dacf 100644 --- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log-base.js +++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log-base.js @@ -107,6 +107,7 @@ log-emerg td { } .log-info { background-color: var(--app-log-info) !important; + /*color: var(--app-log-dark-font-color) !important;*/ } .log-debug { background-color: var(--app-log-debug) !important; @@ -256,7 +257,9 @@ return baseclass.extend({ timeFilterReValue : false, - hostFilterValue : [], + hostFilterValue : null, + + hostFilterReValue : false, facilityFilterValue : [], @@ -274,18 +277,14 @@ return baseclass.extend({ logTimestampFlag : false, - logHostsFlag : false, + logHostFlag : false, logFacilitiesFlag : false, logLevelsFlag : false, - logHosts : {}, - logLevelsStat : {}, - logHostsDropdown : null, - logFacilitiesDropdown: null, logLevelsDropdown : null, @@ -315,6 +314,44 @@ return baseclass.extend({ return (/^[0-9]+$/.test(value)) ? value : 0 }, + makeRegExpButton(filterEl, checked) { + const btnOnClass = 'cbi-button-positive btn important', + btnOnStyle = 'text-decoration:none', + btnOffClass = 'cbi-button-neutral btn', + btnOffStyle = 'text-decoration:line-through'; + let btn = E('button', { + 'class': checked ? btnOnClass : btnOffClass, + 'style': checked ? btnOnStyle : btnOffStyle, + 'title': _('Apply pattern as regular expression'), + 'click': ev => { + ev.target.toggle(); + filterEl.focus(); + ev.preventDefault(); + }, + }, 'RE'); + btn._state = checked; + btn._on = function() { + this._state = true; + this.className = btnOnClass; + this.style = btnOnStyle; + }; + btn._off = function() { + this._state = false; + this.className = btnOffClass; + this.style = btnOffStyle; + }; + btn.checked = function() { + return this._state; + }; + btn.toggle = function() { + this._state ? this._off() : this._on(); + }; + btn.set = function(flag) { + flag ? this._on() : this._off(); + }; + return btn; + }, + makeLogConvertTimestampSection() { if(!this.enableConvertTimestamp) { return ''; @@ -330,7 +367,7 @@ return baseclass.extend({ E('label', {}), ]), E('div', { 'class': 'cbi-value-description' }, - _('Convert timestamps to a human readable date') + _('Convert timestamps to a human readable date.') ), ]), ]); @@ -342,70 +379,52 @@ return baseclass.extend({ 'class': 'cbi-value-title', 'for' : 'timeFilter', }, _('Timestamp filter')), - E('div', { 'class': 'cbi-value-field' }, + E('div', { 'class': 'cbi-value-field' }, [ E('span', { 'class': 'control-group' }, [ this.timeFilter, E('button', { - 'class': 'cbi-button btn', - 'click': L.bind(ev => { + 'class': 'cbi-button-neutral btn', + 'click': ev => { ev.target.blur(); ev.preventDefault(); this.timeFilter.value = null; this.timeFilter.focus(); - }, this), + }, }, '⌫'), - ]) - ), - ]); - }, - - makeLogtimeFilterReSection() { - return E('div', { 'class': 'cbi-value' }, [ - E('label', { - 'class': 'cbi-value-title', - 'for' : 'timeFilterRe', - }, _('Filter is regexp')), - E('div', { 'class': 'cbi-value-field' }, [ - E('div', { 'class': 'cbi-checkbox' }, [ - this.timeFilterRe, - E('label', {}), + this.timeFilterReBtn, ]), E('div', { 'class': 'cbi-value-description' }, - _('Apply timestamp filter as regular expression') + _('!pattern - entries that do not match the pattern.') ), ]), ]); }, - makeLogHostsDropdownItem(host) { - return E( - 'span', - { 'class': 'zonebadge log-host-dropdown-item' }, - E('strong', host) - ); - }, - - makeLogHostsDropdownSection() { - this.logHostsDropdown = new ui.Dropdown( - null, - this.logHosts, - { - id : 'logHostsDropdown', - multiple : true, - select_placeholder: _('All'), - } - ); - return E( - 'div', { 'class': 'cbi-value' }, [ - E('label', { - 'class': 'cbi-value-title', - 'for' : 'logHostsDropdown', - }, _('Hosts')), - E('div', { 'class': 'cbi-value-field' }, - this.logHostsDropdown.render() + makeLogHostFilterSection() { + return E('div', { 'class': 'cbi-value' }, [ + E('label', { + 'class': 'cbi-value-title', + 'for' : 'hostFilter', + }, _('Host filter')), + E('div', { 'class': 'cbi-value-field' }, [ + E('span', { 'class': 'control-group' }, [ + this.hostFilter, + E('button', { + 'class': 'cbi-button-neutral btn', + 'click': ev => { + ev.target.blur(); + ev.preventDefault(); + this.hostFilter.value = null; + this.hostFilter.focus(); + }, + }, '⌫'), + this.hostFilterReBtn, + ]), + E('div', { 'class': 'cbi-value-description' }, + _('!pattern - entries that do not match the pattern.') ), - ] - ); + ]), + ]); }, makeLogFacilitiesDropdownSection() { @@ -456,13 +475,13 @@ return baseclass.extend({ ); }, - setRegexpValidator(elem, flag) { + setRegexpValidator(elem, flagEl) { ui.addValidator( elem, 'string', true, v => { - if(!flag.checked) { + if(!flagEl.checked()) { return true; }; try { @@ -485,10 +504,11 @@ return baseclass.extend({ this.convertTimestampValue = this.convertTimestamp.checked; }; this.timeFilterValue = this.timeFilter.value; - this.timeFilterReValue = this.timeFilterRe.checked; + this.timeFilterReValue = this.timeFilterReBtn.checked() }; - if(this.logHostsFlag) { - this.hostFilterValue = this.logHostsDropdown.getValue(); + if(this.logHostFlag) { + this.hostFilterValue = this.hostFilter.value; + this.hostFilterReValue = this.hostFilterReBtn.checked() }; if(this.logFacilitiesFlag) { this.facilityFilterValue = this.logFacilitiesDropdown.getValue(); @@ -497,7 +517,8 @@ return baseclass.extend({ this.levelFilterValue = this.logLevelsDropdown.getValue(); }; this.msgFilterValue = this.msgFilter.value; - this.msgFilterReValue = this.msgFilterRe.checked; + this.msgFilterReValue = this.msgFilterReBtn.checked() + this.logSortingValue = this.logSorting.value; this.autoRefreshValue = this.autoRefresh.checked; if(this.autorefreshOn) { @@ -517,11 +538,12 @@ return baseclass.extend({ if(this.enableConvertTimestamp) { this.convertTimestamp.checked = this.convertTimestampValue; }; - this.timeFilter.value = this.timeFilterValue; - this.timeFilterRe.checked = this.timeFilterReValue; + this.timeFilter.value = this.timeFilterValue; + this.timeFilterReBtn.set(this.timeFilterReValue); }; - if(this.logHostsFlag) { - this.logHostsDropdown.setValue(this.hostFilterValue); + if(this.logHostFlag) { + this.hostFilter.value = this.hostFilterValue; + this.hostFilterReBtn.set(this.hostFilterReValue); }; if(this.logFacilitiesFlag) { this.logFacilitiesDropdown.setValue(this.facilityFilterValue); @@ -529,8 +551,9 @@ return baseclass.extend({ if(this.logLevelsFlag) { this.logLevelsDropdown.setValue(this.levelFilterValue); }; - this.msgFilter.value = this.msgFilterValue; - this.msgFilterRe.checked = this.msgFilterReValue; + this.msgFilter.value = this.msgFilterValue; + this.msgFilterReBtn.set(this.msgFilterReValue); + this.logSorting.value = this.logSortingValue; this.autoRefresh.checked = this.autoRefreshValue; }, @@ -586,35 +609,63 @@ return baseclass.extend({ }, setStringFilter(entriesArray, fieldNum, pattern) { - let fArr = []; + let not = pattern.startsWith('!'); + pattern = pattern.replace(/^!/, ''); + let isHFunc = (typeof(this.filterHighlightFunc) == 'function'); + let fArr = []; + if(!pattern) { + return entriesArray; + }; entriesArray.forEach((e, i) => { - if(e[fieldNum] !== null && e[fieldNum].includes(pattern)) { - if(typeof(this.filterHighlightFunc) == 'function') { - e[fieldNum] = e[fieldNum].replace(pattern, this.filterHighlightFunc); + if(e[fieldNum] == null) { + return; + }; + if(not) { + if(!(e[fieldNum].includes(pattern))) { + fArr.push(e); + }; + } else { + if(e[fieldNum].includes(pattern)) { + if(isHFunc) { + e[fieldNum] = e[fieldNum].replace(pattern, this.filterHighlightFunc); + }; + fArr.push(e); }; - fArr.push(e); }; }); return fArr; }, - setRegexpFilter(entriesArray, fieldNum, pattern, formElem) { - let fArr = []; + setRegexpFilter(entriesArray, fieldNum, pattern) { + let not = pattern.startsWith('!'); + pattern = pattern.replace(/^!/, ''); + let isHFunc = (typeof(this.filterHighlightFunc) == 'function'); + let fArr = []; + if(!pattern) { + return entriesArray; + }; try { let regExp = new RegExp(pattern, 'giu'); entriesArray.forEach((e, i) => { - if(e[fieldNum] !== null && regExp.test(e[fieldNum])) { - if(this.filterHighlightFunc) { - e[fieldNum] = e[fieldNum].replace(regExp, this.filterHighlightFunc); + if(e[fieldNum] == null) { + return; + }; + if(not) { + if(!(regExp.test(e[fieldNum]))) { + fArr.push(e); + }; + } else { + if(regExp.test(e[fieldNum])) { + if(isHFunc) { + e[fieldNum] = e[fieldNum].replace(regExp, this.filterHighlightFunc); + }; + fArr.push(e); }; - fArr.push(e); }; regExp.lastIndex = 0; }); } catch(err) { if(err.name == 'SyntaxError') { - ui.addNotification(null, - E('p', {}, _('Invalid regular expression') + ': ' + err.message)); return entriesArray; } else { throw err; @@ -629,20 +680,18 @@ return baseclass.extend({ return entriesArray; }; return (this.timeFilterReValue) ? - this.setRegexpFilter(entriesArray, 1, fPattern, this.timeFilter) : + this.setRegexpFilter(entriesArray, 1, fPattern) : this.setStringFilter(entriesArray, 1, fPattern); }, setHostFilter(entriesArray) { - let logHostsKeys = Object.keys(this.logHosts); - if(logHostsKeys.length > 0 && this.logHostsDropdown) { - this.logHostsDropdown.addChoices(logHostsKeys, this.logHosts); - if(this.hostFilterValue.length == 0) { - return entriesArray; - }; - return entriesArray.filter(e => this.hostFilterValue.includes(e[2])); + let fPattern = this.hostFilterValue; + if(!fPattern) { + return entriesArray; }; - return entriesArray; + return (this.hostFilterReValue) ? + this.setRegexpFilter(entriesArray, 2, fPattern) : + this.setStringFilter(entriesArray, 2, fPattern); }, setFacilityFilter(entriesArray) { @@ -673,7 +722,7 @@ return baseclass.extend({ return entriesArray; }; return (this.msgFilterReValue) ? - this.setRegexpFilter(entriesArray, 5, fPattern, this.msgFilter) : + this.setRegexpFilter(entriesArray, 5, fPattern) : this.setStringFilter(entriesArray, 5, fPattern); }, @@ -803,19 +852,15 @@ return baseclass.extend({ if(this.logTimestampFlag && !this.logTimeFilterElem) { this.logTimeFilterElem = this.makeLogTimeFilterSection(); }; - if(this.logTimestampFlag && !this.logtimeFilterReElem) { - this.logtimeFilterReElem = this.makeLogtimeFilterReSection(); + if(this.logHostFlag && !this.logHostFilterElem) { + this.logHostFilterElem = this.makeLogHostFilterSection(); }; - if(this.logFacilitiesFlag && !this.logFacilitiesDropdown) { this.logFacilitiesDropdownElem = this.makeLogFacilitiesDropdownSection(); }; if(this.logLevelsFlag && !this.logLevelsDropdown) { this.logLevelsDropdownElem = this.makeLogLevelsDropdownSection(); }; - if(this.logHostsFlag && !this.logHostsDropdown) { - this.logHostsDropdownElem = this.makeLogHostsDropdownSection(); - }; }; if(!autorefresh) { @@ -845,21 +890,20 @@ return baseclass.extend({ E('span', { 'class': 'control-group' }, [ this.tailInput, E('button', { - 'class': 'cbi-button btn', - 'click': L.bind(ev => { + 'class': 'cbi-button-neutral btn', + 'click': ev => { ev.target.blur(); ev.preventDefault(); this.tailInput.value = 0; this.tailInput.focus(); - }, this), + }, }, '⌫'), ]) ), ]), this.logConvertTimestampElem, this.logTimeFilterElem, - this.logtimeFilterReElem, - this.logHostsDropdownElem, + this.logHostFilterElem, this.logFacilitiesDropdownElem, this.logLevelsDropdownElem, E('div', { 'class': 'cbi-value' }, [ @@ -867,33 +911,22 @@ return baseclass.extend({ 'class': 'cbi-value-title', 'for' : 'msgFilter', }, _('Message filter')), - E('div', { 'class': 'cbi-value-field' }, + E('div', { 'class': 'cbi-value-field' }, [ E('span', { 'class': 'control-group' }, [ this.msgFilter, E('button', { - 'class': 'cbi-button btn', - 'click': L.bind(ev => { + 'class': 'cbi-button-neutral btn', + 'click': ev => { ev.target.blur(); ev.preventDefault(); this.msgFilter.value = null; this.msgFilter.focus(); - }, this), + }, }, '⌫'), - ]) - ) - ]), - E('div', { 'class': 'cbi-value' }, [ - E('label', { - 'class': 'cbi-value-title', - 'for' : 'msgFilterRe', - }, _('Filter is regexp')), - E('div', { 'class': 'cbi-value-field' }, [ - E('div', { 'class': 'cbi-checkbox' }, [ - this.msgFilterRe, - E('label', {}), + this.msgFilterReBtn, ]), E('div', { 'class': 'cbi-value-description' }, - _('Apply message filter as regular expression') + _('!pattern - entries that do not match the pattern.') ), ]), ]), @@ -1057,10 +1090,10 @@ return baseclass.extend({ ui.addValidator(this.tailInput, 'uinteger', true); this.convertTimestamp = E('input', { - 'id' : 'convertTimestamp', - 'name' : 'convertTimestamp', - 'type' : 'checkbox', - 'form' : 'logFilterForm', + 'id' : 'convertTimestamp', + 'name': 'convertTimestamp', + 'type': 'checkbox', + 'form': 'logFilterForm', }); this.convertTimestamp.checked = this.convertTimestampValue; @@ -1073,27 +1106,30 @@ return baseclass.extend({ 'placeholder': _('Type a search pattern...'), }); - this.timeFilterRe = E('input', { - 'id' : 'timeFilterRe', - 'name' : 'timeFilterRe', - 'type' : 'checkbox', - 'form' : 'logFilterForm', - 'change': ev => this.timeFilter.focus(), + this.timeFilterReBtn = this.makeRegExpButton(this.timeFilter, this.timeFilterReValue); + this.setRegexpValidator(this.timeFilter, this.timeFilterReBtn); + + this.hostFilter = E('input', { + 'id' : 'hostFilter', + 'name' : 'hostFilter', + 'type' : 'text', + 'form' : 'logFilterForm', + 'class' : 'cbi-input-text', + 'placeholder': _('Type a search pattern...'), }); - this.setRegexpValidator(this.timeFilter, this.timeFilterRe); + this.hostFilterReBtn = this.makeRegExpButton(this.hostFilter, this.hostFilterReValue); + this.setRegexpValidator(this.hostFilter, this.hostFilterReBtn); this.logConvertTimestampElem = ''; this.logTimeFilterElem = ''; - this.logtimeFilterReElem = ''; - this.logHostsDropdownElem = ''; + this.logHostFilterElem = ''; this.logFacilitiesDropdownElem = ''; this.logLevelsDropdownElem = ''; if(this.logTimestampFlag) { this.logConvertTimestampElem = this.makeLogConvertTimestampSection(); this.logTimeFilterElem = this.makeLogTimeFilterSection(); - this.logtimeFilterReElem = this.makeLogtimeFilterReSection(); }; if(this.logLevelsFlag) { this.logLevelsDropdownElem = this.makeLogLevelsDropdownSection(); @@ -1101,8 +1137,8 @@ return baseclass.extend({ if(this.logFacilitiesFlag) { this.logFacilitiesDropdownElem = this.makeLogFacilitiesDropdownSection(); }; - if(this.logHostsFlag) { - this.logHostsDropdownElem = this.makeLogHostsDropdownSection(); + if(this.logHostFlag) { + this.logHostFilterElem = this.makeLogHostFilterSection(); }; this.msgFilter = E('input', { @@ -1114,15 +1150,8 @@ return baseclass.extend({ 'placeholder': _('Type a search pattern...'), }); - this.msgFilterRe = E('input', { - 'id' : 'msgFilterRe', - 'name' : 'msgFilterRe', - 'type' : 'checkbox', - 'form' : 'logFilterForm', - 'change': ev => this.msgFilter.focus(), - }); - - this.setRegexpValidator(this.msgFilter, this.msgFilterRe); + this.msgFilterReBtn = this.makeRegExpButton(this.msgFilter, this.msgFilterReValue); + this.setRegexpValidator(this.msgFilter, this.msgFilterReBtn); this.logSorting = E('select', { 'id' : 'logSorting', diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log-system.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log-system.js index 34fb157..7000951 100644 --- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log-system.js +++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log-system.js @@ -54,9 +54,6 @@ return baseclass.extend({ // syslog-ng syslog_ngHandler(strArray, lineNum) { - if(!(strArray[2] in this.logHosts)) { - this.logHosts[strArray[2]] = this.makeLogHostsDropdownItem(strArray[2]); - }; return [ lineNum, // # (Number) strArray[1], // Timestamp (String) @@ -130,8 +127,7 @@ return baseclass.extend({ this.logTimestampFlag = true; this.logFacilitiesFlag = true; this.logLevelsFlag = true; - this.logHostsFlag = false; - this.logHosts = {}; + this.logHostFlag = false; this.entriesHandler = this.logdHandler; this.logCols = [ '#', @@ -148,7 +144,7 @@ return baseclass.extend({ this.logTimestampFlag = true; this.logFacilitiesFlag = false; this.logLevelsFlag = false; - this.logHostsFlag = true; + this.logHostFlag = true; this.logFacilities = {}; this.logLevels = {}; this.entriesHandler = this.syslog_ngHandler; diff --git a/luci-app-ruantiblock/po/ru/ruantiblock.po b/luci-app-ruantiblock/po/ru/ruantiblock.po index 22e75f4..cfe3764 100644 --- a/luci-app-ruantiblock/po/ru/ruantiblock.po +++ b/luci-app-ruantiblock/po/ru/ruantiblock.po @@ -13,18 +13,21 @@ msgstr "" "Language: ru\n" "X-Generator: Poedit 2.0.6\n" +msgid "!pattern - entries that do not match the pattern." +msgstr "!шаблон - записи не совпадающие с шаблоном." + msgid "2nd level domains that are excluded from optimization" msgstr "Домены 2-го уровня не подлежащие оптимизации" msgid "Add user entries to the blacklist when updating" msgstr "Добавлять записи пользователя в блэклист при обновлении" -msgid "Alert" -msgstr "Тревога" - msgid "All" msgstr "Все" +msgid "All entries" +msgstr "Все записи" + msgid "All entries except matching patterns" msgstr "Все записи, кроме соответствующих шаблонам" @@ -43,6 +46,9 @@ msgstr "Произошла ошибка при попытке получить msgid "Apply" msgstr "Применить" +msgid "Apply pattern as regular expression" +msgstr "Применять фильтр как регулярное выражение" + msgid "Apply proxy rules to router application traffic" msgstr "Применять правила прокси к трафику приложений роутера" @@ -95,9 +101,6 @@ msgstr "Содержимое сохранено." msgid "Convert cyrillic domains to punycode" msgstr "Конвертировать кириллические домены в punycode" -msgid "Critical" -msgstr "Критическая ситуация" - msgid "Current schedule" msgstr "Текущее расписание" @@ -110,9 +113,6 @@ msgstr "DNS сервер для FQDN записей списка исключе msgid "Day" msgstr "День" -msgid "Debug" -msgstr "Отладка" - msgid "Description" msgstr "Описание" @@ -143,9 +143,6 @@ msgstr "Изменить" msgid "Edit entries" msgstr "Изменить записи" -msgid "Emergency" -msgstr "Чрезвычайная ситуация" - msgid "Enable" msgstr "Включить" @@ -245,9 +242,6 @@ msgstr "Режим ограничения IP адресов" msgid "IP subnet patterns (/24) that are excluded from optimization" msgstr "Шаблоны IP подсетей (/24) не подлежащих оптимизации" -msgid "Info" -msgstr "Информация" - msgid "Instance" msgstr "Экземпляр" @@ -305,6 +299,9 @@ msgstr "Минута" msgid "Module settings" msgstr "Настройки модуля" +msgid "More entries" +msgstr "Больше записей" + msgid "Name" msgstr "Имя" @@ -323,9 +320,6 @@ msgstr "Нет данных" msgid "No entries available..." msgstr "Нет доступных записей..." -msgid "Notice" -msgstr "Сообщение" - msgid "Number of entries" msgstr "Кол-во записей" @@ -598,9 +592,6 @@ msgstr "Режим VPN" msgid "VPN routing error! Need restart" msgstr "Ошибка маршрутизации VPN! Необходим перезапуск" -msgid "Warning" -msgstr "Внимание" - msgid "all" msgstr "все" diff --git a/luci-app-ruantiblock/po/templates/ruantiblock.pot b/luci-app-ruantiblock/po/templates/ruantiblock.pot index 3dec46d..4aebbfa 100644 --- a/luci-app-ruantiblock/po/templates/ruantiblock.pot +++ b/luci-app-ruantiblock/po/templates/ruantiblock.pot @@ -1,16 +1,19 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" +msgid "!pattern - entries that do not match the pattern." +msgstr "" + msgid "2nd level domains that are excluded from optimization" msgstr "" msgid "Add user entries to the blacklist when updating" msgstr "" -msgid "Alert" +msgid "All" msgstr "" -msgid "All" +msgid "All entries" msgstr "" msgid "All entries except matching patterns" @@ -28,6 +31,9 @@ msgstr "" msgid "Apply" msgstr "" +msgid "Apply pattern as regular expression" +msgstr "" + msgid "Apply proxy rules to router application traffic" msgstr "" @@ -80,9 +86,6 @@ msgstr "" msgid "Convert cyrillic domains to punycode" msgstr "" -msgid "Critical" -msgstr "" - msgid "Current schedule" msgstr "" @@ -95,9 +98,6 @@ msgstr "" msgid "Day" msgstr "" -msgid "Debug" -msgstr "" - msgid "Description" msgstr "" @@ -128,8 +128,6 @@ msgstr "" msgid "Edit entries" msgstr "" -msgid "Emergency" -msgstr "" msgid "Enable" msgstr "" @@ -226,9 +224,6 @@ msgstr "" msgid "IP subnet patterns (/24) that are excluded from optimization" msgstr "" -msgid "Info" -msgstr "" - msgid "Instance" msgstr "" @@ -286,6 +281,9 @@ msgstr "" msgid "Module settings" msgstr "" +msgid "More entries" +msgstr "" + msgid "Name" msgstr "" @@ -304,9 +302,6 @@ msgstr "" msgid "No entries available..." msgstr "" -msgid "Notice" -msgstr "" - msgid "Number of entries" msgstr "" @@ -553,9 +548,6 @@ msgstr "" msgid "VPN routing error! Need restart" msgstr "" -msgid "Warning" -msgstr "" - msgid "all" msgstr "все" diff --git a/ruantiblock-mod-lua/Makefile b/ruantiblock-mod-lua/Makefile index c7c3a13..5cfd1a2 100644 --- a/ruantiblock-mod-lua/Makefile +++ b/ruantiblock-mod-lua/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ruantiblock-mod-lua -PKG_VERSION:=2.1.6 +PKG_VERSION:=2.1.7 PKG_RELEASE:=1 PKG_MAINTAINER:=gSpot @@ -35,6 +35,7 @@ define Package/$(PKG_NAME)/install $(INSTALL_BIN) ./files/usr/libexec/ruantiblock/ruab_parser.lua $(1)/usr/libexec/ruantiblock/ruab_parser.lua $(INSTALL_DIR) $(1)/usr/lib/lua $(INSTALL_DATA) ./files/usr/lib/lua/iptool.lua $(1)/usr/lib/lua/iptool.lua + $(INSTALL_DATA) ./files/usr/lib/lua/idn.lua $(1)/usr/lib/lua/idn.lua endef $(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/ruantiblock-mod-lua/files/usr/lib/lua/idn.lua b/ruantiblock-mod-lua/files/usr/lib/lua/idn.lua new file mode 100644 index 0000000..b307551 --- /dev/null +++ b/ruantiblock-mod-lua/files/usr/lib/lua/idn.lua @@ -0,0 +1,337 @@ +--[[ +GitHub: https://github.com/haste/lua-idn/ + +MIT License + +Copyright (c) 2011 Trond A Ekseth + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +--]] + +local bit = require'bit' + +local base = 36 +local tmin = 1 +local tmax = 26 +local skew = 38 +local damp = 700 +local initial_bias = 72 +local initial_n = 0x80 +local delimiter = 0x2D + +-- Bias adaptation function +local adapt = function(delta, numpoints, firsttime) + if(firsttime) then + delta = math.floor(delta / damp) + else + delta = bit.rshift(delta, 1) + end + + delta = delta + math.floor(delta / numpoints) + + local k = 0 + while(delta > math.floor(((base - tmin) * tmax) / 2)) do + delta = math.floor(delta / (base - tmin)) + k = k + base + end + + return math.floor(k + (base - tmin + 1) * delta / (delta + skew)) +end + +-- tests whether cp is a basic code point: +local basic = function(cp) + return cp < 0x80 +end + +local offset = {0, 0x3000, 0xE0000, 0x3C00000} +local utf8code = function(U, ...) + local numBytes = select('#', ...) + for i=1, numBytes do + local b = select(i, ...) + U = bit.lshift(U, 6) + bit.band(b, 63) + end + + return U - offset[numBytes + 1] +end + +local toUCS4 = function(str) + local out = {} + for c in str:gmatch'([%z\1-\127\194-\244][\128-\191]*)' do + table.insert(out, utf8code(string.byte(c, 1, -1))) + end + + return out +end + +local toUnicode = function(n) + if(n < 128) then + return string.char(n) + elseif(n < 2048) then + return string.char(192 + ((n - (n % 64)) / 64), 128 + (n % 64)) + else + return string.char(224 + ((n - (n % 4096)) / 4096), 128 + (((n % 4096) - (n % 64)) / 64), 128 + (n % 64)) + end +end + +local punycode_encode +do + -- returns the basic code point whose value + -- (when used for representing integers) is d, which needs to be in + -- the range 0 to base-1. + local encode_digit = function(d) + return d + 22 + 75 * (d < 26 and 1 or 0) + -- 0..25 map to ASCII a..z + -- 26..35 map to ASCII 0..9 + end + + function punycode_encode(input) + if(type(input) == 'string') then + input = toUCS4(input) + end + + local output = {} + + -- Initialize the state + local n = initial_n + local delta = 0 + local bias = initial_bias + + -- Handle the basic code poinst + for j = 1, #input do + local c = input[j] + if(basic(c)) then + table.insert(output, string.char(c)) + end + end + + local h = #output + local b = h + + -- h is the number of code points that have been handled, b is the + -- number of basic code points. + + if(b > 0) then + table.insert(output, string.char(delimiter)) + end + + -- Main encoding loop + while(h < #input) do + -- All non-basic code points < n have been + -- handled already. Find the next larger one + local m = math.huge + for j = 1, #input do + local c = input[j] + if(c >= n and c < m) then + m = c + end + end + + delta = delta + (m - n) * (h + 1) + n = m + + for j = 1, #input do + local cp = input[j] + if(cp < n) then + delta = delta + 1 + end + + if(cp == n) then + local q = delta + local k = base + while(true) do + local t + if(k <= bias) then + t = tmin + else + if(k >= bias + tmax) then + t = tmax + else + t = k - bias + end + end + + if(q < t) then break end + + table.insert(output, string.char(encode_digit(t + (q - t) % (base - t)))) + q = math.floor((q - t) / (base - t)) + + k = k + base + end + + table.insert(output, string.char(encode_digit(q))) + bias = adapt(delta, h + 1, h == b) + delta = 0 + h = h +1 + end + end + + delta = delta + 1 + n = n + 1 + end + + return table.concat(output) + end +end + +local punycode_decode +do + local decode_digit = function(d) + if(d - 48 < 10) then + return d - 22 + elseif(d - 65 < 26) then + return d - 65 + elseif(d - 97 < 26) then + return d - 97 + else + return base + end + end + + function punycode_decode(input) + if(type(input) == 'string') then + input = toUCS4(input) + end + + local output = {} + + -- Initialize the state + local n = initial_n + local i = 0 + local out = 1 + local bias = initial_bias + + local b = 1 + for j = 1, #input do + if(input[j] == delimiter) then + b = j + end + end + + for j = 1, #input do + local c = input[j] + if(not basic(c)) then return nil, 'Invalid input' end + end + + for j = 1, b - 1 do + local c = input[j] + output[out] = toUnicode(c) + out = out + 1 + end + + local index = 1 + if(b > 1) then + index = b + 1 + end + + local inputLength = #input + while(index <= inputLength) do + local oldi = i + local w = 1 + local k = base + + while(true) do + if(index > inputLength) then return nil, 'Bad input' end + local digit = decode_digit(input[index]) + if(digit >= base) then return nil, 'Bad input' end + index = index + 1 + i = i + (digit * w) + + local t + if(k <= bias) then + t = tmin + elseif(k >= bias + tmax) then + t = tmax + else + t = k - bias + end + + if(digit < t) then + break + end + + w = w * (base - t) + + k = k + base + end + + bias = adapt(i - oldi, out, oldi == 0) + + n = n + math.floor(i / (out)) + i = (i % out) + 1 + + table.insert(output, i, toUnicode(n)) + out = out + 1 + end + + return table.concat(output) + end +end + +local idn_encode +do + function idn_encode(domain) + local labels = {} + for label in domain:gmatch('([^.]+)%.?') do + -- Domain names can only consist of a-z, A-Z, 0-9, - and aren't allowed + -- to start or end with a hyphen + local first, last = label:sub(1, 1), label:sub(-1) + if(first == '-' or last == '-') then + return nil, 'Invalid DNS label' + end + + if(label:match('^[a-zA-Z0-9-]+$')) then + table.insert(labels, label) + elseif(label:sub(1,1) ~= '-' and label:sub(2,2) ~= '-') then + local plabel = punycode_encode(label) + table.insert(labels, string.format('xn--%s', plabel)) + end + end + + return table.concat(labels, '.') + end +end + +local idn_decode +do + function idn_decode(domain) + local labels = {} + for label in domain:gmatch('([^.]+)%.?') do + if(label:sub(1, 4) == 'xn--') then + table.insert(labels, punycode_decode(label:sub(5))) + elseif(label:match('^[a-zA-Z0-9-]+$')) then + table.insert(labels, label) + end + end + + return table.concat(labels, '.') + end +end + +return { + encode = idn_encode, + decode = idn_decode, + + punycode = { + encode = punycode_encode, + decode = punycode_decode, + }, +} diff --git a/ruantiblock-mod-lua/files/usr/libexec/ruantiblock/ruab_parser.lua b/ruantiblock-mod-lua/files/usr/libexec/ruantiblock/ruab_parser.lua index 72ee471..7017b46 100755 --- a/ruantiblock-mod-lua/files/usr/libexec/ruantiblock/ruab_parser.lua +++ b/ruantiblock-mod-lua/files/usr/libexec/ruantiblock/ruab_parser.lua @@ -309,7 +309,7 @@ function BlackListParser:convert_encoding(input) if self.ICONV_TYPE == "lua" and self.iconv_handler then output = self.iconv_handler:iconv(input) elseif self.ICONV_TYPE == "standalone" and self.ICONV_CMD then - local iconv_handler = assert(io.popen('printf \'' .. input .. '\' | ' .. self.ICONV_CMD .. ' -f "' .. self.site_encoding .. '" -t "' .. self.encoding .. '"', 'r')) + local iconv_handler = assert(io.popen('printf \'%s\' \'' .. input .. '\' | ' .. self.ICONV_CMD .. ' -f "' .. self.site_encoding .. '" -t "' .. self.encoding .. '"', 'r')) output = iconv_handler:read("*a") iconv_handler:close() end diff --git a/ruantiblock-mod-py/Makefile b/ruantiblock-mod-py/Makefile index 224395a..4a0f18f 100644 --- a/ruantiblock-mod-py/Makefile +++ b/ruantiblock-mod-py/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ruantiblock-mod-py -PKG_VERSION:=2.1.6 +PKG_VERSION:=2.1.7 PKG_RELEASE:=1 PKG_MAINTAINER:=gSpot diff --git a/ruantiblock/Makefile b/ruantiblock/Makefile index 4bb1d07..7c40d8b 100644 --- a/ruantiblock/Makefile +++ b/ruantiblock/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ruantiblock -PKG_VERSION:=2.1.6 -PKG_RELEASE:=3 +PKG_VERSION:=2.1.7 +PKG_RELEASE:=1 PKG_MAINTAINER:=gSpot include $(INCLUDE_DIR)/package.mk diff --git a/ruantiblock/files/etc/config/ruantiblock b/ruantiblock/files/etc/config/ruantiblock index 4cb8b19..8cc5c6d 100644 --- a/ruantiblock/files/etc/config/ruantiblock +++ b/ruantiblock/files/etc/config/ruantiblock @@ -27,7 +27,7 @@ config main 'config' option bllist_sd_limit '16' option bllist_fqdn_filter '1' option bllist_fqdn_filter_type '0' - option bllist_enable_idn '0' + option bllist_enable_idn '1' option bllist_alt_nslookup '0' option bllist_alt_dns_addr '8.8.8.8' diff --git a/ruantiblock/files/etc/ruantiblock/ruantiblock.conf b/ruantiblock/files/etc/ruantiblock/ruantiblock.conf index 01c3bdf..8ec0b23 100644 --- a/ruantiblock/files/etc/ruantiblock/ruantiblock.conf +++ b/ruantiblock/files/etc/ruantiblock/ruantiblock.conf @@ -140,7 +140,7 @@ BLLIST_FQDN_EXCLUDED_FILE="/etc/ruantiblock/fqdn_excluded" ### Обрезка www[0-9]. в FQDN (0 - выкл, 1 - вкл) BLLIST_STRIP_WWW=1 ### Преобразование кириллических доменов в punycode (0 - выкл, 1 - вкл) -BLLIST_ENABLE_IDN=0 +BLLIST_ENABLE_IDN=1 ### Перенаправлять DNS-запросы на альтернативный DNS-сервер для заблокированных FQDN (0 - выкл, 1 - вкл) BLLIST_ALT_NSLOOKUP=0 ### Альтернативный DNS-сервер