diff --git a/autoinstall/autoinstall.sh b/autoinstall/autoinstall.sh index b8862c4..262c2b2 100755 --- a/autoinstall/autoinstall.sh +++ b/autoinstall/autoinstall.sh @@ -9,9 +9,9 @@ LUA_MODULE=1 LUCI_APP=1 OWRT_VERSION="19.07" -RUAB_VERSION="0.9.0-1" -RUAB_MOD_LUA_VERSION="0.9.0-1" -RUAB_LUCI_APP_VERSION="0.9.0-2" +RUAB_VERSION="0.9.0-2" +RUAB_MOD_LUA_VERSION="0.9.0-2" +RUAB_LUCI_APP_VERSION="0.9.0-3" BASE_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_openwrt/master" PKG_DIR="/tmp" diff --git a/luci-app-ruantiblock/Makefile b/luci-app-ruantiblock/Makefile index eaa1ef4..85c0bbf 100644 --- a/luci-app-ruantiblock/Makefile +++ b/luci-app-ruantiblock/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk PKG_VERSION:=0.9.0 -PKG_RELEASE:=2 +PKG_RELEASE:=3 LUCI_TITLE:=LuCI support for ruantiblock LUCI_DEPENDS:=+ruantiblock +luci-mod-admin-full LUCI_PKGARCH:=all diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/baselog.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/baselog.js new file mode 100644 index 0000000..76437ba --- /dev/null +++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/baselog.js @@ -0,0 +1,502 @@ +'use strict'; +'require ui'; + +return L.Class.extend({ + view: L.view.extend({ + viewName: null, + + title: null, + + logFacilities: [ + 'kern', + 'user', + 'mail', + 'daemon', + 'auth', + 'syslog', + 'lpr', + 'news', + ], + + 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'))), + 'err': E('span', { 'class': 'zonebadge log-err' }, E('strong', _('Error'))), + 'warn': E('span', { 'class': 'zonebadge log-warn' }, E('strong', _('Warning'))), + 'notice': E('span', { 'class': 'zonebadge log-notice' }, E('strong', _('Notice'))), + 'info': E('span', { 'class': 'zonebadge log-info' }, E('strong', _('Info'))), + 'debug': E('span', { 'class': 'zonebadge log-debug' }, E('strong', _('Debug'))), + }, + + tailValue: 25, + + logSortingValue: 'asc', + + logLevelsStat: {}, + + logLevelsDropdown: null, + + totalLogLines: 0, + + htmlEntities: function(str) { + return String(str).replace( + /&/g, '&').replace( + //g, '>').replace( + /"/g, '"'); + }, + + /** + * + * @param {number} tail + * @returns {string} + * Returns the raw content of the log + * + */ + getLogData: function(tail) { + throw new Error('getLogData needs to be reloaded in subclass'); + }, + + /** + * + * @param {string} logdata + * @param {number} tail + * @returns {Array} + * Returns an array of values: [ #, Timestamp, Level, Facility, Message ] + * + */ + parseLogData: function(logdata, tail) { + throw new Error('parseLogData needs to be reloaded in subclass'); + }, + + makeLogArea: function(logdataArray) { + let lines = `
${_('No entries available...')}
`; + let logTable = E('div', { 'id': 'logTable', 'class': 'table' }); + + for(let level of Object.keys(this.logLevels)) { + this.logLevelsStat[level] = 0; + }; + + if(logdataArray.length > 0) { + lines = []; + logdataArray.forEach((e, i) => { + this.logLevelsStat[e[2]] = (this.logLevelsStat[e[2]] != undefined) ? + this.logLevelsStat[e[2]] + 1 : 1; + + lines.push( + `
${e[0]}
` + + ((e[1]) ? `
${e[1]}
` : '') + + ((e[2]) ? `
${e[2]}
` : '') + + ((e[3]) ? `
${e[3]}
` : '') + + ((e[4]) ? `
${e[4]}
` : '') + + `
` + ); + }); + lines = lines.join(''); + + logTable.append( + E('div', { 'class': 'tr table-titles' }, [ + E('div', { 'class': 'th left log-entry-number' }, '#'), + (logdataArray[0][1]) ? E('div', { 'class': 'th left log-entry-time' }, _('Timestamp')) : '', + (logdataArray[0][2]) ? E('div', { 'class': 'th left log-entry-log-level' }, _('Level')) : '', + (logdataArray[0][3]) ? E('div', { 'class': 'th left log-entry-facility' }, _('Facility')) : '', + (logdataArray[0][4]) ? E('div', { 'class': 'th left log-entry-message' }, _('Message')) : '', + ]) + ); + }; + + try { + logTable.insertAdjacentHTML('beforeend', lines); + } catch(err) { + if(err.name === 'SyntaxError') { + ui.addNotification(null, + E('p', {}, _('HTML/XML error') + ': ' + err.message), 'error'); + }; + throw err; + }; + + let levelsStatString = ''; + if((Object.values(this.logLevelsStat).reduce((s,c) => s + c, 0)) > 0) { + Object.entries(this.logLevelsStat).forEach(e => { + if(e[1] > 0) { + levelsStatString += `${e[1]}`; + }; + }); + }; + + return E([ + E('div', { 'class': 'log-entries-count' }, + `${_('Entries')}: ${logdataArray.length} / ${this.totalLogLines}${levelsStatString}` + ), + logTable + ]); + }, + + setLevelFilter: function(cArr) { + let logLevelsKeys = Object.keys(this.logLevels); + if(logLevelsKeys.length > 0) { + let selectedLevels = this.logLevelsDropdown.getValue(); + if(logLevelsKeys.length === selectedLevels.length) { + return cArr; + }; + return cArr.filter(s => selectedLevels.length === 0 || selectedLevels.includes(s[2])); + }; + return cArr; + }, + + setRegexpFilter: function(cArr) { + let fPattern = document.getElementById('logFilter').value; + if(!fPattern) { + return cArr; + }; + let fArr = []; + try { + let regExp = new RegExp(`(${fPattern})`, 'giu'); + cArr.forEach((e, i) => { + if(regExp.test(e[4])) { + e[4] = e[4].replace(regExp, '$1'); + fArr.push(e); + }; + }); + } catch(err) { + if(err.name === 'SyntaxError') { + ui.addNotification(null, + E('p', {}, _('Invalid regular expression') + ': ' + err.message)); + return cArr; + } else { + throw err; + }; + }; + return fArr; + }, + + downloadLog: function() { + let formElems = Array.from(document.forms.logForm.elements); + formElems.forEach(e => e.disabled = true); + + return this.getLogData(0).then(logdata => { + logdata = logdata || ''; + let link = E('a', { + 'download': this.viewName + '.txt', + 'href': URL.createObjectURL( + new Blob([ logdata ], { type: 'text/plain' })), + }); + link.click(); + URL.revokeObjectURL(link.href); + }).catch(() => { + ui.addNotification(null, + E('p', {}, _('Download error') + ': ' + err.message)); + }).finally(() => { + formElems.forEach(e => e.disabled = false); + }); + }, + + load: function() { + + // Restoring settings from localStorage + let tailValueLocal = localStorage.getItem(`luci-app-${this.viewName}-tailValue`); + if(tailValueLocal) { + this.tailValue = Number(tailValueLocal); + }; + let logSortingLocal = localStorage.getItem(`luci-app-${this.viewName}-logSorting`); + if(logSortingLocal) { + this.logSortingValue = logSortingLocal; + }; + + return this.getLogData(this.tailValue); + }, + + render: function(logdata) { + + document.head.append(E('style', {'type': 'text/css'}, +` +.log-entry-empty { +} +.log-entry-number { + min-width: 4em !important; +} +.log-entry-time { + min-width: 14em !important; +} +.log-entry-log-level { + max-width: 5em !important; +} +.log-entry-facility{ + max-width: 7em !important; +} +.log-entry-message { + min-width: 25em !important; +} +.log-empty { +} +.log-emerg { + background-color: #a93734 !important; + color: #fff; +} +.log-alert { + background-color: #ff7968 !important; + color: #fff; +} +.log-crit { + background-color: #fcc3bf !important; +} +.log-err { + background-color: #ffe9e8 !important; +} +.log-warn { + background-color: #fff7e2 !important; +} +.log-notice { + background-color: #e3ffec !important; +} +.log-info { +} +.log-debug { + background-color: #ebf6ff !important; +} +.log-highlight-item { + background-color: #ffef00; +} +.log-entries-count { + margin: 0 0 5px 5px; + font-weight: bold; + opacity: 0.6; +} +.log-entries-count-level { + display: inline-block !important; + margin: 0 0 0 5px; + padding: 0 4px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + border: 1px solid #ccc; + font-weight: normal; +} +` + )); + + let logWrapper = E('div', { + 'id': 'logWrapper', + 'style': 'width:100%; min-height:20em; padding: 0 0 0 45px; font-size:0.9em !important' + }, this.makeLogArea(this.parseLogData(logdata, this.tailValue))); + + let tailInput = E('input', { + 'id': 'tailInput', + 'name': 'tailInput', + 'type': 'text', + 'form': 'logForm', + 'class': 'cbi-input-text', + 'style': 'width:4em !important; min-width:4em !important', + 'maxlength': 5, + }); + tailInput.value = (this.tailValue === 0) ? null : this.tailValue; + ui.addValidator(tailInput, 'uinteger', true); + + let tailReset = E('input', { + 'type': 'button', + 'form': 'logForm', + 'class': 'cbi-button btn cbi-button-reset', + 'value': 'Χ', + 'click': ev => { + tailInput.value = null; + logFormSubmitBtn.click(); + ev.target.blur(); + }, + 'style': 'max-width:4em !important', + }); + + let logLevelsDropdownElem = ''; + let logLevelsKeys = Object.keys(this.logLevels); + if(logLevelsKeys.length > 0) { + this.logLevelsDropdown = new ui.Dropdown( + null, + this.logLevels, + { + id: 'logLevelsDropdown', + sort: logLevelsKeys, + multiple: true, + select_placeholder: _('All'), + display_items: 3, + dropdown_items: -1, + } + ); + logLevelsDropdownElem = E( + 'div', { 'class': 'cbi-value' }, [ + E('label', { + 'class': 'cbi-value-title', + 'for': 'logLevelsDropdown', + }, _('Logging levels')), + E('div', { 'class': 'cbi-value-field' }, + this.logLevelsDropdown.render() + ), + ] + ); + }; + + let logFilter = E('input', { + 'id': 'logFilter', + 'name': 'logFilter', + 'type': 'text', + 'form': 'logForm', + 'class': 'cbi-input-text', + 'placeholder': _('Type an expression...'), + }); + + let logFormSubmitBtn = E('input', { + 'type': 'submit', + 'form': 'logForm', + 'class': 'cbi-button btn cbi-button-action', + 'value': _('Apply'), + 'click': ev => ev.target.blur(), + 'style': 'margin-right: 1em', + }); + + let logSorting = E('select', { + 'id': 'logSorting', + 'form': 'logForm', + 'class': "cbi-input-select", + }, [ + E('option', { 'value': 'asc' }, _('ascending')), + E('option', { 'value': 'desc' }, _('descending')), + ]); + logSorting.value = this.logSortingValue; + + let logDownloadBtn = E('button', { + 'class': 'cbi-button btn', + 'click': ui.createHandlerFn(this, this.downloadLog), + }, _('Download log')); + + return E([ + E('h2', { 'id': 'logTitle', 'class': 'fade-in' }, this.title), + E('div', { 'class': 'cbi-section-descr fade-in' }), + E('div', { 'class': 'cbi-section fade-in' }, + E('div', { 'class': 'cbi-section-node' }, [ + + E('div', { 'class': 'cbi-value' }, [ + E('label', { + 'class': 'cbi-value-title', + 'for': 'tailInput', + }, _('Last entries')), + E('div', { 'class': 'cbi-value-field' }, [ + tailInput, + tailReset, + ]), + ]), + + logLevelsDropdownElem, + + E('div', { 'class': 'cbi-value' }, [ + E('label', { + 'class': 'cbi-value-title', + 'for': 'logFilter', + }, _('Message filter')), + E('div', { 'class': 'cbi-value-field' }, logFilter), + ]), + + E('div', { 'class': 'cbi-value' }, [ + E('label', { + 'class': 'cbi-value-title', + 'for': 'logSorting', + }, _('Sorting entries')), + E('div', { 'class': 'cbi-value-field' }, logSorting,), + ]), + + E('div', { 'class': 'cbi-value' }, [ + E('label', { + 'class': 'cbi-value-title', + 'for': 'logFilter', + }), + E('div', { 'class': 'cbi-value-field' }, [ + logFormSubmitBtn, + E('form', { + 'id': 'logForm', + 'name': 'logForm', + 'style': 'display:inline-block', + 'submit': ui.createHandlerFn(this, function(ev) { + ev.preventDefault(); + let formElems = Array.from(document.forms.logForm.elements); + formElems.forEach(e => e.disabled = true); + logDownloadBtn.disabled = true; + + // Saving settings to localStorage + if(this.tailValue != tailInput.value) { + this.tailValue = (/^[0-9]+$/.test(tailInput.value)) ? tailInput.value : 0; + localStorage.setItem( + `luci-app-${this.viewName}-tailValue`, String(this.tailValue)); + }; + if(this.logSortingValue != logSorting.value) { + this.logSortingValue = logSorting.value; + localStorage.setItem( + `luci-app-${this.viewName}-logSorting`, this.logSortingValue); + }; + + let tail = (tailInput.value && tailInput.value > 0) ? tailInput.value : 0 + return this.getLogData(tail).then(logdata => { + logdata = logdata || ''; + + let loglines = this.makeLogArea( + this.setRegexpFilter( + this.setLevelFilter( + this.parseLogData(logdata, tail) + ) + ) + ); + + logWrapper.innerHTML = ''; + logWrapper.append(loglines); + + }).finally(() => { + formElems.forEach(e => e.disabled = false); + logDownloadBtn.disabled = false; + }); + + }), + }, E('span', {}, ' ')), + ]), + ]), + ]) + ), + E('div', { 'class': 'cbi-section fade-in' }, + E('div', { 'class': 'cbi-section-node' }, + E('div', { 'class': 'cbi-value' }, [ + E('div', { 'style': 'position:fixed; z-index:1 !important' }, [ + E('button', { + 'class': 'btn', + 'style': 'position:relative; display:block; margin:0 !important; left:1px; top:1px', + 'click': ev => { + document.getElementById('logTitle').scrollIntoView(true); + ev.target.blur(); + }, + }, '↑'), + E('button', { + 'class': 'btn', + 'style': 'position:relative; display:block; margin:0 !important; margin-top:1px !important; left:1px; top:1px', + 'click': ev => { + logWrapper.scrollIntoView(false); + ev.target.blur(); + }, + }, '↓'), + ]), + logWrapper, + ]) + ) + ), + E('div', { 'class': 'cbi-section fade-in' }, + E('div', { 'class': 'cbi-section-node' }, + E('div', { 'class': 'cbi-value' }, + E('div', { 'style': 'width:100%; text-align:right !important' }, [ + E('hr'), + logDownloadBtn, + ]) + ) + ) + ), + ]); + }, + + handleSaveApply: null, + handleSave: 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 438cde2..7f2d312 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 @@ -1,195 +1,61 @@ -'use strict'; 'require fs'; 'require ui'; +'require view.ruantiblock.baselog as baselog'; 'require view.ruantiblock.tools as tools'; -let log_regexp = new RegExp(`^.*(user\\.notice ${tools.app_name}).*$`, 'gm'); +return baselog.view.extend({ + viewName: 'ruantiblock-log', -return L.view.extend({ - tail_default: 25, + title: _('Ruantiblock') + ' - ' + _('Log'), - parse_log_data: function(logdata) { - return logdata.trim().match(log_regexp); - }, + getLogData: function(tail) { + return Promise.all([ + L.resolveDefault(fs.stat('/sbin/logread'), null), + L.resolveDefault(fs.stat('/usr/sbin/logread'), null), + ]).then(stat => { + let logger = (stat[0]) ? stat[0].path : (stat[1]) ? stat[1].path : null; - load: function() { - return Promise.all([ - L.resolveDefault(fs.stat('/sbin/logread'), null), - L.resolveDefault(fs.stat('/usr/sbin/logread'), null), - ]).then(stat => { - 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(e => { - ui.addNotification(null, E('p', _('Unable to execute or read contents') - + ': %s
[ %s ]'.format(e.message, logger) + if(logger) { + return fs.exec_direct(logger, [ '-e', '^' + tools.app_name ]).catch(err => { + ui.addNotification(null, E('p', _('Unable to execute or read contents') + + ': %s
[ %s ]'.format(err.message, logger) )); - return ''; - }); - }; - }); - }, + return ''; + }); + }; + }); + }, - render: function(logdata) { - let nav_btns_top = '1px'; - let loglines = this.parse_log_data(logdata); + parseLogData: function(logdata, tail) { + if(!logdata) { + return []; + }; - let log_textarea = E('textarea', { - 'id': 'syslog', - 'class': 'cbi-input-textarea', - 'style': 'width:100% !important; resize:horizontal; padding: 0 0 0 45px; font-size:12px', - 'readonly': 'readonly', - 'wrap': 'off', - 'rows': this.tail_default, - 'spellcheck': 'false', - }, [ loglines.slice(-this.tail_default).join('\n') ]); + let strings = logdata.trim().split(/\n/); - let tail_value = E('input', { - 'id': 'tail_value', - 'name': 'tail_value', - 'type': 'text', - 'form': 'log_form', - 'class': 'cbi-input-text', - 'style': 'width:4em !important; min-width:4em !important; margin-bottom:0.3em !important', - 'maxlength': 5, - }); - tail_value.value = this.tail_default; - ui.addValidator(tail_value, 'uinteger', true); + if(tail && tail > 0 && strings) { + strings = strings.slice(-tail); + }; - let log_filter = E('input', { - 'id': 'log_filter', - 'name': 'log_filter', - 'type': 'text', - 'form': 'log_form', - 'class': 'cbi-input-text', - 'style': 'min-width:16em !important; margin-right:1em !important; margin-bottom:0.3em !important', - 'placeholder': _('Message filter'), - 'data-tooltip': _('Filter messages with a regexp'), - }); + this.totalLogLines = strings.length; - let log_form_submit_btn = E('input', { - 'type': 'submit', - 'form': 'log_form', - 'class': 'cbi-button btn cbi-button-action', - 'style': 'margin-right:1em !important; margin-bottom:0.3em !important;', - 'value': _('Apply'), - 'click': ev => ev.target.blur(), - }); + let entriesArray = strings.map((e, i) => { + let strArray = e.split(/\s+/); + let logLevel = strArray[5].split('.'); - function set_log_tail(c_arr) { - let tail_num_val = tail_value.value; - if(tail_num_val && tail_num_val > 0 && c_arr) { - return c_arr.slice(-tail_num_val); - }; - return c_arr; - } + return [ + i + 1, // # (Number) + strArray.slice(0, 5).join(' '), // Timestamp (String) + logLevel[1], // Level (String) + logLevel[0], // Facility (String) + this.htmlEntities(strArray.slice(6).join(' ')), // Message (String) + ]; + }); - function set_log_filter(c_arr) { - let f_pattern = log_filter.value; - if(!f_pattern) { - return c_arr; - }; - let f_arr = []; - try { - f_arr = c_arr.filter(s => new RegExp(f_pattern.toLowerCase()).test(s.toLowerCase())); - } catch(err) { - if(err.name === 'SyntaxError') { - ui.addNotification(null, - E('p', {}, _('Wrong regular expression') + ': ' + err.message)); - return c_arr; - } else { - throw err; - }; - }; - if(f_arr.length === 0) { - f_arr.push(_('No matches...')); - }; - return f_arr; - } + if(this.logSortingValue === 'desc') { + entriesArray.reverse(); + }; - return E([ - E('h2', { 'id': 'log_title', 'class': 'fade-in' }, _('Ruantiblock') + ' - ' + _('Log')), - E('div', { 'class': 'cbi-section-descr fade-in' }), - E('div', { 'class': 'cbi-section fade-in' }, - E('div', { 'class': 'cbi-section-node' }, - E('div', { 'class': 'cbi-value' }, [ - E('label', { - 'class': 'cbi-value-title', - 'for': 'tailValue', - 'style': 'margin-bottom:0.3em !important', - }, _('Show only the last messages')), - E('div', { 'class': 'cbi-value-field' }, [ - tail_value, - E('input', { - 'type': 'button', - 'form': 'log_form', - 'class': 'cbi-button btn cbi-button-reset', - 'value': 'Χ', - 'click': ev => { - tail_value.value = null; - log_form_submit_btn.click(); - ev.target.blur(); - }, - 'style': 'margin-right:1em !important; margin-bottom:0.3em !important; max-width:4em !important', - }), - log_filter, - log_form_submit_btn, - E('form', { - 'id': 'log_form', - 'name': 'log_form', - 'style': 'display:inline-block; margin-bottom:0.3em !important', - 'submit': ui.createHandlerFn(this, function(ev) { - ev.preventDefault(); - let form_elems = Array.from(document.forms.log_form.elements); - form_elems.forEach(e => e.disabled = true); - - return this.load().then(logdata => { - let loglines = set_log_filter(set_log_tail( - this.parse_log_data(logdata))); - log_textarea.rows = (loglines.length < this.tail_default) ? - this.tail_default : loglines.length; - log_textarea.value = loglines.join('\n'); - }).finally(() => { - form_elems.forEach(e => e.disabled = false); - }); - }), - }, E('span', {}, ' ')), - ]), - ]) - ) - ), - E('div', { 'class': 'cbi-section fade-in' }, - E('div', { 'class': 'cbi-section-node' }, - E('div', { 'class': 'cbi-value' }, [ - E('div', { 'style': 'position:fixed' }, [ - E('button', { - 'class': 'btn', - 'style': 'position:relative; display:block; margin:0 !important; left:1px; top:' - + nav_btns_top, - 'click': ev => { - document.getElementById('log_title').scrollIntoView(true); - ev.target.blur(); - }, - }, '↑'), - E('button', { - 'class': 'btn', - 'style': 'position:relative; display:block; margin:0 !important; margin-top:1px !important; left:1px; top:' - + nav_btns_top, - 'click': ev => { - log_textarea.scrollIntoView(false); - ev.target.blur(); - }, - }, '↓'), - ]), - log_textarea, - ]) - ) - ), - ]); - }, - - handleSaveApply: null, - handleSave: null, - handleReset: null, + return entriesArray; + }, }); - diff --git a/luci-app-ruantiblock/po/ru/ruantiblock.po b/luci-app-ruantiblock/po/ru/ruantiblock.po index ba54b69..aac0bc3 100644 --- a/luci-app-ruantiblock/po/ru/ruantiblock.po +++ b/luci-app-ruantiblock/po/ru/ruantiblock.po @@ -117,9 +117,6 @@ msgstr "Исключение IP адресов из блэклиста по ша msgid "Expecting:" msgstr "Ожидается:" -msgid "Filter messages with a regexp" -msgstr "Фильтровать сообщения с помощью регулярного выражения" - msgid "FQDN configuration" msgstr "Конфигурация FQDN" @@ -171,9 +168,6 @@ msgstr "Основные настройки" msgid "Match-set" msgstr "Правило" -msgid "Message filter" -msgstr "Фильтр сообщений" - msgid "Minute" msgstr "Минута" @@ -189,9 +183,6 @@ msgstr "Нет изменений для сохранения." msgid "No data" msgstr "Нет данных" -msgid "No matches..." -msgstr "Нет совпадений..." - msgid "No Shedule" msgstr "Нет расписания" @@ -262,9 +253,6 @@ msgstr "Установить" msgid "Settings" msgstr "Настройки" -msgid "Show only the last messages" -msgstr "Показать только последние сообщения" - msgid "Shutdown" msgstr "Выключение" @@ -371,3 +359,77 @@ msgstr "верный IP-адрес" msgid "valid address#port" msgstr "верный IP-адрес#порт" + + + +msgid "Alert" +msgstr "Тревога" + +msgid "All" +msgstr "Все" + +msgid "Critical" +msgstr "Критическая ситуация" + +msgid "Debug" +msgstr "Отладка" + +msgid "Download log" +msgstr "Скачать лог" + +msgid "Emergency" +msgstr "Чрезвычайная ситуация" + +msgid "Entries" +msgstr "Записи" + +msgid "Facility" +msgstr "Категория" + +msgid "Info" +msgstr "Информация" + +msgid "Invalid regular expression" +msgstr "Неправильное регулярное выражение" + +msgid "Last entries" +msgstr "Последние записи" + +msgid "Level" +msgstr "Уровень" + +msgid "Logging levels" +msgstr "Уровни логирования" + +msgid "Message" +msgstr "Сообщение" + +msgid "Message filter" +msgstr "Фильтр сообщений" + +msgid "No entries available..." +msgstr "Нет доступных записей..." + +msgid "Notice" +msgstr "Сообщение" + +msgid "Sorting entries" +msgstr "Сортировка записей" + +msgid "Timestamp" +msgstr "Время" + +msgid "Type an expression..." +msgstr "Введите выражение..." + +msgid "Unable to load log data:" +msgstr "Невозможно загрузить данные лога:" + +msgid "Warning" +msgstr "Внимание" + +msgid "ascending" +msgstr "по возрастанию" + +msgid "descending" +msgstr "по убыванию" diff --git a/luci-app-ruantiblock/po/templates/ruantiblock.pot b/luci-app-ruantiblock/po/templates/ruantiblock.pot index c258ba2..069ba5c 100644 --- a/luci-app-ruantiblock/po/templates/ruantiblock.pot +++ b/luci-app-ruantiblock/po/templates/ruantiblock.pot @@ -104,9 +104,6 @@ msgstr "" msgid "Expecting:" msgstr "" -msgid "Filter messages with a regexp" -msgstr "" - msgid "FQDN configuration" msgstr "" @@ -158,9 +155,6 @@ msgstr "" msgid "Match-set" msgstr "" -msgid "Message filter" -msgstr "" - msgid "Minute" msgstr "" @@ -176,9 +170,6 @@ msgstr "" msgid "No data" msgstr "" -msgid "No matches..." -msgstr "" - msgid "No Shedule" msgstr "" @@ -237,9 +228,6 @@ msgstr "" msgid "Settings" msgstr "" -msgid "Show only the last messages" -msgstr "" - msgid "Shutdown" msgstr "" @@ -341,3 +329,77 @@ msgstr "" msgid "valid address#port" msgstr "" + + + +msgid "Alert" +msgstr "" + +msgid "All" +msgstr "" + +msgid "Critical" +msgstr "" + +msgid "Debug" +msgstr "" + +msgid "Download log" +msgstr "" + +msgid "Emergency" +msgstr "" + +msgid "Entries" +msgstr "" + +msgid "Facility" +msgstr "" + +msgid "Info" +msgstr "" + +msgid "Invalid regular expression" +msgstr "" + +msgid "Last entries" +msgstr "" + +msgid "Level" +msgstr "" + +msgid "Logging levels" +msgstr "" + +msgid "Message" +msgstr "" + +msgid "Message filter" +msgstr "" + +msgid "No entries available..." +msgstr "" + +msgid "Notice" +msgstr "" + +msgid "Sorting entries" +msgstr "" + +msgid "Timestamp" +msgstr "" + +msgid "Type an expression..." +msgstr "" + +msgid "Unable to load log data:" +msgstr "" + +msgid "Warning" +msgstr "" + +msgid "ascending" +msgstr "" + +msgid "descending" +msgstr "" diff --git a/luci-app-ruantiblock/root/usr/share/rpcd/acl.d/luci-app-ruantiblock.json b/luci-app-ruantiblock/root/usr/share/rpcd/acl.d/luci-app-ruantiblock.json index 7c239e0..32e0b22 100644 --- a/luci-app-ruantiblock/root/usr/share/rpcd/acl.d/luci-app-ruantiblock.json +++ b/luci-app-ruantiblock/root/usr/share/rpcd/acl.d/luci-app-ruantiblock.json @@ -18,8 +18,8 @@ "/etc/init.d/cron enabled": [ "exec" ], "/etc/init.d/cron enable": [ "exec" ], "/etc/init.d/cron restart": [ "exec" ], - "/sbin/logread -e ruantiblock": [ "exec" ], - "/usr/sbin/logread -e ruantiblock": [ "exec" ] + "/sbin/logread -e ^ruantiblock": [ "exec" ], + "/usr/sbin/logread -e ^ruantiblock": [ "exec" ] }, "uci": [ "network", "ruantiblock" ] }, diff --git a/luci-i18n-ruantiblock-ru/Makefile b/luci-i18n-ruantiblock-ru/Makefile deleted file mode 100644 index fc37880..0000000 --- a/luci-i18n-ruantiblock-ru/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# (с) 2020 gSpot (https://github.com/gSpotx2f/ruantiblock_openwrt) -# - -include $(TOPDIR)/rules.mk - -PKG_VERSION:=0.9.0 -PKG_RELEASE:=2 -LUCI_TITLE:=Translation for luci-app-ruantiblock - Русский (Russian) -LUCI_DEPENDS:=+luci-app-ruantiblock -LUCI_PKGARCH:=all - -include ../../luci.mk - -# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-i18n-ruantiblock-ru/luasrc/i18n/ruantiblock.ru.lmo b/luci-i18n-ruantiblock-ru/luasrc/i18n/ruantiblock.ru.lmo deleted file mode 100644 index 0b598a0..0000000 Binary files a/luci-i18n-ruantiblock-ru/luasrc/i18n/ruantiblock.ru.lmo and /dev/null differ diff --git a/packages/19.07/luci-app-ruantiblock_0.9.0-2_all.ipk b/packages/19.07/luci-app-ruantiblock_0.9.0-2_all.ipk deleted file mode 100644 index 348ce3a..0000000 Binary files a/packages/19.07/luci-app-ruantiblock_0.9.0-2_all.ipk and /dev/null differ diff --git a/packages/19.07/luci-app-ruantiblock_0.9.0-3_all.ipk b/packages/19.07/luci-app-ruantiblock_0.9.0-3_all.ipk new file mode 100644 index 0000000..236617e Binary files /dev/null and b/packages/19.07/luci-app-ruantiblock_0.9.0-3_all.ipk differ diff --git a/packages/19.07/luci-i18n-ruantiblock-ru_0.9.0-2_all.ipk b/packages/19.07/luci-i18n-ruantiblock-ru_0.9.0-2_all.ipk deleted file mode 100644 index 29b8dee..0000000 Binary files a/packages/19.07/luci-i18n-ruantiblock-ru_0.9.0-2_all.ipk and /dev/null differ diff --git a/packages/19.07/luci-i18n-ruantiblock-ru_0.9.0-3_all.ipk b/packages/19.07/luci-i18n-ruantiblock-ru_0.9.0-3_all.ipk new file mode 100644 index 0000000..57cd059 Binary files /dev/null and b/packages/19.07/luci-i18n-ruantiblock-ru_0.9.0-3_all.ipk differ diff --git a/packages/19.07/ruantiblock-mod-lua_0.9.0-1_all.ipk b/packages/19.07/ruantiblock-mod-lua_0.9.0-1_all.ipk deleted file mode 100644 index a625414..0000000 Binary files a/packages/19.07/ruantiblock-mod-lua_0.9.0-1_all.ipk and /dev/null differ diff --git a/packages/19.07/ruantiblock-mod-lua_0.9.0-2_all.ipk b/packages/19.07/ruantiblock-mod-lua_0.9.0-2_all.ipk new file mode 100644 index 0000000..8ab8f73 Binary files /dev/null and b/packages/19.07/ruantiblock-mod-lua_0.9.0-2_all.ipk differ diff --git a/packages/19.07/ruantiblock-mod-py_0.9.0-1_all.ipk b/packages/19.07/ruantiblock-mod-py_0.9.0-1_all.ipk deleted file mode 100644 index 807e2c2..0000000 Binary files a/packages/19.07/ruantiblock-mod-py_0.9.0-1_all.ipk and /dev/null differ diff --git a/packages/19.07/ruantiblock-mod-py_0.9.0-2_all.ipk b/packages/19.07/ruantiblock-mod-py_0.9.0-2_all.ipk new file mode 100644 index 0000000..cd4489c Binary files /dev/null and b/packages/19.07/ruantiblock-mod-py_0.9.0-2_all.ipk differ diff --git a/packages/19.07/ruantiblock_0.9.0-1_all.ipk b/packages/19.07/ruantiblock_0.9.0-1_all.ipk deleted file mode 100644 index 6e60442..0000000 Binary files a/packages/19.07/ruantiblock_0.9.0-1_all.ipk and /dev/null differ diff --git a/packages/19.07/ruantiblock_0.9.0-2_all.ipk b/packages/19.07/ruantiblock_0.9.0-2_all.ipk new file mode 100644 index 0000000..ff8abec Binary files /dev/null and b/packages/19.07/ruantiblock_0.9.0-2_all.ipk differ diff --git a/ruantiblock-mod-lua/Makefile b/ruantiblock-mod-lua/Makefile index 3302d61..8452161 100644 --- a/ruantiblock-mod-lua/Makefile +++ b/ruantiblock-mod-lua/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ruantiblock-mod-lua PKG_VERSION:=0.9.0 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_MAINTAINER:=gSpot PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) diff --git a/ruantiblock-mod-lua/files/usr/bin/ruab_parser.lua b/ruantiblock-mod-lua/files/usr/bin/ruab_parser.lua index 3fb1895..36b7539 100755 --- a/ruantiblock-mod-lua/files/usr/bin/ruab_parser.lua +++ b/ruantiblock-mod-lua/files/usr/bin/ruab_parser.lua @@ -317,8 +317,8 @@ function BlackListParser:fill_domain_tables(val) end function BlackListParser:sink() - -- Must be reload in the subclass - error("Method BlackListParser:sink() must be reload in the subclass!") + -- Needs to be reloaded in subclass + error("Method BlackListParser:sink() needs to be reloaded in subclass!") end function BlackListParser:optimize_ip_table() diff --git a/ruantiblock-mod-py/Makefile b/ruantiblock-mod-py/Makefile index 5b230d5..5e16a74 100644 --- a/ruantiblock-mod-py/Makefile +++ b/ruantiblock-mod-py/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ruantiblock-mod-py PKG_VERSION:=0.9.0 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_MAINTAINER:=gSpot PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) diff --git a/ruantiblock-mod-py/files/usr/bin/ruab_parser.py b/ruantiblock-mod-py/files/usr/bin/ruab_parser.py index f59d2d2..e64652a 100755 --- a/ruantiblock-mod-py/files/usr/bin/ruab_parser.py +++ b/ruantiblock-mod-py/files/usr/bin/ruab_parser.py @@ -294,9 +294,7 @@ class BlackListParser(Config): raise FieldValueError() def parser_func(self): - """ - Must be reload in the subclass - """ + """Needs to be reloaded in subclass""" raise NotImplementedError() def _check_sld_masks(self, sld): diff --git a/ruantiblock/Makefile b/ruantiblock/Makefile index a2bf3b9..f30ff58 100644 --- a/ruantiblock/Makefile +++ b/ruantiblock/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ruantiblock PKG_VERSION:=0.9.0 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_MAINTAINER:=gSpot PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) diff --git a/ruantiblock/files/usr/bin/ruantiblock b/ruantiblock/files/usr/bin/ruantiblock index 5cf4427..509d439 100755 --- a/ruantiblock/files/usr/bin/ruantiblock +++ b/ruantiblock/files/usr/bin/ruantiblock @@ -17,6 +17,7 @@ CONFIG_DIR="/etc/${NAME}" CONFIG_FILE="${CONFIG_DIR}/${NAME}.conf" export DATA_DIR="${CONFIG_DIR}/var" export EXEC_DIR="/usr/bin" + ### Команда для перезапуска dnsmasq export DNSMASQ_RESTART_CMD="/etc/init.d/dnsmasq restart" ### Директория для html-страницы статуса (не используется в OpenWrt) @@ -123,12 +124,14 @@ export AF_ENCODING="" ############################ Configuration ############################# +### External config [ -f "$CONFIG_FILE" ] && . "$CONFIG_FILE" CONFIG_SCRIPT="${CONFIG_DIR}/scripts/config_script" START_SCRIPT="${CONFIG_DIR}/scripts/start_script" STOP_SCRIPT="${CONFIG_DIR}/scripts/stop_script" +### Config script [ -f "$CONFIG_SCRIPT" ] && . "$CONFIG_SCRIPT" AWK_CMD="awk" @@ -208,7 +211,15 @@ EOF } MakeLogRecord() { - [ $USE_LOGGER = "1" ] && $LOGGER_CMD $LOGGER_PARAMS $1 + local _log_level + if [ $USE_LOGGER = "1" ]; then + if [ -z "$2" ]; then + _log_level="info" + else + _log_level="$2" + fi + $LOGGER_CMD $LOGGER_PARAMS -p "user.${_log_level}" "$1" + fi } DnsmasqRestart() { @@ -250,7 +261,7 @@ TotalProxyOn() { IptTotalProxyAdd if [ $? -eq 0 ]; then echo " ${IPSET_TOTAL_PROXY} enabled" - MakeLogRecord "${IPSET_TOTAL_PROXY} enabled" + MakeLogRecord "${IPSET_TOTAL_PROXY} enabled" "notice" fi MakeToken fi @@ -263,7 +274,7 @@ TotalProxyOff() { echo " ${IPSET_TOTAL_PROXY} is already disabled" >&2 else echo " ${IPSET_TOTAL_PROXY} disabled" - MakeLogRecord "${IPSET_TOTAL_PROXY} disabled" + MakeLogRecord "${IPSET_TOTAL_PROXY} disabled" "notice" fi MakeToken fi @@ -291,6 +302,7 @@ DelIptRules() { SetNetConfig() { local _set + ### Создание списков ipset. Проверка на наличие списка с таким же именем, если нет, то создается новый for _set in "$IPSET_TOTAL_PROXY" "$IPSET_CIDR_TMP" "$IPSET_CIDR" do IsIpsetExists "$_set" || $IPSET_CMD create "$_set" hash:net maxelem $IPSET_MAXELEM @@ -311,6 +323,7 @@ DropNetConfig() { FillIpsets() { local _set + ### Заполнение списков ipset $IPSET_IP и $IPSET_CIDR. Сначала restore загружает во временные списки, а затем swap из временных добавляет в основные if [ -f "$IP_DATA_FILE" ]; then echo " Filling ipsets..." FlushIpSets "$IPSET_IP_TMP" "$IPSET_CIDR_TMP" @@ -321,7 +334,7 @@ FillIpsets() { FlushIpSets "$IPSET_IP_TMP" "$IPSET_CIDR_TMP" else echo " Error! Ipset wasn't updated" >&2 - MakeLogRecord "Error! Ipset wasn't updated" + MakeLogRecord "Error! Ipset wasn't updated" "err" fi fi } @@ -353,6 +366,7 @@ CheckStatus() { PreStartCheck() { [ -d "$DATA_DIR" ] || mkdir -p "$DATA_DIR" [ "$HTML_INFO" = "1" -a ! -d "$HTML_DIR" ] && mkdir -p "$HTML_DIR" + ### Костыль для старта dnsmasq [ -e "$DNSMASQ_DATA_FILE" ] || printf "\n" > "$DNSMASQ_DATA_FILE" } @@ -404,8 +418,9 @@ GetDataFiles() { $BLLIST_MODULE _return_code=$? [ $_return_code -eq 0 ] && break + ### STDOUT echo " Module run attempt ${_attempt}: failed [${BLLIST_MODULE}]" - MakeLogRecord "Module run attempt ${_attempt}: failed [${BLLIST_MODULE}]" + MakeLogRecord "Module run attempt ${_attempt}: failed [${BLLIST_MODULE}]" "err" _attempt=`expr $_attempt + 1` [ $_attempt -gt $MODULE_RUN_ATTEMPTS ] && break sleep $MODULE_RUN_TIMEOUT @@ -416,8 +431,9 @@ GetDataFiles() { printf "Received entries: %s\n", (NF < 3) ? "No data" : "IP: "$1", CIDR: "$2", FQDN: "$3; exit; }' "$UPDATE_STATUS_FILE"` + ### STDOUT echo " ${_update_string}" - MakeLogRecord "${_update_string}" + MakeLogRecord "${_update_string}" "info" printf " `date +%d.%m.%Y-%H:%M`\n" >> "$UPDATE_STATUS_FILE" fi else @@ -429,6 +445,7 @@ GetDataFiles() { if [ "$PROXY_MODE" = "2" ]; then printf "\n" >> "$DNSMASQ_DATA_FILE" else + ### Запись для .onion в $DNSMASQ_DATA_FILE printf "server=/onion/%s\nipset=/onion/%s\n" "${ONION_DNS_ADDR}" "${IPSET_ONION}" >> "$DNSMASQ_DATA_FILE" fi rm -f "$UPDATE_PID_FILE" @@ -450,11 +467,11 @@ Update() { MakeToken if [ -e "$UPDATE_PID_FILE" ] && [ "$1" != "force-update" ]; then echo " ${NAME} ${1} - Error! Another instance of update is already running" >&2 - MakeLogRecord "${1} - Error! Another instance of update is already running" + MakeLogRecord "${1} - Error! Another instance of update is already running" "err" _return_code=2 else echo " ${NAME} ${1}..." - MakeLogRecord "${1}..." + MakeLogRecord "${1}..." "notice" if [ "$IPSET_CLEAR_SETS" = "1" ]; then FlushIpSets "$IPSET_IP" "$IPSET_CIDR" "$IPSET_DNSMASQ" fi @@ -462,16 +479,16 @@ Update() { case $? in 0) echo " Blacklist updated" - MakeLogRecord "Blacklist updated" + MakeLogRecord "Blacklist updated" "info" ;; 2) echo " Error! Blacklist update error" >&2 - MakeLogRecord "Error! Blacklist update error" + MakeLogRecord "Error! Blacklist update error" "err" _return_code=1 ;; *) echo " Module error! [${BLLIST_MODULE}]" >&2 - MakeLogRecord "Module error! [${BLLIST_MODULE}]" + MakeLogRecord "Module error! [${BLLIST_MODULE}]" "err" _return_code=1 ;; esac @@ -498,7 +515,7 @@ Start() { _return_code=1 else echo " ${NAME} ${1}..." - MakeLogRecord "${1}..." + MakeLogRecord "${1}..." "notice" DropNetConfig &> /dev/null SetNetConfig PreStartCheck @@ -517,7 +534,7 @@ Stop() { if CheckStatus; then MakeToken echo " ${NAME} ${1}..." - MakeLogRecord "${1}..." + MakeLogRecord "${1}..." "notice" DropNetConfig &> /dev/null _return_code=$? ### Stop script