From 5ab68705647e4de0949567c514379ef374e58c6f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 22 Jun 2026 01:15:34 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8F=85=20Sync=202026-06-22=2001:15:34?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dae/Makefile | 2 +- dae/files/dae.init | 13 + daed/Makefile | 2 +- daed/files/daed.init | 16 +- gecoosac/Makefile | 47 +- gecoosac/files/etc/init.d/gecoosac | 11 +- luci-app-daede/Makefile | 4 +- .../resources/view/daede/config.js | 9 +- .../luci-static/resources/view/daede/dae.js | 17 + .../luci-static/resources/view/daede/daed.js | 2 +- .../resources/view/daede/styles.js | 3 +- .../resources/view/daede/updates.js | 12 +- luci-app-daede/po/zh-cn/daede.po | 22 +- luci-app-daede/po/zh_Hans/daede.po | 22 +- luci-app-passwall/Makefile | 2 +- .../root/usr/share/passwall/nftables.sh | 20 +- luci-app-run/Makefile | 12 +- .../luci-static/resources/view/run/index.js | 32 +- .../root/usr/libexec/rpcd/luci-app-run | 503 ++++----- luci-app-ssr-plus/Makefile | 14 +- .../luasrc/controller/shadowsocksr.lua | 87 ++ .../model/cbi/shadowsocksr/client-config.lua | 42 +- .../model/cbi/shadowsocksr/server-config.lua | 56 +- .../luasrc/model/cbi/shadowsocksr/servers.lua | 21 + .../luasrc/model/cbi/shadowsocksr/status.lua | 6 +- .../luasrc/view/shadowsocksr/log.htm | 4 +- .../view/shadowsocksr/server_header.htm | 78 ++ .../luasrc/view/shadowsocksr/server_list.htm | 4 +- .../luasrc/view/shadowsocksr/server_table.htm | 2 +- .../luasrc/view/shadowsocksr/ssrurl.htm | 61 +- .../shadowsocksr/subscribe_actions_footer.htm | 55 +- luci-app-ssr-plus/po/templates/ssr-plus.pot | 945 +++++++++-------- luci-app-ssr-plus/po/zh_Hans/ssr-plus.po | 951 ++++++++++-------- .../root/etc/init.d/shadowsocksr | 324 ++++-- .../root/etc/uci-defaults/luci-ssr-plus | 7 + luci-app-ssr-plus/root/usr/bin/ssr-switch | 28 +- .../usr/share/shadowsocksr/clash_yaml.lua | 475 ++++++++- .../usr/share/shadowsocksr/gen_config.lua | 56 +- .../share/shadowsocksr/shadowsocksr.config | 2 +- .../root/usr/share/shadowsocksr/subscribe.lua | 637 +++++++++++- natflow/Makefile | 4 +- 41 files changed, 3203 insertions(+), 1407 deletions(-) create mode 100644 luci-app-ssr-plus/luasrc/view/shadowsocksr/server_header.htm diff --git a/dae/Makefile b/dae/Makefile index 80828161..0b01a497 100644 --- a/dae/Makefile +++ b/dae/Makefile @@ -4,7 +4,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dae PKG_VERSION:=2026.06.14 -PKG_RELEASE:=10 +PKG_RELEASE:=11 PKG_SOURCE:=dae-src-2026.06.14-fa89ea7197a5.tar.gz PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/dae-src diff --git a/dae/files/dae.init b/dae/files/dae.init index 4feb5f41..7650ff13 100644 --- a/dae/files/dae.init +++ b/dae/files/dae.init @@ -46,6 +46,19 @@ start_service() { stop_service() { rm -rf "$LOG_DIR" + # kill lingering procs in daens: TERM first, then KILL for stubborn ones + for pid in $(ip netns pids daens 2>/dev/null); do kill "$pid" 2>/dev/null; done + if [ -n "$(ip netns pids daens 2>/dev/null)" ]; then + sleep 1 + for pid in $(ip netns pids daens 2>/dev/null); do kill -9 "$pid" 2>/dev/null; done + fi + # cleanup daens netns; ip-full needed for netns, busybox fallback via umount + if ! ip netns del daens 2>/dev/null; then + umount /run/netns/daens 2>/dev/null + rm -f /run/netns/daens + fi + # clean orphaned dae0 + ip link del dae0 2>/dev/null || true } service_triggers() { diff --git a/daed/Makefile b/daed/Makefile index 04aec5a4..c17ecc55 100644 --- a/daed/Makefile +++ b/daed/Makefile @@ -4,7 +4,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=daed PKG_VERSION:=2026.06.14 -PKG_RELEASE:=11 +PKG_RELEASE:=12 PKG_SOURCE:=daed-src-2026.06.14-4e215048068a.tar.gz PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/daed-src diff --git a/daed/files/daed.init b/daed/files/daed.init index 415809a4..623683a0 100644 --- a/daed/files/daed.init +++ b/daed/files/daed.init @@ -40,9 +40,19 @@ start_service() { stop_service() { rm -f "$LOG" - # daed creates /run/netns/daens on start; a stale entry makes the next - # start fail with "failed to create netns: ... file exists". Clean it here. - ip netns del daens 2>/dev/null || true + # kill lingering procs in daens: TERM first, then KILL for stubborn ones + for pid in $(ip netns pids daens 2>/dev/null); do kill "$pid" 2>/dev/null; done + if [ -n "$(ip netns pids daens 2>/dev/null)" ]; then + sleep 1 + for pid in $(ip netns pids daens 2>/dev/null); do kill -9 "$pid" 2>/dev/null; done + fi + # cleanup daens netns; ip-full needed for netns, busybox fallback via umount + if ! ip netns del daens 2>/dev/null; then + umount /run/netns/daens 2>/dev/null + rm -f /run/netns/daens + fi + # clean orphaned dae0 + ip link del dae0 2>/dev/null || true } service_triggers() { diff --git a/gecoosac/Makefile b/gecoosac/Makefile index 5bddf9d9..72a851f3 100644 --- a/gecoosac/Makefile +++ b/gecoosac/Makefile @@ -2,38 +2,40 @@ include $(TOPDIR)/rules.mk PKG_NAME:=gecoosac PKG_VERSION:=2.2.20251015 -PKG_RELEASE:=12 +PKG_RELEASE:=13 -ifeq ($(ARCH),aarch64) +PKG_MAINTAINER:=lwb1978 +PKG_LICENSE:=AGPL-3.0-only +PKG_LICENSE_FILES:=LICENSE + +ARCH_ID:=$(strip $(if $(ARCH_PACKAGES),$(ARCH_PACKAGES),$(ARCH))) + +ifneq (,$(filter x86_64,$(ARCH_ID))) + PKG_ARCH:=ac_linux_amd64 + PKG_HASH:=skip +else ifneq (,$(filter aarch64%,$(ARCH_ID))) PKG_ARCH:=ac_linux_arm64 PKG_HASH:=skip -else ifeq ($(ARCH),arm) +else ifneq (,$(filter arm%,$(ARCH_ID))) PKG_ARCH:=ac_linux_arm PKG_HASH:=skip -else ifeq ($(ARCH),mips) - PKG_ARCH:=ac_linux_mips - PKG_HASH:=skip -else ifeq ($(ARCH),mipsel) +else ifneq (,$(filter mipsel%,$(ARCH_ID))) PKG_ARCH:=ac_linux_mipsle PKG_HASH:=skip -else ifeq ($(ARCH),i386) - PKG_ARCH:=ac_linux_386 +else ifneq (,$(filter mips%,$(ARCH_ID))) + PKG_ARCH:=ac_linux_mips PKG_HASH:=skip -else ifeq ($(ARCH),x86_64) - PKG_ARCH:=ac_linux_amd64 +else ifneq (,$(filter i386%,$(ARCH_ID))) + PKG_ARCH:=ac_linux_386 PKG_HASH:=skip else PKG_HASH:=skip endif -PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(ARCH_PACKAGES) +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(ARCH_ID) PKG_SOURCE_URL:=https://github.com/laipeng668/luci-app-gecoosac/releases/download/V$(PKG_VERSION)/$(PKG_ARCH)? UNPACK_CMD=$(CP) $(DL_DIR)/$(PKG_SOURCE) $(PKG_BUILD_DIR)/$(PKG_NAME) -PKG_LICENSE:=AGPL-3.0-only -PKG_LICENSE_FILES:=LICENSE -PKG_MAINTAINER:=lwb1978 - include $(INCLUDE_DIR)/package.mk define Package/$(PKG_NAME) @@ -59,14 +61,15 @@ endef define Package/$(PKG_NAME)/install $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(PKG_NAME) $(1)/usr/bin - $(INSTALL_DIR) $(1)/etc/init.d - $(INSTALL_BIN) ./files/etc/init.d/gecoosac $(1)/etc/init.d/gecoosac $(INSTALL_DIR) $(1)/etc/config - $(INSTALL_CONF) ./files/etc/config/gecoosac $(1)/etc/config/gecoosac - $(INSTALL_DIR) $(1)/etc/uci-defaults - $(INSTALL_BIN) ./files/etc/uci-defaults/gecoosac $(1)/etc/uci-defaults/gecoosac $(INSTALL_DIR) $(1)/etc/gecoosac/tls + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_DIR) $(1)/etc/uci-defaults + + $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(PKG_NAME) $(1)/usr/bin + $(INSTALL_BIN) ./files/etc/init.d/gecoosac $(1)/etc/init.d/gecoosac + $(INSTALL_BIN) ./files/etc/uci-defaults/gecoosac $(1)/etc/uci-defaults/gecoosac + $(INSTALL_CONF) ./files/etc/config/gecoosac $(1)/etc/config/gecoosac endef $(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/gecoosac/files/etc/init.d/gecoosac b/gecoosac/files/etc/init.d/gecoosac index 67629e4f..580e5cf0 100644 --- a/gecoosac/files/etc/init.d/gecoosac +++ b/gecoosac/files/etc/init.d/gecoosac @@ -318,6 +318,8 @@ ensure_dirs() { } start_service() { + local runtime_upload_dir runtime_db_dir runtime_piddir + init_conf normalize_conf @@ -333,6 +335,9 @@ start_service() { fi ensure_dirs || return 1 + runtime_upload_dir="${upload_dir%/}/" + runtime_db_dir="${db_dir%/}/" + runtime_piddir="${piddir%/}/" if [ "$isonlyoneprot" = "0" ] && [ "$https" = "1" ]; then if [ "$crt_file" = "$DEFAULT_CRT_FILE" ] && [ "$key_file" = "$DEFAULT_KEY_FILE" ]; then @@ -352,13 +357,13 @@ start_service() { procd_open_instance gecoosac procd_set_param command "$PROG" - procd_append_param command -f "$upload_dir" + procd_append_param command -f "$runtime_upload_dir" procd_append_param command -p "$port" procd_append_param command -debug "$debug" - procd_append_param command -dbpath "$db_dir" + procd_append_param command -dbpath "$runtime_db_dir" procd_append_param command -token "1" procd_append_param command -lang "$lang" - procd_append_param command -piddir "$piddir" + procd_append_param command -piddir "$runtime_piddir" if [ "$isonlyoneprot" = "0" ]; then procd_append_param command -isonlyoneprot "0" procd_append_param command -mp "$m_port" diff --git a/luci-app-daede/Makefile b/luci-app-daede/Makefile index aff5c614..c7135162 100644 --- a/luci-app-daede/Makefile +++ b/luci-app-daede/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-daede -PKG_VERSION:=1.14.1 -PKG_RELEASE:=20 +PKG_VERSION:=1.14.6 +PKG_RELEASE:=21 PKG_MAINTAINER:=kenzok8 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) diff --git a/luci-app-daede/htdocs/luci-static/resources/view/daede/config.js b/luci-app-daede/htdocs/luci-static/resources/view/daede/config.js index 91708388..bb83ec1b 100644 --- a/luci-app-daede/htdocs/luci-static/resources/view/daede/config.js +++ b/luci-app-daede/htdocs/luci-static/resources/view/daede/config.js @@ -2,6 +2,7 @@ 'use strict'; 'require uci'; +'require network'; 'require view'; 'require view.daede.backend as backend'; 'require view.daede.styles as styles'; @@ -13,7 +14,13 @@ return view.extend({ _loadContext: function() { return backend.detectBackend().then(function(ctx) { return uci.load(ctx.backend.uci).catch(function() {}).then(function() { - return ctx; + /* enumerate L3 devices so the dae LAN/WAN fields offer a dropdown + (still free-text, so undetectable WANs can be typed) */ + return network.getDevices().catch(function() { return []; }).then(function(devs) { + ctx.netDevs = (devs || []).map(function(d) { return d.getName(); }) + .filter(function(n) { return n && n !== 'dae0'; }).sort(); + return ctx; + }); }); }); }, diff --git a/luci-app-daede/htdocs/luci-static/resources/view/daede/dae.js b/luci-app-daede/htdocs/luci-static/resources/view/daede/dae.js index 970b6f00..12aacf16 100644 --- a/luci-app-daede/htdocs/luci-static/resources/view/daede/dae.js +++ b/luci-app-daede/htdocs/luci-static/resources/view/daede/dae.js @@ -327,6 +327,23 @@ function renderDaeForms(ctx) { /* Logging — folded into the main form so the single Save button covers it too (no separate native save bar) */ + /* Network interfaces — override dae auto WAN detect, fails on legacy swconfig (#15). + Combobox: dropdown of real devices but still free-text for undetectable WANs */ + const netDevs = (ctx && ctx.netDevs) || []; + s = m.section(form.NamedSection, 'config', 'dae', _('Network interfaces')); + s.addremove = false; + o = s.option(form.Value, 'lan_interface', _('LAN interface'), + _('Interface to proxy the LAN from. Usually br-lan.')); + o.default = 'br-lan'; + o.placeholder = 'br-lan'; + netDevs.forEach(function(d) { o.value(d); }); + o = s.option(form.Value, 'wan_interface', _('WAN interface'), + _('Uplink. auto = detect by default route; on legacy swconfig or multi-WAN set it, e.g. eth0.2.')); + o.default = 'auto'; + o.placeholder = 'auto'; + o.value('auto', 'auto'); + netDevs.forEach(function(d) { o.value(d); }); + s = m.section(form.NamedSection, 'config', 'dae', _('Logging')); s.addremove = false; o = s.option(form.Value, 'log_maxsize', _('Max Log Size (MB)'), diff --git a/luci-app-daede/htdocs/luci-static/resources/view/daede/daed.js b/luci-app-daede/htdocs/luci-static/resources/view/daede/daed.js index 07e86c35..7ad11d7c 100644 --- a/luci-app-daede/htdocs/luci-static/resources/view/daede/daed.js +++ b/luci-app-daede/htdocs/luci-static/resources/view/daede/daed.js @@ -33,7 +33,7 @@ function renderDaedSettings() { _('daede Settings'), null, m.render(), - _('Log Advanced Settings'), + _('Log Settings'), ['log_maxsize', 'log_maxbackups'] ).then(function(card) { /* native Save/Apply footer is suppressed view-wide, so daed carries its diff --git a/luci-app-daede/htdocs/luci-static/resources/view/daede/styles.js b/luci-app-daede/htdocs/luci-static/resources/view/daede/styles.js index e4a2f799..954bdf0e 100644 --- a/luci-app-daede/htdocs/luci-static/resources/view/daede/styles.js +++ b/luci-app-daede/htdocs/luci-static/resources/view/daede/styles.js @@ -72,7 +72,7 @@ const CSS = [ '.dd-settings-card .cbi-section-remove .cbi-button{border-color:#d96d6d !important;color:#d96d6d !important}', /* themes (esp. Argon) restyle checkboxes into faint, near-invisible boxes; force native rendering + brand accent so the checkmark is always clear */ - '.dd-settings-card input[type="checkbox"]{-webkit-appearance:checkbox !important;appearance:checkbox !important;accent-color:#4aa065;width:16px;height:16px;background:none !important;border:0 !important;box-shadow:none !important;background-image:none !important}', + '.dd-settings-card input[type="checkbox"]{-webkit-appearance:checkbox !important;appearance:checkbox !important;width:16px;height:16px;background:none !important;border:0 !important;box-shadow:none !important;background-image:none !important}', '.dd-settings-card input[type="checkbox"]:before,.dd-settings-card input[type="checkbox"]:after{content:none !important;display:none !important}', /* line the Subscriptions and Nodes grid tables up column-for-column. fixed layout + explicit per-column percentages make the widths authoritative @@ -210,6 +210,7 @@ const CSS = [ '.dd-conv-import,.dd-conv-toolbar,.dd-conv-heading{display:flex;align-items:center;gap:8px;flex-wrap:wrap}', '.dd-converter input,.dd-converter select,.dd-converter .cbi-button{box-sizing:border-box!important;height:32px!important;min-height:32px!important;margin:0!important;font-size:12px!important;line-height:22px!important}', '.dd-converter input,.dd-converter select{padding:4px 8px!important;border:1px solid rgba(128,128,128,.28)!important;border-radius:6px!important;background-color:transparent;color:inherit;box-shadow:none!important}', + '.dd-converter input::placeholder,.dd-conv-yaml::placeholder,.dd-conv-filter::placeholder,.dd-conv-airport-name::placeholder{color:inherit;opacity:.55}', '.dd-converter select{padding-right:28px!important}', '.dd-converter .cbi-button{padding:4px 12px!important}', '.dd-conv-url-row input,.dd-conv-filter,.dd-conv-target,.dd-conv-ua,.dd-conv-yaml{box-sizing:border-box;border:1px solid rgba(128,128,128,.28);border-radius:6px;background:transparent;color:inherit;font-size:12px;padding:7px 9px}', diff --git a/luci-app-daede/htdocs/luci-static/resources/view/daede/updates.js b/luci-app-daede/htdocs/luci-static/resources/view/daede/updates.js index d73cc859..29756728 100644 --- a/luci-app-daede/htdocs/luci-static/resources/view/daede/updates.js +++ b/luci-app-daede/htdocs/luci-static/resources/view/daede/updates.js @@ -55,9 +55,11 @@ const CSS = [ '.dd-geo-row{display:grid;grid-template-columns:96px 1fr;gap:10px;align-items:center;font-size:12px;padding:6px 0}', '.dd-geo-row label{opacity:.75;font-weight:600}', '.dd-geo-row input[type=text],.dd-geo-row select{font-size:12px;padding:4px 8px;border:1px solid rgba(128,128,128,.35);border-radius:5px;background:transparent;color:inherit;width:100%}', - /* fixed width so the Source and Auto-update selects line up consistently */ - '.dd-geo-row select{width:180px;flex:0 0 auto}', - '.dd-geo-chk{display:flex;align-items:center;gap:6px}', + /* selects cap at 200px on wide screens, shrink to the column on mobile (no overflow) */ + '.dd-geo-row select{width:100%!important;max-width:200px;box-sizing:border-box}', + '.dd-geo-auto{display:inline-flex;align-items:center;gap:6px}', + /* Argon shifts label>checkbox down (top:.4rem); reset so flex centers it */ + '.dd-geo-auto input[type="checkbox"]{position:static;top:auto;right:auto;margin:0}', '.dd-geo-actions{margin-top:10px;display:flex;gap:10px;align-items:center}', '.dd-up-log{margin-top:10px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:11px;padding:10px;border:1px solid rgba(128,128,128,.14);border-radius:8px;max-height:200px;overflow:auto;white-space:pre-wrap;word-break:break-all;display:none;background:inherit;color:#4a8c63}', '.dd-up-log.show{display:block}', @@ -473,8 +475,8 @@ return view.extend({ E('div', { 'class': 'dd-geo-row' }, [ E('label', {}, _('Source')), presetSel ]), customRows, E('div', { 'class': 'dd-geo-row' }, [ - E('label', {}, _('Auto-update')), - E('div', { 'class': 'dd-geo-chk' }, [ autoCb, freqSel ]) + E('label', { 'class': 'dd-geo-auto' }, [ E('span', {}, _('Auto-update')), autoCb ]), + freqSel ]), E('div', { 'class': 'dd-geo-actions' }, [ saveBtn ]) ]) diff --git a/luci-app-daede/po/zh-cn/daede.po b/luci-app-daede/po/zh-cn/daede.po index e6ef851b..552204c8 100644 --- a/luci-app-daede/po/zh-cn/daede.po +++ b/luci-app-daede/po/zh-cn/daede.po @@ -117,8 +117,8 @@ msgstr "保留旧日志数" msgid "Number of rotated log files to keep." msgstr "轮转后保留的旧日志文件数。" -msgid "Log Advanced Settings" -msgstr "日志高级设置" +msgid "Log Settings" +msgstr "日志设置" # ---- config.js: dae Settings ---- msgid "dae Parameters" @@ -1014,3 +1014,21 @@ msgid "" "%s is running. Deleting the daens netns now will break its networking until " "you restart it. Continue?" msgstr "%s 正在运行。现在删除 daens netns 会中断其网络,直到重启它。确定继续?" + +# ---- dae.js: Network interfaces ---- +msgid "Network interfaces" +msgstr "网络接口" + +msgid "LAN interface" +msgstr "LAN 接口" + +msgid "WAN interface" +msgstr "WAN 接口" + +msgid "Interface to proxy the LAN from. Usually br-lan." +msgstr "要绑定的 LAN 接口,通常是 br-lan。" + +msgid "" +"Uplink. auto = detect by default route; on legacy swconfig or multi-WAN set " +"it, e.g. eth0.2." +msgstr "上行 WAN 接口。auto 按默认路由自动检测;老式 swconfig 交换机或多 WAN 时手动指定,例如 eth0.2。" diff --git a/luci-app-daede/po/zh_Hans/daede.po b/luci-app-daede/po/zh_Hans/daede.po index e6ef851b..552204c8 100644 --- a/luci-app-daede/po/zh_Hans/daede.po +++ b/luci-app-daede/po/zh_Hans/daede.po @@ -117,8 +117,8 @@ msgstr "保留旧日志数" msgid "Number of rotated log files to keep." msgstr "轮转后保留的旧日志文件数。" -msgid "Log Advanced Settings" -msgstr "日志高级设置" +msgid "Log Settings" +msgstr "日志设置" # ---- config.js: dae Settings ---- msgid "dae Parameters" @@ -1014,3 +1014,21 @@ msgid "" "%s is running. Deleting the daens netns now will break its networking until " "you restart it. Continue?" msgstr "%s 正在运行。现在删除 daens netns 会中断其网络,直到重启它。确定继续?" + +# ---- dae.js: Network interfaces ---- +msgid "Network interfaces" +msgstr "网络接口" + +msgid "LAN interface" +msgstr "LAN 接口" + +msgid "WAN interface" +msgstr "WAN 接口" + +msgid "Interface to proxy the LAN from. Usually br-lan." +msgstr "要绑定的 LAN 接口,通常是 br-lan。" + +msgid "" +"Uplink. auto = detect by default route; on legacy swconfig or multi-WAN set " +"it, e.g. eth0.2." +msgstr "上行 WAN 接口。auto 按默认路由自动检测;老式 swconfig 交换机或多 WAN 时手动指定,例如 eth0.2。" diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index dc9fc1b5..7086e4c7 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.6.2 -PKG_RELEASE:=162 +PKG_RELEASE:=163 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall/root/usr/share/passwall/nftables.sh b/luci-app-passwall/root/usr/share/passwall/nftables.sh index 3944df4e..14039fd4 100755 --- a/luci-app-passwall/root/usr/share/passwall/nftables.sh +++ b/luci-app-passwall/root/usr/share/passwall/nftables.sh @@ -905,7 +905,7 @@ add_firewall_rule() { #echolog "使用缓存加载chnroute..." nft -f $RULES_PATH/chnroute.nft else - cat $RULES_PATH/chnroute | tr -s '\n' | grep -v "^#" | gen_nftset $NFTSET_CHN ipv4_addr "2d" 0 + cat $RULES_PATH/chnroute | tr -s '\n' | sed 's/#.*//' | gen_nftset $NFTSET_CHN ipv4_addr "2d" 0 fi gen_nftset $NFTSET_BLACK ipv4_addr "2d" 0 gen_nftset $NFTSET_WHITE ipv4_addr "2d" 0 @@ -921,7 +921,7 @@ add_firewall_rule() { #echolog "使用缓存加载chnroute6..." nft -f $RULES_PATH/chnroute6.nft else - cat $RULES_PATH/chnroute6 | tr -s '\n' | grep -v "^#" | gen_nftset $NFTSET_CHN6 ipv6_addr "2d" 0 + cat $RULES_PATH/chnroute6 | tr -s '\n' | sed 's/#.*//' | gen_nftset $NFTSET_CHN6 ipv6_addr "2d" 0 fi gen_nftset $NFTSET_BLACK6 ipv6_addr "2d" 0 gen_nftset $NFTSET_WHITE6 ipv6_addr "2d" 0 @@ -957,8 +957,8 @@ add_firewall_rule() { #直连列表 [ "$USE_DIRECT_LIST_ALL" = "1" ] && { - cat $RULES_PATH/direct_ip | grep -v "^#" | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | insert_nftset $NFTSET_WHITE "0" - cat $RULES_PATH/direct_ip | grep -v "^#" | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | insert_nftset $NFTSET_WHITE6 "0" + cat $RULES_PATH/direct_ip | sed 's/#.*//' | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | insert_nftset $NFTSET_WHITE "0" + cat $RULES_PATH/direct_ip | sed 's/#.*//' | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | insert_nftset $NFTSET_WHITE6 "0" [ "$USE_GEOVIEW" = "1" ] && { local GEOIP_CODE=$(cat $RULES_PATH/direct_ip | tr -s "\r\n" "\n" | sed -e "/^$/d" | grep -E "^geoip:" | grep -v "^geoip:private" | sed -E 's/^geoip:(.*)/\1/' | sed ':a;N;$!ba;s/\n/,/g') if [ -n "$GEOIP_CODE" ]; then @@ -971,8 +971,8 @@ add_firewall_rule() { #代理列表 [ "$USE_PROXY_LIST_ALL" = "1" ] && { - cat $RULES_PATH/proxy_ip | grep -v "^#" | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | insert_nftset $NFTSET_BLACK "0" - cat $RULES_PATH/proxy_ip | grep -v "^#" | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | insert_nftset $NFTSET_BLACK6 "0" + cat $RULES_PATH/proxy_ip | sed 's/#.*//' | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | insert_nftset $NFTSET_BLACK "0" + cat $RULES_PATH/proxy_ip | sed 's/#.*//' | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | insert_nftset $NFTSET_BLACK6 "0" [ "$USE_GEOVIEW" = "1" ] && { local GEOIP_CODE=$(cat $RULES_PATH/proxy_ip | tr -s "\r\n" "\n" | sed -e "/^$/d" | grep -E "^geoip:" | grep -v "^geoip:private" | sed -E 's/^geoip:(.*)/\1/' | sed ':a;N;$!ba;s/\n/,/g') if [ -n "$GEOIP_CODE" ]; then @@ -985,8 +985,8 @@ add_firewall_rule() { #屏蔽列表 [ "$USE_BLOCK_LIST_ALL" = "1" ] && { - cat $RULES_PATH/block_ip | grep -v "^#" | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | insert_nftset $NFTSET_BLOCK "0" - cat $RULES_PATH/block_ip | grep -v "^#" | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | insert_nftset $NFTSET_BLOCK6 "0" + cat $RULES_PATH/block_ip | sed 's/#.*//' | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | insert_nftset $NFTSET_BLOCK "0" + cat $RULES_PATH/block_ip | sed 's/#.*//' | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | insert_nftset $NFTSET_BLOCK6 "0" [ "$USE_GEOVIEW" = "1" ] && { local GEOIP_CODE=$(cat $RULES_PATH/block_ip | tr -s "\r\n" "\n" | sed -e "/^$/d" | grep -E "^geoip:" | grep -v "^geoip:private" | sed -E 's/^geoip:(.*)/\1/' | sed ':a;N;$!ba;s/\n/,/g') if [ -n "$GEOIP_CODE" ]; then @@ -1002,8 +1002,8 @@ add_firewall_rule() { local GEOIP_CODE="" local shunt_ids=$(uci show $CONFIG | grep "=shunt_rules" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}') for shunt_id in $shunt_ids; do - config_n_get $shunt_id ip_list | grep -v "^#" | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | insert_nftset $NFTSET_SHUNT "0" - config_n_get $shunt_id ip_list | grep -v "^#" | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | insert_nftset $NFTSET_SHUNT6 "0" + config_n_get $shunt_id ip_list | sed 's/#.*//' | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | insert_nftset $NFTSET_SHUNT "0" + config_n_get $shunt_id ip_list | sed 's/#.*//' | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | insert_nftset $NFTSET_SHUNT6 "0" [ "$USE_GEOVIEW" = "1" ] && { local geoip_code=$(config_n_get $shunt_id ip_list | tr -s "\r\n" "\n" | sed -e "/^$/d" | grep -E "^geoip:" | grep -v "^geoip:private" | sed -E 's/^geoip:(.*)/\1/' | sed ':a;N;$!ba;s/\n/,/g') [ -n "$geoip_code" ] && GEOIP_CODE="${GEOIP_CODE:+$GEOIP_CODE,}$geoip_code" diff --git a/luci-app-run/Makefile b/luci-app-run/Makefile index 0c7d1a14..7487dd5f 100644 --- a/luci-app-run/Makefile +++ b/luci-app-run/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-run PKG_VERSION:=1.0.0 -PKG_RELEASE:=3 +PKG_RELEASE:=4 LUCI_TITLE:=LuCI support for running makeself .run installers LUCI_DESCRIPTION:=Upload and execute makeself-generated .run installers from LuCI. @@ -11,8 +11,14 @@ LUCI_PKGARCH:=all PKG_MAINTAINER:=wukongdaily <2666180@gmail.com> - +# 定义版本号用于缓存刷新 +define Package/luci-app-run/postinst +#!/bin/sh +# 设置版本号到临时文件,用于前端资源缓存刷新 +echo "$(PKG_VERSION)-$(PKG_RELEASE)" > /tmp/luci-app-run.version +exit 0 +endef include $(TOPDIR)/feeds/luci/luci.mk -# call BuildPackage - OpenWrt buildroot signature +# call BuildPackage - OpenWrt buildroot signature \ No newline at end of file diff --git a/luci-app-run/htdocs/luci-static/resources/view/run/index.js b/luci-app-run/htdocs/luci-static/resources/view/run/index.js index b9ca8986..67352a8e 100644 --- a/luci-app-run/htdocs/luci-static/resources/view/run/index.js +++ b/luci-app-run/htdocs/luci-static/resources/view/run/index.js @@ -101,6 +101,11 @@ var getStatus = rpc.declare({ method: 'status' }); +var getVersion = rpc.declare({ + object: 'luci-app-run', + method: 'version' +}); + var readLog = rpc.declare({ object: 'luci-app-run', method: 'read_log', @@ -140,10 +145,29 @@ return view.extend({ logOffset: 0, currentUploadId: null, + appVersion: 'unknown', load: function () { - return getStatus().catch(function () { - return {}; + var self = this; + return getVersion().then(function (res) { + if (res && res.version) { + self.appVersion = res.version; + // 检查版本是否变化,如果变化则强制刷新页面 + var storedVersion = localStorage.getItem('luci-app-run-version'); + if (storedVersion && storedVersion !== self.appVersion) { + localStorage.setItem('luci-app-run-version', self.appVersion); + window.location.reload(true); + } else { + localStorage.setItem('luci-app-run-version', self.appVersion); + } + } + return getStatus().catch(function () { + return {}; + }); + }).catch(function () { + return getStatus().catch(function () { + return {}; + }); }); }, @@ -180,7 +204,7 @@ return view.extend({ var runButton = E('button', { class: 'btn cbi-button cbi-button-action', disabled: true, - style: 'min-width:140px;padding:8px 32px;', + style: 'min-width:140px;margin-left:15px;', click: function (ev) { ev.preventDefault(); self.startRun(runButton, state); @@ -227,7 +251,7 @@ return view.extend({ }, [ E('h3', [_('upload_title')]), E('p', [state]), - E('p', [pickButton, ' ', runButton, cleanButton]), + E('p', [pickButton, runButton, cleanButton]), progress, fileInput ]); diff --git a/luci-app-run/root/usr/libexec/rpcd/luci-app-run b/luci-app-run/root/usr/libexec/rpcd/luci-app-run index d9f7fbdd..e72d82fa 100755 --- a/luci-app-run/root/usr/libexec/rpcd/luci-app-run +++ b/luci-app-run/root/usr/libexec/rpcd/luci-app-run @@ -13,83 +13,83 @@ umask 077 mkdir -p "$UPLOAD_DIR" "$RUN_DIR" reply() { - printf '%s\n' "$1" + printf '%s\n' "$1" } json_error() { - local msg="$1" - json_init - json_add_int code 1 - json_add_string error "$msg" - json_dump + local msg="$1" + json_init + json_add_int code 1 + json_add_string error "$msg" + json_dump } json_ok() { - json_init - json_add_int code 0 - [ -n "$1" ] && json_add_string message "$1" - json_dump + json_init + json_add_int code 0 + [ -n "$1" ] && json_add_string message "$1" + json_dump } sanitize_name() { - local name="$1" - name="${name##*/}" - name="${name##*\\}" - printf '%s' "$name" | tr -c 'A-Za-z0-9._-' '_' + local name="$1" + name="${name##*/}" + name="${name##*\\}" + printf '%s' "$name" | tr -c 'A-Za-z0-9._-' '_' } valid_id() { - case "$1" in - ""|*[!A-Za-z0-9_-]*) return 1 ;; - esac - return 0 + case "$1" in + ""|*[!A-Za-z0-9_-]*) return 1 ;; + esac + return 0 } load_input() { - local input - input="$(cat)" - json_load "$input" >/dev/null 2>&1 + local input + input="$(cat)" + json_load "$input" >/dev/null 2>&1 } get_string() { - json_get_var "$1" "$1" + json_get_var "$1" "$1" } get_int() { - json_get_var "$1" "$1" + json_get_var "$1" "$1" } new_token() { - local token - token="$(hexdump -n 16 -e '16/1 "%02x"' /dev/urandom 2>/dev/null)" - [ -n "$token" ] || token="$(date +%s)_$$_$(awk 'BEGIN{srand();print int(rand()*1000000)}')" - printf '%s' "$token" | tr -c 'A-Za-z0-9_' '_' + local token + token="$(hexdump -n 16 -e '16/1 "%02x"' /dev/urandom 2>/dev/null)" + [ -n "$token" ] || token="$(date +%s)_$$_$(awk 'BEGIN{srand();print int(rand()*1000000)}')" + printf '%s' "$token" | tr -c 'A-Za-z0-9_' '_' } session_dir() { - printf '%s/%s' "$UPLOAD_DIR" "$1" + printf '%s/%s' "$UPLOAD_DIR" "$1" } write_state() { - local pid="$1" - local file="$2" - local log="$3" - local started="$4" - { - printf 'PID=%s\n' "$pid" - printf 'FILE=%s\n' "$file" - printf 'LOG=%s\n' "$log" - printf 'STARTED=%s\n' "$started" - } > "$STATE_FILE" + local pid="$1" + local file="$2" + local log="$3" + local started="$4" + { + printf 'PID=%s\n' "$pid" + printf 'FILE=%s\n' "$file" + printf 'LOG=%s\n' "$log" + printf 'STARTED=%s\n' "$started" + } > "$STATE_FILE" } read_state() { - [ -f "$STATE_FILE" ] && . "$STATE_FILE" + [ -f "$STATE_FILE" ] && . "$STATE_FILE" } is_running() { - local pid="$1" - [ -n "$pid" ] && [ -d "/proc/$pid" ] + local pid="$1" + [ -n "$pid" ] && [ -d "/proc/$pid" ] } method_list() { @@ -114,235 +114,246 @@ method_list() { "read_log": { "offset": "Integer" }, - "cleanup": {} + "cleanup": {}, + "version": {} } JSON } upload_start() { - load_input - get_string filename - get_int size - - [ -n "$filename" ] || { json_error "Missing filename"; return; } - [ -n "$size" ] || size=0 - [ "$size" -le "$MAX_SIZE" ] 2>/dev/null || { json_error "File is larger than 256 MiB"; return; } - - local clean id token dir file - clean="$(sanitize_name "$filename")" - case "$clean" in - *.run|*.sh) ;; - *) json_error "Only .run and .sh files are accepted"; return ;; - esac - - id="$(date +%s)_$$" - token="$(new_token)" - dir="$(session_dir "$id")" - file="$dir/$clean" - mkdir -p "$dir" || { json_error "Unable to create upload directory"; return; } - : > "$file" || { json_error "Unable to create upload file"; return; } - printf '%s\n' "$clean" > "$dir/name" - printf '%s\n' "$size" > "$dir/size" - printf '%s\n' "$token" > "$dir/token" - - json_init - json_add_int code 0 - json_add_string id "$id" - json_add_string token "$token" - json_add_string filename "$clean" - json_dump + load_input + get_string filename + get_int size + + [ -n "$filename" ] || { json_error "Missing filename"; return; } + [ -n "$size" ] || size=0 + [ "$size" -le "$MAX_SIZE" ] 2>/dev/null || { json_error "File is larger than 256 MiB"; return; } + + local clean id token dir file + clean="$(sanitize_name "$filename")" + case "$clean" in + *.run|*.sh) ;; + *) json_error "Only .run and .sh files are accepted"; return ;; + esac + + id="$(date +%s)_$$" + token="$(new_token)" + dir="$(session_dir "$id")" + file="$dir/$clean" + mkdir -p "$dir" || { json_error "Unable to create upload directory"; return; } + : > "$file" || { json_error "Unable to create upload file"; return; } + printf '%s\n' "$clean" > "$dir/name" + printf '%s\n' "$size" > "$dir/size" + printf '%s\n' "$token" > "$dir/token" + + json_init + json_add_int code 0 + json_add_string id "$id" + json_add_string token "$token" + json_add_string filename "$clean" + json_dump } upload_chunk() { - load_input - get_string id - get_string data - get_int index - - valid_id "$id" || { json_error "Invalid upload id"; return; } - [ -n "$data" ] || { json_error "Missing chunk data"; return; } - - local dir name file - dir="$(session_dir "$id")" - [ -d "$dir" ] || { json_error "Unknown upload id"; return; } - name="$(cat "$dir/name" 2>/dev/null)" - file="$dir/$name" - - printf '%s' "$data" | base64 -d >> "$file" 2>/dev/null || { - json_error "Unable to decode upload chunk" - return - } - - json_init - json_add_int code 0 - json_add_int index "$index" - json_add_int received "$(wc -c < "$file" 2>/dev/null)" - json_dump + load_input + get_string id + get_string data + get_int index + + valid_id "$id" || { json_error "Invalid upload id"; return; } + [ -n "$data" ] || { json_error "Missing chunk data"; return; } + + local dir name file + dir="$(session_dir "$id")" + [ -d "$dir" ] || { json_error "Unknown upload id"; return; } + name="$(cat "$dir/name" 2>/dev/null)" + file="$dir/$name" + + printf '%s' "$data" | base64 -d >> "$file" 2>/dev/null || { + json_error "Unable to decode upload chunk" + return + } + + json_init + json_add_int code 0 + json_add_int index "$index" + json_add_int received "$(wc -c < "$file" 2>/dev/null)" + json_dump } upload_finish() { - load_input - get_string id - - valid_id "$id" || { json_error "Invalid upload id"; return; } - - local dir name file expected actual - dir="$(session_dir "$id")" - [ -d "$dir" ] || { json_error "Unknown upload id"; return; } - name="$(cat "$dir/name" 2>/dev/null)" - expected="$(cat "$dir/size" 2>/dev/null)" - file="$dir/$name" - actual="$(wc -c < "$file" 2>/dev/null)" - - [ -s "$file" ] || { json_error "Uploaded file is empty"; return; } - if [ -n "$expected" ] && [ "$expected" -gt 0 ] 2>/dev/null; then - [ "$actual" -eq "$expected" ] 2>/dev/null || { - json_error "Upload size mismatch" - return - } - fi - - chmod 700 "$file" || { json_error "Unable to chmod uploaded file"; return; } - - json_init - json_add_int code 0 - json_add_string id "$id" - json_add_string filename "$name" - json_add_int size "$actual" - json_dump + load_input + get_string id + + valid_id "$id" || { json_error "Invalid upload id"; return; } + + local dir name file expected actual + dir="$(session_dir "$id")" + [ -d "$dir" ] || { json_error "Unknown upload id"; return; } + name="$(cat "$dir/name" 2>/dev/null)" + expected="$(cat "$dir/size" 2>/dev/null)" + file="$dir/$name" + actual="$(wc -c < "$file" 2>/dev/null)" + + [ -s "$file" ] || { json_error "Uploaded file is empty"; return; } + if [ -n "$expected" ] && [ "$expected" -gt 0 ] 2>/dev/null; then + [ "$actual" -eq "$expected" ] 2>/dev/null || { + json_error "Upload size mismatch" + return + } + fi + + chmod 700 "$file" || { json_error "Unable to chmod uploaded file"; return; } + + json_init + json_add_int code 0 + json_add_string id "$id" + json_add_string filename "$name" + json_add_int size "$actual" + json_dump } run_installer() { - load_input - get_string id - - valid_id "$id" || { json_error "Invalid upload id"; return; } - - local dir name file log work pid now - dir="$(session_dir "$id")" - [ -d "$dir" ] || { json_error "Unknown upload id"; return; } - name="$(cat "$dir/name" 2>/dev/null)" - file="$dir/$name" - - # 确保文件可执行(.run 和 .sh 都需要) - chmod 700 "$file" 2>/dev/null || true - - [ -x "$file" ] || { - json_error "Uploaded file is not executable. Please check file permissions." - return - } - - read_state - if is_running "$PID"; then - json_error "Another installer is already running" - return - fi - - now="$(date '+%Y-%m-%d %H:%M:%S')" - work="$RUN_DIR/$id" - log="$work/output.log" - mkdir -p "$work" || { json_error "Unable to create run directory"; return; } - - ( - cd "$work" || exit 1 - printf 'luci-app-run: started %s\n' "$now" - printf 'luci-app-run: executing %s\n\n' "$file" - "$file" - rc=$? - printf '\nluci-app-run: exited with status %s at %s\n' "$rc" "$(date '+%Y-%m-%d %H:%M:%S')" - exit "$rc" - ) > "$log" 2>&1 & - - pid="$!" - write_state "$pid" "$file" "$log" "$now" - - json_init - json_add_int code 0 - json_add_int pid "$pid" - json_add_string log "$log" - json_dump + load_input + get_string id + + valid_id "$id" || { json_error "Invalid upload id"; return; } + + local dir name file log work pid now + dir="$(session_dir "$id")" + [ -d "$dir" ] || { json_error "Unknown upload id"; return; } + name="$(cat "$dir/name" 2>/dev/null)" + file="$dir/$name" + + # 确保文件可执行(.run 和 .sh 都需要) + chmod 700 "$file" 2>/dev/null || true + + [ -x "$file" ] || { + json_error "Uploaded file is not executable. Please check file permissions." + return + } + + read_state + if is_running "$PID"; then + json_error "Another installer is already running" + return + fi + + now="$(date '+%Y-%m-%d %H:%M:%S')" + work="$RUN_DIR/$id" + log="$work/output.log" + mkdir -p "$work" || { json_error "Unable to create run directory"; return; } + + ( + cd "$work" || exit 1 + printf 'luci-app-run: started %s\n' "$now" + printf 'luci-app-run: executing %s\n\n' "$file" + "$file" + rc=$? + printf '\nluci-app-run: exited with status %s at %s\n' "$rc" "$(date '+%Y-%m-%d %H:%M:%S')" + exit "$rc" + ) > "$log" 2>&1 & + + pid="$!" + write_state "$pid" "$file" "$log" "$now" + + json_init + json_add_int code 0 + json_add_int pid "$pid" + json_add_string log "$log" + json_dump } status() { - read_state - - json_init - json_add_int code 0 - if is_running "$PID"; then - json_add_boolean running 1 - else - json_add_boolean running 0 - fi - [ -n "$PID" ] && json_add_int pid "$PID" - [ -n "$FILE" ] && json_add_string file "$FILE" - [ -n "$LOG" ] && json_add_string log "$LOG" - [ -n "$STARTED" ] && json_add_string started "$STARTED" - json_dump + read_state + + json_init + json_add_int code 0 + if is_running "$PID"; then + json_add_boolean running 1 + else + json_add_boolean running 0 + fi + [ -n "$PID" ] && json_add_int pid "$PID" + [ -n "$FILE" ] && json_add_string file "$FILE" + [ -n "$LOG" ] && json_add_string log "$LOG" + [ -n "$STARTED" ] && json_add_string started "$STARTED" + json_dump } read_log() { - load_input - get_int offset - [ -n "$offset" ] || offset=0 - - read_state - [ -n "$LOG" ] && [ -f "$LOG" ] || { - json_init - json_add_int code 0 - json_add_string data "" - json_add_int offset 0 - json_add_boolean running 0 - json_dump - return - } - - local size data start - size="$(wc -c < "$LOG" 2>/dev/null)" - [ "$offset" -le "$size" ] 2>/dev/null || offset=0 - start=$((offset + 1)) - data="$(tail -c +"$start" "$LOG" 2>/dev/null)" - - json_init - json_add_int code 0 - json_add_string data "$data" - json_add_int offset "$size" - if is_running "$PID"; then - json_add_boolean running 1 - else - json_add_boolean running 0 - fi - json_dump + load_input + get_int offset + [ -n "$offset" ] || offset=0 + + read_state + [ -n "$LOG" ] && [ -f "$LOG" ] || { + json_init + json_add_int code 0 + json_add_string data "" + json_add_int offset 0 + json_add_boolean running 0 + json_dump + return + } + + local size data start + size="$(wc -c < "$LOG" 2>/dev/null)" + [ "$offset" -le "$size" ] 2>/dev/null || offset=0 + start=$((offset + 1)) + data="$(tail -c +"$start" "$LOG" 2>/dev/null)" + + json_init + json_add_int code 0 + json_add_string data "$data" + json_add_int offset "$size" + if is_running "$PID"; then + json_add_boolean running 1 + else + json_add_boolean running 0 + fi + json_dump } cleanup() { - read_state - if is_running "$PID"; then - json_error "Cannot clean up while installer is running" - return - fi + read_state + if is_running "$PID"; then + json_error "Cannot clean up while installer is running" + return + fi + + rm -rf "$UPLOAD_DIR" "$RUN_DIR" "$STATE_FILE" + mkdir -p "$UPLOAD_DIR" "$RUN_DIR" + json_ok "Cleaned" +} - rm -rf "$UPLOAD_DIR" "$RUN_DIR" "$STATE_FILE" - mkdir -p "$UPLOAD_DIR" "$RUN_DIR" - json_ok "Cleaned" +version() { + local ver="unknown" + [ -f "/tmp/luci-app-run.version" ] && ver="$(cat /tmp/luci-app-run.version)" + json_init + json_add_int code 0 + json_add_string version "$ver" + json_dump } case "$1" in - list) - method_list - ;; - call) - case "$2" in - upload_start) upload_start ;; - upload_chunk) upload_chunk ;; - upload_finish) upload_finish ;; - run) run_installer ;; - status) status ;; - read_log) read_log ;; - cleanup) cleanup ;; - *) json_error "Unknown method" ;; - esac - ;; - *) - reply '{}' - ;; -esac + list) + method_list + ;; + call) + case "$2" in + upload_start) upload_start ;; + upload_chunk) upload_chunk ;; + upload_finish) upload_finish ;; + run) run_installer ;; + status) status ;; + read_log) read_log ;; + cleanup) cleanup ;; + version) version ;; + *) json_error "Unknown method" ;; + esac + ;; + *) + reply '{}' + ;; +esac \ No newline at end of file diff --git a/luci-app-ssr-plus/Makefile b/luci-app-ssr-plus/Makefile index f118549e..8ae40426 100644 --- a/luci-app-ssr-plus/Makefile +++ b/luci-app-ssr-plus/Makefile @@ -3,8 +3,8 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=luci-app-ssr-plus LUCI_PKGARCH:=all PKG_NAME:=luci-app-ssr-plus -PKG_VERSION:=193 -PKG_RELEASE:=27 +PKG_VERSION:=195 +PKG_RELEASE:=28 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ @@ -34,15 +34,16 @@ LUCI_DEPENDS:= \ +jq +ip-full +lua-neturl +libuci-lua +microsocks +ipt2socks +lyaml \ +resolveip +curl +nping +unzip +xz-utils \ +PACKAGE_$(PKG_NAME)_INCLUDE_Xray:xray-core \ + +PACKAGE_$(PKG_NAME)_INCLUDE_Xray:coreutils-timeout \ + +PACKAGE_$(PKG_NAME)_INCLUDE_Http_Proxy:3proxy \ + +PACKAGE_$(PKG_NAME)_INCLUDE_Mihomo:mihomo \ + +PACKAGE_$(PKG_NAME)_INCLUDE_GeoData:v2ray-geoip \ + +PACKAGE_$(PKG_NAME)_INCLUDE_GeoData:v2ray-geosite \ +PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG:chinadns-ng \ +PACKAGE_$(PKG_NAME)_INCLUDE_MosDNS:mosdns \ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadow_TLS:shadow-tls \ +PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun:kcptun-client \ +PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \ - +PACKAGE_$(PKG_NAME)_INCLUDE_Http_Proxy:3proxy \ - +PACKAGE_$(PKG_NAME)_INCLUDE_Mihomo:mihomo \ - +PACKAGE_$(PKG_NAME)_INCLUDE_GeoData:v2ray-geoip \ - +PACKAGE_$(PKG_NAME)_INCLUDE_GeoData:v2ray-geosite \ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client:shadowsocks-rust-sslocal \ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server:shadowsocks-rust-ssserver \ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Simple_Obfs:simple-obfs-client \ @@ -104,7 +105,6 @@ endchoice choice prompt "V2ray-core Selection" - default PACKAGE_$(PKG_NAME)_INCLUDE_Xray default PACKAGE_$(PKG_NAME)_INCLUDE_NONE_V2RAY config PACKAGE_$(PKG_NAME)_INCLUDE_NONE_V2RAY diff --git a/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua b/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua index 62af2858..d6eae2d7 100644 --- a/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua +++ b/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua @@ -661,6 +661,8 @@ function index() entry({"admin", "services", "shadowsocksr", "clash_client_policies"}, call("clash_client_policies")).leaf = true entry({"admin", "services", "shadowsocksr", "clash_client_rule_save"}, call("clash_client_rule_save")).leaf = true entry({"admin", "services", "shadowsocksr", "clash_client_rule_clear"}, call("clash_client_rule_clear")).leaf = true + entry({"admin", "services", "shadowsocksr", "fetch_certsha256"}, call("fetch_certsha256")).leaf = true + entry({"admin", "services", "shadowsocksr", "fetch_certbyname"}, call("fetch_certbyname")).leaf = true --[[Backup]] entry({"admin", "services", "shadowsocksr", "backup"}, call("create_backup")).leaf = true entry({'admin', 'services', "shadowsocksr", 'ip'}, call('check_ip')) -- 获取ip情况 @@ -873,6 +875,13 @@ function add_subscribe_item() return end + local commit_subscribe = luci.sys.call("uci -q commit shadowsocksr >/dev/null 2>&1") + if commit_subscribe ~= 0 then + luci.http.prepare_content("application/json") + luci.http.write_json({ ret = 0, error = "commit failed" }) + return + end + luci.http.prepare_content("application/json") luci.http.write_json({ ret = 1, sid = sid, alias = alias, enabled = "1" }) end @@ -1320,6 +1329,84 @@ function clash_client_rule_clear() }) end +function fetch_certsha256() + local function fetch_cert_sha256(host, port, sni, timeout) + if not host then return "" end + port = tonumber(port) or 443 + sni = sni or host + timeout = tonumber(timeout) or 5 + + local cmd = string.format( + "timeout %d openssl s_client -connect %s:%d -servername %s -showcerts /dev/null " .. + "| awk 'BEGIN{c=0}/BEGIN CERT/{c++} c==1{print} /END CERT/{if(c==1)exit}' " .. + "| openssl x509 -outform der 2>/dev/null " .. + "| sha256sum 2>/dev/null", + timeout, host, port, sni + ) + + local out = trim(luci.sys.exec(cmd)) + + local fp = out:match("^([0-9a-fA-F]+)") + if not fp or fp:lower():match("^e3b0c44298fc1c149afbf4c8996fb924") then + return "" + end + return fp:upper() + end + + local sid = luci.http.formvalue("sid") or "" + local address = (sid ~= "") and uci:get("shadowsocksr", sid, "server") or "" + local port_raw = (sid ~= "") and uci:get("shadowsocksr", sid, "server_port") or "" + local port = tonumber(port_raw) or 0 + local sni = (id ~= "") and uci:get("shadowsocksr", sid, "tls_host") or "" + sni = (sni and sni ~= "") and sni or address + if address == "" or port == 0 then + luci.http.prepare_content("application/json") + luci.http.write_json({ code = 0, msg = "Address or Port is invalid" }) + return + end + local data = fetch_cert_sha256(address, port, sni, 5) + luci.http.prepare_content("application/json") + luci.http.write_json(data ~= "" and { code = 1, data = data } or { code = 0 }) +end + +function fetch_certbyname() + local function fetch_cert_byname(host, port, sni, timeout) + if not host then return "" end + port = tonumber(port) or 443 + sni = sni or host + timeout = tonumber(timeout) or 5 + + local cmd = string.format( + "timeout %d openssl s_client -connect %s:%d -servername %s -showcerts /dev/null " .. + "| openssl x509 -noout -subject 2>/dev/null " .. + "| awk '{gsub(/^.*=[[:space:]]*/, \"\"); gsub(/,.*$/, \"\"); print}'", + timeout, host, port, sni + ) + + local out = trim(luci.sys.exec(cmd)) + + if out == "" then + return "" + end + return out + end + + local sid = luci.http.formvalue("sid") or "" + local address = (sid ~= "") and uci:get("shadowsocksr", sid, "server") or "" + local port_raw = (sid ~= "") and uci:get("shadowsocksr", sid, "server_port") or "" + local port = tonumber(port_raw) or 0 + local sni = (id ~= "") and uci:get("shadowsocksr", sid, "tls_host") or "" + sni = (sni and sni ~= "") and sni or address + if address == "" or port == 0 then + luci.http.prepare_content("application/json") + luci.http.write_json({ code = 0, msg = "Address or Port is invalid" }) + return + end + local data = fetch_cert_byname(address, port, sni, 5) + luci.http.prepare_content("application/json") + luci.http.write_json(data ~= "" and { code = 1, data = data } or { code = 0 }) +end + function act_ping() local e = {} local domain = luci.http.formvalue("domain") diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua index d1f006ba..1dfa1ba0 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua @@ -321,6 +321,10 @@ m.on_after_save = function(self) end end +local server_header = Template("/shadowsocksr/server_header") +server_header.section = sid +m:append(server_header) + -- [[ Servers Setting ]]-- s = m:section(NamedSection, sid, "servers") s.anonymous = true @@ -417,6 +421,9 @@ end if is_finded("xray") then o:value("hysteria2", translate("Hysteria2")) end +if is_finded("mihomo") then + o:value("snell", translate("Snell")) +end o:value("socks", translate("Socks")) o:value("http", translate("HTTP")) o:depends("type", "v2ray") @@ -500,6 +507,11 @@ o:depends({type = "v2ray", v2ray_protocol = "socks", socks_ver = "5", auth_enabl o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"}) o:depends({type = "v2ray", v2ray_protocol = "trojan"}) +o = s:option(Value, "snell_psk", translate("Snell PSK")) +o.password = true +o.rmempty = true +o:depends({type = "v2ray", v2ray_protocol = "snell"}) + o = s:option(ListValue, "encrypt_method", translate("Encrypt Method")) for _, v in ipairs(encrypt_methods) do o:value(v) @@ -946,6 +958,28 @@ o.rmempty = true o.default = "5" o:depends({type = "v2ray", v2ray_protocol = "socks"}) +o = s:option(ListValue, "snell_version", translate("Snell Version")) +o:value("1", "v1") +o:value("2", "v2") +o:value("3", "v3") +o:value("4", "v4") +o:value("5", "v5") +o.default = "4" +o.rmempty = true +o:depends({type = "v2ray", v2ray_protocol = "snell"}) + +o = s:option(ListValue, "snell_obfs", translate("Snell Obfs")) +o:value("", translate("Disable")) +o:value("http", "HTTP") +o:value("tls", "TLS") +o.default = "" +o.rmempty = true +o:depends({type = "v2ray", v2ray_protocol = "snell"}) + +o = s:option(Value, "snell_obfs_host", translate("Snell Obfs Host")) +o.rmempty = true +o:depends({type = "v2ray", v2ray_protocol = "snell"}) + -- 传输协议 o = s:option(ListValue, "transport", translate("Transport")) o:value("raw", "RAW (TCP)") @@ -1510,14 +1544,18 @@ o.description = translate("If true, allowss insecure connection at TLS client, e if xray_version_val >= 260131 then -- Xray 版本大于等于 26.1.31 -- [[ Xray TLS pinSHA256 ]] -- - o = s:option(Value, "tls_CertSha", translate("TLS Chain Fingerprint (SHA256)"), translate("Once set, connects only when the server’s chain fingerprint matches.")) + o = s:option(Value, "tls_CertSha", translate("TLS Chain Fingerprint (SHA256)")) o.rmempty = true o:depends({type = "v2ray", tls = true}) + o.description = translate("Once set, connects only when the server’s chain fingerprint matches.") .. + string.format("%s", "→ " .. translate("Fetch Manually")) -- [[ Xray TLS verify leaf certificate name ]] -- - o = s:option(Value, "tls_CertByName", translate("TLS Certificate Name (CertName)"), translate("TLS is used to verify the leaf certificate name.")) + o = s:option(Value, "tls_CertByName", translate("TLS Certificate Name (CertName)")) o.rmempty = true o:depends({type = "v2ray", tls = true}) + o.description = translate("TLS is used to verify the leaf certificate name.") .. + string.format("%s", "→ " .. translate("Fetch Manually")) end -- [[ Hysteria2 TLS pinSHA256 ]] -- diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua index 2fdf777d..4c8fcca1 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua @@ -7,7 +7,7 @@ require "nixio.fs" local m, s, o local sid = arg[1] --- ܷʽSS/SSRã +-- 加密方式(SS/SSR用) local encrypt_methods = { "rc4-md5", "rc4-md5-6", "rc4", "table", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", @@ -23,13 +23,13 @@ local encrypt_methods_ss = { "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" } --- Shadowsocks ܷXray 棩 +-- Shadowsocks 加密方法(Xray 版) local v_ss_encrypt_method_list = { "aes-128-cfb", "aes-256-cfb", "aes-128-gcm", "aes-256-gcm", "chacha20", "chacha20-ietf", "chacha20-poly1305", "chacha20-ietf-poly1305" } --- αװͣ mKCP/QUIC +-- 伪装类型(用于 mKCP/QUIC) local header_type_list = { "none", "srtp", "utp", "wechat-video", "dtls", "wireguard" } @@ -50,7 +50,7 @@ s = m:section(NamedSection, sid, "server_config") s.anonymous = true s.addremove = false --- ========== ========== +-- ========== 基本设置 ========== o = s:option(Flag, "enable", translate("Enable")) o.default = 1 o.rmempty = false @@ -63,12 +63,14 @@ end if nixio.fs.access("/usr/bin/ssr-server") then o:value("ssr", translate("ShadowsocksR")) end --- Xray Э֧ -if nixio.fs.access("/usr/bin/xray") or nixio.fs.access("/usr/libexec/xray") then - o:value("vmess", "VMess (Xray)") - o:value("vless", "VLESS (Xray)") - o:value("trojan", "Trojan (Xray)") - o:value("shadowsocks", "Shadowsocks (Xray)") +-- Xray 协议支持 +if nixio.fs.access("/usr/bin/mihomo") or nixio.fs.access("/usr/libexec/mihomo") + or nixio.fs.access("/usr/bin/xray") or nixio.fs.access("/usr/libexec/xray") +then + o:value("vmess", "VMess (Mihomo/Xray)") + o:value("vless", "VLESS (Mihomo/Xray)") + o:value("trojan", "Trojan (Mihomo/Xray)") + o:value("shadowsocks", "Shadowsocks (Mihomo/Xray)") end o.default = "socks5" @@ -99,7 +101,7 @@ o:depends("type", "ssr") o:depends("type", "trojan") o:depends("type", "shadowsocks") --- ========== SS/SSR Э ========== +-- ========== SS/SSR 协议特有 ========== o = s:option(ListValue, "encrypt_method", translate("Encrypt Method")) for _, v in ipairs(encrypt_methods) do o:value(v) end o.rmempty = false @@ -128,8 +130,8 @@ o.rmempty = false o:depends("type", "ss") o:depends("type", "ssr") --- ========== Xray Эֶͨ ========== --- ûע +-- ========== Xray 协议通用字段 ========== +-- 用户备注 o = s:option(Value, "remarks", translate("Remarks")) o.default = translate("Remarks") o.rmempty = true @@ -138,7 +140,7 @@ o:depends("type", "vless") o:depends("type", "trojan") o:depends("type", "shadowsocks") --- ûȼ +-- 用户等级 o = s:option(Value, "level", translate("User Level")) o.datatype = "uinteger" o.default = 1 @@ -148,21 +150,21 @@ o:depends("type", "vless") o:depends("type", "shadowsocks") o:depends("type", "trojan") --- ========== Xray Эֶ֤ ========== --- UUID ( vmess/vless) +-- ========== Xray 协议认证字段 ========== +-- UUID (用于 vmess/vless) o = s:option(Value, "uuid", translate("UUID")) o.description = translate("Required for VMess/VLESS. Generate with: uuidgen") o.rmempty = true o:depends("type", "vmess") o:depends("type", "vless") --- Trojan +-- Trojan 密码 o = s:option(Value, "trojan_password", translate("Trojan Password")) o.password = true o.rmempty = true o:depends("type", "trojan") --- Shadowsocks ͼܣXray ã +-- Shadowsocks 密码和加密(Xray 内置) o = s:option(Value, "ss_password", translate("Shadowsocks Password")) o.password = true o.rmempty = true @@ -195,7 +197,7 @@ o.default = "none" o.rmempty = true o:depends("type", "vless") --- ========== TLS / XTLS ========== +-- ========== TLS / XTLS 设置 ========== o = s:option(Flag, "tls", translate("TLS")) o.default = 0 o.rmempty = true @@ -234,7 +236,7 @@ o.description = translate("e.g.: /etc/ssl/private.key") o.rmempty = true o:depends("tls", "1") --- ========== (Transport) ========== +-- ========== 传输层设置 (Transport) ========== o = s:option(ListValue, "transport", translate("Transport Protocol")) o:value("tcp", "TCP") o:value("mkcp", "mKCP") @@ -248,7 +250,7 @@ o:depends("type", "vmess") o:depends("type", "vless") o:depends("type", "trojan") --- ----- WebSocket ----- +-- ----- WebSocket 设置 ----- o = s:option(Value, "ws_host", translate("WebSocket Host")) o.rmempty = true o:depends("transport", "ws") @@ -264,7 +266,7 @@ o:depends("type", "vmess") o:depends("type", "vless") o:depends("type", "trojan") --- ----- HTTP/2 ----- +-- ----- HTTP/2 设置 ----- o = s:option(Value, "h2_host", translate("HTTP/2 Host")) o.rmempty = true o:depends("transport", "h2") @@ -278,7 +280,7 @@ o:depends("transport", "h2") o:depends("type", "vmess") o:depends("type", "vless") --- ----- TCP αװ ----- +-- ----- TCP 伪装设置 ----- o = s:option(ListValue, "tcp_guise", translate("TCP Camouflage Type")) o:value("none", "none") o:value("http", "http") @@ -296,7 +298,7 @@ o = s:option(DynamicList, "tcp_guise_http_path", translate("HTTP Path")) o.rmempty = true o:depends("tcp_guise", "http") --- ----- mKCP ----- +-- ----- mKCP 设置 ----- o = s:option(ListValue, "mkcp_guise", translate("mKCP Camouflage Type")) for _, v in ipairs(header_type_list) do o:value(v) end o.default = "none" @@ -349,13 +351,13 @@ o.datatype = "uinteger" o.rmempty = true o:depends("transport", "mkcp") --- ----- DomainSocket ----- +-- ----- DomainSocket 设置 ----- o = s:option(Value, "ds_path", translate("DomainSocket Path")) o.description = translate("A legal file path. This file must not exist before running.") o.rmempty = true o:depends("transport", "ds") --- ----- QUIC ----- +-- ----- QUIC 设置 ----- o = s:option(ListValue, "quic_security", translate("QUIC Security")) o:value("none", "none") o:value("aes-128-gcm", "aes-128-gcm") @@ -374,7 +376,7 @@ o.default = "none" o.rmempty = true o:depends("transport", "quic") --- ========== ʿ ========== +-- ========== 访问控制 ========== o = s:option(Flag, "bind_local", translate("Bind Local Only")) o.description = translate("When selected, it can only be accessed locally. Recommended when using reverse proxies.") o.default = 0 diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua index 6e5e01e3..3802d9f7 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua @@ -458,6 +458,7 @@ o.remove = function() end o = s:option(Value, "filter_words", translate("Subscribe Filter Words")) o.rmempty = true +o.default = "过期/重置/套餐/剩余/网址/QQ群/官网/防失联/回国" o.description = translate("Filter Words splited by /") o:depends("_subscribe_advanced_toggle", "1") preserve_when_hidden(o, "_subscribe_advanced_toggle", "1") @@ -544,6 +545,26 @@ if has_mihomo then o = s:option(DummyValue, "_upload_clash_yaml", translate("Upload Custom YAML File")) o.template = "shadowsocksr/clash_yaml_upload" o.description = translate("Upload a custom Clash/Mihomo YAML file. The file will be preprocessed and saved as a local Clash node.") + + o = s:option(Flag, "sub_convert", translate("Subscribe Convert Online")) + o.description = translate("Convert subscriptions to Clash/Mihomo YAML with a subscription template URL.") + o.default = "0" + o.rmempty = false + + o = s:option(Value, "convert_address", translate("Convert Address")) + o.default = "https://api.asailor.org/sub" + o.placeholder = "https://api.asailor.org/sub" + o:value("https://api.asailor.org/sub", "api.asailor.org") + o:value("https://api.wcc.best/sub", "api.wcc.best") + o.rmempty = true + o:depends("sub_convert", "1") + + o = s:option(Value, "template_url", translate("Subscribe Template URL")) + o.default = "https://raw.githubusercontent.com/Fzlwhyc/OpenClash-Templates/main//fzlwhyc-openclash.ini" + o.placeholder = "https://raw.githubusercontent.com/Fzlwhyc/OpenClash-Templates/main//fzlwhyc-openclash.ini" + o:value("https://raw.githubusercontent.com/Fzlwhyc/OpenClash-Templates/main//fzlwhyc-openclash.ini", "Fzlwhyc") + o.rmempty = true + o:depends("sub_convert", "1") end s:append(cbi.Template("shadowsocksr/subscribe_schedule_compact")) diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua index 51b563d1..9f219a08 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua @@ -117,7 +117,7 @@ if global_type == "socks5" and Process_list:find("ipt2socks") then if Process_list:find("%-U") or Process_list:find("%-%-udp%-only") then reudp_run = 1 end - if global_socks_enabled and (global_socks_server == "same" and global_socks_server == global_server) then + if global_socks_enabled and (global_socks_server == "same" or global_socks_server == global_server) then sock5_run = 1 end end @@ -125,7 +125,7 @@ end if (global_type == "clash" or global_type == "tuic" or global_type == "ss") and Process_list:find("ssr%-retcp") then redir_run = 1 reudp_run = 1 - if global_socks_enabled and (global_socks_server == "same" and global_socks_server == global_server) then + if global_socks_enabled and (global_socks_server == "same" or global_socks_server == global_server) then sock5_run = 1 end end @@ -133,7 +133,7 @@ end if (global_type == "clash" or global_type == "tuic" or global_type == "ss") and Process_list:find("mihomo") and (Process_list:find("/clash%-") or Process_list:find("/tuic%-") or Process_list:find("/ss%-")) then redir_run = 1 reudp_run = 1 - if global_socks_enabled and (global_socks_server == "same" and global_socks_server == global_server) then + if global_socks_enabled and (global_socks_server == "same" or global_socks_server == global_server) then sock5_run = 1 end end diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/log.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/log.htm index 251f14b2..b00de918 100644 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/log.htm +++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/log.htm @@ -4,7 +4,7 @@ local dsp = require "luci.dispatcher" diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm index 5218cc27..2f12c4ef 100644 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm +++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm @@ -165,7 +165,7 @@ end return; } port.innerHTML = 'connect'; - XHR.get('<%=luci.dispatcher.build_url("admin/services/shadowsocksr/ping")%>', { + XHR.get('<%=luci.dispatcher.build_url("admin", "services", "shadowsocksr", "ping")%>', { index, sid: dom.getAttribute("data-sid"), domain: dom.getAttribute("hint"), @@ -280,7 +280,7 @@ end var server_page = pageElem ? pageElem.value : '<%=self.server_page or 1%>'; var server_page_size = pageSizeElem ? pageSizeElem.value : '<%=self.server_page_size or 0%>'; if (input) input.value = order; - XHR.post('<%=luci.dispatcher.build_url("admin/services/shadowsocksr/save_order")%>', { + XHR.post('<%=luci.dispatcher.build_url("admin", "services", "shadowsocksr", "save_order")%>', { order: order, page: server_page, page_size: server_page_size diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm index 82b9eeaf..7364db25 100644 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm +++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_table.htm @@ -248,7 +248,7 @@ end ', { + XHR.post('<%=luci.dispatcher.build_url("admin", "services", "shadowsocksr", "delete_node")%>', { sid: sid }, function(x, result) { result = result || {}; diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm index 025fd51b..a7390a24 100644 --- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm +++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm @@ -3,7 +3,7 @@ local map = self.map local has_ss_rust = luci.sys.exec('type -t -p sslocal 2>/dev/null || type -t -p ssserver 2>/dev/null') ~= "" -local has_mihomo = luci.sys.exec('type -t -p mihomo -p /usr/libexec/mihomo 2>/dev/null') ~= "" +local has_mihomo = luci.sys.exec('type -t -p mihomo 2>/dev/null || { test -x /usr/libexec/mihomo && echo /usr/libexec/mihomo; }') ~= "" local has_xray = luci.sys.exec('type -t -p xray 2>/dev/null') ~= "" -%>