diff --git a/dae/Makefile b/dae/Makefile index 05d96b5d5..59bde7c20 100644 --- a/dae/Makefile +++ b/dae/Makefile @@ -5,10 +5,10 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dae -PKG_VERSION:=2026.10.18 -PKG_RELEASE:=52 +PKG_VERSION:=2026.10.30 +PKG_RELEASE:=53 -PKG_SOURCE:=dae-src-2026.10.18-32ed09f0d784.tar.gz +PKG_SOURCE:=dae-src-2026.10.30-55c59e68c059.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 1562341d3..04e221940 100644 --- a/daed/Makefile +++ b/daed/Makefile @@ -5,10 +5,10 @@ include $(TOPDIR)/rules.mk PKG_NAME:=daed -PKG_VERSION:=2026.10.18 -PKG_RELEASE:=64 +PKG_VERSION:=2026.10.30 +PKG_RELEASE:=65 -PKG_SOURCE:=daed-src-2026.10.18-97c371b47eb5.tar.gz +PKG_SOURCE:=daed-src-2026.10.30-1850c01d032c.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/dockerd/Makefile b/dockerd/Makefile index 45e4e7011..9827df6c7 100644 --- a/dockerd/Makefile +++ b/dockerd/Makefile @@ -3,7 +3,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dockerd PKG_FLAGS:=hold PKG_VERSION:=27.3.1 -PKG_RELEASE:=6 +PKG_RELEASE:=8 PKG_LICENSE:=Apache-2.0 PKG_LICENSE_FILES:=LICENSE diff --git a/dockerd/files/dockerd.init b/dockerd/files/dockerd.init index 6fe073cfc..1ea3520cd 100755 --- a/dockerd/files/dockerd.init +++ b/dockerd/files/dockerd.init @@ -223,6 +223,8 @@ start_service() { procd_set_param command /usr/bin/dockerd --config-file="${DOCKERD_CONF}" fi procd_set_param limits nofile="${nofile} ${nofile}" + # Give dockerd the time to stop the containers before it gets killed + procd_set_param term_timeout 300 procd_close_instance } @@ -286,8 +288,50 @@ iptables_add_blocking_rule() { config_list_foreach "${cfg}" blocked_interfaces handle_iptables_rule "${device}" "${extra_iptables_args}" } +# Read procd's notifications until one contains the given text, or none comes for the given seconds +procd_notification() { + local line + + while read -r -t "${2}" line <&3; do + case "${line}" in + *"${1}"*) return 0 ;; + esac + done + return 1 +} + stop_service() { - if /etc/init.d/dockerd running; then - service_stop "/usr/bin/dockerd" - fi + local i=0 + + procd_running dockerd || return 0 + + # Subscribe to procd's notifications before it stops dockerd, to learn when it is done. + # The subscriber leaves procd's lock (fd 1000) to this script, which releases it on exit. + STOP_EVENTS="/var/run/dockerd.stop.$$" + mkfifo "${STOP_EVENTS}" || return 0 + ubus -t 330 subscribe service > "${STOP_EVENTS}" 1000>&- & + STOP_SUBSCRIBER=$! + exec 3< "${STOP_EVENTS}" + + # The subscription takes effect a moment later, and a stop notified before it would be missed: + # wait until procd passes on an event sent to itself + while [ "${i}" -lt 10 ]; do + ubus call service event '{ "type": "dockerd.stopping", "data": {} }' + if procd_notification '"type":"dockerd.stopping"' 1; then + STOP_SUBSCRIBED=1 + return 0 + fi + i=$((i + 1)) + done +} + +service_stopped() { + [ -n "${STOP_EVENTS}" ] || return 0 + + # Wait for dockerd, which exits after stopping the containers, so that a shutdown unmounts the data root after them + [ -n "${STOP_SUBSCRIBED}" ] && procd_notification '"service.stop": {"service":"dockerd"}' 330 + exec 3<&- + # A restart ignores SIGTERM while it stops dockerd, and so does the subscriber it started + kill -KILL "${STOP_SUBSCRIBER}" 2> /dev/null + rm -f "${STOP_EVENTS}" } diff --git a/gately/Makefile b/gately/Makefile index 3a9c6e88e..ddd971c8e 100644 --- a/gately/Makefile +++ b/gately/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=gately -PKG_VERSION:=0.6.1.1 -PKG_RELEASE:=19 +PKG_VERSION:=0.6.2 +PKG_RELEASE:=20 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/wangwanjie/gately/tar.gz/v$(PKG_VERSION)? diff --git a/gowebdav/Makefile b/gowebdav/Makefile index 67866eda0..3ee2d3bf9 100644 --- a/gowebdav/Makefile +++ b/gowebdav/Makefile @@ -6,8 +6,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=gowebdav -PKG_VERSION:=5.17.2 -PKG_RELEASE:=27 +PKG_VERSION:=5.17.3 +PKG_RELEASE:=28 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/hacdias/webdav/tar.gz/v$(PKG_VERSION)? diff --git a/grpcurl/Makefile b/grpcurl/Makefile index 75d7d3e65..6cbe428cf 100644 --- a/grpcurl/Makefile +++ b/grpcurl/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=grpcurl PKG_VERSION:=1.9.4 -PKG_RELEASE:=8 +PKG_RELEASE:=9 PKG_SOURCE:=v$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://github.com/fullstorydev/grpcurl/archive/refs/tags/ @@ -32,7 +32,7 @@ GO_PKG_LDFLAGS:=-s -w GO_PKG_TAGS:=master include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk +include ../golang/golang-package.mk define Package/grpcurl TITLE:=grpcurl is a command-line tool that lets you interact with gRPC servers diff --git a/kaiplus/Makefile b/kaiplus/Makefile index cd8ea4c72..e35d723fc 100644 --- a/kaiplus/Makefile +++ b/kaiplus/Makefile @@ -10,12 +10,12 @@ KAIPLUS_ARCH_x86_64:=amd64 KAIPLUS_ARCH_aarch64:=arm64 KAIPLUS_ARCH:=$(KAIPLUS_ARCH_$(ARCH)) -KAIPLUS_HASH_x86_64:=5588a5e1b7874bc5e631ab8ff1288226f567a84d3115808f22352d142c40f5d6 -KAIPLUS_HASH_aarch64:=5be29e4715a1181937c0156a6954738ce96fde2f338a1b03cd32c68b00e61524 +KAIPLUS_HASH_x86_64:=9e28ac8f2ec7b59dfa546b5ed58375397dfda3cd95d35b776fe7f252acb8878f +KAIPLUS_HASH_aarch64:=af045078037244a4fd80e21ef5a3ba3a9391918adc4a7791fda5ae777386c122 PKG_NAME:=kaiplus -PKG_VERSION:=1.0.9 -PKG_RELEASE:=15 +PKG_VERSION:=1.0.10 +PKG_RELEASE:=16 KAIPLUS_URL_FILE:=kaiplus-linux-$(KAIPLUS_ARCH) KAIPLUS_DOWNLOAD:=$(KAIPLUS_URL_FILE)-$(KAIPLUS_HASH_$(ARCH)) diff --git a/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js index 087aca0de..fe4688bc6 100644 --- a/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js @@ -130,13 +130,14 @@ return view.extend({ o = s.option(form.RichListValue, "offloading_type", _("Flow offloading type")); o.value('0', _("None")); - o.value('1', _("Software flow offloading"), _('Software based offloading for routing/NAT.')); + if (L.hasSystemFeature('offloading')) + o.value('1', _("Software flow offloading"), _('Software based offloading for routing/NAT.')); if (L.hasSystemFeature('offloading_hw')) o.value('2', _("Hardware flow offloading"), _('Hardware based offloading for routing with/without NAT.') + ' ' + _(' Requires hardware NAT support.')); if (hasMediatekHNAT) - o.value('3', "Mediatek HNAT", "基于Mediatek原厂闭源驱动的HNAT卸载"); + o.value('3', _('MediaTek HNAT'), _('Hardware NAT offloading using the MediaTek vendor driver.')); if (hasQualcommECM) - o.value('4', 'Qualcomm NSS ECM 加速', 'ECM Auto 模式,自动选择加速引擎。'); + o.value('4', _('Qualcomm NSS ECM acceleration'), _('Automatically select the acceleration engine in ECM Auto mode.')); o.optional = false; o.load = function (section_id) { const flow_offloading = uci.get('firewall', section_id, 'flow_offloading'); @@ -146,7 +147,7 @@ return view.extend({ return '4'; if (hasMediatekHNAT && flow_offloading === '3') return '3'; - return (flow_offloading === '1') + return (flow_offloading === '1' && L.hasSystemFeature('offloading')) ? ((flow_offloading_hw === '1' && has_hw_offloading) ? '2' : '1') : '0'; }; diff --git a/luci-app-firewall/po/zh_Hans/firewall.po b/luci-app-firewall/po/zh_Hans/firewall.po index 4efb87740..d0a496d4c 100644 --- a/luci-app-firewall/po/zh_Hans/firewall.po +++ b/luci-app-firewall/po/zh_Hans/firewall.po @@ -1587,3 +1587,19 @@ msgstr "Shell 脚本语法错误。" #: applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js msgid "Unable to restart the firewall." msgstr "无法重启防火墙。" + +#: applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +msgid "MediaTek HNAT" +msgstr "MediaTek HNAT" + +#: applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +msgid "Hardware NAT offloading using the MediaTek vendor driver." +msgstr "使用 MediaTek 原厂驱动的硬件 NAT 卸载。" + +#: applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +msgid "Qualcomm NSS ECM acceleration" +msgstr "Qualcomm NSS ECM 加速" + +#: applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +msgid "Automatically select the acceleration engine in ECM Auto mode." +msgstr "在 ECM Auto 模式下自动选择加速引擎。" diff --git a/luci-app-firewall/po/zh_Hant/firewall.po b/luci-app-firewall/po/zh_Hant/firewall.po index b028558d4..a3fef7a53 100644 --- a/luci-app-firewall/po/zh_Hant/firewall.po +++ b/luci-app-firewall/po/zh_Hant/firewall.po @@ -1573,3 +1573,19 @@ msgstr "Shell 指令碼語法錯誤。" #: applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js msgid "Unable to restart the firewall." msgstr "無法重新啟動防火牆。" + +#: applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +msgid "MediaTek HNAT" +msgstr "MediaTek HNAT" + +#: applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +msgid "Hardware NAT offloading using the MediaTek vendor driver." +msgstr "使用 MediaTek 原廠驅動的硬體 NAT 卸載。" + +#: applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +msgid "Qualcomm NSS ECM acceleration" +msgstr "Qualcomm NSS ECM 加速" + +#: applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +msgid "Automatically select the acceleration engine in ECM Auto mode." +msgstr "在 ECM Auto 模式下自動選擇加速引擎。" diff --git a/luci-app-open-box/Makefile b/luci-app-open-box/Makefile index 1d616b01f..96b679006 100644 --- a/luci-app-open-box/Makefile +++ b/luci-app-open-box/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-open-box -PKG_VERSION:=0.1.378 -PKG_RELEASE:=54 +PKG_VERSION:=0.1.383 +PKG_RELEASE:=55 PKG_MAINTAINER:=liandu2024 PKG_LICENSE:=GPL-3.0-or-later diff --git a/luci-app-openvpn-plus/Makefile b/luci-app-openvpn-plus/Makefile index 8094f0fd1..ae30d79d4 100755 --- a/luci-app-openvpn-plus/Makefile +++ b/luci-app-openvpn-plus/Makefile @@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-openvpn-plus PKG_VERSION:=1.0.0 -PKG_RELEASE:=10 +PKG_RELEASE:=11 PKG_LICENSE:=Apache-2.0 PKG_MAINTAINER:=Manfred Jaider diff --git a/luci-app-openvpn-plus/README.md b/luci-app-openvpn-plus/README.md index 2abfb7011..1870f99ae 100755 --- a/luci-app-openvpn-plus/README.md +++ b/luci-app-openvpn-plus/README.md @@ -51,15 +51,15 @@ Even though the traffic has to pass through **Double-NAT** and simple port forwa ## Screenshots -| 01 - Server/Client View | 02 - Status View | +| Server/Client View | Status View | | :---: | :---: | -| 01 | 02 -| 03 | 15 -| 09 | 10 -| 13 | 11 -| 12 | 04 -| 05 | 06 - +| ![Server/Client View](screenshots/server.png) | ![Status View](screenshots/status-dark.png) | +| ![Client View](screenshots/client.png) | ![QR Export](screenshots/qr-client-export.png) | +| ![Wizard Mobile Start](screenshots/wizard-mobile-server-01.png) | ![Wizard Mobile Tunnel](screenshots/wizard-mobile-server-02.png) | +| ![Wizard Mobile IP Setup](screenshots/wizard-mobile-server-03.png) | ![Wizard DDNS Setup](screenshots/wizard-mobile-server-04.png) | +| ![Wizard Site-To-Site Start](screenshots/wizard-main-office-01.png) | ![Wizard Site-To-Site Routing](screenshots/wizard-main-office-02.png) | +| ![Wizard Port Forwarding](screenshots/port-forward.png) | ![Wizard Add Instance](screenshots/add-instance.png) | +| ![Wizard Key View](screenshots/keyview.png) | ![Wizard KeyGen](screenshots/keygen.png) ## Configuration Layout @@ -84,6 +84,7 @@ luci-app-openvpn-plus/ │ │ └── luci-app-openvpn-plus.po │ ├── zh-cn/ │ │ └── luci-app-openvpn-plus.po +├── screenshots/ └── root/ ├── etc/ │ ├── config/ diff --git a/luci-app-openvpn-plus/root/usr/libexec/luci-app-openvpn-plus b/luci-app-openvpn-plus/root/usr/libexec/luci-app-openvpn-plus index 7dbc4eafc..aa550d6bb 100755 --- a/luci-app-openvpn-plus/root/usr/libexec/luci-app-openvpn-plus +++ b/luci-app-openvpn-plus/root/usr/libexec/luci-app-openvpn-plus @@ -730,6 +730,33 @@ openssldgst() { return 0 } +# Clean up empty symlink folder +internal_cleansymlink() { + # internal function (no shift) + local ram_link_dir="${1}" + local www_link_dir="${2}" + + # Remove the temporary RAM directory ONLY if it is completely empty + [ -d "${ram_link_dir}" ] && rmdir "${ram_link_dir}" 2>/dev/null + + # Smart Web-Folder Cleanup: Check if files other than index.html exist + if [ -d "${www_link_dir}" ]; then + local has_profiles="0" + local check_link + # If a real symlink or folder matching the pattern exists, has_profiles becomes 1 + for check_link in "${www_link_dir}"/ovpn-tmp-*-*; do + if [ -e "${check_link}" ] || [ -L "${check_link}" ]; then + has_profiles="1" + break + fi + done + # Remove the web folder if no active profile links are left + if [ "${has_profiles}" = "0" ]; then + rm -rf "${www_link_dir}" + fi + fi +} + # Manage temporary download links for mobile profiles [create|delete] symlink() { shift # Remove "symlink" from the arguments list @@ -834,25 +861,8 @@ symlink() { # Remove the temporary session files for this instance from RAM rm -rf "${ram_link_dir}"/ovpn-tmp-*-"${ovpn_instance}" - # Remove RAM base directory if it has become completely empty - rmdir "${ram_link_dir}" 2>/dev/null - - # Smart Web-Folder Cleanup: Check if files other than index.html exist - if [ -d "${www_link_dir}" ]; then - local has_profiles="0" - local check_link - # If a real symlink or folder matching the pattern exists, has_profiles becomes 1 - for check_link in "${www_link_dir}"/ovpn-tmp-*-*; do - if [ -e "${check_link}" ] || [ -L "${check_link}" ]; then - has_profiles="1" - break - fi - done - # Remove the web folder if no active profile links are left - if [ "${has_profiles}" = "0" ]; then - rm -rf "${www_link_dir}" - fi - fi + # Clean up empty symlink folder + internal_cleansymlink "${ram_link_dir}" "${www_link_dir}" printf "%s\n" "SUCCESS: Link directory and static profile deleted from RAM." else @@ -869,7 +879,6 @@ symlink() { return 0 } - # Helper to prevent routing loops for IPv4 and IPv6 subnets internal_checkloopback() { # internal (no shift) @@ -1944,7 +1953,6 @@ internal_cleaninst() { if internal_checkname "${instname}"; then # Safely remove files, dead symlinks or directories rm -rf "${f}" - logger -t openvpn-luci "Cleanup: Removed orphaned item '${f}'." fi ;; esac @@ -1988,20 +1996,7 @@ cleanup() { # Step 3: Remove orphan symlink files internal_cleaninst "${active_list}" "${www_link_dir}/ovpn-tmp-*-*" internal_cleaninst "${active_list}" "${ram_link_dir}/ovpn-tmp-*-*" - - # Remove the temporary RAM directory ONLY if it is completely empty - [ -d "${ram_link_dir}" ] && rmdir "${ram_link_dir}" 2>/dev/null - - # Smart Web-Folder Cleanup: Check if files other than index.html exist - if [ -d "${www_link_dir}" ]; then - local found_profiles - found_profiles="${www_link_dir}/ovpn-tmp-"*-* - - # If the text still has a '*', no active profiles were found - if [ "${found_profiles}" = "${www_link_dir}/ovpn-tmp-*-*" ]; then - rm -rf "${www_link_dir}" - fi - fi + internal_cleansymlink "${ram_link_dir}" "${www_link_dir}" return 0 } diff --git a/luci-app-openvpn-plus/root/www/luci-static/resources/view/vpn/openvpn-keygen.js b/luci-app-openvpn-plus/root/www/luci-static/resources/view/vpn/openvpn-keygen.js index c2065abe5..203461cf9 100755 --- a/luci-app-openvpn-plus/root/www/luci-static/resources/view/vpn/openvpn-keygen.js +++ b/luci-app-openvpn-plus/root/www/luci-static/resources/view/vpn/openvpn-keygen.js @@ -774,10 +774,11 @@ const openAutomatedPostKeyGenModal = async function (newInstanceItem, appData, w if (optionalShowBtnCancel !== true) { styleHide = ' display:none !important;'; } + const backupHide = (wizardParams && wizardParams.isServerBackup) ? '' : styleHide; const yesBtn = E('button', { 'class': 'btn cbi-button cbi-button-action important', 'style': 'margin-right:10px;' }, TXT.KEY.generate_unique_keys); const noBtn = E('button', { 'class': 'btn cbi-button cbi-button-neutral', 'style': 'margin-right:10px;' }, TXT.KEY.clone_default_keys); - const backupBtn = E('button', { 'class': 'btn cbi-button cbi-button-positive important', 'style': 'margin-right:10px;' }, TXT.BTN.backup); + const backupBtn = E('button', { 'class': 'btn cbi-button cbi-button-positive important', 'style': 'margin-right:10px;' + backupHide }, TXT.BTN.backup); const cancelBtn = E('button', { 'class': 'btn cbi-button cbi-button-neutral', 'style': 'margin-right:10px;' + styleHide }, TXT.BTN.cancel); const closeBtn = E('button', { 'class': 'cbi-button cbi-button-action important', 'style': 'display:none;' }, TXT.BTN.close); @@ -904,7 +905,14 @@ const openAutomatedPostKeyGenModal = async function (newInstanceItem, appData, w callbacks.uciSaveApplyRestart(instance_id); }); - L.ui.showModal(TXT.KEY.add_server_instance + ' (' + instance_id + ')', [ + let displayName; + if (cnName) { + displayName = ': ' + cnName; + } else { + displayName = ' (' + instance_id + ')'; + } + + L.ui.showModal(TXT.KEY.add_server_instance + displayName, [ E('div', { 'class': 'cbi-map' }, [ E('div', { 'class': 'cbi-section' }, [ promptMessageNode, diff --git a/luci-app-openvpn-plus/root/www/luci-static/resources/view/vpn/openvpn-wizard.js b/luci-app-openvpn-plus/root/www/luci-static/resources/view/vpn/openvpn-wizard.js index 06fa42007..a891091b4 100755 --- a/luci-app-openvpn-plus/root/www/luci-static/resources/view/vpn/openvpn-wizard.js +++ b/luci-app-openvpn-plus/root/www/luci-static/resources/view/vpn/openvpn-wizard.js @@ -392,54 +392,10 @@ const getValidCommonName = function (name) { return cleanName; }; -/** - * Validate and clean any given IPv4 or IPv6 address string - */ -const checkIPAddress = function (rawIp) { - if (!rawIp) { - return null; - } - - // Delete all spaces, tabs and hidden lines from the text (tr -d ' \t\r\n') - const ip = rawIp.replace(/[\s\t\r\n]/g, ''); - if (ip === '') { - return null; - } - - const ipv4Regex = /^([0-9]{1,3}\.){3}[0-9]{1,3}$/; - - // FIXED: Standard compliant IPv6 pattern that correctly handles "::" and blocks ":::" - const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){1,7}:$|^(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}$|^(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}$|^(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}$|^[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}$|^:(?::[0-9a-fA-F]{1,4}){1,7}$|^::$/; - - // Case 1: Check if the text is a valid IPv4 address (numbers 0 to 255) - if (ipv4Regex.test(ip)) { - const segments = ip.split('.'); - const octet1 = parseInt(segments[0], 10); - const octet2 = parseInt(segments[1], 10); - const octet3 = parseInt(segments[2], 10); - const octet4 = parseInt(segments[3], 10); - - // Match the awk rule: $1<=255 && $2<=255 && $3<=255 && $4<=255 - if (octet1 <= 255 && octet2 <= 255 && octet3 <= 255 && octet4 <= 255) { - return { ip: ip, isV6: false }; - } - } - - // Case 2: Check if the text matches the verified IPv6 regex - if (ipv6Regex.test(ip)) { - if (ip.indexOf(':') !== -1) { - // Change all hex letters to lowercase for safe matching later (tr 'A-Z' 'a-z') - return { ip: ip.toLowerCase(), isV6: true }; - } - } - - return null; -}; - /** * Generates an isolated, self-validating Site-to-Site network inputs row layout block */ -const renderSubnetInputs = function () { +const renderSubnetInputs = function (checkIpCallback) { // Create the 3 input fields with simple, easy text placeholders const cnInput = E('input', { 'type': 'text', 'class': 'cbi-input-text', 'placeholder': TXT.INFO.remote_office_name, 'style': 'width:32%; font-family:monospace; margin-right:1%;' }); const subnetInput = E('input', { 'type': 'text', 'class': 'cbi-input-text', 'placeholder': TXT.INFO.lan_ip + ' (192.168.2.0)', 'style': 'width:32%; font-family:monospace; margin-right:1%;' }); @@ -503,7 +459,7 @@ const renderSubnetInputs = function () { } // 2. Validate IP Address using your verified template logic - const ipResult = checkIPAddress(rawSub); + const ipResult = (typeof checkIpCallback === 'function') ? checkIpCallback(rawSub) : null if (!ipResult) { subnetInput.classList.add('cbi-input-invalid'); hasValidationError = true; @@ -1111,7 +1067,6 @@ const showMessage = function (text, type, box) { box.style.setProperty('display', 'block', 'important'); }; - const hideMessage = function (box) { box.style.setProperty('display', 'none', 'important'); } @@ -1411,7 +1366,7 @@ const renderOptionSiteServer = function (portForwardingAlert, wizardData) { }; // 4. Load the input fields row component - const networkInputComponent = renderSubnetInputs(); + const networkInputComponent = renderSubnetInputs(wizardData.networkCallbacks.checkIp); // 5. Create the "Add" button const addEntryBtn = E('button', { diff --git a/luci-app-openvpn-plus/root/www/luci-static/resources/view/vpn/openvpn.js b/luci-app-openvpn-plus/root/www/luci-static/resources/view/vpn/openvpn.js index 476f6e16c..82f759de3 100755 --- a/luci-app-openvpn-plus/root/www/luci-static/resources/view/vpn/openvpn.js +++ b/luci-app-openvpn-plus/root/www/luci-static/resources/view/vpn/openvpn.js @@ -572,27 +572,71 @@ const sha256sum = async function (textToHash) { return 'ERROR'; }; +/** + * Validate and clean any given IPv4 or IPv6 address string safely + */ +const checkIp = function (rawIp) { + if (!rawIp) { + return null; + } + + // Delete all spaces, tabs and hidden lines from the text (tr -d ' \t\r\n') + const ip = rawIp.replace(/[\s\t\r\n]/g, '').trim(); + if (ip === '') { + return null; + } + + const ipv4Regex = /^([0-9]{1,3}\.){3}[0-9]{1,3}$/; + const ipv6Regex = /^([\da-fA-F]{1,4}:|:){1,7}([\da-fA-F]{1,4}|:)$/; + + // Case 1: Check if the text is a valid IPv4 address (numbers 0 to 255) + if (ipv4Regex.test(ip)) { + const segments = ip.split('.'); + if (parseInt(segments[0], 10) <= 255 && + parseInt(segments, 10) <= 255 && + parseInt(segments, 10) <= 255 && + parseInt(segments, 10) <= 255) { + return { ip: ip, isV6: false }; + } + } + + // Case 2: Check if the text is a syntactically valid IPv6 address. Extra check for triple colons (:::) to keep the regex small + if (ipv6Regex.test(ip) && ip.indexOf(':') !== -1 && ip.indexOf(':::') === -1) { + return { ip: ip.toLowerCase(), isV6: true }; + } + + return null; +}; + /** * Global helper function to determine the fallback IP and mask from browser or UCI config. */ const getHostnameFallback = function (returnMask) { - // Basic regex patterns to check for valid IPv4 or IPv6 layouts - const ipv4Pattern = /^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/; - const ipv6Pattern = /^(([0-9a-fA-F]{1,4}:){1,7}|:)(:[0-9a-fA-F]{1,4}){1,7}$|^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/; - // Get the address string from the browser URL bar and remove IPv6 brackets - let ip = (window.location.hostname || "").trim().replace(/^\[|\]$/g, ''); + let browserIp = (window.location.hostname || "").trim().replace(/^\[|\]$/g, ''); + let ip = ''; let mask = '255.255.255.0'; - // If browser URL is text (like openwrt.lan), fallback to configured UCI IPs - if (!ipv4Pattern.test(ip) && !ipv6Pattern.test(ip)) { - ip = L.uci.get('network', 'lan', 'ipaddr') || L.uci.get('network', 'lan', 'ip6addr') || '192.168.1.1'; + // Use our solid validation function to check the browser IP + let checked = checkIp(browserIp); + + if (checked) { + ip = checked.ip; + } else { + // If browser URL is a hostname (like openwrt.lan), fallback to configured UCI IPs + let uciIp = L.uci.get('network', 'lan', 'ipaddr') || L.uci.get('network', 'lan', 'ip6addr') || '192.168.1.1'; + + // Remove any trailing subnet mask from UCI strings (like /64) safely + ip = uciIp.split('/')[0].trim(); + + // Re-validate the UCI fallback IP to know its family (v4 or v6) + checked = checkIp(ip); } // Set the matching subnet mask format based on the detected IP family - if (ipv4Pattern.test(ip)) { + if (checked && checked.isV6 === false) { mask = L.uci.get('network', 'lan', 'netmask') || OPENVPN.IPv4.MASK24; - } else if (ipv6Pattern.test(ip)) { + } else if (checked && checked.isV6 === true) { mask = L.uci.get('network', 'lan', 'ip6assign') || '64'; } @@ -965,7 +1009,7 @@ const checkNetworkStructure = function (appData) { gatewayIp = gw4; } - // Check WAN IPv4 addresses for Double NAT and extract WAN net-boundaries securely [sh] + // Check WAN IPv4 addresses for Double NAT and extract WAN net-boundaries securely const ipaddrs = net.getIPAddrs ? net.getIPAddrs() : []; let deviceMask = (net.getNetmask && net.getNetmask()) ? net.getNetmask() : (net.data && net.data.netmask) ? net.data.netmask : null; if (deviceMask === null || deviceMask === undefined || deviceMask === '') { @@ -977,7 +1021,7 @@ const checkNetworkStructure = function (appData) { const wanIpStr = String(rawWanIp); const ip = wanIpStr.split('/')[0]; - // If the WAN IP is private, we have a Double NAT [sh] + // If the WAN IP is private, we have a Double NAT if (privateIpRegex.test(ip)) { isDoubleNat = true; } @@ -1004,7 +1048,7 @@ const checkNetworkStructure = function (appData) { gatewayIp = OPENVPN.IPv4.ZERO; } - // Set values to global object (Fixed: changed 'gateway' to 'gatewayIp') + // Set values to global object networkStructure.doubleNat = isDoubleNat; networkStructure.apMode = isApMode; networkStructure.gateway = gatewayIp; @@ -1038,6 +1082,7 @@ const checkNetworkStructure = function (appData) { */ const networkCallbacks = ({ sha256sum: sha256sum, + checkIp: checkIp, getLanIp: getLanIp, queryPublicIp: queryPublicIp, getDdnsOrPublicIp: getDdnsOrPublicIp, @@ -2785,7 +2830,7 @@ const openSiteToSiteExportModal = function (instance_id, nextId, serverAssets, a selectDropdown.appendChild(E('option', { 'disabled': true }, ['- - -'])); selectDropdown.appendChild(E('option', { 'value': 'backup_server_profile' }, [ICON.BACKUP + TXT.MSG.backup_server_profile + ': ' + displayId])); - const subnetInputs = appData.wizardClass.renderSubnetInputs(); + const subnetInputs = appData.wizardClass.renderSubnetInputs(networkCallbacks.checkIp); // Creates a hidden yellowish warning message box for network conflicts or duplicate names const errorDisplayNode = E('div', { @@ -4789,7 +4834,7 @@ const generate_s2s_nft_file = async function (deviceName, localSubnet, remoteSub let lanDevice = 'br-lan'; const res = await luci_app_openvpn_plus([CFG.LIBEXEC.getl3dev]); - if (res && res !='' && !res.includes("ERROR:")) { + if (res && res != '' && !res.includes("ERROR:")) { lanDevice = res; } diff --git a/luci-app-openvpn-plus/screenshots/add-instance.png b/luci-app-openvpn-plus/screenshots/add-instance.png new file mode 100755 index 000000000..8845fccfe Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/add-instance.png differ diff --git a/luci-app-openvpn-plus/screenshots/add-new.png b/luci-app-openvpn-plus/screenshots/add-new.png new file mode 100755 index 000000000..6636e204a Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/add-new.png differ diff --git a/luci-app-openvpn-plus/screenshots/client.png b/luci-app-openvpn-plus/screenshots/client.png new file mode 100755 index 000000000..7313409eb Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/client.png differ diff --git a/luci-app-openvpn-plus/screenshots/iperf-mobile-5G-download.png b/luci-app-openvpn-plus/screenshots/iperf-mobile-5G-download.png new file mode 100755 index 000000000..2d8e3f254 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/iperf-mobile-5G-download.png differ diff --git a/luci-app-openvpn-plus/screenshots/iperf-mobile-5G-upload.png b/luci-app-openvpn-plus/screenshots/iperf-mobile-5G-upload.png new file mode 100755 index 000000000..fcd209178 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/iperf-mobile-5G-upload.png differ diff --git a/luci-app-openvpn-plus/screenshots/iperf-mobile-wlan-download.png b/luci-app-openvpn-plus/screenshots/iperf-mobile-wlan-download.png new file mode 100755 index 000000000..6244ffbbe Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/iperf-mobile-wlan-download.png differ diff --git a/luci-app-openvpn-plus/screenshots/iperf-mobile-wlan-upload.png b/luci-app-openvpn-plus/screenshots/iperf-mobile-wlan-upload.png new file mode 100755 index 000000000..af1d9a503 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/iperf-mobile-wlan-upload.png differ diff --git a/luci-app-openvpn-plus/screenshots/iperf-sito-to-site-download.png b/luci-app-openvpn-plus/screenshots/iperf-sito-to-site-download.png new file mode 100755 index 000000000..9e5dd4174 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/iperf-sito-to-site-download.png differ diff --git a/luci-app-openvpn-plus/screenshots/iperf-sito-to-site-upload.png b/luci-app-openvpn-plus/screenshots/iperf-sito-to-site-upload.png new file mode 100755 index 000000000..100c606f0 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/iperf-sito-to-site-upload.png differ diff --git a/luci-app-openvpn-plus/screenshots/keygen.png b/luci-app-openvpn-plus/screenshots/keygen.png new file mode 100755 index 000000000..05ba5f799 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/keygen.png differ diff --git a/luci-app-openvpn-plus/screenshots/keyview.png b/luci-app-openvpn-plus/screenshots/keyview.png new file mode 100755 index 000000000..94a909df3 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/keyview.png differ diff --git a/luci-app-openvpn-plus/screenshots/port-forward.png b/luci-app-openvpn-plus/screenshots/port-forward.png new file mode 100755 index 000000000..75a7ee1e8 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/port-forward.png differ diff --git a/luci-app-openvpn-plus/screenshots/qr-client-export.png b/luci-app-openvpn-plus/screenshots/qr-client-export.png new file mode 100755 index 000000000..721f4cfce Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/qr-client-export.png differ diff --git a/luci-app-openvpn-plus/screenshots/server.png b/luci-app-openvpn-plus/screenshots/server.png new file mode 100755 index 000000000..cfa867252 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/server.png differ diff --git a/luci-app-openvpn-plus/screenshots/status-dark.png b/luci-app-openvpn-plus/screenshots/status-dark.png new file mode 100755 index 000000000..f58c6d428 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/status-dark.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-main-office-01.png b/luci-app-openvpn-plus/screenshots/wizard-main-office-01.png new file mode 100755 index 000000000..af6b83cd1 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-main-office-01.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-main-office-02.png b/luci-app-openvpn-plus/screenshots/wizard-main-office-02.png new file mode 100755 index 000000000..887a41807 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-main-office-02.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-main-office-03.png b/luci-app-openvpn-plus/screenshots/wizard-main-office-03.png new file mode 100755 index 000000000..fa64bb424 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-main-office-03.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-main-office-04.png b/luci-app-openvpn-plus/screenshots/wizard-main-office-04.png new file mode 100755 index 000000000..395e2f7ee Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-main-office-04.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-main-office-05.png b/luci-app-openvpn-plus/screenshots/wizard-main-office-05.png new file mode 100755 index 000000000..e421f60c6 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-main-office-05.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-main-office-06.png b/luci-app-openvpn-plus/screenshots/wizard-main-office-06.png new file mode 100755 index 000000000..caa97bd2a Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-main-office-06.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-main-office-07.png b/luci-app-openvpn-plus/screenshots/wizard-main-office-07.png new file mode 100755 index 000000000..a5e1ab48f Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-main-office-07.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-main-office-08.png b/luci-app-openvpn-plus/screenshots/wizard-main-office-08.png new file mode 100755 index 000000000..c4b8a7698 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-main-office-08.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-main-office-09.png b/luci-app-openvpn-plus/screenshots/wizard-main-office-09.png new file mode 100755 index 000000000..f2b02336b Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-main-office-09.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-main-office-10.png b/luci-app-openvpn-plus/screenshots/wizard-main-office-10.png new file mode 100755 index 000000000..74ea67f74 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-main-office-10.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-main-office-11.png b/luci-app-openvpn-plus/screenshots/wizard-main-office-11.png new file mode 100755 index 000000000..a77ac53d5 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-main-office-11.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-main-office-12.png b/luci-app-openvpn-plus/screenshots/wizard-main-office-12.png new file mode 100755 index 000000000..eff797be2 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-main-office-12.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-mobile-server-01.png b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-01.png new file mode 100755 index 000000000..d75d73294 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-01.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-mobile-server-02.png b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-02.png new file mode 100755 index 000000000..c001bb156 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-02.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-mobile-server-03.png b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-03.png new file mode 100755 index 000000000..df76ac1fa Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-03.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-mobile-server-04.png b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-04.png new file mode 100755 index 000000000..32dc7a810 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-04.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-mobile-server-05.png b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-05.png new file mode 100755 index 000000000..ddcab2880 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-05.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-mobile-server-06.png b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-06.png new file mode 100755 index 000000000..a2cdcbd15 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-06.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-mobile-server-07.png b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-07.png new file mode 100755 index 000000000..3728b0c0e Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-07.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-mobile-server-08.png b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-08.png new file mode 100755 index 000000000..632d2e6af Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-08.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-mobile-server-09.png b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-09.png new file mode 100755 index 000000000..9a0f6c421 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-09.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-mobile-server-10.png b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-10.png new file mode 100755 index 000000000..f917a6d35 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-10.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-mobile-server-11.png b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-11.png new file mode 100755 index 000000000..c5734ce3d Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-11.png differ diff --git a/luci-app-openvpn-plus/screenshots/wizard-mobile-server-12.png b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-12.png new file mode 100755 index 000000000..cef5ecce4 Binary files /dev/null and b/luci-app-openvpn-plus/screenshots/wizard-mobile-server-12.png differ diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index c3aa024fd..d04f2d4b6 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.10.29 -PKG_RELEASE:=359 +PKG_RELEASE:=360 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall/luasrc/controller/passwall.lua b/luci-app-passwall/luasrc/controller/passwall.lua index b3b3d4a9d..a58f6879e 100644 --- a/luci-app-passwall/luasrc/controller/passwall.lua +++ b/luci-app-passwall/luasrc/controller/passwall.lua @@ -963,17 +963,17 @@ function read_rulelist() end local backup_files = { - "/etc/config/passwall", - "/etc/config/passwall_server", - "/etc/passwall/rules/block_host", - "/etc/passwall/rules/block_ip", - "/etc/passwall/rules/direct_host", - "/etc/passwall/rules/direct_ip", - "/etc/passwall/rules/proxy_host", - "/etc/passwall/rules/proxy_ip", - "/etc/passwall/rules/lanlist_ipv4", - "/etc/passwall/rules/lanlist_ipv6", - "/etc/passwall/rules/domains_excluded" + "/etc/config/passwall", + "/etc/config/passwall_server", + "/etc/passwall/rules/block_host", + "/etc/passwall/rules/block_ip", + "/etc/passwall/rules/direct_host", + "/etc/passwall/rules/direct_ip", + "/etc/passwall/rules/proxy_host", + "/etc/passwall/rules/proxy_ip", + "/etc/passwall/rules/lanlist_ipv4", + "/etc/passwall/rules/lanlist_ipv6", + "/etc/passwall/rules/domains_excluded" } function create_backup() diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua index 9f5d2d9d0..4b2e49c27 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua @@ -172,7 +172,7 @@ o.validate = port_validate ---- UDP No Redir Ports local UDP_NO_REDIR_PORTS = m:get("@global_forwarding[0]", "udp_no_redir_ports") o = s:taboption("Proxy", Value, "udp_no_redir_ports", translate("UDP No Redir Ports"), - "" .. + "" .. translate("Fill in the ports you don't want to be forwarded by the agent, with the highest priority.") .. "") o:value("", translate("Use global config") .. "(" .. UDP_NO_REDIR_PORTS .. ")") diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua index 2904eab23..8762ace12 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua @@ -119,7 +119,7 @@ o.rawhtml = true o.cfgvalue = function(self, section) return string.format([[ ]], - translate("Manual subscription All")) + translate("Manual subscription All")) end s = m:section(TypedSection, "subscribe_list", "", "" .. translate("When adding a new subscription, please save and apply before manually subscribing. If you only change the subscription URL, you can subscribe manually, and the system will save it automatically.") .. "") diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua index 94d826d04..437d52807 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua @@ -68,9 +68,9 @@ o.validate = port_validate ---- UDP No Redir Ports o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"), - "" .. translate( - "Fill in the ports you don't want to be forwarded by the agent, with the highest priority.") .. - "") + "" .. translate( + "Fill in the ports you don't want to be forwarded by the agent, with the highest priority.") .. + "") o.default = "disable" o:value("disable", translate("No patterns are used")) o:value("1:65535", translate("All")) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/0_socks.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/0_socks.lua index 23856bad1..39900e778 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/0_socks.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/0_socks.lua @@ -18,7 +18,7 @@ s.type_name = type_name s.option_prefix = "socks_" api.set_type_cbi(s) -o = s:option(ListValue, "del_protocol", "¡¡") --ʼÖÕÒþ²أ¬ÓÃÓÚɾ³ý protocol +o = s:option(ListValue, "del_protocol", " ") --始终隐藏,用于删除 protocol o:depends({ __hide = "1" }) o.rewrite_option = "protocol" diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua index d5748302a..c36f30739 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua @@ -167,7 +167,7 @@ if load_urltest_options then -- [[ URLTest Start ]] o = s:option(Flag, "urltest_interrupt_exist_connections", translate("Interrupt existing connections")) o:depends({ protocol = "_urltest" }) o.default = "0" - o.description = translate("Interrupt existing connections when the selected outbound has changed.") + o.description = translate("Interrupt existing connections when the selected outbound has changed.") end -- [[ URLTest End ]] if load_iface_options then -- [[ 自定义接口 Start ]] diff --git a/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/luci-app-passwall/luasrc/passwall/util_sing-box.lua index f5421b71e..dc45f1b63 100644 --- a/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -2037,7 +2037,7 @@ function gen_config(var) table.insert(dns.servers, remote_server) fakedns_tag = "remote_fakeip" - if remote_dns_fake or inner_fakedns == "1" then + if remote_dns_fake or inner_fakedns == "1" then table.insert(dns.servers, { tag = fakedns_tag, type = "fakeip", @@ -2178,7 +2178,7 @@ function gen_config(var) local remote_dns_server = api.clone(remote_server) remote_dns_server.tag = value.shunt_tag local is_local = (remote_server.address and api.is_local_ip(remote_server.address)) or - (remote_server.server and api.is_local_ip(remote_server.server)) --dns为本地ip,不走代理 + (remote_server.server and api.is_local_ip(remote_server.server)) --dns为本地ip,不走代理 remote_dns_server.detour = is_local and "direct" or value.outboundTag table.insert(dns.servers, remote_dns_server) dns_rule.server = remote_dns_server.tag diff --git a/luci-app-passwall/luasrc/view/passwall/cbi/nodes_dynamiclist_com.htm b/luci-app-passwall/luasrc/view/passwall/cbi/nodes_dynamiclist_com.htm index cabdaaf27..3a74ce204 100644 --- a/luci-app-passwall/luasrc/view/passwall/cbi/nodes_dynamiclist_com.htm +++ b/luci-app-passwall/luasrc/view/passwall/cbi/nodes_dynamiclist_com.htm @@ -175,7 +175,7 @@ const ctx = canvas.getContext('2d', { willReadFrequently: true }); return function(colorStr) { if (!colorStr) - return null; + return null; ctx.clearRect(0, 0, 1, 1); // 2. Apply the color ctx.fillStyle = colorStr; diff --git a/luci-app-passwall/luasrc/view/passwall/cbi/nodes_listvalue_com.htm b/luci-app-passwall/luasrc/view/passwall/cbi/nodes_listvalue_com.htm index 2a066287b..30de14bb8 100644 --- a/luci-app-passwall/luasrc/view/passwall/cbi/nodes_listvalue_com.htm +++ b/luci-app-passwall/luasrc/view/passwall/cbi/nodes_listvalue_com.htm @@ -169,7 +169,7 @@ const ctx = canvas.getContext('2d', { willReadFrequently: true }); return function(colorStr) { if (!colorStr) - return null; + return null; ctx.clearRect(0, 0, 1, 1); // 2. Apply the color ctx.fillStyle = colorStr; diff --git a/luci-app-passwall/luasrc/view/passwall/cbi/nodes_multivalue.htm b/luci-app-passwall/luasrc/view/passwall/cbi/nodes_multivalue.htm index 93fa800e0..f5c6ea39b 100644 --- a/luci-app-passwall/luasrc/view/passwall/cbi/nodes_multivalue.htm +++ b/luci-app-passwall/luasrc/view/passwall/cbi/nodes_multivalue.htm @@ -35,10 +35,10 @@ local groups = {} local group_order = {} for _, item in ipairs(values) do local g = item.group - if not g or g == "" then - g = translate("default") + if not g or g == "" then + g = translate("default") end - if not groups[g] then + if not groups[g] then groups[g] = {} table.insert(group_order, g) end diff --git a/luci-app-passwall/luasrc/view/passwall/cbi/nodes_multivalue_com.htm b/luci-app-passwall/luasrc/view/passwall/cbi/nodes_multivalue_com.htm index 43c6cf3ab..9d22aeefa 100644 --- a/luci-app-passwall/luasrc/view/passwall/cbi/nodes_multivalue_com.htm +++ b/luci-app-passwall/luasrc/view/passwall/cbi/nodes_multivalue_com.htm @@ -125,7 +125,7 @@ const ctx = canvas.getContext('2d', { willReadFrequently: true }); return function(colorStr) { if (!colorStr) - return null; + return null; ctx.clearRect(0, 0, 1, 1); // 2. Apply the color ctx.fillStyle = colorStr; @@ -258,7 +258,7 @@ const keyword = searchInput.value.trim().toLowerCase(); const isSearching = keyword.length > 0; // 当前实例下的所有 checkbox - const cbs = isSearching + const cbs = isSearching ? Array.from(nodeList.querySelectorAll("input[type=checkbox]")).filter(cb => cb.closest("li").style.display !== "none") : nodeList.querySelectorAll("input[type=checkbox]"); let checked = 0; diff --git a/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value.htm b/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value.htm index 7fe732073..e09e9bce2 100644 --- a/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value.htm +++ b/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value.htm @@ -137,7 +137,7 @@ local dropdown_data = { - +
diff --git a/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value_com.htm b/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value_com.htm index 0c5f5c02c..920601c50 100644 --- a/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value_com.htm +++ b/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value_com.htm @@ -164,7 +164,7 @@ const ctx = canvas.getContext('2d', { willReadFrequently: true }); return function(colorStr) { if (!colorStr) - return null; + return null; ctx.clearRect(0, 0, 1, 1); // 2. Apply the color ctx.fillStyle = colorStr; diff --git a/luci-app-passwall/luasrc/view/passwall/global/footer.htm b/luci-app-passwall/luasrc/view/passwall/global/footer.htm index ad87dba3d..8c9eabfe6 100644 --- a/luci-app-passwall/luasrc/view/passwall/global/footer.htm +++ b/luci-app-passwall/luasrc/view/passwall/global/footer.htm @@ -5,11 +5,11 @@ local appname = map.config local sid = "@global[0]" -%> ]] diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/socks_config.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/socks_config.lua index 65dd0ed83..13dad7327 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/socks_config.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/socks_config.lua @@ -160,7 +160,7 @@ o = s:option(Value, "autoswitch_retry_num", translate("Timeout retry num")) o.datatype = "min(1)" o.default = 1 o:depends("enable_autoswitch", true) - + o = s:option(Flag, "autoswitch_restore_switch", translate("Restore Switch"), translate("When detects main node is available, switch back to the main node.")) o:depends("enable_autoswitch", true) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/1_sing-box.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/1_sing-box.lua index 83887a53e..5a9587fb2 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/1_sing-box.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/1_sing-box.lua @@ -715,7 +715,7 @@ if singbox_tags:find("with_utls") then o = s:option(Value, "reality_publicKey", translate("Public Key")) o:depends({ reality = true }) - + o = s:option(Value, "reality_shortId", translate("Short Id")) o:depends({ reality = true }) end diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/1_sing-box.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/1_sing-box.lua index 8b1dbff5f..2f6c94818 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/1_sing-box.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/1_sing-box.lua @@ -304,10 +304,10 @@ if singbox_tags:find("with_utls") then o:depends({ protocol = "vless", tls = true }) o:depends({ protocol = "trojan", tls = true }) o:depends({ protocol = "anytls", tls = true }) - + o = s:option(Value, "reality_private_key", translate("Private Key")) o:depends({ reality = true }) - + o = s:option(Value, "reality_shortId", translate("Short Id")) o:depends({ reality = true }) diff --git a/luci-app-passwall2/luasrc/passwall2/api.lua b/luci-app-passwall2/luasrc/passwall2/api.lua index 7211e67c5..40bde4ec0 100644 --- a/luci-app-passwall2/luasrc/passwall2/api.lua +++ b/luci-app-passwall2/luasrc/passwall2/api.lua @@ -536,7 +536,7 @@ function strToTable(str) if str == nil or type(str) ~= "string" then return {} end - + return loadstring("return " .. str)() end @@ -922,7 +922,7 @@ function clone(org) end end end - + local res = {} copy(org, res) return res diff --git a/luci-app-passwall2/luasrc/passwall2/util_shadowsocks.lua b/luci-app-passwall2/luasrc/passwall2/util_shadowsocks.lua index 83bafd917..0a47ef2dc 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_shadowsocks.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_shadowsocks.lua @@ -78,7 +78,7 @@ function gen_config(var) fast_open = (node.tcp_fast_open and node.tcp_fast_open == "1") and true or false, reuse_port = true } - + if node.type == "SSR" then config.protocol = node.protocol config.protocol_param = node.protocol_param @@ -115,7 +115,7 @@ function gen_config(var) }) end end - + return jsonc.stringify(config, 1) end diff --git a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua index 5f6e8b27d..a73d89494 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua @@ -1730,7 +1730,7 @@ function gen_config(var) end end end - + local rule = { action = "route", inbound = inboundTag, @@ -2326,7 +2326,7 @@ function gen_config(var) table.insert(route.rule_set, v) end end - + if inbounds or outbounds then local config = { log = { @@ -2468,7 +2468,7 @@ function gen_proto_config(var) } if outbound then table.insert(outbounds, outbound) end end - + local config = { log = { disabled = true, diff --git a/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/luci-app-passwall2/luasrc/passwall2/util_xray.lua index bf3d63707..1a03a2164 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -115,7 +115,7 @@ function gen_outbound(flag, node, tag, proxy_table) else dialer_proxy_tag = proxy_tag end - + if node.type == "Xray" then if node.tls and node.tls == "1" then node.stream_security = "tls" @@ -982,7 +982,7 @@ function gen_config(var) local routing = nil local observatory = nil local burstObservatory = nil - local strategy = nil + local strategy = nil local COMMON = {} local CACHE_TEXT_FILE = CACHE_PATH .. "/cache_" .. flag .. ".txt" @@ -1253,7 +1253,7 @@ function gen_config(var) table.insert(rules, { inboundTag = { inbound_tag }, balancerTag = balancer_tag }) return balancer_tag, loopback_outbound end - + function set_outbound_detour(node, outbound, outbounds_table) if not node or not outbound or not outbounds_table then return nil end local default_outTag = outbound.tag @@ -1684,7 +1684,7 @@ function gen_config(var) rules = {} } end - + local dns_host = "" if flag == "global" then dns_host = api.uci_get_c("@global[0]", "dns_hosts") or "" @@ -1708,7 +1708,7 @@ function gen_config(var) end end) end - + local _remote_dns = { tag = remote_dns_tag, queryStrategy = (remote_dns_query_strategy and remote_dns_query_strategy ~= "") and remote_dns_query_strategy or "UseIPv4" @@ -1858,12 +1858,12 @@ function gen_config(var) outboundTag = "dns-out" }) end - + local default_dns_tag_name = remote_dns_tag if not COMMON.default_outbound_tag or COMMON.default_outbound_tag == "direct" then default_dns_tag_name = direct_dns_tag end - + if dns_servers and #dns_servers > 0 then -- Default DNS logic local default_dns_server = nil @@ -2064,7 +2064,7 @@ function gen_config(var) udp_inbound.settings.allowedNetwork = "udp" table.insert(inbounds, udp_inbound) end - + if inbounds or outbounds then local config = { env = (function() @@ -2138,7 +2138,7 @@ function gen_config(var) for index, value in ipairs(config.outbounds) do local s = value.settings if not value["_flag_proxy_tag"] and value["_id"] and s and not NO_RUN and - ((s.vnext and s.vnext[1] and s.vnext[1].address and s.vnext[1].port) or + ((s.vnext and s.vnext[1] and s.vnext[1].address and s.vnext[1].port) or (s.servers and s.servers[1] and s.servers[1].address and s.servers[1].port) or (s.peers and s.peers[1] and s.peers[1].endpoint) or (s.address and s.port)) then @@ -2168,7 +2168,7 @@ function gen_proto_config(var) local server_port = var["server_port"] local server_username = var["server_username"] local server_password = var["server_password"] - + local inbounds = {} local outbounds = {} local routing = nil @@ -2194,7 +2194,7 @@ function gen_proto_config(var) end table.insert(inbounds, inbound) end - + if local_http_address and local_http_port then local inbound = { listen = local_http_address, @@ -2214,7 +2214,7 @@ function gen_proto_config(var) end table.insert(inbounds, inbound) end - + if server_proto ~= "nil" and server_address ~= "nil" and server_port ~= "nil" then local outbound = { protocol = server_proto, @@ -2250,7 +2250,7 @@ function gen_proto_config(var) sockopt = {mark = 255} } }) - + local config = { log = { loglevel = "warning" diff --git a/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_dynamiclist_com.htm b/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_dynamiclist_com.htm index 4f932a215..38594857b 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_dynamiclist_com.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_dynamiclist_com.htm @@ -175,7 +175,7 @@ const ctx = canvas.getContext('2d', { willReadFrequently: true }); return function(colorStr) { if (!colorStr) - return null; + return null; ctx.clearRect(0, 0, 1, 1); // 2. Apply the color ctx.fillStyle = colorStr; @@ -213,7 +213,7 @@ if (!rgb) return 'unknown'; // Handle invalid colors // Calculate YIQ brightness (human eye perception) const brightness = ((rgb.r * 299) + (rgb.g * 587) + (rgb.b * 114)) / 1000; - + return brightness > 128 ? 'light' : 'dark'; } diff --git a/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_listvalue_com.htm b/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_listvalue_com.htm index 2a066287b..30de14bb8 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_listvalue_com.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_listvalue_com.htm @@ -169,7 +169,7 @@ const ctx = canvas.getContext('2d', { willReadFrequently: true }); return function(colorStr) { if (!colorStr) - return null; + return null; ctx.clearRect(0, 0, 1, 1); // 2. Apply the color ctx.fillStyle = colorStr; diff --git a/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_multivalue.htm b/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_multivalue.htm index fabcf77e9..8e52206cb 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_multivalue.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_multivalue.htm @@ -35,10 +35,10 @@ local groups = {} local group_order = {} for _, item in ipairs(values) do local g = item.group - if not g or g == "" then - g = translate("default") + if not g or g == "" then + g = translate("default") end - if not groups[g] then + if not groups[g] then groups[g] = {} table.insert(group_order, g) end diff --git a/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_multivalue_com.htm b/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_multivalue_com.htm index 646f691b4..9d22aeefa 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_multivalue_com.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_multivalue_com.htm @@ -125,7 +125,7 @@ const ctx = canvas.getContext('2d', { willReadFrequently: true }); return function(colorStr) { if (!colorStr) - return null; + return null; ctx.clearRect(0, 0, 1, 1); // 2. Apply the color ctx.fillStyle = colorStr; @@ -163,7 +163,7 @@ if (!rgb) return 'unknown'; // Handle invalid colors // Calculate YIQ brightness (human eye perception) const brightness = ((rgb.r * 299) + (rgb.g * 587) + (rgb.b * 114)) / 1000; - + return brightness > 128 ? 'light' : 'dark'; } @@ -258,7 +258,7 @@ const keyword = searchInput.value.trim().toLowerCase(); const isSearching = keyword.length > 0; // 当前实例下的所有 checkbox - const cbs = isSearching + const cbs = isSearching ? Array.from(nodeList.querySelectorAll("input[type=checkbox]")).filter(cb => cb.closest("li").style.display !== "none") : nodeList.querySelectorAll("input[type=checkbox]"); let checked = 0; diff --git a/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_value.htm b/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_value.htm index 7fe732073..e09e9bce2 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_value.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_value.htm @@ -137,7 +137,7 @@ local dropdown_data = {
- +
diff --git a/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_value_com.htm b/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_value_com.htm index 0c5f5c02c..920601c50 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_value_com.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/cbi/nodes_value_com.htm @@ -164,7 +164,7 @@ const ctx = canvas.getContext('2d', { willReadFrequently: true }); return function(colorStr) { if (!colorStr) - return null; + return null; ctx.clearRect(0, 0, 1, 1); // 2. Apply the color ctx.fillStyle = colorStr; diff --git a/luci-app-passwall2/luasrc/view/passwall2/cbi/sortable.htm b/luci-app-passwall2/luasrc/view/passwall2/cbi/sortable.htm index 2f90bf8c7..45c0fcf74 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/cbi/sortable.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/cbi/sortable.htm @@ -36,7 +36,7 @@ local appname = self.appname or map.config background-color: rgba(131, 191, 255, 0.7) !important; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } - + @media screen and (max-width: 1152px) { #cbi-<%=appname%>-<%=sectiontype%> .cbi-section-table-titles { display: none !important; @@ -116,7 +116,7 @@ local appname = self.appname or map.config hiddenInput.value = changed ? newOrder.join(" ") : ""; } } - + // hide lua luci version up/down function hideSortColumn(section) { var table = section.getElementsByTagName("table")[0]; diff --git a/luci-app-passwall2/luasrc/view/passwall2/global/backup.htm b/luci-app-passwall2/luasrc/view/passwall2/global/backup.htm index dc13e726d..f53c66366 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/global/backup.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/global/backup.htm @@ -153,7 +153,7 @@ local api = map.api if (confirm("<%: Are you sure you want to restore the client to default settings?%>")) { const xhr = new XMLHttpRequest(); xhr.open("GET",'<%= api.url("reset_config") %>', false); - xhr.send(); + xhr.send(); window.location.href = '<%= api.url("log") %>' } }, 1000); diff --git a/luci-app-passwall2/luasrc/view/passwall2/global/faq.htm b/luci-app-passwall2/luasrc/view/passwall2/global/faq.htm index 60044c8a0..416ec5084 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/global/faq.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/global/faq.htm @@ -4,25 +4,25 @@ local api = map.api -%> {% endif -%}