diff --git a/autoinstall/autoinstall.sh b/autoinstall/autoinstall.sh index 262c2b2..7a061ba 100755 --- a/autoinstall/autoinstall.sh +++ b/autoinstall/autoinstall.sh @@ -11,7 +11,7 @@ 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-3" +RUAB_LUCI_APP_VERSION="0.9.0-4" 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 85c0bbf..833340a 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:=3 +PKG_RELEASE:=4 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 index 76437ba..f6b13cf 100644 --- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/baselog.js +++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/baselog.js @@ -44,7 +44,8 @@ return L.Class.extend({ /&/g, '&').replace( //g, '>').replace( - /"/g, '"'); + /"/g, '"').replace( + /'/g, '''); }, /** @@ -70,6 +71,44 @@ return L.Class.extend({ throw new Error('parseLogData needs to be reloaded in subclass'); }, + 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(e[4] !== null && 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; + }, + makeLogArea: function(logdataArray) { let lines = `
${_('No entries available...')}
`; let logTable = E('div', { 'id': 'logTable', 'class': 'table' }); @@ -81,15 +120,16 @@ return L.Class.extend({ if(logdataArray.length > 0) { lines = []; logdataArray.forEach((e, i) => { - this.logLevelsStat[e[2]] = (this.logLevelsStat[e[2]] != undefined) ? - this.logLevelsStat[e[2]] + 1 : 1; + if(e[2] in this.logLevels) { + this.logLevelsStat[e[2]] = this.logLevelsStat[e[2]] + 1; + }; lines.push( `
${e[0]}
` + ((e[1]) ? `
${e[1]}
` : '') + ((e[2]) ? `
${e[2]}
` : '') + ((e[3]) ? `
${e[3]}
` : '') + - ((e[4]) ? `
${e[4]}
` : '') + + ((e[4]) ? `
${e[4]}
` : '') + `
` ); }); @@ -119,7 +159,7 @@ return L.Class.extend({ let levelsStatString = ''; if((Object.values(this.logLevelsStat).reduce((s,c) => s + c, 0)) > 0) { Object.entries(this.logLevelsStat).forEach(e => { - if(e[1] > 0) { + if(e[0] in this.logLevels && e[1] > 0) { levelsStatString += `${e[1]}`; }; }); @@ -133,52 +173,14 @@ return L.Class.extend({ ]); }, - 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() { + downloadLog: function(ev) { 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', + 'download': this.viewName + '.log', 'href': URL.createObjectURL( new Blob([ logdata ], { type: 'text/plain' })), }); @@ -228,16 +230,32 @@ return L.Class.extend({ .log-entry-message { min-width: 25em !important; } +.log-entry-message-cell { + overflow-x: hidden !important; + text-overflow: ellipsis !important; +} .log-empty { } .log-emerg { background-color: #a93734 !important; color: #fff; } +log-emerg .td { + color: #fff !important; +} +log-emerg td { + color: #fff !important; +} .log-alert { background-color: #ff7968 !important; color: #fff; } +.log-alert .td { + color: #fff !important; +} +.log-alert td { + color: #fff !important; +} .log-crit { background-color: #fcc3bf !important; } @@ -354,6 +372,7 @@ return L.Class.extend({ let logSorting = E('select', { 'id': 'logSorting', + 'name': 'logSorting', 'form': 'logForm', 'class': "cbi-input-select", }, [ @@ -363,6 +382,8 @@ return L.Class.extend({ logSorting.value = this.logSortingValue; let logDownloadBtn = E('button', { + 'id': 'logDownloadBtn', + 'name': 'logDownloadBtn', 'class': 'cbi-button btn', 'click': ui.createHandlerFn(this, this.downloadLog), }, _('Download log')); @@ -412,7 +433,7 @@ return L.Class.extend({ E('form', { 'id': 'logForm', 'name': 'logForm', - 'style': 'display:inline-block', + 'style': 'display:inline-block; margin-top:0.5em', 'submit': ui.createHandlerFn(this, function(ev) { ev.preventDefault(); let formElems = Array.from(document.forms.logForm.elements); @@ -458,38 +479,33 @@ return L.Class.extend({ ]) ), 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-node' }, [ + 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, - ]) - ) + E('div', { 'style': 'width:100%; text-align:right !important' }, logDownloadBtn) + ), ) ), ]); 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 7f2d312..ad21c26 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,13 +1,44 @@ 'require fs'; 'require ui'; -'require view.ruantiblock.baselog as baselog'; +'require view.log.baselog as baselog'; 'require view.ruantiblock.tools as tools'; return baselog.view.extend({ - viewName: 'ruantiblock-log', + viewName: 'ruantiblock', title: _('Ruantiblock') + ' - ' + _('Log'), + appRegexp: new RegExp(`^.*${tools.app_name}\[[0-9]+\].*$`, 'gm'), + + testRegexp: new RegExp(/([0-9]{2}:){2}[0-9]{2}/), + + isLoggerChecked: false, + + entriesHandler: null, + + // logd + logdHandler: function(strArray, lineNum) { + let logLevel = strArray[5].split('.'); + return [ + lineNum, // # (Number) + strArray.slice(0, 5).join(' '), // Timestamp (String) + logLevel[1], // Level (String) + logLevel[0], // Facility (String) + this.htmlEntities(strArray.slice(6).join(' ')), // Message (String) + ]; + }, + + // syslog-ng + syslog_ngHandler: function(strArray, lineNum) { + return [ + lineNum, // # (Number) + strArray.slice(0, 3).join(' '), // Timestamp (String) + null, // Level (String) + null, // Facility (String) + this.htmlEntities(strArray.slice(4).join(' ')), // Message (String) + ]; + }, + getLogData: function(tail) { return Promise.all([ L.resolveDefault(fs.stat('/sbin/logread'), null), @@ -16,10 +47,8 @@ return baselog.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 execute or read contents') - + ': %s
[ %s ]'.format(err.message, 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 ''; }); }; @@ -31,7 +60,7 @@ return baselog.view.extend({ return []; }; - let strings = logdata.trim().split(/\n/); + let strings = logdata.trim().match(this.appRegexp) || []; if(tail && tail > 0 && strings) { strings = strings.slice(-tail); @@ -41,15 +70,22 @@ return baselog.view.extend({ let entriesArray = strings.map((e, i) => { let strArray = e.split(/\s+/); - let logLevel = strArray[5].split('.'); - 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) - ]; + if(!this.isLoggerChecked) { + /** + * Checking the third field of a line. + * If it contains time then syslog-ng. + */ + if(this.testRegexp.test(strArray[2])) { + this.logLevels = {}; + this.entriesHandler = this.syslog_ngHandler; + } else { + this.entriesHandler = this.logdHandler; + }; + this.isLoggerChecked = true; + }; + + return this.entriesHandler(strArray, i + 1); }); if(this.logSortingValue === 'desc') { 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 32e0b22..7c239e0 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/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 deleted file mode 100644 index 236617e..0000000 Binary files a/packages/19.07/luci-app-ruantiblock_0.9.0-3_all.ipk and /dev/null differ diff --git a/packages/19.07/luci-app-ruantiblock_0.9.0-4_all.ipk b/packages/19.07/luci-app-ruantiblock_0.9.0-4_all.ipk new file mode 100644 index 0000000..6d91ce6 Binary files /dev/null and b/packages/19.07/luci-app-ruantiblock_0.9.0-4_all.ipk 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 deleted file mode 100644 index 57cd059..0000000 Binary files a/packages/19.07/luci-i18n-ruantiblock-ru_0.9.0-3_all.ipk and /dev/null differ diff --git a/packages/19.07/luci-i18n-ruantiblock-ru_0.9.0-4_all.ipk b/packages/19.07/luci-i18n-ruantiblock-ru_0.9.0-4_all.ipk new file mode 100644 index 0000000..00b3f45 Binary files /dev/null and b/packages/19.07/luci-i18n-ruantiblock-ru_0.9.0-4_all.ipk differ