diff --git a/dae/Makefile b/dae/Makefile index 42c24ce4..83581c3c 100644 --- a/dae/Makefile +++ b/dae/Makefile @@ -5,10 +5,10 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dae -PKG_VERSION:=2026.07.21 -PKG_RELEASE:=20 +PKG_VERSION:=2026.07.22 +PKG_RELEASE:=21 -PKG_SOURCE:=dae-src-2026.07.21-f6edc5e8af8c.tar.gz +PKG_SOURCE:=dae-src-2026.07.22-1ff7a6abc0ad.tar.gz PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/dae-src PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_HASH:=skip diff --git a/daed/Makefile b/daed/Makefile index cbee6fa3..a643382b 100644 --- a/daed/Makefile +++ b/daed/Makefile @@ -5,10 +5,10 @@ include $(TOPDIR)/rules.mk PKG_NAME:=daed -PKG_VERSION:=2026.07.21 -PKG_RELEASE:=28 +PKG_VERSION:=2026.07.22 +PKG_RELEASE:=29 -PKG_SOURCE:=daed-src-2026.07.21-7ab100147a57.tar.gz +PKG_SOURCE:=daed-src-2026.07.22-4a6a3994ced1.tar.gz PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/daed-src PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_HASH:=skip diff --git a/golang/golang1.26/Makefile b/golang/golang1.26/Makefile index dab9884c..1c760ccb 100644 --- a/golang/golang1.26/Makefile +++ b/golang/golang1.26/Makefile @@ -8,10 +8,10 @@ include $(TOPDIR)/rules.mk PKG_NAME:=golang1.26 GO_VERSION_MAJOR_MINOR:=1.26 -GO_VERSION_PATCH:=4 +GO_VERSION_PATCH:=5 GO_VERSION_RC:= GO_BOOTSTRAP_VERSION:=bootstrap -PKG_HASH:=4f668a32fbfc1132e6a881fb968c2f1dada631492a339211735fbb255a42602d +PKG_HASH:=495be4bc87176ac567392e5b4116abd98466d33d7b49d41e764ccc6976b2dc42 PKG_VERSION:=$(GO_VERSION_MAJOR_MINOR)$(if $(GO_VERSION_RC),.0)$(if $(GO_VERSION_PATCH),.$(GO_VERSION_PATCH)) PKG_FILE_VERSION:=$(GO_VERSION_MAJOR_MINOR)$(if $(GO_VERSION_RC),rc$(GO_VERSION_RC))$(if $(GO_VERSION_PATCH),.$(GO_VERSION_PATCH)) diff --git a/luci-app-csshnpd/Makefile b/luci-app-csshnpd/Makefile deleted file mode 100644 index 769ce45e..00000000 --- a/luci-app-csshnpd/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=luci-app-csshnpd -PKG_LICENSE:=GPL-2.0 -PKG_MAINTAINER:=Chris Swan -PKG_RELEASE:=1 - -LUCI_TITLE:=NoPorts Web UI -LUCI_DESCRIPTION:=LuCI config app for NoPorts daemon (csshnpd) -LUCI_DEPENDS:=+luci-base +csshnpd -LUCI_PKGARCH:=all - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-csshnpd/htdocs/luci-static/resources/view/sshnpd/config.js b/luci-app-csshnpd/htdocs/luci-static/resources/view/sshnpd/config.js deleted file mode 100644 index 1e9855ce..00000000 --- a/luci-app-csshnpd/htdocs/luci-static/resources/view/sshnpd/config.js +++ /dev/null @@ -1,88 +0,0 @@ -'use strict'; -'require view'; -'require form'; - -function validateAtsign(section_id, value) { - if (value.length < 1) { - return _('Must not be empty and should start with @ (e.g., "@a").'); - } - return true; -} - -function validateDevice(section_id, value) { - if (value.length < 1) { - return _('Must be at least one character long (e.g., "a").'); - } - if (value.length == 1) { - if (!/^[a-z]+$/.test(value)) { - return _('First character should be a lowercase letter (e.g., "a").'); - } else { - return true; - } - } - if (!/^[a-z][a-z0-9_-]+$/.test(value)) { - return _('Device names may contain a-z 0-9 _ or - (e.g., "my_thing1").'); - } - if (value.length > 36) { - return _('Maximum device name length is 36 characters.'); - } - return true; -} - -function validateOTP(section_id, value) { - if (value.length != 6) { - return _('Must be six characters (e.g., "S3CR3T").'); - } - return true; -} - -function firstAt(section_id, value) { - if (value && !value.startsWith('@')) { - value = '@' + value; // Ensure @ at start - } - return this.super('write', [section_id, value]); -} - -return view.extend({ - render: function() { - let m, s, o; - - m = new form.Map('sshnpd', _('NoPorts'), - _('Daemon Configuration')); - - s = m.section(form.TypedSection, 'sshnpd', _('sshnpd config')); - s.anonymous = true; - - o = s.option(form.Value, 'atsign', _('Device atSign'), - _('The device atSign e.g. @device')); - o.default = '@device'; - o.validate = validateAtsign; - o.write = firstAt; - - o = s.option(form.Value, 'manager', _('Manager atSign'), - _('The manager atSign e.g. @manager')); - o.default = '@manager'; - o.validate = validateAtsign; - o.write = firstAt; - - o = s.option(form.Value, 'device', _('Device name'), - _('The name for this device e.g. openwrt')); - o.default = 'openwrt'; - o.validate = validateDevice; - - s.option(form.Value, 'args', _('Additional arguments'), - _('Further command line arguments for the NoPorts daemon')); - - o = s.option(form.Value, 'otp', _('Enrollment OTP/SPP'), - _('One Time Passcode (OTP) for device atSign enrollment')); - o.default = '000000'; - o.validate = validateOTP; - - o = s.option(form.Flag, 'enabled', _('Enabled'), - _('Check here to enable the service')); - o.default = '1'; - o.rmempty = false; - - return m.render(); - }, -}); diff --git a/luci-app-csshnpd/htdocs/luci-static/resources/view/sshnpd/enroll.js b/luci-app-csshnpd/htdocs/luci-static/resources/view/sshnpd/enroll.js deleted file mode 100644 index a97cefb9..00000000 --- a/luci-app-csshnpd/htdocs/luci-static/resources/view/sshnpd/enroll.js +++ /dev/null @@ -1,97 +0,0 @@ -'use strict'; -'require view'; -'require dom'; -'require fs'; -'require ui'; -'require uci'; -'require network'; - - -return view.extend({ - handleCommand: function(exec, args) { - let buttons = document.querySelectorAll('.diag-action > .cbi-button'); - - for (let i = 0; i < buttons.length; i++) - buttons[i].setAttribute('disabled', 'true'); - - return fs.exec(exec, args).then(function(res) { - let out = document.querySelector('textarea'); - - dom.content(out, [ res.stdout || '', res.stderr || '' ]); - }).catch(function(err) { - ui.addNotification(null, E('p', [ err ])) - }).finally(function() { - for (let i = 0; i < buttons.length; i++) - buttons[i].removeAttribute('disabled'); - }); - }, - - handleEnroll: function() { - return this.handleCommand('at_enroll.sh', ""); - }, - - load: function() { - return uci.load('sshnpd').then(function() { - let atsign = uci.get_first('sshnpd','','atsign'), - keyfile = '/root/.atsign/keys/'+atsign+'_key.atKeys'; - return L.resolveDefault(fs.stat(keyfile), {}); - }); - }, - - render: function(res) { - - const has_atkey = res.path; - const atsign = uci.get_first('sshnpd','','atsign'); - const device = uci.get_first('sshnpd','','device'); - const otp = uci.get_first('sshnpd','','otp'); - const enrollready = atsign && device && otp && !has_atkey; - - const instructions = E('div', { 'class': 'cbi-map-descr'}, _('Press the Enroll button then run this command on a system where '+atsign+' is activated:')); - - const enrollcmd = E('code','at_activate approve -a '+atsign+' --arx noports --drx '+device); - - let table = E('table', { 'class': 'table' }, [ - E('tr', { 'class': 'tr' }, [ - E('td', { 'class': 'td left' }, [ - E('span', { 'class': 'diag-action' }, [ - E('button', { - 'class': 'cbi-button cbi-button-action', - 'click': ui.createHandlerFn(this, 'handleEnroll') - }, [ _('Enroll') ]) - ]) - ]), - ]) - ]); - - const cmdwindow = E('div', {'class': 'cbi-section'}, [ - E('div', { 'id' : 'command-output'}, - E('textarea', { - 'id': 'widget.command-output', - 'style': 'width: 100%; font-family:monospace; white-space:pre', - 'readonly': true, - 'wrap': 'on', - 'rows': '20' - }) - ) - ]); - - let view = E('div', { 'class': 'cbi-map'}, [ - E('h2', {}, [ _('NoPorts atSign Enrollment') ]), - atsign ? E([]) : E('div', { 'class': 'cbi-map-descr'}, _('atSign must be configured')), - device ? E([]) : E('div', { 'class': 'cbi-map-descr'}, _('Device must be configured')), - otp ? E([]) : E('div', { 'class': 'cbi-map-descr'}, _('OTP must be configured. An OTP can be generated using:')), - otp ? E([]) : E('code','at_activate otp -a '+atsign), - has_atkey ? E('div', { 'class': 'cbi-map-descr'}, _('Existing key found at: '+has_atkey)) : E([]), - enrollready ? instructions : E([]), - enrollready ? enrollcmd : E([]), - enrollready ? table : E([]), - enrollready ? cmdwindow : E([]), - ]); - - return view; - }, - - handleSaveApply: null, - handleSave: null, - handleReset: null -}); diff --git a/luci-app-csshnpd/root/usr/share/luci/menu.d/luci-app-csshnpd.json b/luci-app-csshnpd/root/usr/share/luci/menu.d/luci-app-csshnpd.json deleted file mode 100644 index 7d987bbe..00000000 --- a/luci-app-csshnpd/root/usr/share/luci/menu.d/luci-app-csshnpd.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "admin/network/sshnpd": { - "title": "NoPorts", - "order": 70, - "action": { - "type": "firstchild" - }, - "depends": { - "acl": [ "luci-app-csshnpd" ] - } - }, - - "admin/network/sshnpd/config": { - "title": "NoPorts Config", - "order": 1, - "action": { - "type": "view", - "path": "sshnpd/config" - } - }, - - "admin/network/sshnpd/enroll": { - "title": "NoPorts Enrollment", - "order": 2, - "action": { - "type": "view", - "path": "sshnpd/enroll" - } - } -} diff --git a/luci-app-csshnpd/root/usr/share/rpcd/acl.d/luci-app-csshnpd.json b/luci-app-csshnpd/root/usr/share/rpcd/acl.d/luci-app-csshnpd.json deleted file mode 100644 index 07054b54..00000000 --- a/luci-app-csshnpd/root/usr/share/rpcd/acl.d/luci-app-csshnpd.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "luci-app-csshnpd": { - "description": "Grant UCI access for luci-app-csshnpd", - "read": { - "uci": [ "sshnpd" ], - "file": { - "/usr/bin/at_enroll.sh": ["exec"], - "/root/.atsign/keys/*": ["stat"] - } - }, - "write": { - "uci": [ "sshnpd" ] - } - } -} diff --git a/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js b/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js index da464bb6..0365ba45 100644 --- a/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js +++ b/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js @@ -171,9 +171,9 @@ return view.extend({ .catch(function(e) { ui.addNotification(null, E('p', e.message)) }); }, - HandleStopDDnsRule(m, section_id, ev) { + handleStopDDnsRule(m, section_id, ev) { return fs.exec('/usr/lib/ddns/dynamic_dns_lucihelper.sh', - [ '-S', section_id, '--', 'start' ]) + [ '-S', section_id, '--', 'stop' ]) .then(L.bind(m.render, m)) .catch(function(e) { ui.addNotification(null, E('p', e.message)) }); }, @@ -551,7 +551,7 @@ return view.extend({ }, stop_opt = { 'class': 'cbi-button cbi-button-neutral stop', - 'click': ui.createHandlerFn(_this, 'HandleStopDDnsRule', m, section_id), + 'click': ui.createHandlerFn(_this, 'handleStopDDnsRule', m, section_id), 'title': _('Stop this service'), }; diff --git a/luci-app-ddns/root/usr/share/rpcd/ucode/ddns.uc b/luci-app-ddns/root/usr/share/rpcd/ucode/ddns.uc index f8901a0a..c7b5a38b 100644 --- a/luci-app-ddns/root/usr/share/rpcd/ucode/ddns.uc +++ b/luci-app-ddns/root/usr/share/rpcd/ucode/ddns.uc @@ -15,7 +15,12 @@ const luci_helper = '/usr/lib/ddns/dynamic_dns_lucihelper.sh'; const ddns_version_file = '/usr/share/ddns/version'; +function shellquote(value) { + if (value == null) + value = ''; + return "'" + replace(value, "'", "'\\''") + "'"; +} function get_dateformat() { return uci.get('ddns', 'global', 'ddns_dateformat') || '%F %R'; @@ -126,9 +131,9 @@ const methods = { if (forceDnsTcp == 1) push(command, '-t'); // if (isGlue == 1) push(command, '-g'); - push(command, '-l', lookupHost); - push(command, '-S', section); - if (length(dnsServer) > 0) push(command, '-d', dnsServer); + push(command, '-l', shellquote(lookupHost)); + push(command, '-S', shellquote(section)); + if (length(dnsServer) > 0) push(command, '-d', shellquote(dnsServer)); push(command, '-- get_registered_ip'); const result = system(`${join(' ', command)}`); @@ -221,50 +226,40 @@ const methods = { const hasCommand = (command) => { return (system(`command -v ${command} 1>/dev/null`) == 0) ? true : false }; - const hasWget = () => hasCommand('wget'); + const hasWget = () => { + return cache.has_wget ??= hasCommand('wget'); + } const hasWgetSsl = () => { - if (cache['has_wgetssl']) return cache['has_wgetssl']; - const result = hasWget() && system(`wget 2>&1 | grep -iqF 'https'`) == 0 ? true : false; - cache['has_wgetssl'] = result; - return result; + return cache.has_wgetssl ??= hasWget() && system(`wget 2>&1 | grep -iqF 'https'`) == 0 ? true : false; }; const hasGNUWgetSsl = () => { - if (cache['has_gnuwgetssl']) return cache['has_gnuwgetssl']; - const result = hasWget() && system(`wget -V 2>&1 | grep -iqF '+https'`) == 0 ? true : false; - cache['has_gnuwgetssl'] = result; - return result; + return cache.has_gnuwgetssl ??= hasWget() && system(`wget -V 2>&1 | grep -iqF '+https'`) == 0 ? true : false; }; const hasCurl = () => { - if (cache['has_curl']) return cache['has_curl']; - const result = hasCommand('curl'); - cache['has_curl'] = result; - return result; + return cache.has_curl ??= hasCommand('curl'); }; const hasCurlSsl = () => { - return system(`curl -V 2>&1 | grep -qF 'https'`) == 0 ? true : false; + return cache.has_curl_ssl ??= system(`curl -V 2>&1 | grep -qF 'https'`) == 0 ? true : false; }; const hasFetch = () => { - if (cache['has_fetch']) return cache['has_fetch']; - const result = hasCommand('uclient-fetch'); - cache['has_fetch'] = result; - return result; + return cache.has_fetch ??= hasCommand('uclient-fetch'); }; const hasFetchSsl = () => { - return stat('/lib/libustream-ssl.so') == 0 ? true : false; + return cache.has_fetch_ssl ??= stat('/lib/libustream-ssl.so') ? true : false; }; const hasCurlPxy = () => { - return system(`grep -i 'all_proxy' /usr/lib/libcurl.so*`) == 0 ? true : false; + return cache.has_curl_proxy ??= system(`grep -i 'all_proxy' /usr/lib/libcurl.so*`) == 0 ? true : false; }; const hasBbwget = () => { - return system(`wget -V 2>&1 | grep -iqF 'busybox'`) == 0 ? true : false; + return cache.has_bbwget ??= system(`wget -V 2>&1 | grep -iqF 'busybox'`) == 0 ? true : false; }; diff --git a/luci-app-libreswan/Makefile b/luci-app-libreswan/Makefile deleted file mode 100644 index 5c67d2a2..00000000 --- a/luci-app-libreswan/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (C) 2022 Jaymin Patel -# -# This is free software, licensed under the GNU General Public License v2. -# - -include $(TOPDIR)/rules.mk - -PKG_LICENSE:=GPL-2.0-or-later -PKG_MAINTAINER:=Jaymin Patel - -LUCI_TITLE=Luci Application for IPSec VPN (Libreswan) -LUCI_DEPENDS:=+luci-base +libreswan -LUCI_PKGARCH:=all - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature - diff --git a/luci-app-libreswan/htdocs/luci-static/resources/view/libreswan/globals.js b/luci-app-libreswan/htdocs/luci-static/resources/view/libreswan/globals.js deleted file mode 100644 index 62b9dfe3..00000000 --- a/luci-app-libreswan/htdocs/luci-static/resources/view/libreswan/globals.js +++ /dev/null @@ -1,71 +0,0 @@ -'use strict'; -'require view'; -'require form'; -'require network'; -'require tools.widgets as widgets'; - -return view.extend({ - load() { - return Promise.all([ - network.getDevices(), - ]); - }, - - render([netDevs]) { - let m, s, o; - - m = new form.Map('libreswan', _('IPSec Global Settings')); - - s = m.section(form.NamedSection, 'globals', 'libreswan'); - s.anonymous = false; - s.addremove = false; - - o = s.option(form.ListValue, 'debug', _('Debug Logs')); - o.default = false; - o.rmempty = false; - o.value('none', _('none - No Logging')); - o.value('base', _('base - Moderate Logging')); - o.value('cpu-usage', _('cpu-usage - Timing/Load Logging')); - o.value('crypto', _('crypto - All crypto related Logging')); - o.value('tmi', _('tmi - Too Much/Excessive Logging')); - o.value('private', _('private - Sensitive private-key/password Logging')); - o.default = 'none' - - o = s.option(form.Flag, 'uniqueids', _('Uniquely Identify Remotes'), - _('Whether IDs should be considered identifying remote parties uniquely')); - o.default = false; - o.rmempty = false; - - o = s.option(widgets.NetworkSelect, 'listen_interface', _('Listen Interface'), - _('Interface for IPsec to use')); - o.datatype = 'string'; - o.multiple = false; - o.optional = true; - - o = s.option(form.Value, 'listen', _('Listen Address'), - _('IP address to listen on, default depends on Listen Interface')); - o.datatype = 'ip4addr'; - for (let nd of netDevs) { - var addrs = nd.getIPAddrs(); - for (let ad of addrs) { - o.value(ad.split('/')[0]); - } - } - o.depends({ 'listen_interface' : '' }); - - o = s.option(form.Value, 'nflog_all', _('Enable nflog on nfgroup'), - _('NFLOG group number to log all pre-crypt and post-decrypt traffic to')); - o.datatype = 'uinteger'; - o.default = 0; - o.rmempty = true; - o.optional = true; - - o = s.option(form.DynamicList, 'virtual_private', _('Allowed Virtual Private'), - _('The address ranges that may live behind a NAT router through which a client connects')); - o.datatype = 'neg(ip4addr)'; - o.multiple = true; - o.optional = true; - - return m.render(); - } -}); diff --git a/luci-app-libreswan/htdocs/luci-static/resources/view/libreswan/overview.js b/luci-app-libreswan/htdocs/luci-static/resources/view/libreswan/overview.js deleted file mode 100644 index d09bf20e..00000000 --- a/luci-app-libreswan/htdocs/luci-static/resources/view/libreswan/overview.js +++ /dev/null @@ -1,82 +0,0 @@ -'use strict'; -'require view'; -'require rpc'; -'require form'; -'require poll'; - -const callLibreswanStatus = rpc.declare({ - object: 'libreswan', - method: 'status', - expect: { }, -}); - -function secondsToString(seconds) { - const numdays = Math.floor(seconds / 86400); - seconds %= 86400; - const numhours = Math.floor(seconds / 3600); - seconds %= 3600; - const numminutes = Math.floor(seconds / 60); - const numseconds = seconds % 60; - - return [ - numdays ? `${numdays}d` : '', - numhours ? `${numhours}h` : '', - numminutes ? `${numminutes}m` : '', - `${numseconds}s` - ].filter(Boolean).join(' '); -} - -return view.extend({ - render: function() { - const table = - E('table', { 'class': 'table lases' }, [ - E('tr', { 'class': 'tr table-titles' }, [ - E('th', { 'class': 'th' }, _('Name')), - E('th', { 'class': 'th' }, _('Remote')), - E('th', { 'class': 'th' }, _('Local Subnet')), - E('th', { 'class': 'th' }, _('Remote Subnet')), - E('th', { 'class': 'th' }, _('Tx')), - E('th', { 'class': 'th' }, _('Rx')), - E('th', { 'class': 'th' }, _('Phase1')), - E('th', { 'class': 'th' }, _('Phase2')), - E('th', { 'class': 'th' }, _('Status')), - E('th', { 'class': 'th' }, _('Uptime')), - E([]) - ]) - ]); - - poll.add(function() { - return callLibreswanStatus().then(function(tunnelsInfo) { - const tunnels = Array.isArray(tunnelsInfo.tunnels) ? tunnelsInfo.tunnels : []; - - cbi_update_table(table, - tunnels.map(function(tunnel) { - return [ - tunnel.name, - tunnel.right, - tunnel.leftsubnet, - tunnel.rightsubnet, - tunnel.tx, - tunnel.rx, - tunnel.phase1 ? _('Up') : _('Down'), - tunnel.phase2 ? _('Up') : _('Down'), - tunnel.connected ? _('Up') : _('Down'), - secondsToString(tunnel.uptime), - ]; - }), - E('em', _('There are no active Tunnels')) - ); - }); - }); - - return E([ - E('h3', _('IPSec Tunnels Summary')), - E('br'), - table - ]); - }, - - handleSave: null, - handleSaveApply:null, - handleReset: null -}); diff --git a/luci-app-libreswan/htdocs/luci-static/resources/view/libreswan/proposals.js b/luci-app-libreswan/htdocs/luci-static/resources/view/libreswan/proposals.js deleted file mode 100644 index bdc23268..00000000 --- a/luci-app-libreswan/htdocs/luci-static/resources/view/libreswan/proposals.js +++ /dev/null @@ -1,76 +0,0 @@ -'use strict'; -'require view'; -'require ui'; -'require form'; -'require uci'; - -return view.extend({ - render() { - let m, s, o; - - m = new form.Map('libreswan', _('IPSec Proposals')); - - s = m.section(form.GridSection, 'crypto_proposal'); - s.anonymous = false; - s.addremove = true; - s.nodescriptions = true; - s.addbtntitle = _('Add Proposal'); - - s.renderSectionAdd = function(extra_class) { - const el = form.GridSection.prototype.renderSectionAdd.apply(this, arguments), - nameEl = el.querySelector('.cbi-section-create-name'); - ui.addValidator(nameEl, 'uciname', true, function(v) { - let sections = [ - ...uci.sections('libreswan', 'crypto_proposal'), - ...uci.sections('libreswan', 'tunnel'), - ]; - if (sections.find(function(s) { - return s['.name'] == v; - })) { - return _('This may not share the same name as other proposals or configured tunnels.'); - } - if (v.length > 15) return _('Name length shall not exceed 15 characters'); - return true; - }, 'blur', 'keyup'); - return el; - }; - - o = s.tab('general', _('General')); - - o = s.taboption('general', form.MultiValue, 'hash_algorithm', _('Hash Algorithm'), ('* = %s').format(_('Unsafe'))); - o.default = 'md5'; - o.value('md5', _('MD5*')); - o.value('sha1', _('SHA1*')); - o.value('sha256', _('SHA256')); - o.value('sha384', _('SHA384')); - o.value('sha512', _('SHA512')); - - o = s.taboption('general', form.MultiValue, 'encryption_algorithm', _('Encryption Method'), ('* = %s').format(_('Unsafe'))); - o.default = 'aes'; - o.value('3des', _('3DES*')) - o.value('aes', _('AES')) - o.value('aes_ctr', _('AES_CTR')); - o.value('aes_cbc', _('AES_CBC')); - o.value('aes128', _('AES128')); - o.value('aes192', _('AES192')); - o.value('aes256', _('AES256')); - o.value('camellia_cbc', _('CAMELLIA_CBC')); - - o = s.taboption('general', form.MultiValue, 'dh_group', _('DH Group'), - ('* = %s RFC8247.').format(_('Unsafe, See'), 'https://www.rfc-editor.org/rfc/rfc8247#section-2.4')); - o.default = 'modp1536'; - o.value('modp1536', _('DH Group 5*')); - o.value('modp2048', _('DH Group 14')); - o.value('modp3072', _('DH Group 15')); - o.value('modp4096', _('DH Group 16')); - o.value('modp6144', _('DH Group 17')); - o.value('modp8192', _('DH Group 18')); - o.value('dh19', _('DH Group 19')); - o.value('dh20', _('DH Group 20')); - o.value('dh21', _('DH Group 21')); - o.value('dh22', _('DH Group 22*')); - o.value('dh31', _('DH Group 31')); - - return m.render(); - } -}); diff --git a/luci-app-libreswan/htdocs/luci-static/resources/view/libreswan/tunnels.js b/luci-app-libreswan/htdocs/luci-static/resources/view/libreswan/tunnels.js deleted file mode 100644 index f133d436..00000000 --- a/luci-app-libreswan/htdocs/luci-static/resources/view/libreswan/tunnels.js +++ /dev/null @@ -1,274 +0,0 @@ -'use strict'; -'require view'; -'require form'; -'require ui'; -'require uci'; -'require network'; -'require validation'; -'require tools.widgets as widgets'; - -function calculateNetwork(addr, mask) { - const parsedAddr = validation.parseIPv4(String(addr)); - if (parsedAddr == null) return null; - - const parsedMask = !isNaN(mask) - ? validation.parseIPv4(network.prefixToMask(+mask)) - : validation.parseIPv4(String(mask)); - if (parsedMask == null) return null; - - const networkAddr = parsedAddr.map((byte, i) => byte & (parsedMask[i] >>> 0 & 255)); - - return `${networkAddr.join('.')}/${network.maskToPrefix(parsedMask.join('.'))}`; -} - -return view.extend({ - load() { - return Promise.all([ - network.getDevices(), - uci.load('libreswan'), - ]); - }, - - render([netDevs]) { - let m, s, o; - - let proposals = uci.sections('libreswan', 'crypto_proposal'); - if (proposals == '') { - ui.addNotification(null, E('p', _('Proposals must be configured for Tunnels'))); - return; - } - - m = new form.Map('libreswan', 'IPSec Tunnels'); - - s = m.section(form.GridSection, 'tunnel'); - s.anonymous = false; - s.addremove = true; - s.nodedescription = false; - s.addbtntitle = _('Add Tunnel'); - - s.renderSectionAdd = function(extra_class) { - const el = form.GridSection.prototype.renderSectionAdd.apply(this, arguments); - const nameEl = el.querySelector('.cbi-section-create-name'); - ui.addValidator(nameEl, 'uciname', true, function(v) { - let sections = [ - ...uci.sections('libreswan', 'crypto_proposal'), - ...uci.sections('libreswan', 'tunnel'), - ]; - - if (sections.find(function(s) { - return s['.name'] == v; - })) { - return _('This may not share the same name as other proposals or configured tunnels.'); - } - if (v.length > 15) return _('Name length shall not exceed 15 characters'); - return true; - }, 'blur', 'keyup'); - return el; - }; - - o = s.tab('general', _('General')); - o = s.tab('authentication', _('Authentication')); - o = s.tab('interface', _('Interface')); - o = s.tab('advanced', _('Advanced')); - - o = s.taboption('general', form.ListValue, 'auto', _('Mode')); - o.default = 'start'; - o.value('add', _('Listen')); - o.value('start', _('Initiate')); - - o = s.taboption('general', widgets.NetworkSelect, 'left_interface', _('Left Interface')); - o.datatype = 'string'; - o.multiple = false; - o.optional = true; - - o = s.taboption('general', form.Value, 'left', _('Left IP/Device')); - o.datatype = 'or(string, ipaddr)'; - netDevs.forEach(netDev => { - netDev.getIPAddrs().forEach(addr => { - o.value(addr.split('/')[0]); - }); - }); - netDevs.forEach(netDev => { - o.value(`%${netDev.device}`); - }); - o.value('%defaultroute'); - o.optional = false; - o.depends({ 'left_interface' : '' }); - - o = s.taboption('general', form.Value, 'leftid', _('Left ID')); - o.datatype = 'string'; - o.value('%any'); - o.modalonly = true; - - o = s.taboption('general', form.Value, 'right', _('Remote IP')); - o.datatype = 'or(string, ipaddr)'; - o.value('0.0.0.0'); - o.value('%any'); - o.optional = false; - - o = s.taboption('general', form.Value, 'rightid', _('Right ID')); - o.datatype = 'string'; - o.value('%any'); - o.modalonly = true; - - o = s.taboption('general', form.Value, 'leftsourceip', _('Local Source IP')); - o.datatype = 'ipaddr'; - netDevs.forEach(netDev => { - netDev.getIPAddrs().forEach(addr => { - o.value(addr.split('/')[0]); - }); - }); - o.optional = false; - o.modalonly = true; - - o = s.taboption('general', form.Value, 'rightsourceip', _('Remote Source IP')); - o.datatype = 'ipaddr'; - o.optional = false; - o.modalonly = true; - - o = s.taboption('general', form.DynamicList, 'leftsubnets', _('Local Subnets')); - o.datatype = 'ipaddr'; - for (let nd of netDevs) { - const addrs = nd.getIPAddrs(); - for (let ad of addrs) { - const subnet = calculateNetwork(ad.split('/')[0], ad.split('/')[1]); - if (subnet) { - o.value(subnet); - } - } - } - o.value('0.0.0.0/0'); - - o = s.taboption('general', form.DynamicList, 'rightsubnets', _('Remote Subnets')); - o.datatype = 'ipaddr'; - o.value('0.0.0.0/0'); - - o = s.taboption('authentication', form.ListValue, 'authby', _('Auth Method')); - o.default = 'secret' - o.value('secret', _('Shared Secret')); - o.value('never', 'Never'); - o.value('null', 'Null'); - o.modalonly = true; - o.optional = false; - - o = s.taboption('authentication', form.Value, 'psk', _('Preshared Key')); - o.datatype = 'and(string, minlength(8))' - o.depends({ 'authby' : 'secret' }); - o.password = true; - o.modalonly = true; - o.optional = false; - - o = s.taboption('advanced', form.ListValue, 'ikev2', _('IKE V2')); - o.default = 'yes'; - o.value('yes', _('IKE Version 2')); - o.value('no', _('IKE Version 1')); - o.modalonly = true; - - o = s.taboption('advanced', form.MultiValue, 'ike', _('Phase1 Proposals')); - for (let prop of proposals) { - o.value(prop['.name']); - } - o.modalonly = true; - - function timevalidate(section_id, value) { - if (!/^[0-9]{1,3}[smhd]$/.test(value)) { - return _('Acceptable values are an integer followed by m, h, d'); - } - return true; - } - - o = s.taboption('advanced', form.Value, 'ikelifetime', _('IKE Life Time'), _('Acceptable values are an integer followed by m, h, d')); - o.default = '8h'; - o.value('1h', '1h'); - o.value('2h', '2h'); - o.value('4h', '4h'); - o.value('8h', '8h'); - o.value('12h', '12h'); - o.value('16h', '16h'); - o.value('24h', '24h'); - o.modalonly = false; - o.modalonly = true; - o.validate = timevalidate; - - o = s.taboption('advanced', form.Flag, 'rekey', _('Rekey')); - o.default = false; - o.modalonly = false; - o.modalonly = true; - - o = s.taboption('advanced', form.Value, 'rekeymargin', _('Rekey Margin Time'), _('Acceptable values are an integer followed by m, h, d')); - o.default = '9m'; - o.value('5m', '5m'); - o.value('9m', '9m'); - o.value('15m', '15m'); - o.value('20m', '20m'); - o.value('30m', '30m'); - o.value('60m', '60m'); - o.modalonly = false; - o.modalonly = true; - o.validate = timevalidate; - - o = s.taboption('advanced', form.ListValue, 'dpdaction', _('DPD Action')); - o.default = 'restart'; - o.value('none', _('None')); - o.value('clear', _('Clear')); - o.value('hold', _('Hold')); - o.value('restart', _('Restart')); - o.modalonly = true; - - o = s.taboption('advanced', form.Value, 'dpddelay', _('DPD Delay')); - o.datatype = 'uinteger'; - o.default = 30; - o.modalonly = true; - - o = s.taboption('advanced', form.Value, 'dpdtimeout', _('DPD Timeout')); - o.datatype = 'uinteger'; - o.default = 150; - o.modalonly = true; - - o = s.taboption('advanced', form.ListValue, 'phase2', _('Phase2 Protocol')); - o.default = 'esp'; - o.value('esp', 'ESP'); - o.modalonly = true; - o.optional = false; - - o = s.taboption('advanced', form.MultiValue, 'phase2alg', _('Phase2 Proposals')); - for (let prop of proposals) { - o.value(prop['.name']); - } - o.modalonly = true; - - o = s.taboption('advanced', form.Value, 'nflog', _('Enable nflog on nfgroup')); - o.default = 0; - o.datatype = 'uinteger'; - o.rmempty = true; - o.optional = true; - o.modalonly = true; - - let interfaces = uci.sections('network', 'interface'); - o = s.taboption('advanced', form.ListValue, 'interface', _('Tunnel Interface'), - _('Lists XFRM interfaces in format "ipsecN", N denotes ifid of xfrm interface') + '
' + - _('Lists VTI interfaces configured with ikey and okey')); - o.datatype = 'string'; - o.rmempty = true; - o.modalonly = true; - o.value(''); - interfaces.forEach(iface => { - const { proto, ikey, okey, ifid, ['.name']: name } = iface; - - if (proto === "vti" && ikey && okey) { - o.value(name, `VTI - ${name}`); - } - - if (proto === "xfrm" && ifid && name.match(`ipsec${ifid}`)) { - o.value(name, `XFRM - ${name}`); - } - }); - - o = s.taboption('advanced', form.Flag, 'update_peeraddr', _('Update Peer Address'), - _('Auto Update Peer Address of VTI interface')); - o.rmempty = true; - o.modalonly = true; - - return m.render(); - } -}); diff --git a/luci-app-libreswan/root/usr/share/luci/menu.d/luci-app-libreswan.json b/luci-app-libreswan/root/usr/share/luci/menu.d/luci-app-libreswan.json deleted file mode 100644 index a2974b51..00000000 --- a/luci-app-libreswan/root/usr/share/luci/menu.d/luci-app-libreswan.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "admin/vpn/libreswan": { - "title": "Libreswan IPSec", - "order": 90, - "action": { - "type": "firstchild" - } - }, - - "admin/vpn/libreswan/overview": { - "title": "Overview", - "order": 10, - "action": { - "type": "view", - "path": "libreswan/overview" - } - }, - - "admin/vpn/libreswan/globals": { - "title": "IPSec Globals", - "order": 20, - "action": { - "type": "view", - "path": "libreswan/globals" - } - }, - - "admin/vpn/libreswan/proposals": { - "title": "IPSec Proposals", - "order": 30, - "action": { - "type": "view", - "path": "libreswan/proposals" - } - }, - - "admin/vpn/libreswan/tunnels": { - "title": "IPSec Tunnels", - "order": 40, - "action": { - "type": "view", - "path": "libreswan/tunnels" - } - } -} diff --git a/luci-app-libreswan/root/usr/share/rpcd/acl.d/luci-app-libreswan.json b/luci-app-libreswan/root/usr/share/rpcd/acl.d/luci-app-libreswan.json deleted file mode 100644 index a846496d..00000000 --- a/luci-app-libreswan/root/usr/share/rpcd/acl.d/luci-app-libreswan.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "luci-app-libreswan" : { - "description" : "Grant access to LuCI app Libreswan IPSec", - "read" : { - "ubus" : { - "libreswan" : [ "*" ] - }, - "uci": [ "libreswan" ] - }, - "write" : { - "uci": [ "libreswan" ] - } - } -} diff --git a/luci-app-libreswan/root/usr/share/ucitrack/luci-app-libreswan.json b/luci-app-libreswan/root/usr/share/ucitrack/luci-app-libreswan.json deleted file mode 100644 index 5bfe1e9d..00000000 --- a/luci-app-libreswan/root/usr/share/ucitrack/luci-app-libreswan.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "config": "libreswan", - "init": "ipsec" -} diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index 8e736086..68fd3b8c 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall PKG_VERSION:=26.7.16 -PKG_RELEASE:=189 +PKG_RELEASE:=190 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua index 6c2ae8a5..c0f20f84 100644 --- a/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -1049,7 +1049,7 @@ function gen_config(var) api.log(" - 加载 Xray 负载均衡 节点【" .. (_node.remarks or "") .. "】,子节点数量:" .. #(blc_nodes or {})) - local valid_nodes = {} + local valid_nodes, valid_fallback = {}, true for i = 1, #(blc_nodes or {}) do local blc_node_id = blc_nodes[i] local blc_node_tag = "blc-" .. blc_node_id @@ -1067,12 +1067,16 @@ function gen_config(var) valid_nodes[#valid_nodes + 1] = outboundTag end end + -- Check if balancing node duplicates fallback node + if _node.fallback_node == blc_node_id then + valid_fallback = false + end end if #valid_nodes == 0 then return nil end -- fallback node local fallback_node_id = _node.fallback_node - fallback_node_id = (fallback_node_id and fallback_node_id ~= "") and fallback_node_id or nil + fallback_node_id = (valid_fallback and fallback_node_id and fallback_node_id ~= "") and fallback_node_id or nil local fallback_node_tag = (fallback_node_id == "_direct") and "direct" or "blackhole" if fallback_node_id and fallback_node_id ~= "_direct" then local is_new_node = true diff --git a/luci-app-strongswan-swanctl/Makefile b/luci-app-strongswan-swanctl/Makefile deleted file mode 100644 index 89ec4c05..00000000 --- a/luci-app-strongswan-swanctl/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2021 Nicholas Smith (nicholas@nbembedded.com) -# Copyright (C) 2023 TDT AG -# -# This is free software, licensed under the GNU General Public License v2. - -include $(TOPDIR)/rules.mk - -PKG_LICENSE:=GPL-2.0-or-later -PKG_MAINTAINER:=Nicholas Smith , Lukas Voegl - -LUCI_TITLE:=LuCI support for strongSwan via swanctl -LUCI_DESCRIPTION:=Status and configuration for strongSwan based on swanctl -LUCI_DEPENDS:=+strongswan-swanctl +swanmon - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-strongswan-swanctl/htdocs/luci-static/resources/strongswan_algorithms.js b/luci-app-strongswan-swanctl/htdocs/luci-static/resources/strongswan_algorithms.js deleted file mode 100644 index 2c7c3370..00000000 --- a/luci-app-strongswan-swanctl/htdocs/luci-static/resources/strongswan_algorithms.js +++ /dev/null @@ -1,143 +0,0 @@ -'use strict'; -'require baseclass'; - -return baseclass.extend({ - - _encryptionAlgorithms: new Map([ - ['3des', true], - ['cast128', true], - ['blowfish128', true], - ['blowfish192', true], - ['blowfish256', true], - ['null', true], - ['aes128'], - ['aes192'], - ['aes256'], - ['aes128ctr'], - ['aes192ctr'], - ['aes256ctr'], - ['camellia128'], - ['camellia192'], - ['camellia256'], - ['camellia128ctr'], - ['camellia192ctr'], - ['camellia256ctr'] - ]), - - _authenticatedEncryptionAlgorithms: new Map([ - ['aes128ccm64'], - ['aes192ccm64'], - ['aes256ccm64'], - ['aes128ccm96'], - ['aes192ccm96'], - ['aes256ccm96'], - ['aes128ccm128'], - ['aes192ccm128'], - ['aes256ccm128'], - ['aes128gcm64'], - ['aes192gcm64'], - ['aes256gcm64'], - ['aes128gcm96'], - ['aes192gcm96'], - ['aes256gcm96'], - ['aes128gcm128'], - ['aes192gcm128'], - ['aes256gcm128'], - ['aes128gmac'], - ['aes192gmac'], - ['aes256gmac'], - ['camellia128ccm64'], - ['camellia192ccm64'], - ['camellia256ccm64'], - ['camellia128ccm96'], - ['camellia192ccm96'], - ['camellia256ccm96'], - ['camellia128ccm128'], - ['camellia192ccm128'], - ['camellia256ccm128'], - ['chacha20poly1305'] - ]), - - _hashAlgorithms: new Map([ - ['md5', true], - ['md5_128', true], - ['sha1', true], - ['sha1_160', true], - ['aesxcbc'], - ['aescmac'], - ['aes128gmac'], - ['aes192gmac'], - ['aes256gmac'], - ['sha256'], - ['sha384'], - ['sha512'], - ['sha256_96'] - ]), - - _dhAlgorithms: new Map([ - ['modp768', true], - ['modp1024', true], - ['modp1536', true], - ['modp2048'], - ['modp3072'], - ['modp4096'], - ['modp6144'], - ['modp8192'], - ['modp1024s160', true], - ['modp2048s224', true], - ['modp2048s256', true], - ['ecp192', true], - ['ecp224'], - ['ecp256'], - ['ecp384'], - ['ecp521'], - ['ecp224bp'], - ['ecp256bp'], - ['ecp384bp'], - ['ecp512bp'], - ['curve25519'], - ['curve448'] - ]), - - _prfAlgorithms: new Map([ - ['prfmd5', true], - ['prfsha1', true], - ['prfaesxcbc'], - ['prfaescmac'], - ['prfsha256'], - ['prfsha384'], - ['prfsha512'] - ]), - - _getAlgorithmNames(algorithms) { - return Array.from(algorithms.keys()); - }, - - isInsecure(algorithmName) { - return this._encryptionAlgorithms.get(algorithmName) == true - || this._authenticatedEncryptionAlgorithms.get(algorithmName) == true - || this._hashAlgorithms.get(algorithmName) == true - || this._dhAlgorithms.get(algorithmName) == true - || this._prfAlgorithms.get(algorithmName) == true; - }, - - getEncryptionAlgorithms() { - return this._getAlgorithmNames(this._encryptionAlgorithms); - }, - - getAuthenticatedEncryptionAlgorithms() { - return this._getAlgorithmNames(this._authenticatedEncryptionAlgorithms); - }, - - getHashAlgorithms() { - return this._getAlgorithmNames(this._hashAlgorithms); - }, - - getDiffieHellmanAlgorithms() { - return this._getAlgorithmNames(this._dhAlgorithms); - }, - - getPrfAlgorithms() { - return this._getAlgorithmNames(this._prfAlgorithms); - } -}); diff --git a/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/status.js b/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/status.js deleted file mode 100644 index 40494a0b..00000000 --- a/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/status.js +++ /dev/null @@ -1,189 +0,0 @@ -'use strict'; -'require view'; -'require dom'; -'require poll'; -'require fs'; -'require ui'; - -function formatTime(seconds, selectCount) { - const days = Math.floor(seconds / (60 * 60 * 24)); - const hours = Math.floor(seconds / (60 * 60)) % 24; - const minutes = Math.floor(seconds / 60) % 60; - seconds = Math.floor(seconds % 60); - - const times = [ - [days, _('Day'), _('Days')], - [hours, _('Hour'), _('Hours')], - [minutes, _('Minute'), _('Minutes')], - [seconds, _('Second'), _('Seconds')] - ].filter(function ([time, singular, plural]) { - return time > 0; - }); - - const selectedTimes = times.slice(0, selectCount); - return selectedTimes.map(function ([time, singular, plural]) { - const unit = time > 1 ? plural : singular; - return '%d %s'.format(time, unit); - }).join(', '); -} - -function buildSection(name, table) { - return E('div', { 'class': 'cbi-section' }, [ - E('h2', [name]), - table - ]); -} - -function buildTable(rows) { - return E('table', { 'class': 'table', }, rows); -} - -function buildKeyValueTable(kvPairs) { - const rows = kvPairs.map(function (row) { - return E('tr', { 'class': 'tr' }, [ - E('td', { 'class': 'td', 'width': '33%' }, E('strong', [row[0]])), - E('td', { 'class': 'td' }, [row[1]]) - ]); - }); - return buildTable(rows); -} - -function collectErrorMessages(results) { - const errorMessages = results.reduce(function (messages, result) { - return messages.concat(result.errors.map(function (error) { - return error.message; - })); - }, []); - const uniqueErrorMessages = new Set(errorMessages); - - return [...uniqueErrorMessages]; -} - -return view.extend({ - load() { - return Promise.all([ - fs.exec_direct('/usr/sbin/swanmon', ['version'], 'json'), - fs.exec_direct('/usr/sbin/swanmon', ['stats'], 'json'), - fs.exec_direct('/usr/sbin/swanmon', ['list-sas'], 'json') - ]); - }, - - pollData(container) { - poll.add(L.bind(function () { - return this.load().then(L.bind(function (results) { - dom.content(container, this.renderContent(results)); - }, this)); - }, this)); - }, - - renderContent(results) { - const node = E('div', [E('div')]); - const firstNode = node.firstElementChild; - - const errorMessages = collectErrorMessages(results); - if (errorMessages.length > 0) { - const messageEls = errorMessages.map(function (message) { - return E('li', message); - }); - - firstNode.appendChild(E('h4', _('Querying strongSwan failed'))); - firstNode.appendChild(E('ul', messageEls)); - - return node; - } - - const [version, stats, sas] = results.map(function (r) { - return r.data; - }); - - const uptimeSeconds = (new Date() - new Date(stats.uptime.since)) / 1000; - const statsSection = buildSection(_('Stats'), buildKeyValueTable([ - [_('Version'), version.version], - [_('Uptime'), formatTime(uptimeSeconds, 2)], - [_('Daemon'), version.daemon], - [_('Active IKE_SAs'), stats.ikesas.total], - [_('Half-Open IKE_SAs'), stats.ikesas['half-open']] - ])); - firstNode.appendChild(statsSection); - - const tableRows = sas.map(function (conn) { - const name = Object.keys(conn)[0]; - const data = conn[name]; - const childSas = []; - - Object.entries(data['child-sas']).forEach(function ([name, data]) { - const table = buildKeyValueTable([ - [_('State'), data.state], - [_('Mode'), data.mode], - [_('Protocol'), data.protocol], - [_('Local Traffic Selectors'), data['local-ts'].join(', ')], - [_('Remote Traffic Selectors'), data['remote-ts'].join(', ')], - [_('Encryption Algorithm'), data['encr-alg']], - [_('Encryption Keysize'), data['encr-keysize']], - [_('Bytes in'), data['bytes-in']], - [_('Bytes out'), data['bytes-out']], - [_('Life Time'), formatTime(data['life-time'], 2)], - [_('Install Time'), formatTime(data['install-time'], 2)], - [_('Rekey in'), formatTime(data['rekey-time'], 2)], - [_('SPI in'), data['spi-in']], - [_('SPI out'), data['spi-out']] - ]); - childSas.push(E('div', { 'class': 'cbi-section' }, [ - E('h4', { 'style': 'margin-top: 0; padding-top: 0;' }, [name]), - table - ])); - }); - childSas.push(E('button', { - 'class': 'btn cbi-button cbi-button-apply', - 'click': ui.hideModal - }, _('Close'))); - - return E('tr', { 'class': 'tr' }, [ - E('td', { 'class': 'td' }, [name]), - E('td', { 'class': 'td' }, [data.state]), - E('td', { 'class': 'td' }, [data['remote-host']]), - E('td', { 'class': 'td' }, [data.version]), - E('td', { 'class': 'td' }, [formatTime(data.established, 2)]), - E('td', { 'class': 'td' }, [formatTime(data['reauth-time'], 2)]), - E('td', { 'class': 'td' }, [E('button', { - 'class': 'btn cbi-button cbi-button-apply', - 'click': function (ev) { - ui.showModal(_('CHILD_SAs'), childSas) - } - }, _('Show Details'))]) - ]); - }); - const connSection = buildSection(_('Security Associations (SAs)'), buildTable([ - E('tr', { 'class': 'tr' }, [ - E('th', { 'class': 'th' }, [_('Name')]), - E('th', { 'class': 'th' }, [_('State')]), - E('th', { 'class': 'th' }, [_('Remote')]), - E('th', { 'class': 'th' }, [_('IKE Version')]), - E('th', { 'class': 'th' }, [_('Established for')]), - E('th', { 'class': 'th' }, [_('Reauthentication in')]), - E('th', { 'class': 'th' }, [_('Details')]) - ]), - ...tableRows - ])); - firstNode.appendChild(connSection); - - return node; - }, - - render(results) { - const content = E([], [ - E('h2', [_('strongSwan Status')]), - E('div') - ]); - const container = content.lastElementChild; - - dom.content(container, this.renderContent(results)); - this.pollData(container); - - return content; - }, - - handleSaveApply: null, - handleSave: null, - handleReset: null -}); diff --git a/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js deleted file mode 100644 index aea22185..00000000 --- a/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ /dev/null @@ -1,435 +0,0 @@ -'use strict'; -'require view'; -'require form'; -'require uci'; -'require ui'; -'require tools.widgets as widgets'; -'require strongswan_algorithms'; - -function validateTimeFormat(section_id, value) { - if (value && !value.match(/^\d+[smhd]$/)) { - return _('Number must have suffix s, m, h or d'); - } - - return true; -} - -function addAlgorithms(o, algorithms) { - algorithms.forEach(function (algorithm) { - if (strongswan_algorithms.isInsecure(algorithm)) { - o.value(algorithm, '%s*'.format(algorithm)); - } else { - o.value(algorithm); - } - }); -} - -function sectionNameCheck(extra_class) { - var el = form.GridSection.prototype.renderSectionAdd.apply(this, arguments), - nameEl = el.querySelector('.cbi-section-create-name'); - ui.addValidator(nameEl, 'uciname', true, function(v) { - let sections = [ - ...uci.sections('ipsec', 'remote'), - ...uci.sections('ipsec', 'tunnel'), - ...uci.sections('ipsec', 'crypto_proposal'), - ]; - if (sections.find(function(s) { - return s['.name'] == v; - })) { - return _('Remotes, Encryption Proposals and Tunnels may not share the same names.') + ' ' + - _('Use combinations like tunnel1_phase1 that do not exceed 15 characters.'); - } - if (v.length > 15) return _('Name length shall not exceed 15 characters'); - return true; - }, 'blur', 'keyup'); - return el; -}; - -return view.extend({ - load: function () { - return uci.load('network'); - }, - - render: function () { - let m, s, o; - - m = new form.Map('ipsec', _('strongSwan Configuration'), - _('Configure strongSwan for secure VPN connections.')); - m.tabbed = true; - - // strongSwan General Settings - s = m.section(form.TypedSection, 'ipsec', _('General Settings')); - s.anonymous = true; - s.addremove = true; - - o = s.option(widgets.ZoneSelect, 'zone', _('Zone'), - _('Firewall zone that has to match the defined firewall zone')); - o.default = 'lan'; - o.multiple = true; - - o = s.option(widgets.NetworkSelect, 'listen', _('Listening Interfaces'), - _('Interfaces that accept VPN traffic')); - o.datatype = 'interface'; - o.placeholder = _('Select an interface or leave empty for all interfaces'); - o.default = 'wan'; - o.multiple = true; - o.rmempty = false; - - o = s.option(form.Value, 'debug', _('Debug Level'), - _('Trace level: 0 is least verbose, 4 is most')); - o.default = '0'; - o.datatype = 'range(0,4)'; - - // Remote Configuration - s = m.section(form.GridSection, 'remote', _('Remote Configuration'), - _('Define Remote IKE Configurations.')); - s.addremove = true; - s.nodescriptions = true; - s.renderSectionAdd = sectionNameCheck - - o = s.tab('general', _('General')); - o = s.tab('authentication', _('Authentication')); - o = s.tab('advanced', _('Advanced')); - - o = s.taboption('general', form.Flag, 'enabled', _('Enabled'), - _('Configuration is enabled or not')); - o.rmempty = false; - - o = s.taboption('general', form.Value, 'gateway', _('Gateway (Remote Endpoint)'), - _('IP address or FQDN name of the tunnel remote endpoint')); - o.datatype = 'or(hostname,ipaddr)'; - o.rmempty = false; - - o = s.taboption('general', form.Value, 'local_gateway', _('Local Gateway'), - _('IP address or FQDN of the tunnel local endpoint')); - o.datatype = 'or(hostname,ipaddr)'; - o.modalonly = true; - - o = s.taboption('general', form.Value, 'local_sourceip', _('Local Source IP'), - _('Virtual IP(s) to request in IKEv2 configuration payloads requests')); - o.datatype = 'ipaddr'; - o.modalonly = true; - - o = s.taboption('general', form.Value, 'local_ip', _('Local IP'), - _('Local address(es) to use in IKE negotiation')); - o.datatype = 'ipaddr'; - o.modalonly = true; - - o = s.taboption('general', form.MultiValue, 'crypto_proposal', _('Crypto Proposal'), - _('List of IKE (phase 1) proposals to use for authentication')); - o.load = function (section_id) { - this.keylist = []; - this.vallist = []; - - var sections = uci.sections('ipsec', 'crypto_proposal').filter(function (section) { - return section.is_esp != '1'; - }); - if (sections.length == 0) { - this.value('', _('Please create a Proposal first')); - } else { - sections.forEach(L.bind(function (section) { - this.value(section['.name']); - }, this)); - } - - return this.super('load', [section_id]); - }; - o.rmempty = false; - - o = s.taboption('general', form.MultiValue, 'tunnel', _('Tunnel'), - _('The Tunnel containing the ESP (phase 2) section')); - o.load = function (section_id) { - this.keylist = []; - this.vallist = []; - - var sections = uci.sections('ipsec', 'tunnel'); - if (sections.length == 0) { - this.value('', _('Please create a Tunnel first')); - } else { - sections.forEach(L.bind(function (section) { - this.value(section['.name']); - }, this)); - } - - return this.super('load', [section_id]); - }; - o.rmempty = false; - - o = s.taboption('authentication', form.ListValue, 'authentication_method', - _('Authentication Method'), _('IKE authentication (phase 1)')); - o.modalonly = true; - o.value('psk', 'Pre-shared Key'); - o.value('pubkey', 'Public Key'); - - o = s.taboption('authentication', form.Value, 'local_identifier', _('Local Identifier'), - _('Local identifier for IKE (phase 1)')); - o.datatype = 'string'; - o.placeholder = 'C=US, O=Acme Corporation, CN=headquarters'; - o.modalonly = true; - - o = s.taboption('authentication', form.Value, 'remote_identifier', _('Remote Identifier'), - _('Remote identifier for IKE (phase 1)')); - o.datatype = 'string'; - o.placeholder = 'C=US, O=Acme Corporation, CN=soho'; - o.modalonly = true; - - o = s.taboption('authentication', form.Value, 'pre_shared_key', _('Pre-Shared Key'), - _('The pre-shared key for the tunnel')); - o.datatype = 'string'; - o.password = true; - o.modalonly = true; - o.rmempty = false; - o.depends('authentication_method', 'psk'); - - o = s.taboption('authentication', form.Value, 'local_cert', _('Local Certificate'), - _('Certificate pathname to use for authentication')); - o.datatype = 'file'; - o.depends('authentication_method', 'pubkey'); - o.modalonly = true; - - o = s.taboption('authentication', form.Value, 'local_key', _('Local Key'), - _('Private key pathname to use with above certificate')); - o.datatype = 'file'; - o.modalonly = true; - - o = s.taboption('authentication', form.Value, 'ca_cert', _('CA Certificate'), - _("CA certificate that need to lie in remote peer's certificate's path of trust")); - o.datatype = 'file'; - o.depends('authentication_method', 'pubkey'); - o.modalonly = true; - - - o = s.taboption('advanced', form.Flag, 'mobike', _('MOBIKE'), - _('MOBIKE (IKEv2 Mobility and Multihoming Protocol)')); - o.default = '1'; - o.modalonly = true; - - o = s.taboption('advanced', form.ListValue, 'fragmentation', _('IKE Fragmentation'), - _('Use IKE fragmentation')); - o.value('yes'); - o.value('no'); - o.value('force'); - o.value('accept'); - o.default = 'yes'; - o.modalonly = true; - - o = s.taboption('advanced', form.Value, 'keyingtries', _('Keying Retries'), - _('Number of retransmissions attempts during initial negotiation')); - o.datatype = 'uinteger'; - o.default = '3'; - o.modalonly = true; - - o = s.taboption('advanced', form.Value, 'dpddelay', _('DPD Delay'), - _('Interval to check liveness of a peer')); - o.validate = validateTimeFormat; - o.default = '30s'; - o.modalonly = true; - - o = s.taboption('advanced', form.Value, 'inactivity', _('Inactivity'), - _('Interval before closing an inactive CHILD_SA')); - o.validate = validateTimeFormat; - o.modalonly = true; - - o = s.taboption('advanced', form.Value, 'rekeytime', _('Rekey Time'), - _('IKEv2 interval to refresh keying material; also used to compute lifetime')); - o.validate = validateTimeFormat; - o.modalonly = true; - - o = s.taboption('advanced', form.Value, 'overtime', _('Overtime'), - _('Limit on time to complete rekeying/reauthentication')); - o.validate = validateTimeFormat; - o.modalonly = true; - - o = s.taboption('advanced', form.ListValue, 'keyexchange', _('Keyexchange'), - _('Version of IKE for negotiation')); - o.value('ikev1', 'IKEv1 (%s)', _('deprecated')); - o.value('ikev2', 'IKEv2'); - o.value('ike', 'IKE (%s, %s)'.format(_('both'), _('deprecated'))); - o.default = 'ikev2'; - o.modalonly = true; - - // Tunnel Configuration - s = m.section(form.GridSection, 'tunnel', _('Tunnel Configuration'), - _('Define Connection Children to be used as Tunnels in Remote Configurations.')); - s.addremove = true; - s.nodescriptions = true; - s.renderSectionAdd = sectionNameCheck; - - o = s.tab('general', _('General')); - o = s.tab('advanced', _('Advanced')); - - o = s.taboption('general', form.DynamicList, 'local_subnet', _('Local Subnet'), - _('Local network(s)')); - o.datatype = 'subnet'; - o.placeholder = '192.168.1.1/24'; - o.rmempty = false; - - o = s.taboption('general', form.DynamicList, 'remote_subnet', _('Remote Subnet'), - _('Remote network(s)')); - o.datatype = 'subnet'; - o.placeholder = '192.168.2.1/24'; - o.rmempty = false; - - o = s.taboption('general', form.Value, 'local_nat', _('Local NAT'), - _('NAT range for tunnels with overlapping IP addresses')); - o.datatype = 'subnet'; - o.modalonly = true; - - o = s.taboption('general', form.ListValue, 'if_id', ('XFRM Interface ID'), - _('XFRM interface ID set on input and output interfaces')); - o.load = function (section_id) { - this.keylist = []; - this.vallist = []; - - var xfrmSections = uci.sections('network').filter(function (section) { - return section.proto == 'xfrm'; - }); - - xfrmSections.forEach(L.bind(function (section) { - this.value(section.ifid, - '%s (%s)'.format(section.ifid, section['.name'])); - }, this)); - - return this.super('load', [section_id]); - } - o.optional = true; - o.modalonly = true; - - o = s.taboption('general', form.ListValue, 'startaction', _('Start Action'), - _('Action on initial configuration load')); - o.value('none'); - o.value('trap'); - o.value('start'); - o.default = 'trap'; - o.modalonly = true; - - o = s.taboption('general', form.ListValue, 'closeaction', _('Close Action'), - _('Action when CHILD_SA is closed')); - o.value('none'); - o.value('trap'); - o.value('start'); - o.optional = true; - o.modalonly = true; - - o = s.taboption('general', form.MultiValue, 'crypto_proposal', - _('Crypto Proposal (Phase 2)'), - _('List of ESP (phase two) proposals. Only Proposals with checked ESP flag are selectable')); - o.load = function (section_id) { - this.keylist = []; - this.vallist = []; - - var sections = uci.sections('ipsec', 'crypto_proposal').filter(function (section) { - return section.is_esp == '1'; - }); - if (sections.length == 0) { - this.value('', _('Please create an ESP Proposal first')); - } else { - sections.forEach(L.bind(function (section) { - this.value(section['.name']); - }, this)); - } - - return this.super('load', [section_id]); - }; - o.rmempty = false; - - o = s.taboption('advanced', form.Value, 'updown', _('Up/Down Script Path'), - _('Path to script to run on CHILD_SA up/down events')); - o.datatype = 'file'; - o.modalonly = true; - - o = s.taboption('advanced', form.Value, 'lifetime', _('Lifetime'), - _('Maximum duration of the CHILD_SA before closing')); - o.validate = validateTimeFormat; - o.modalonly = true; - - o = s.taboption('advanced', form.ListValue, 'dpdaction', _('DPD Action'), - _('Action when DPD timeout occurs')); - o.value('none'); - o.value('clear'); - o.value('trap'); - o.value('start'); - o.optional = true; - o.modalonly = true; - - o = s.taboption('advanced', form.Value, 'rekeytime', _('Rekey Time'), - _('Duration of the CHILD_SA before rekeying')); - o.validate = validateTimeFormat; - o.modalonly = true; - - o = s.taboption('advanced', form.Flag, 'ipcomp', _('IPComp'), - _('Enable ipcomp compression')); - o.default = '0'; - o.modalonly = true; - - o = s.taboption('advanced', form.ListValue, 'hw_offload', _('H/W Offload'), - _('Enable Hardware offload')); - o.value('yes'); - o.value('no'); - o.value('auto'); - o.optional = true; - o.modalonly = true; - - o = s.taboption('advanced', form.Value, 'priority', _('Priority'), - _('Priority of the CHILD_SA')); - o.datatype = 'uinteger'; - o.modalonly = true; - - o = s.taboption('advanced', form.Value, 'replay_window', _('Replay Window'), - '%s; %s'.format(_('Replay Window of the CHILD_SA'), - _('Values larger than 32 are supported by the Netlink backend only'))); - o.datatype = 'uinteger'; - o.modalonly = true; - - // Crypto Proposals - s = m.section(form.GridSection, 'crypto_proposal', - _('Encryption Proposals'), - _('Configure Cipher Suites to define IKE (Phase 1) or ESP (Phase 2) Proposals.')); - s.addremove = true; - s.nodescriptions = true; - s.renderSectionAdd = sectionNameCheck; - - o = s.option(form.Flag, 'is_esp', _('ESP Proposal'), - _('Whether this is an ESP (phase 2) proposal or not')); - - o = s.option(form.ListValue, 'encryption_algorithm', - _('Encryption Algorithm'), - _('Algorithms marked with * are considered insecure')); - o.default = 'aes256gcm128'; - addAlgorithms(o, strongswan_algorithms.getEncryptionAlgorithms()); - addAlgorithms(o, strongswan_algorithms.getAuthenticatedEncryptionAlgorithms()); - - - o = s.option(form.ListValue, 'hash_algorithm', _('Hash Algorithm'), - _('Algorithms marked with * are considered insecure')); - strongswan_algorithms.getEncryptionAlgorithms().forEach(function (algorithm) { - o.depends('encryption_algorithm', algorithm); - }); - o.default = 'sha512'; - o.rmempty = false; - addAlgorithms(o, strongswan_algorithms.getHashAlgorithms()); - - o = s.option(form.ListValue, 'dh_group', _('Diffie-Hellman Group'), - _('Algorithms marked with * are considered insecure')); - o.default = 'modp3072'; - addAlgorithms(o, strongswan_algorithms.getDiffieHellmanAlgorithms()); - - o = s.option(form.ListValue, 'prf_algorithm', _('PRF Algorithm'), - _('Algorithms marked with * are considered insecure')); - o.validate = function (section_id, value) { - var encryptionAlgorithm = this.section.formvalue(section_id, 'encryption_algorithm'); - - if (strongswan_algorithms.getAuthenticatedEncryptionAlgorithms().includes( - encryptionAlgorithm) && !value) { - return _('PRF Algorithm must be configured when using an Authenticated Encryption Algorithm'); - } - - return true; - }; - o.optional = true; - o.depends('is_esp', '0'); - addAlgorithms(o, strongswan_algorithms.getPrfAlgorithms()); - - return m.render(); - } -}); diff --git a/luci-app-strongswan-swanctl/root/usr/share/luci/menu.d/luci-app-strongswan-swanctl.json b/luci-app-strongswan-swanctl/root/usr/share/luci/menu.d/luci-app-strongswan-swanctl.json deleted file mode 100644 index d229869d..00000000 --- a/luci-app-strongswan-swanctl/root/usr/share/luci/menu.d/luci-app-strongswan-swanctl.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "admin/vpn/strongswan-swanctl": { - "title": "strongSwan IPsec", - "order": 90, - "action": { - "type": "view", - "path": "strongswan-swanctl/swanctl" - }, - "depends": { - "acl": [ - "luci-app-strongswan-swanctl" - ] - } - }, - "admin/status/strongswan": { - "title": "strongSwan IPsec", - "order": 90, - "action": { - "type": "view", - "path": "strongswan-swanctl/status" - }, - "depends": { - "acl": [ - "luci-app-strongswan-swanctl" - ] - } - } -} diff --git a/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json b/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json deleted file mode 100644 index d3b44a27..00000000 --- a/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "luci-app-strongswan-swanctl": { - "description": "Grant access to luci-app-strongswan-swanctl", - "read": { - "file": { - "/usr/sbin/swanmon version": [ "exec" ], - "/usr/sbin/swanmon stats": [ "exec" ], - "/usr/sbin/swanmon list-sas": [ "exec" ] - }, - "uci": [ "ipsec" ] - }, - "write": { - "uci": [ "ipsec" ] - } - } -} diff --git a/luci-app-wifihistory/Makefile b/luci-app-wifihistory/Makefile deleted file mode 100644 index 0e1aee8f..00000000 --- a/luci-app-wifihistory/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -include $(TOPDIR)/rules.mk - -LUCI_TITLE:=LuCI support for WiFi Station History -LUCI_DEPENDS:=+luci-base +rpcd-mod-iwinfo +ucode +ucode-mod-fs +ucode-mod-ubus -LUCI_DESCRIPTION:=Track and display history of WiFi associated stations - -PKG_LICENSE:=Apache-2.0 - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-wifihistory/htdocs/luci-static/resources/view/status/wifihistory.js b/luci-app-wifihistory/htdocs/luci-static/resources/view/status/wifihistory.js deleted file mode 100644 index 076c97ab..00000000 --- a/luci-app-wifihistory/htdocs/luci-static/resources/view/status/wifihistory.js +++ /dev/null @@ -1,181 +0,0 @@ -'use strict'; -'require view'; -'require poll'; -'require rpc'; -'require ui'; - -const callGetHistory = rpc.declare({ - object: 'luci.wifihistory', - method: 'getHistory', - expect: { history: {} } -}); - -const callClearHistory = rpc.declare({ - object: 'luci.wifihistory', - method: 'clearHistory', - expect: { result: true } -}); - -function formatDate(epoch) { - if (!epoch || epoch <= 0) - return '-'; - - return new Date(epoch * 1000).toLocaleString(); -} - -return view.extend({ - load() { - return callGetHistory(); - }, - - updateTable(table, history) { - const stations = Object.values(history); - - /* Sort connected stations first, then by most recently seen */ - stations.sort((a, b) => { - if (a.connected !== b.connected) - return a.connected ? -1 : 1; - - return (b.last_seen || 0) - (a.last_seen || 0); - }); - - const rows = []; - - for (const s of stations) { - let hint; - if (s.hostname && s.ipv4 && s.ipv6) - hint = '%s (%s, %s)'.format(s.hostname, s.ipv4, s.ipv6); - else if (s.hostname && (s.ipv4 || s.ipv6)) - hint = '%s (%s)'.format(s.hostname, s.ipv4 || s.ipv6); - else if (s.ipv4 || s.ipv6) - hint = s.ipv4 || s.ipv6; - else - hint = '-'; - - let sig_value = '-'; - let sig_title = ''; - - if (s.signal && s.signal !== 0) { - if (s.noise && s.noise !== 0) { - sig_value = '%d/%d\xa0%s'.format(s.signal, s.noise, _('dBm')); - sig_title = '%s: %d %s / %s: %d %s / %s %d'.format( - _('Signal'), s.signal, _('dBm'), - _('Noise'), s.noise, _('dBm'), - _('SNR'), s.signal - s.noise); - } - else { - sig_value = '%d\xa0%s'.format(s.signal, _('dBm')); - sig_title = '%s: %d %s'.format(_('Signal'), s.signal, _('dBm')); - } - } - - let icon; - if (!s.connected) { - icon = L.resource('icons/signal-none.svg'); - } - else { - /* Estimate signal quality as percentage: - * Map dBm range [-110, -40] to [0%, 100%] */ - const q = Math.min((s.signal + 110) / 70 * 100, 100); - if (q == 0) - icon = L.resource('icons/signal-000-000.svg'); - else if (q < 25) - icon = L.resource('icons/signal-000-025.svg'); - else if (q < 50) - icon = L.resource('icons/signal-025-050.svg'); - else if (q < 75) - icon = L.resource('icons/signal-050-075.svg'); - else - icon = L.resource('icons/signal-075-100.svg'); - } - - rows.push([ - E('span', { - 'class': 'ifacebadge', - 'style': s.connected ? '' : 'opacity:0.5', - 'title': s.connected ? _('Connected') : _('Disconnected') - }, [ - E('img', { 'src': icon, 'style': 'width:16px;height:16px' }), - E('span', {}, [ ' ', s.connected ? _('Yes') : _('No') ]) - ]), - s.mac, - hint, - s.network || '-', - E('span', { 'title': sig_title }, sig_value), - formatDate(s.first_seen), - formatDate(s.last_seen) - ]); - } - - cbi_update_table(table, rows, E('em', _('No station history available'))); - }, - - handleClearHistory(ev) { - return ui.showModal(_('Clear Station History'), [ - E('p', _('This will permanently delete all recorded station history. Are you sure?')), - E('div', { 'class': 'right' }, [ - E('button', { - 'class': 'btn', - 'click': ui.hideModal - }, _('Cancel')), ' ', - E('button', { - 'class': 'btn cbi-button-negative', - 'click': ui.createHandlerFn(this, function() { - return callClearHistory().then(L.bind(function() { - ui.hideModal(); - return callGetHistory().then(L.bind(function(history) { - this.updateTable('#wifi_history_table', history); - }, this)); - }, this)); - }) - }, _('Clear')) - ]) - ]); - }, - - render(history) { - const isReadonlyView = !L.hasViewPermission(); - - const v = E([], [ - E('h2', _('Station History')), - E('div', { 'class': 'cbi-map-descr' }, - _('This page displays a history of all WiFi stations that have connected to this device, including currently connected and previously seen devices.')), - - E('div', { 'class': 'cbi-section' }, [ - E('div', { 'class': 'right', 'style': 'margin-bottom:1em' }, [ - E('button', { - 'class': 'btn cbi-button-negative', - 'disabled': isReadonlyView, - 'click': ui.createHandlerFn(this, 'handleClearHistory') - }, _('Clear History')) - ]), - - E('table', { 'class': 'table', 'id': 'wifi_history_table' }, [ - E('tr', { 'class': 'tr table-titles' }, [ - E('th', { 'class': 'th' }, _('Connected')), - E('th', { 'class': 'th' }, _('MAC address')), - E('th', { 'class': 'th' }, _('Host')), - E('th', { 'class': 'th' }, _('Network')), - E('th', { 'class': 'th' }, '%s / %s'.format(_('Signal'), _('Noise'))), - E('th', { 'class': 'th' }, _('First seen')), - E('th', { 'class': 'th' }, _('Last seen')) - ]) - ]) - ]) - ]); - - this.updateTable(v.querySelector('#wifi_history_table'), history); - - poll.add(L.bind(function() { - return callGetHistory().then(L.bind(function(history) { - this.updateTable('#wifi_history_table', history); - }, this)); - }, this), 5); - - return v; - }, - - handleSaveApply: null, - handleSave: null, - handleReset: null -}); diff --git a/luci-app-wifihistory/po/lo/wifihistory.po b/luci-app-wifihistory/po/lo/wifihistory.po deleted file mode 100644 index efd33c57..00000000 --- a/luci-app-wifihistory/po/lo/wifihistory.po +++ /dev/null @@ -1,82 +0,0 @@ -msgid "" -msgstr "" -"PO-Revision-Date: 2026-05-03 08:19+0000\n" -"Last-Translator: BoneNI \n" -"Language-Team: Lao \n" -"Language: lo\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 5.17.1\n" - -#~ msgid "Cancel" -#~ msgstr "ຍົກເລີກ" - -#~ msgid "Clear" -#~ msgstr "ລ້າງ" - -#~ msgid "Clear History" -#~ msgstr "ລ້າງປະຫວັດ" - -#~ msgid "Clear Station History" -#~ msgstr "ລ້າງປະຫວັດສະຖານີ" - -#~ msgid "Connected" -#~ msgstr "ເຊື່ອມຕໍ່ແລ້ວ" - -#~ msgid "Disconnected" -#~ msgstr "ຕັດການເຊື່ອມຕໍ່ແລ້ວ" - -#~ msgid "First seen" -#~ msgstr "ເຫັນຄັ້ງທຳອິດ" - -#~ msgid "Grant access to WiFi station history" -#~ msgstr "ອະນຸຍາດໃຫ້ເຂົ້າເຖິງປະຫວັດສະຖານີ WiFi" - -#~ msgid "Host" -#~ msgstr "ໂຮສ (Host)" - -#~ msgid "Last seen" -#~ msgstr "ເຫັນຄັ້ງສຸດທ້າຍ" - -#~ msgid "MAC address" -#~ msgstr "ທີ່ຢູ່ MAC" - -#~ msgid "Network" -#~ msgstr "ເຄືອຂ່າຍ" - -#~ msgid "No" -#~ msgstr "ບໍ່" - -#~ msgid "No station history available" -#~ msgstr "ບໍ່ມີຂໍ້ມູນປະຫວັດສະຖານີ" - -#~ msgid "Noise" -#~ msgstr "ສັນຍານລົບກວນ" - -#~ msgid "SNR" -#~ msgstr "SNR" - -#~ msgid "Signal" -#~ msgstr "ສັນຍານ" - -#~ msgid "Station History" -#~ msgstr "ປະຫວັດສະຖານີ" - -#~ msgid "" -#~ "This page displays a history of all WiFi stations that have connected to " -#~ "this device, including currently connected and previously seen devices." -#~ msgstr "" -#~ "ໜ້ານີ້ສະແດງປະຫວັດຂອງທຸກສະຖານີ WiFi ທີ່ເຄີຍເຊື່ອມຕໍ່ກັບອຸປະກອນນີ້, ລວມທັງອຸປະກອນທີ່ກຳລັງເຊື່ອມຕໍ່ຢູ່ " -#~ "ແລະ ອຸປະກອນທີ່ເຄີຍເຫັນກ່ອນໜ້ານີ້." - -#~ msgid "" -#~ "This will permanently delete all recorded station history. Are you sure?" -#~ msgstr "ນີ້ຈະເປັນການລຶບປະຫວັດສະຖານີທີ່ບັນທຶກໄວ້ທັງໝົດແບບຖາວອນ. ທ່ານແນ່ໃຈຫຼືບໍ່?" - -#~ msgid "Yes" -#~ msgstr "ແມ່ນ" - -#~ msgid "dBm" -#~ msgstr "dBm" diff --git a/luci-app-wifihistory/root/etc/init.d/wifihistory b/luci-app-wifihistory/root/etc/init.d/wifihistory deleted file mode 100755 index 2811c684..00000000 --- a/luci-app-wifihistory/root/etc/init.d/wifihistory +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh /etc/rc.common - -START=99 -STOP=10 -USE_PROCD=1 - -NAME=wifihistory -PROG=/usr/sbin/wifihistory -INTERVAL=30 - -start_service() { - mkdir -p /var/lib/wifihistory - - procd_open_instance "$NAME" - procd_set_param command /bin/sh -c "while true; do /usr/bin/ucode $PROG; sleep $INTERVAL; done" - procd_set_param respawn 3600 5 5 - procd_set_param stdout 1 - procd_set_param stderr 1 - procd_close_instance -} - -service_triggers() { - procd_add_reload_trigger "wireless" -} diff --git a/luci-app-wifihistory/root/usr/sbin/wifihistory b/luci-app-wifihistory/root/usr/sbin/wifihistory deleted file mode 100755 index c0cfcd2a..00000000 --- a/luci-app-wifihistory/root/usr/sbin/wifihistory +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env ucode - -'use strict'; - -import { readfile, writefile, open, mkdir, rename } from 'fs'; -import { connect } from 'ubus'; - -const HISTORY_DIR = '/var/lib/wifihistory'; -const HISTORY_FILE = HISTORY_DIR + '/history.json'; -const LOCK_FILE = '/var/lock/wifihistory.lock'; - -function load_history() { - let content = readfile(HISTORY_FILE); - if (content == null) - return {}; - - try { - return json(content) || {}; - } - catch (e) { - return {}; - } -} - -function save_history(data) { - let tmp = HISTORY_FILE + '.tmp'; - - writefile(tmp, sprintf('%J', data)); - rename(tmp, HISTORY_FILE); -} - -function poll_stations() { - let ubus = connect(); - if (!ubus) { - warn('Failed to connect to ubus\n'); - return; - } - - let now = time(); - let history = load_history(); - let seen_macs = {}; - - let wifi_status = ubus.call('network.wireless', 'status'); - if (!wifi_status) - return; - - let hints = ubus.call('luci-rpc', 'getHostHints') || {}; - - for (let radio in wifi_status) { - let ifaces = wifi_status[radio]?.interfaces; - if (!ifaces) - continue; - - for (let iface in ifaces) { - let ifname = iface?.ifname; - if (!ifname) - continue; - - let info = ubus.call('iwinfo', 'info', { device: ifname }); - let ssid = info?.ssid || ''; - - let assoc = ubus.call('iwinfo', 'assoclist', { device: ifname }); - if (!assoc?.results) - continue; - - for (let bss in assoc.results) { - let mac = bss?.mac; - if (!mac) - continue; - - mac = uc(mac); - seen_macs[mac] = true; - - let hostname = hints?.[mac]?.name || ''; - let ipv4 = hints?.[mac]?.ipaddrs?.[0] || ''; - let ipv6 = hints?.[mac]?.ip6addrs?.[0] || ''; - - let existing = history[mac]; - let first_seen = existing?.first_seen || now; - - history[mac] = { - mac: mac, - hostname: hostname, - ipv4: ipv4, - ipv6: ipv6, - network: ssid, - ifname: ifname, - connected: true, - signal: bss?.signal || 0, - noise: bss?.noise || 0, - first_seen: first_seen, - last_seen: now - }; - } - } - } - - for (let mac in history) - if (!seen_macs[mac]) - history[mac].connected = false; - - ubus.disconnect(); - - save_history(history); -} - -mkdir(HISTORY_DIR); - -let lock_fd = open(LOCK_FILE, 'w'); -if (!lock_fd) { - warn('Failed to open lock file\n'); - exit(1); -} - -if (!lock_fd.lock('xn')) { - warn('Another instance is already running\n'); - lock_fd.close(); - exit(1); -} - -poll_stations(); - -lock_fd.lock('u'); -lock_fd.close(); diff --git a/luci-app-wifihistory/root/usr/share/luci/menu.d/luci-app-wifihistory.json b/luci-app-wifihistory/root/usr/share/luci/menu.d/luci-app-wifihistory.json deleted file mode 100644 index b43addaf..00000000 --- a/luci-app-wifihistory/root/usr/share/luci/menu.d/luci-app-wifihistory.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "admin/status/wifihistory": { - "title": "Station History", - "order": 8, - "action": { - "type": "view", - "path": "status/wifihistory" - }, - "depends": { - "acl": [ "luci-app-wifihistory" ], - "uci": { "wireless": { "@wifi-device": true } } - } - } -} diff --git a/luci-app-wifihistory/root/usr/share/rpcd/acl.d/luci-app-wifihistory.json b/luci-app-wifihistory/root/usr/share/rpcd/acl.d/luci-app-wifihistory.json deleted file mode 100644 index b0f790fc..00000000 --- a/luci-app-wifihistory/root/usr/share/rpcd/acl.d/luci-app-wifihistory.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "luci-app-wifihistory": { - "description": "Grant access to WiFi station history", - "read": { - "ubus": { - "iwinfo": [ "assoclist" ], - "luci.wifihistory": [ "getHistory" ] - } - }, - "write": { - "ubus": { - "luci.wifihistory": [ "clearHistory" ] - } - } - } -} diff --git a/luci-app-wifihistory/root/usr/share/rpcd/ucode/wifihistory.uc b/luci-app-wifihistory/root/usr/share/rpcd/ucode/wifihistory.uc deleted file mode 100644 index 918ad981..00000000 --- a/luci-app-wifihistory/root/usr/share/rpcd/ucode/wifihistory.uc +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env ucode - -'use strict'; - -import { readfile, writefile } from 'fs'; - -const HISTORY_FILE = '/var/lib/wifihistory/history.json'; - -const methods = { - getHistory: { - call: function() { - let content = readfile(HISTORY_FILE); - if (content == null) - return { history: {} }; - - try { - return { history: json(content) || {} }; - } - catch (e) { - return { history: {} }; - } - } - }, - - clearHistory: { - call: function() { - writefile(HISTORY_FILE, '{}'); - return { result: true }; - } - } -}; - -return { 'luci.wifihistory': methods }; diff --git a/luci-theme-kucat/Makefile b/luci-theme-kucat/Makefile index 16fb7ee4..499c31e4 100644 --- a/luci-theme-kucat/Makefile +++ b/luci-theme-kucat/Makefile @@ -11,7 +11,7 @@ PKG_NAME:=luci-theme-$(THEME_NAME) LUCI_TITLE:=Kucat Theme by sirpdboy LUCI_DEPENDS:=+wget +curl +jsonfilter PKG_VERSION:=3.3.2 -PKG_RELEASE:=2 +PKG_RELEASE:=3 define Package/luci-theme-$(THEME_NAME)/conffiles /www/luci-static/resources/background/ diff --git a/luci-theme-kucat/htdocs/luci-static/kucat/css/style.css b/luci-theme-kucat/htdocs/luci-static/kucat/css/style.css index e0fdfd81..c894df0e 100644 --- a/luci-theme-kucat/htdocs/luci-static/kucat/css/style.css +++ b/luci-theme-kucat/htdocs/luci-static/kucat/css/style.css @@ -1428,7 +1428,6 @@ button:hover, .btn:hover, .cbi-button:hover { - color: var(--menu-hover-color); transform: translateY(-2px) ; box-shadow: 0 0.3rem 0.5rem var(--input-boxhovercolor); -webkit-box-shadow: 0 0.3rem 0.5rem var(--input-boxhovercolor); @@ -1463,6 +1462,32 @@ button:active { box-shadow: none } + +.modal label.btn { + color: var(--body-color); + background-color: rgba(var(--primary-rgbm), 0); + display: inline-flex; + align-items: center; + -webkit-user-select: none; + -moz-user-select: none; + border: none; + background-image: none; + box-shadow: none; + -ms-user-select: none; +} + +.modal label.btn:focus, +.modal label.btn:hover + { + color: var(--body-color); + background-color: rgba(var(--primary-rgbm), 0.1); + transform: none; + box-shadow: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + border: none; +} + .cbi-dynlist>.add-item:not([ondrop])>input, .cbi-dynlist>.item>span, .cbi-dynlist>.add-item input { @@ -2690,7 +2715,7 @@ td>.ifacebadge, } .ifacebox-head { - width: 7rem; + width: 6rem; min-width: 100%; background-color: rgba(var(--primary-rgbm), 0.3); transform: translate(-50, -50%); diff --git a/qBittorrent-Enhanced-Edition/Makefile b/qBittorrent-Enhanced-Edition/Makefile index a848382d..b076ed19 100644 --- a/qBittorrent-Enhanced-Edition/Makefile +++ b/qBittorrent-Enhanced-Edition/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=qBittorrent-Enhanced-Edition -PKG_VERSION:=5.2.1.10 -PKG_RELEASE:=11 +PKG_VERSION:=5.2.3.10 +PKG_RELEASE:=12 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/c0re100/qBittorrent-Enhanced-Edition/tar.gz/release-$(PKG_VERSION)? diff --git a/qBittorrent-Enhanced-Edition/patches/100-use-original-user-agent.patch b/qBittorrent-Enhanced-Edition/patches/100-use-original-user-agent.patch index 252fc857..3e1f0261 100644 --- a/qBittorrent-Enhanced-Edition/patches/100-use-original-user-agent.patch +++ b/qBittorrent-Enhanced-Edition/patches/100-use-original-user-agent.patch @@ -1,6 +1,6 @@ --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp -@@ -128,7 +128,7 @@ const std::chrono::seconds FREEDISKSPACE +@@ -129,7 +129,7 @@ const std::chrono::seconds FREEDISKSPACE namespace { const char PEER_ID[] = "qB"; @@ -14,7 +14,7 @@ @@ -31,7 +31,7 @@ #define QBT_VERSION_MAJOR 5 #define QBT_VERSION_MINOR 2 - #define QBT_VERSION_BUGFIX 1 + #define QBT_VERSION_BUGFIX 3 -#define QBT_VERSION_BUILD 10 +#define QBT_VERSION_BUILD 0 #define QBT_VERSION_STATUS "" // Should be empty for stable releases! diff --git a/rustdesk-server/Makefile b/rustdesk-server/Makefile index 8db042ab..21da5019 100644 --- a/rustdesk-server/Makefile +++ b/rustdesk-server/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=rustdesk-server -PKG_VERSION:=1.1.15 -PKG_RELEASE:=2 +PKG_VERSION:=1.1.16 +PKG_RELEASE:=3 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/rustdesk/rustdesk-server.git diff --git a/watchcat/Makefile b/watchcat/Makefile index 28fd0c08..d3a4edf1 100644 --- a/watchcat/Makefile +++ b/watchcat/Makefile @@ -9,9 +9,9 @@ include $(TOPDIR)/rules.mk PKG_NAME:=watchcat PKG_VERSION:=1 -PKG_RELEASE:=4 +PKG_RELEASE:=5 -PKG_MAINTAINER:=Roger D +PKG_MAINTAINER:=Daniel F. Dickinson , Dharmik Parmar PKG_LICENSE:=GPL-2.0 include $(INCLUDE_DIR)/package.mk diff --git a/watchcat/files/watchcat.sh b/watchcat/files/watchcat.sh index e0ecb5cf..87c9678c 100644 --- a/watchcat/files/watchcat.sh +++ b/watchcat/files/watchcat.sh @@ -7,6 +7,77 @@ # . /lib/network/config.sh +. /lib/functions/network.sh + +# Accept the historical real-device input while also handling @logical +# interface references used by other OpenWrt configs. +watchcat_resolve_ping_iface() { + local iface="$1" + local logical device network + + [ -n "$iface" ] || return 1 + + case "$iface" in + @*) + logical="${iface#@}" + [ -n "$logical" ] || return 1 + if network_get_device device "$logical"; then + printf '%s\n' "$device" + return 0 + fi + printf '%s\n' "$iface" + return 1 + ;; + esac + + network="$(find_config "$iface")" + if [ -n "$network" ]; then + printf '%s\n' "$iface" + return 0 + fi + + if network_get_device device "$iface"; then + printf '%s\n' "$device" + return 0 + fi + + printf '%s\n' "$iface" + return 1 +} + +watchcat_resolve_restart_iface() { + local iface="$1" + local network device + + [ -n "$iface" ] || return 1 + + case "$iface" in + @*) + network="${iface#@}" + [ -n "$network" ] || return 1 + if ! network_get_device device "$network"; then + printf '%s\n' "$network" + return 1 + fi + printf '%s\n' "$network" + return 0 + ;; + esac + + network="$(find_config "$iface")" + if [ -n "$network" ]; then + printf '%s\n' "$network" + return 0 + fi + + if network_get_device device "$iface"; then + printf '%s\n' "$iface" + return 0 + fi + + printf '%s\n' "$iface" + return 1 +} get_ping_size() { ps=$1 @@ -84,8 +155,11 @@ watchcat_restart_modemmanager_iface() { } watchcat_restart_network_iface() { - local network - network="$(find_config "$1")" + local iface="$1" + local network="$2" + + [ -z "$network" ] && network="$(watchcat_resolve_restart_iface "$iface")" + logger -p daemon.info -t "watchcat[$$]" "Restarting network interface: \"$1\" (network: \"$network\")." ifup "$network" } @@ -110,11 +184,26 @@ watchcat_monitor_network() { mm_iface_unlock_bands="$7" address_family="$8" script="$9" + ping_iface="" + restart_iface="" reset_failure_timer="" if [ "$#" -gt 9 ]; then shift 9 reset_failure_timer="$1" fi + [ "$mm_iface_name" = "null" ] && mm_iface_name="" + if [ "$iface" != "" ]; then + if ! ping_iface="$(watchcat_resolve_ping_iface "$iface")"; then + logger -p daemon.warn -t "watchcat[$$]" "Could not resolve interface \"$iface\" for pinging." + case "$iface" in + @*) ping_iface="" ;; + *) ping_iface="$iface" ;; + esac + fi + if ! restart_iface="$(watchcat_resolve_restart_iface "$iface")"; then + logger -p daemon.warn -t "watchcat[$$]" "Could not resolve interface \"$iface\" for restart." + fi + fi time_now="$(cat /proc/uptime)" time_now="${time_now%%.*}" @@ -143,9 +232,9 @@ watchcat_monitor_network() { time_lastcheck="$time_now" for host in $ping_hosts; do - if [ "$iface" != "" ]; then + if [ "$ping_iface" != "" ]; then ping_result="$( - ping $ping_family -I "$iface" -s "$ping_size" -c 1 "$host" &> /dev/null + ping $ping_family -I "$ping_iface" -s "$ping_size" -c 1 "$host" &> /dev/null echo $? )" else @@ -178,7 +267,7 @@ watchcat_monitor_network() { watchcat_restart_modemmanager_iface "$mm_iface_name" "$mm_iface_unlock_bands" fi if [ "$iface" != "" ]; then - watchcat_restart_network_iface "$iface" + watchcat_restart_network_iface "$iface" "$restart_iface" else watchcat_restart_all_network fi @@ -207,6 +296,16 @@ watchcat_ping() { ping_size="$5" address_family="$6" iface="$7" + ping_iface="" + if [ "$iface" != "" ]; then + if ! ping_iface="$(watchcat_resolve_ping_iface "$iface")"; then + logger -p daemon.warn -t "watchcat[$$]" "Could not resolve interface \"$iface\" for pinging." + case "$iface" in + @*) ping_iface="" ;; + *) ping_iface="$iface" ;; + esac + fi + fi time_now="$(cat /proc/uptime)" time_now="${time_now%%.*}" @@ -235,9 +334,9 @@ watchcat_ping() { time_lastcheck="$time_now" for host in $ping_hosts; do - if [ "$iface" != "" ]; then + if [ "$ping_iface" != "" ]; then ping_result="$( - ping $ping_family -I "$iface" -s "$ping_size" -c 1 "$host" &> /dev/null + ping $ping_family -I "$ping_iface" -s "$ping_size" -c 1 "$host" &> /dev/null echo $? )" else