From 3a0bd7b071af60f0257187b0657ca87a2d9caf73 Mon Sep 17 00:00:00 2001 From: "github-action[bot]" Date: Sat, 20 Sep 2025 20:32:25 +0200 Subject: [PATCH] Update On Sat Sep 20 20:32:24 CEST 2025 --- .github/update.log | 1 + clash-nyanpasu/backend/Cargo.lock | 51 ++-- .../backend/tauri/src/config/nyanpasu/mod.rs | 10 + .../backend/tauri/src/core/tray/mod.rs | 22 +- clash-nyanpasu/backend/tauri/src/feat.rs | 3 +- .../frontend/interface/src/ipc/bindings.ts | 6 + .../frontend/interface/src/provider/index.tsx | 4 +- .../frontend/interface/src/service/types.ts | 1 + clash-nyanpasu/frontend/nyanpasu/package.json | 10 +- .../app/modules/route-list-item.tsx | 10 +- .../src/components/dashboard/data-panel.tsx | 8 +- .../src/components/dashboard/dataline.tsx | 8 +- .../src/components/profiles/profile-item.tsx | 6 +- .../providers/proxies-provider-traffic.tsx | 4 +- .../frontend/nyanpasu/src/pages/dashboard.tsx | 10 +- clash-nyanpasu/frontend/ui/package.json | 2 +- .../frontend/ui/src/chart/sparkline.tsx | 18 +- clash-nyanpasu/manifest/version.json | 4 +- clash-nyanpasu/pnpm-lock.yaml | 68 +++--- filebrowser/frontend/src/i18n/ar.json | 5 +- filebrowser/frontend/src/i18n/ca.json | 5 +- filebrowser/frontend/src/i18n/cs.json | 5 +- filebrowser/frontend/src/i18n/de.json | 5 +- filebrowser/frontend/src/i18n/el.json | 5 +- filebrowser/frontend/src/i18n/es.json | 5 +- filebrowser/frontend/src/i18n/fa.json | 5 +- filebrowser/frontend/src/i18n/fr.json | 8 +- filebrowser/frontend/src/i18n/he.json | 5 +- filebrowser/frontend/src/i18n/hu.json | 5 +- filebrowser/frontend/src/i18n/is.json | 5 +- filebrowser/frontend/src/i18n/it.json | 5 +- filebrowser/frontend/src/i18n/ja.json | 5 +- filebrowser/frontend/src/i18n/ko.json | 5 +- filebrowser/frontend/src/i18n/nl-be.json | 5 +- filebrowser/frontend/src/i18n/no.json | 5 +- filebrowser/frontend/src/i18n/pl.json | 5 +- filebrowser/frontend/src/i18n/pt-br.json | 5 +- filebrowser/frontend/src/i18n/pt.json | 5 +- filebrowser/frontend/src/i18n/ro.json | 5 +- filebrowser/frontend/src/i18n/ru.json | 5 +- filebrowser/frontend/src/i18n/sk.json | 5 +- filebrowser/frontend/src/i18n/sv-se.json | 5 +- filebrowser/frontend/src/i18n/tr.json | 5 +- filebrowser/frontend/src/i18n/uk.json | 5 +- filebrowser/frontend/src/i18n/vi.json | 5 +- filebrowser/frontend/src/i18n/zh-cn.json | 5 +- filebrowser/frontend/src/i18n/zh-tw.json | 5 +- .../package/base-files/files/lib/functions.sh | 5 + lede/package/libs/openssl/Makefile | 6 +- ...p-the-store-open-in-by_store_ctrl_ex.patch | 129 ---------- .../package/network/services/dnsmasq/Makefile | 14 +- .../services/dnsmasq/files/dhcp-script.sh | 9 + .../network/services/dnsmasq/files/dhcp.conf | 2 +- .../services/dnsmasq/files/dnsmasq.init | 205 ++++++++++++---- .../dnsmasq/patches/200-ubus_dns.patch | 2 +- ...ate-documentation-for-gpio-gate-cloc.patch | 27 +++ ...e-dev_err_probe-for-gpio-get-failure.patch | 44 ++++ ...io-add-driver-for-gated-fixed-clocks.patch | 229 ++++++++++++++++++ .../nekohasekai/sagernet/fmt/ConfigBuilder.kt | 2 +- .../fmt/shadowsocks/ShadowsocksFmt.kt | 4 + .../sagernet/ui/AppListActivity.kt | 11 - .../src/main/res/menu/app_list_neko_menu.xml | 5 - .../buildScript/lib/core/get_source_env.sh | 2 +- nekobox-android/libcore/go.mod | 6 +- nekobox-android/libcore/go.sum | 12 +- nekobox-android/libcore/init.sh | 3 +- nekobox-android/nb4a.properties | 6 +- .../Auto compile with openwrt sdk.yml | 6 + .../Auto compile with openwrt sdk.yml | 6 + small/README.md | 4 +- .../htdocs/luci-static/resources/fchomo.js | 13 +- .../resources/view/fchomo/global.js | 16 +- .../luci-static/resources/view/fchomo/log.js | 62 ++++- .../resources/view/fchomo/ruleset.js | 6 +- .../resources/view/fchomo/server.js | 2 +- .../resources/view/homeproxy/client.js | 1 + .../resources/view/homeproxy/node.js | 4 +- .../resources/view/homeproxy/server.js | 12 +- .../etc/homeproxy/scripts/generate_client.uc | 8 +- .../root/usr/share/rpcd/ucode/luci.homeproxy | 2 +- small/luci-app-passwall2/Makefile | 11 +- .../{ => view/passwall2}/qrcode.min.js | 0 .../model/cbi/passwall2/client/type/ray.lua | 158 ++++++------ .../cbi/passwall2/client/type/sing-box.lua | 22 +- .../model/cbi/passwall2/server/type/ray.lua | 30 +-- .../luasrc/passwall2/api.lua | 2 +- .../luasrc/passwall2/util_xray.lua | 46 +--- .../luasrc/view/passwall2/global/backup.htm | 84 +++---- .../passwall2/node_list/link_add_node.htm | 41 ++-- .../passwall2/node_list/link_share_man.htm | 40 ++- .../luci-app-passwall2/po/zh-cn/passwall2.po | 3 - .../root/usr/share/passwall2/app.sh | 5 +- .../root/usr/share/passwall2/subscribe.lua | 19 +- .../luasrc/view/shadowsocksr/ssrurl.htm | 166 ++++++++++++- .../po/templates/ssr-plus.pot | 29 ++- .../luci-app-ssr-plus/po/zh_Hans/ssr-plus.po | 29 ++- .../root/usr/share/shadowsocksr/subscribe.lua | 144 +++++++++++ v2rayn/v2rayN/Directory.Build.props | 2 +- .../ViewModels/CheckUpdateViewModel.cs | 25 +- yt-dlp/yt_dlp/extractor/applepodcasts.py | 8 +- yt-dlp/yt_dlp/extractor/flextv.py | 29 ++- yt-dlp/yt_dlp/extractor/vk.py | 5 +- 102 files changed, 1465 insertions(+), 687 deletions(-) delete mode 100644 lede/package/libs/openssl/patches/0001-Don-t-keep-the-store-open-in-by_store_ctrl_ex.patch create mode 100644 lede/target/linux/generic/backport-6.12/801-02-v6.13-clk-clk-gpio-update-documentation-for-gpio-gate-cloc.patch create mode 100644 lede/target/linux/generic/backport-6.12/801-03-v6.13-clk-clk-gpio-use-dev_err_probe-for-gpio-get-failure.patch create mode 100644 lede/target/linux/generic/backport-6.12/801-04-v6.13-clk-clk-gpio-add-driver-for-gated-fixed-clocks.patch delete mode 100644 nekobox-android/app/src/main/res/menu/app_list_neko_menu.xml rename small/luci-app-passwall2/htdocs/luci-static/resources/{ => view/passwall2}/qrcode.min.js (100%) diff --git a/.github/update.log b/.github/update.log index 7fad5d1610..126b6f43a0 100644 --- a/.github/update.log +++ b/.github/update.log @@ -1126,3 +1126,4 @@ Update On Tue Sep 16 20:39:19 CEST 2025 Update On Wed Sep 17 20:39:45 CEST 2025 Update On Thu Sep 18 20:45:33 CEST 2025 Update On Fri Sep 19 20:36:14 CEST 2025 +Update On Sat Sep 20 20:32:16 CEST 2025 diff --git a/clash-nyanpasu/backend/Cargo.lock b/clash-nyanpasu/backend/Cargo.lock index 3282dfd6e4..f3231e7ab9 100644 --- a/clash-nyanpasu/backend/Cargo.lock +++ b/clash-nyanpasu/backend/Cargo.lock @@ -973,7 +973,7 @@ dependencies = [ "boa_interner", "boa_macros", "boa_string", - "indexmap 2.11.1", + "indexmap 2.11.4", "num-bigint", "rustc-hash 2.1.1", ] @@ -999,7 +999,7 @@ dependencies = [ "fast-float2", "hashbrown 0.15.5", "icu_normalizer 1.5.0", - "indexmap 2.11.1", + "indexmap 2.11.4", "intrusive-collections", "itertools 0.13.0", "num-bigint", @@ -1045,7 +1045,7 @@ dependencies = [ "boa_gc", "boa_macros", "hashbrown 0.15.5", - "indexmap 2.11.1", + "indexmap 2.11.4", "once_cell", "phf 0.11.3", "rustc-hash 2.1.1", @@ -1544,7 +1544,7 @@ dependencies = [ "hex", "humansize", "image", - "indexmap 2.11.1", + "indexmap 2.11.4", "itertools 0.14.0", "log", "md-5", @@ -3784,7 +3784,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.11.1", + "indexmap 2.11.4", "slab", "tokio", "tokio-util", @@ -4433,13 +4433,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.1" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "serde", + "serde_core", ] [[package]] @@ -4834,7 +4835,7 @@ checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" dependencies = [ "cssparser", "html5ever", - "indexmap 2.11.1", + "indexmap 2.11.4", "selectors", ] @@ -5361,7 +5362,7 @@ dependencies = [ "half", "hashbrown 0.15.5", "hexf-parse", - "indexmap 2.11.1", + "indexmap 2.11.4", "log", "num-traits", "once_cell", @@ -5752,7 +5753,7 @@ dependencies = [ "http-body-util", "hyper", "hyper-util", - "indexmap 2.11.1", + "indexmap 2.11.4", "interprocess", "nyanpasu-utils", "pin-project-lite", @@ -6722,7 +6723,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset 0.4.2", - "indexmap 2.11.1", + "indexmap 2.11.4", ] [[package]] @@ -6966,7 +6967,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1" dependencies = [ "base64 0.22.1", - "indexmap 2.11.1", + "indexmap 2.11.4", "quick-xml 0.38.3", "serde", "time", @@ -8161,7 +8162,7 @@ version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.4", "itoa", "memchr", "ryu", @@ -8230,7 +8231,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.1", + "indexmap 2.11.4", "schemars 0.9.0", "schemars 1.0.4", "serde", @@ -8258,7 +8259,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.4", "itoa", "ryu", "serde", @@ -8270,7 +8271,7 @@ name = "serde_yaml_ng" version = "0.10.0" source = "git+https://github.com/libnyanpasu/serde-yaml-ng.git?branch=feat/specta#3078760ab9e9a3a9e18ebb4c5d3e577eb74c4a5c" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.4", "itoa", "ryu", "serde", @@ -8669,7 +8670,7 @@ version = "2.0.0-rc.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab7f01e9310a820edd31c80fde3cae445295adde21a3f9416517d7d65015b971" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.4", "paste", "serde", "serde_json", @@ -9937,7 +9938,7 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.4", "serde", "serde_spanned 1.0.0", "toml_datetime 0.7.0", @@ -9970,7 +9971,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.4", "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -9981,7 +9982,7 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.4", "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -9992,7 +9993,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.4", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.11", @@ -11093,7 +11094,7 @@ dependencies = [ "cfg_aliases", "document-features", "hashbrown 0.15.5", - "indexmap 2.11.1", + "indexmap 2.11.4", "log", "naga", "once_cell", @@ -12505,7 +12506,7 @@ dependencies = [ "flate2", "getrandom 0.3.3", "hmac", - "indexmap 2.11.1", + "indexmap 2.11.4", "lzma-rs", "memchr", "pbkdf2", @@ -12525,7 +12526,7 @@ checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" dependencies = [ "arbitrary", "crc32fast", - "indexmap 2.11.1", + "indexmap 2.11.4", "memchr", ] diff --git a/clash-nyanpasu/backend/tauri/src/config/nyanpasu/mod.rs b/clash-nyanpasu/backend/tauri/src/config/nyanpasu/mod.rs index da292c2670..1e1788889e 100644 --- a/clash-nyanpasu/backend/tauri/src/config/nyanpasu/mod.rs +++ b/clash-nyanpasu/backend/tauri/src/config/nyanpasu/mod.rs @@ -277,6 +277,11 @@ pub struct IVerge { /// 是否启用网络统计信息浮窗 #[serde(skip_serializing_if = "Option::is_none")] pub network_statistic_widget: Option, + + /// enable tray text display on Linux systems + /// When enabled, shows proxy and TUN mode status as text next to the tray icon + /// When disabled, only shows status via icon changes (prevents text display issues on Wayland) + pub enable_tray_text: Option, } #[derive(Default, Debug, Clone, Deserialize, Serialize, Type)] @@ -345,6 +350,10 @@ impl IVerge { config.break_when_mode_change = template.break_when_mode_change; } + if config.enable_tray_text.is_none() { + config.enable_tray_text = template.enable_tray_text; + } + config } @@ -379,6 +388,7 @@ impl IVerge { clash_tray_selector: Some(ProxiesSelectorMode::default()), enable_service_mode: Some(false), always_on_top: Some(false), + enable_tray_text: Some(false), ..Self::default() } } diff --git a/clash-nyanpasu/backend/tauri/src/core/tray/mod.rs b/clash-nyanpasu/backend/tauri/src/core/tray/mod.rs index 9b7e7b1d5a..e092cd787f 100644 --- a/clash-nyanpasu/backend/tauri/src/core/tray/mod.rs +++ b/clash-nyanpasu/backend/tauri/src/core/tray/mod.rs @@ -328,12 +328,14 @@ impl Tray { .and_then(|item| item.as_check_menuitem()?.set_checked(mode == "script").ok()); } - let (system_proxy, tun_mode) = { + #[allow(unused_variables)] + let (system_proxy, tun_mode, enable_tray_text) = { let verge = Config::verge(); let verge = verge.latest(); ( *verge.enable_system_proxy.as_ref().unwrap_or(&false), *verge.enable_tun_mode.as_ref().unwrap_or(&false), + *verge.enable_tray_text.as_ref().unwrap_or(&false), ) }; @@ -378,13 +380,17 @@ impl Tray { } #[cfg(target_os = "linux")] { - let _ = tray.set_title(Some(&format!( - "{}: {}\n{}: {}", - t!("tray.system_proxy"), - switch_map[&system_proxy], - t!("tray.tun_mode"), - switch_map[&tun_mode] - ))); + if enable_tray_text { + let _ = tray.set_title(Some(&format!( + "{}: {}\n{}: {}", + t!("tray.system_proxy"), + switch_map[&system_proxy], + t!("tray.tun_mode"), + switch_map[&tun_mode] + ))); + } else { + let _ = tray.set_title::<&str>(None); + } } Ok(()) diff --git a/clash-nyanpasu/backend/tauri/src/feat.rs b/clash-nyanpasu/backend/tauri/src/feat.rs index f1bc7839c3..a7065974de 100644 --- a/clash-nyanpasu/backend/tauri/src/feat.rs +++ b/clash-nyanpasu/backend/tauri/src/feat.rs @@ -291,6 +291,7 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> { let log_level = patch.app_log_level; let log_max_files = patch.max_log_files; let enable_tray_selector = patch.clash_tray_selector; + let enable_tray_text = patch.enable_tray_text; let network_statistic_widget = patch.network_statistic_widget; let res = || async move { let service_mode = patch.enable_service_mode; @@ -356,7 +357,7 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> { if language.is_some() { rust_i18n::set_locale(language.unwrap().as_str()); handle::Handle::update_systray()?; - } else if system_proxy.or(tun_mode).is_some() { + } else if system_proxy.or(tun_mode).or(enable_tray_text).is_some() { handle::Handle::update_systray_part()?; } diff --git a/clash-nyanpasu/frontend/interface/src/ipc/bindings.ts b/clash-nyanpasu/frontend/interface/src/ipc/bindings.ts index 354339b209..b1541f6c91 100644 --- a/clash-nyanpasu/frontend/interface/src/ipc/bindings.ts +++ b/clash-nyanpasu/frontend/interface/src/ipc/bindings.ts @@ -1025,6 +1025,12 @@ export type IVerge = { * 是否启用网络统计信息浮窗 */ network_statistic_widget?: NetworkStatisticWidgetConfig | null + /** + * enable tray text display on Linux systems + * When enabled, shows proxy and TUN mode status as text next to the tray icon + * When disabled, only shows status via icon changes (prevents text display issues on Wayland) + */ + enable_tray_text: boolean | null } export type JsonValue = | null diff --git a/clash-nyanpasu/frontend/interface/src/provider/index.tsx b/clash-nyanpasu/frontend/interface/src/provider/index.tsx index 2c3d2ae773..ed0cb622bb 100644 --- a/clash-nyanpasu/frontend/interface/src/provider/index.tsx +++ b/clash-nyanpasu/frontend/interface/src/provider/index.tsx @@ -1,6 +1,6 @@ import type { PropsWithChildren } from 'react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { ClashWSProvider } from './clash-ws-provider' +import { ClashWSProvider, useClashWSContext } from './clash-ws-provider' import { MutationProvider } from './mutation-provider' const queryClient = new QueryClient() @@ -14,3 +14,5 @@ export const NyanpasuProvider = ({ children }: PropsWithChildren) => { ) } + +export { useClashWSContext } diff --git a/clash-nyanpasu/frontend/interface/src/service/types.ts b/clash-nyanpasu/frontend/interface/src/service/types.ts index f22fb4fc50..fe63be6e95 100644 --- a/clash-nyanpasu/frontend/interface/src/service/types.ts +++ b/clash-nyanpasu/frontend/interface/src/service/types.ts @@ -48,6 +48,7 @@ export interface VergeConfig { clash_strategy?: { external_controller_port_strategy: 'fixed' | 'random' | 'allow_fallback' } + enable_tray_text?: boolean tun_stack?: 'system' | 'gvisor' | 'mixed' always_on_top?: boolean } diff --git a/clash-nyanpasu/frontend/nyanpasu/package.json b/clash-nyanpasu/frontend/nyanpasu/package.json index 840a06721a..1677f1b252 100644 --- a/clash-nyanpasu/frontend/nyanpasu/package.json +++ b/clash-nyanpasu/frontend/nyanpasu/package.json @@ -31,7 +31,7 @@ "country-code-emoji": "2.3.0", "country-emoji": "1.5.6", "dayjs": "1.11.18", - "framer-motion": "12.23.15", + "framer-motion": "12.23.16", "i18next": "25.5.2", "jotai": "2.14.0", "json-schema": "0.4.0", @@ -56,12 +56,12 @@ "@csstools/normalize.css": "12.1.1", "@emotion/babel-plugin": "11.13.5", "@emotion/react": "11.14.0", - "@iconify/json": "2.2.385", + "@iconify/json": "2.2.386", "@monaco-editor/react": "4.7.0", "@tanstack/react-query": "5.87.4", - "@tanstack/react-router": "1.131.48", - "@tanstack/react-router-devtools": "1.131.48", - "@tanstack/router-plugin": "1.131.48", + "@tanstack/react-router": "1.131.49", + "@tanstack/react-router-devtools": "1.131.49", + "@tanstack/router-plugin": "1.131.49", "@tauri-apps/plugin-clipboard-manager": "2.3.0", "@tauri-apps/plugin-dialog": "2.4.0", "@tauri-apps/plugin-fs": "2.4.2", diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/app/modules/route-list-item.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/app/modules/route-list-item.tsx index 0bc2f90184..534d72f43c 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/app/modules/route-list-item.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/app/modules/route-list-item.tsx @@ -2,7 +2,7 @@ import { createElement } from 'react' import { useTranslation } from 'react-i18next' import { languageQuirks } from '@/utils/language' import { SvgIconComponent } from '@mui/icons-material' -import { Box, ListItemButton, ListItemIcon } from '@mui/material' +import { Box, ListItemButton, ListItemIcon, Tooltip } from '@mui/material' import { useSetting } from '@nyanpasu/interface' import { alpha, cn } from '@nyanpasu/ui' import { useMatch, useNavigate } from '@tanstack/react-router' @@ -29,7 +29,7 @@ export const RouteListItem = ({ const { value: language } = useSetting('language') - return ( + const listItemButton = ( ) + + return onlyIcon ? ( + {listItemButton} + ) : ( + listItemButton + ) } export default RouteListItem diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/data-panel.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/data-panel.tsx index ad5128511f..8020d2d387 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/data-panel.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/data-panel.tsx @@ -20,7 +20,7 @@ import { useSetting, } from '@nyanpasu/interface' -export const DataPanel = () => { +export const DataPanel = ({ visible = true }: { visible?: boolean }) => { const { t } = useTranslation() const { data: clashTraffic } = useClashTraffic() @@ -40,7 +40,7 @@ export const DataPanel = () => { .fill(0) .concat(data.slice(-max)) - const Datalines: DatalineProps[] = [ + const Datalines: (DatalineProps & { visible?: boolean })[] = [ { data: padData( clashTraffic?.map((item) => item.down), @@ -50,6 +50,7 @@ export const DataPanel = () => { title: t('Download Traffic'), total: clashConnections?.at(-1)?.downloadTotal, type: 'speed', + visible, }, { data: padData( @@ -60,6 +61,7 @@ export const DataPanel = () => { title: t('Upload Traffic'), total: clashConnections?.at(-1)?.uploadTotal, type: 'speed', + visible, }, { data: padData( @@ -69,6 +71,7 @@ export const DataPanel = () => { icon: SettingsEthernet, title: t('Active Connections'), type: 'raw', + visible, }, ] @@ -80,6 +83,7 @@ export const DataPanel = () => { ), icon: MemoryOutlined, title: t('Memory'), + visible, }) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/dataline.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/dataline.tsx index 1106a83cb6..79204b8d7f 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/dataline.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/dataline.tsx @@ -12,6 +12,7 @@ export interface DatalineProps { title: string total?: number type?: 'speed' | 'raw' + visible?: boolean } export const Dataline: FC = ({ @@ -21,12 +22,17 @@ export const Dataline: FC = ({ total, type, className, + visible = true, }) => { const { t } = useTranslation() return ( - +
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/profiles/profile-item.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/profiles/profile-item.tsx index 96bbc307ce..891b0fc074 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/profiles/profile-item.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/profiles/profile-item.tsx @@ -80,7 +80,7 @@ export const ProfileItem = memo(function ProfileItem({ used = download + upload - progress = (used / total) * 100 + progress = (used / (total || 1)) * 100 } return { progress, total, used } @@ -284,9 +284,7 @@ export const ProfileItem = memo(function ProfileItem({
-
- {((used / total) * 100).toFixed(2)}% -
+
{progress.toFixed(2)}%
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/providers/proxies-provider-traffic.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/providers/proxies-provider-traffic.tsx index 2ebc553820..e8b4cab188 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/providers/proxies-provider-traffic.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/providers/proxies-provider-traffic.tsx @@ -30,9 +30,7 @@ export const ProxiesProviderTraffic = ({ provider }: ProxiesProviderProps) => { -
- {((used / total) * 100).toFixed(2)}% -
+
{progress.toFixed(2)}%
) diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/dashboard.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/dashboard.tsx index a9652d6fef..e4bd2bdfc3 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/dashboard.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/dashboard.tsx @@ -3,7 +3,9 @@ import DataPanel from '@/components/dashboard/data-panel' import HealthPanel from '@/components/dashboard/health-panel' import ProxyShortcuts from '@/components/dashboard/proxy-shortcuts' import ServiceShortcuts from '@/components/dashboard/service-shortcuts' +import { useVisibility } from '@/hooks/use-visibility' import Grid from '@mui/material/Grid' +import { useClashWSContext } from '@nyanpasu/interface' import { BasePage } from '@nyanpasu/ui' import { createFileRoute } from '@tanstack/react-router' @@ -13,11 +15,17 @@ export const Route = createFileRoute('/dashboard')({ function Dashboard() { const { t } = useTranslation() + const visible = useVisibility() + const { setRecordTraffic } = useClashWSContext() + + // When the page is not visible, reduce the traffic data update frequency + // to prevent performance issues when the page is restored + setRecordTraffic(visible) return ( - + diff --git a/clash-nyanpasu/frontend/ui/package.json b/clash-nyanpasu/frontend/ui/package.json index 2d81290bc9..a409a29052 100644 --- a/clash-nyanpasu/frontend/ui/package.json +++ b/clash-nyanpasu/frontend/ui/package.json @@ -23,7 +23,7 @@ "@vitejs/plugin-react": "5.0.3", "ahooks": "3.9.5", "d3": "7.9.0", - "framer-motion": "12.23.15", + "framer-motion": "12.23.16", "react": "19.1.1", "react-dom": "19.1.1", "react-error-boundary": "6.0.0", diff --git a/clash-nyanpasu/frontend/ui/src/chart/sparkline.tsx b/clash-nyanpasu/frontend/ui/src/chart/sparkline.tsx index 5d0657fd46..f81171030d 100644 --- a/clash-nyanpasu/frontend/ui/src/chart/sparkline.tsx +++ b/clash-nyanpasu/frontend/ui/src/chart/sparkline.tsx @@ -7,9 +7,15 @@ interface SparklineProps { data: number[] className?: string style?: CSSProperties + visible?: boolean } -export const Sparkline: FC = ({ data, className, style }) => { +export const Sparkline: FC = ({ + data, + className, + style, + visible = true, +}) => { const theme = useTheme() const { mode } = useColorScheme() @@ -97,6 +103,14 @@ export const Sparkline: FC = ({ data, className, style }) => { .attr('d', line) const updateChart = () => { + // Skip animation if component is not visible to prevent performance issues + if (!visible) { + // Update without animation + svg.select('.area').datum(data).attr('d', area) + svg.select('.line').datum(data).attr('d', line) + return + } + xScale.domain([0, data.length - 1]) yScale.domain([0, d3.max(data) ?? 0]) @@ -123,7 +137,7 @@ export const Sparkline: FC = ({ data, className, style }) => { } updateChart() - }, [data, lineColor, areaColor]) + }, [data, lineColor, areaColor, visible]) return ( =12'} peerDependencies: - '@tanstack/react-router': ^1.131.48 + '@tanstack/react-router': ^1.131.49 react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' - '@tanstack/react-router@1.131.48': - resolution: {integrity: sha512-iT9k/+J4vkoXyI1lBu0StSCLXgfOIMf/IDPh+pZ5HhMPab/wx0PDgIFFgEq9qM1CCykDnKqqeDY0QZWBUS4V1A==} + '@tanstack/react-router@1.131.49': + resolution: {integrity: sha512-WHgWJ053W8VU8lUYh8abSHVPeQdpaCpfaUAbV+3uYXbip2G+qlmI/Gsbh/BBV3bYtIi6l3t5dqx3ffCXNTzB5Q==} engines: {node: '>=12'} peerDependencies: react: '>=18.0.0 || >=19.0.0' @@ -3100,12 +3100,12 @@ packages: resolution: {integrity: sha512-spLqLJ1pD6y8wTxdKSRUS7fMINbuqsTEk1Ot0wxdrD1lKwJT8F7yKovSfl+h2WcifFN84B1gc5F3ZRmcp7fTeA==} engines: {node: '>=12'} - '@tanstack/router-plugin@1.131.48': - resolution: {integrity: sha512-5Bt7M3rP6bYNIwFYhLj5AjPdfBqWmrjIliq06rV1iCQ8GJvXPVSuZHwT+jDzxEsyRzHUjk5kuK3ytimXmexpSQ==} + '@tanstack/router-plugin@1.131.49': + resolution: {integrity: sha512-npL9wqKGMAqaTPqZyZIp1k+omo5Imwvlg/gqQdnphZYIhCJGoxe8CBGQT2zrVnRtL5D7BD9vvpRh2moEDaJF8A==} engines: {node: '>=12'} peerDependencies: '@rsbuild/core': '>=1.0.2' - '@tanstack/react-router': ^1.131.48 + '@tanstack/react-router': ^1.131.49 vite: '>=5.0.0 || >=6.0.0' vite-plugin-solid: ^2.11.2 webpack: '>=5.92.0' @@ -5273,8 +5273,8 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - framer-motion@12.23.15: - resolution: {integrity: sha512-MBxUEHjWr/fRQ2aHg2CgdcjJpHMJ9ttHiPeClHDGiOJOYgmde3OXZUrbWDeeE8yvFrWA62hsPS4+rKQ9OJaoQA==} + framer-motion@12.23.16: + resolution: {integrity: sha512-N81A8hiHqVsexOzI3wzkibyLURW1nEJsZaRuctPhG4AdbbciYu+bKJq9I2lQFzAO4Bx3h4swI6pBbF/Hu7f7BA==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -10243,7 +10243,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@iconify/json@2.2.385': + '@iconify/json@2.2.386': dependencies: '@iconify/types': 2.0.0 pathe: 1.1.2 @@ -11362,9 +11362,9 @@ snapshots: '@tanstack/query-core': 5.87.4 react: 19.1.1 - '@tanstack/react-router-devtools@1.131.48(@tanstack/react-router@1.131.48(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.48)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.5)(tiny-invariant@1.3.3)': + '@tanstack/react-router-devtools@1.131.49(@tanstack/react-router@1.131.49(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.48)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.5)(tiny-invariant@1.3.3)': dependencies: - '@tanstack/react-router': 1.131.48(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@tanstack/react-router': 1.131.49(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@tanstack/router-devtools-core': 1.131.48(@tanstack/router-core@1.131.48)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3) react: 19.1.1 react-dom: 19.1.1(react@19.1.1) @@ -11374,7 +11374,7 @@ snapshots: - solid-js - tiny-invariant - '@tanstack/react-router@1.131.48(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@tanstack/react-router@1.131.49(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@tanstack/history': 1.131.2 '@tanstack/react-store': 0.7.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -11437,7 +11437,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.131.48(@tanstack/react-router@1.131.48(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.6(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))': + '@tanstack/router-plugin@1.131.49(@tanstack/react-router@1.131.49(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.6(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.4 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) @@ -11454,7 +11454,7 @@ snapshots: unplugin: 2.3.10 zod: 3.25.76 optionalDependencies: - '@tanstack/react-router': 1.131.48(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@tanstack/react-router': 1.131.49(react-dom@19.1.1(react@19.1.1))(react@19.1.1) vite: 7.1.6(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -11470,9 +11470,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.131.48(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(zod@4.1.9)': + '@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.131.49(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(zod@4.1.9)': dependencies: - '@tanstack/react-router': 1.131.48(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@tanstack/react-router': 1.131.49(react-dom@19.1.1(react@19.1.1))(react@19.1.1) zod: 4.1.9 '@tanstack/store@0.7.0': {} @@ -14009,7 +14009,7 @@ snapshots: fraction.js@4.3.7: {} - framer-motion@12.23.15(@emotion/is-prop-valid@1.3.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + framer-motion@12.23.16(@emotion/is-prop-valid@1.3.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: motion-dom: 12.23.12 motion-utils: 12.23.6 diff --git a/filebrowser/frontend/src/i18n/ar.json b/filebrowser/frontend/src/i18n/ar.json index 7dcc555d43..70feef517a 100644 --- a/filebrowser/frontend/src/i18n/ar.json +++ b/filebrowser/frontend/src/i18n/ar.json @@ -101,7 +101,10 @@ "submit": "تسجيل دخول", "username": "إسم المستخدم", "usernameTaken": "إسم المستخدم غير متاح", - "wrongCredentials": "بيانات دخول خاطئة" + "wrongCredentials": "بيانات دخول خاطئة", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "دائم", "prompts": { diff --git a/filebrowser/frontend/src/i18n/ca.json b/filebrowser/frontend/src/i18n/ca.json index 6ba909dfec..4d698fa54d 100644 --- a/filebrowser/frontend/src/i18n/ca.json +++ b/filebrowser/frontend/src/i18n/ca.json @@ -101,7 +101,10 @@ "submit": "Iniciar sessió", "username": "Usuari", "usernameTaken": "Nom d'usuari no disponible", - "wrongCredentials": "Usuari i/o contrasenya incorrectes" + "wrongCredentials": "Usuari i/o contrasenya incorrectes", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/filebrowser/frontend/src/i18n/cs.json b/filebrowser/frontend/src/i18n/cs.json index 58029d3a85..c7e3284278 100644 --- a/filebrowser/frontend/src/i18n/cs.json +++ b/filebrowser/frontend/src/i18n/cs.json @@ -101,7 +101,10 @@ "submit": "Přihlásit se", "username": "Uživatelské jméno", "usernameTaken": "Uživatelské jméno již existuje", - "wrongCredentials": "Nesprávné přihlašovací údaje" + "wrongCredentials": "Nesprávné přihlašovací údaje", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Trvalý", "prompts": { diff --git a/filebrowser/frontend/src/i18n/de.json b/filebrowser/frontend/src/i18n/de.json index aaa647de41..d22a3be16f 100644 --- a/filebrowser/frontend/src/i18n/de.json +++ b/filebrowser/frontend/src/i18n/de.json @@ -101,7 +101,10 @@ "submit": "Login", "username": "Benutzername", "usernameTaken": "Benutzername ist bereits vergeben", - "wrongCredentials": "Falsche Zugangsdaten" + "wrongCredentials": "Falsche Zugangsdaten", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/filebrowser/frontend/src/i18n/el.json b/filebrowser/frontend/src/i18n/el.json index 131503564f..9fed72f1fc 100644 --- a/filebrowser/frontend/src/i18n/el.json +++ b/filebrowser/frontend/src/i18n/el.json @@ -101,7 +101,10 @@ "submit": "Είσοδος", "username": "Όνομα χρήστη", "usernameTaken": "Το όνομα χρήστη χρησιμοποιείται ήδη", - "wrongCredentials": "Λάθος όνομα ή/και κωδικός πρόσβασης" + "wrongCredentials": "Λάθος όνομα ή/και κωδικός πρόσβασης", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Μόνιμο", "prompts": { diff --git a/filebrowser/frontend/src/i18n/es.json b/filebrowser/frontend/src/i18n/es.json index 3ab1025d3c..e7f9e882d0 100644 --- a/filebrowser/frontend/src/i18n/es.json +++ b/filebrowser/frontend/src/i18n/es.json @@ -101,7 +101,10 @@ "submit": "Iniciar sesión", "username": "Usuario", "usernameTaken": "Nombre usuario no disponible", - "wrongCredentials": "Usuario y/o contraseña incorrectos" + "wrongCredentials": "Usuario y/o contraseña incorrectos", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanente", "prompts": { diff --git a/filebrowser/frontend/src/i18n/fa.json b/filebrowser/frontend/src/i18n/fa.json index eb8ef99e92..70e10c1221 100644 --- a/filebrowser/frontend/src/i18n/fa.json +++ b/filebrowser/frontend/src/i18n/fa.json @@ -101,7 +101,10 @@ "submit": "ورود", "username": "نام کاربری", "usernameTaken": "نام کاربری تکراری", - "wrongCredentials": "خطا در اعتبارسنجی" + "wrongCredentials": "خطا در اعتبارسنجی", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "دائمی", "prompts": { diff --git a/filebrowser/frontend/src/i18n/fr.json b/filebrowser/frontend/src/i18n/fr.json index c9110f6626..165088077e 100644 --- a/filebrowser/frontend/src/i18n/fr.json +++ b/filebrowser/frontend/src/i18n/fr.json @@ -42,7 +42,8 @@ "update": "Mettre à jour", "upload": "Importer", "openFile": "Ouvrir le fichier", - "discardChanges": "Annuler" + "discardChanges": "Annuler", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Télécharger le fichier", @@ -100,7 +101,10 @@ "submit": "Se connecter", "username": "Utilisateur·ice", "usernameTaken": "Le nom d'utilisateur·ice est déjà pris", - "wrongCredentials": "Identifiants incorrects !" + "wrongCredentials": "Identifiants incorrects !", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/filebrowser/frontend/src/i18n/he.json b/filebrowser/frontend/src/i18n/he.json index b7f13d8874..a8e89a93ed 100644 --- a/filebrowser/frontend/src/i18n/he.json +++ b/filebrowser/frontend/src/i18n/he.json @@ -101,7 +101,10 @@ "submit": "התחברות", "username": "שם משתמש", "usernameTaken": "שם המשתמש כבר קיים", - "wrongCredentials": "פרטי התחברות שגויים" + "wrongCredentials": "פרטי התחברות שגויים", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "קבוע", "prompts": { diff --git a/filebrowser/frontend/src/i18n/hu.json b/filebrowser/frontend/src/i18n/hu.json index 2b426eb68f..00fc419eb9 100644 --- a/filebrowser/frontend/src/i18n/hu.json +++ b/filebrowser/frontend/src/i18n/hu.json @@ -101,7 +101,10 @@ "submit": "Belépés", "username": "Felhasználói név", "usernameTaken": "A felhasználói név már foglalt", - "wrongCredentials": "Hibás hitelesítő adatok" + "wrongCredentials": "Hibás hitelesítő adatok", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Állandó", "prompts": { diff --git a/filebrowser/frontend/src/i18n/is.json b/filebrowser/frontend/src/i18n/is.json index c29ce69854..c55455e56d 100644 --- a/filebrowser/frontend/src/i18n/is.json +++ b/filebrowser/frontend/src/i18n/is.json @@ -101,7 +101,10 @@ "submit": "Innskráning", "username": "Notendanafn", "usernameTaken": "Þetta norendanafn er þegar í notkun", - "wrongCredentials": "Rangar notendaupplýsingar" + "wrongCredentials": "Rangar notendaupplýsingar", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Varanlegt", "prompts": { diff --git a/filebrowser/frontend/src/i18n/it.json b/filebrowser/frontend/src/i18n/it.json index 000bd8ce81..995ba7cdcc 100644 --- a/filebrowser/frontend/src/i18n/it.json +++ b/filebrowser/frontend/src/i18n/it.json @@ -101,7 +101,10 @@ "submit": "Entra", "username": "Nome utente", "usernameTaken": "Username già usato", - "wrongCredentials": "Credenziali errate" + "wrongCredentials": "Credenziali errate", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanente", "prompts": { diff --git a/filebrowser/frontend/src/i18n/ja.json b/filebrowser/frontend/src/i18n/ja.json index 6ce903f75a..99e4b017c1 100644 --- a/filebrowser/frontend/src/i18n/ja.json +++ b/filebrowser/frontend/src/i18n/ja.json @@ -101,7 +101,10 @@ "submit": "ログイン", "username": "ユーザー名", "usernameTaken": "ユーザー名はすでに取得されています", - "wrongCredentials": "ユーザー名またはパスワードが間違っています" + "wrongCredentials": "ユーザー名またはパスワードが間違っています", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "永久", "prompts": { diff --git a/filebrowser/frontend/src/i18n/ko.json b/filebrowser/frontend/src/i18n/ko.json index 54307897b9..ec64bd6249 100644 --- a/filebrowser/frontend/src/i18n/ko.json +++ b/filebrowser/frontend/src/i18n/ko.json @@ -101,7 +101,10 @@ "submit": "로그인", "username": "사용자 이름", "usernameTaken": "사용자 이름이 존재합니다", - "wrongCredentials": "사용자 이름 또는 비밀번호를 확인하십시오" + "wrongCredentials": "사용자 이름 또는 비밀번호를 확인하십시오", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "영구", "prompts": { diff --git a/filebrowser/frontend/src/i18n/nl-be.json b/filebrowser/frontend/src/i18n/nl-be.json index 860f12eda1..c104ef8146 100644 --- a/filebrowser/frontend/src/i18n/nl-be.json +++ b/filebrowser/frontend/src/i18n/nl-be.json @@ -101,7 +101,10 @@ "submit": "Log in", "username": "Gebruikersnaam", "usernameTaken": "Gebruikersnaam reeds in gebruik", - "wrongCredentials": "Verkeerde inloggegevens" + "wrongCredentials": "Verkeerde inloggegevens", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/filebrowser/frontend/src/i18n/no.json b/filebrowser/frontend/src/i18n/no.json index ae35e04e6c..b3ff472f2a 100644 --- a/filebrowser/frontend/src/i18n/no.json +++ b/filebrowser/frontend/src/i18n/no.json @@ -101,7 +101,10 @@ "submit": "Logg inn", "username": "Brukernavn", "usernameTaken": "Brukernavn er allerede i bruk", - "wrongCredentials": "Feil legitimasjon" + "wrongCredentials": "Feil legitimasjon", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/filebrowser/frontend/src/i18n/pl.json b/filebrowser/frontend/src/i18n/pl.json index 5837faa76e..54dd9aed3d 100644 --- a/filebrowser/frontend/src/i18n/pl.json +++ b/filebrowser/frontend/src/i18n/pl.json @@ -101,7 +101,10 @@ "submit": "Zaloguj", "username": "Nazwa użytkownika", "usernameTaken": "Ta nazwa użytkownika jest zajęta", - "wrongCredentials": "Błędne dane logowania" + "wrongCredentials": "Błędne dane logowania", + "logout_reasons": { + "inactivity": "Wylogowano z powodu braku aktywności." + } }, "permanent": "Permanentny", "prompts": { diff --git a/filebrowser/frontend/src/i18n/pt-br.json b/filebrowser/frontend/src/i18n/pt-br.json index ccce0f4d62..8e314c77fb 100644 --- a/filebrowser/frontend/src/i18n/pt-br.json +++ b/filebrowser/frontend/src/i18n/pt-br.json @@ -101,7 +101,10 @@ "submit": "Login", "username": "Nome do usuário", "usernameTaken": "Nome de usuário já existe", - "wrongCredentials": "Ops! Dados incorretos." + "wrongCredentials": "Ops! Dados incorretos.", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanente", "prompts": { diff --git a/filebrowser/frontend/src/i18n/pt.json b/filebrowser/frontend/src/i18n/pt.json index 7babc212c1..4c719cc9e4 100644 --- a/filebrowser/frontend/src/i18n/pt.json +++ b/filebrowser/frontend/src/i18n/pt.json @@ -101,7 +101,10 @@ "submit": "Entrar na conta", "username": "Nome de utilizador", "usernameTaken": "O nome de utilizador já está registado", - "wrongCredentials": "Dados errados" + "wrongCredentials": "Dados errados", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanente", "prompts": { diff --git a/filebrowser/frontend/src/i18n/ro.json b/filebrowser/frontend/src/i18n/ro.json index b03d8c2136..232b0e4dcd 100644 --- a/filebrowser/frontend/src/i18n/ro.json +++ b/filebrowser/frontend/src/i18n/ro.json @@ -101,7 +101,10 @@ "submit": "Autentificare", "username": "Utilizator", "usernameTaken": "Utilizatorul există", - "wrongCredentials": "Informații greșite" + "wrongCredentials": "Informații greșite", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/filebrowser/frontend/src/i18n/ru.json b/filebrowser/frontend/src/i18n/ru.json index 3a9ff33aa2..931cf68dc2 100644 --- a/filebrowser/frontend/src/i18n/ru.json +++ b/filebrowser/frontend/src/i18n/ru.json @@ -101,7 +101,10 @@ "submit": "Войти", "username": "Имя пользователя", "usernameTaken": "Данное имя пользователя уже занято", - "wrongCredentials": "Неверные данные" + "wrongCredentials": "Неверные данные", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Постоянный", "prompts": { diff --git a/filebrowser/frontend/src/i18n/sk.json b/filebrowser/frontend/src/i18n/sk.json index d8b66b581f..2f01ef8c1f 100644 --- a/filebrowser/frontend/src/i18n/sk.json +++ b/filebrowser/frontend/src/i18n/sk.json @@ -101,7 +101,10 @@ "submit": "Prihlásiť", "username": "Používateľské meno", "usernameTaken": "Meno je už obsadené", - "wrongCredentials": "Nesprávne prihlasovacie údaje" + "wrongCredentials": "Nesprávne prihlasovacie údaje", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Trvalé", "prompts": { diff --git a/filebrowser/frontend/src/i18n/sv-se.json b/filebrowser/frontend/src/i18n/sv-se.json index 1131572820..319b7eb2aa 100644 --- a/filebrowser/frontend/src/i18n/sv-se.json +++ b/filebrowser/frontend/src/i18n/sv-se.json @@ -101,7 +101,10 @@ "submit": "Logga in", "username": "Användarnamn", "usernameTaken": "Användarnamn upptaget", - "wrongCredentials": "Fel inloggning" + "wrongCredentials": "Fel inloggning", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/filebrowser/frontend/src/i18n/tr.json b/filebrowser/frontend/src/i18n/tr.json index 6b87681ce1..aa0d3558a1 100644 --- a/filebrowser/frontend/src/i18n/tr.json +++ b/filebrowser/frontend/src/i18n/tr.json @@ -101,7 +101,10 @@ "submit": "Giriş", "username": "Kullanıcı adı", "usernameTaken": "Kullanıcı adı mevcut", - "wrongCredentials": "Yanlış hesap bilgileri" + "wrongCredentials": "Yanlış hesap bilgileri", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Kalıcı", "prompts": { diff --git a/filebrowser/frontend/src/i18n/uk.json b/filebrowser/frontend/src/i18n/uk.json index 7cddd9103a..d3f01c9f64 100644 --- a/filebrowser/frontend/src/i18n/uk.json +++ b/filebrowser/frontend/src/i18n/uk.json @@ -101,7 +101,10 @@ "submit": "Увійти", "username": "Ім'я користувача", "usernameTaken": "Ім'я користувача вже використовується", - "wrongCredentials": "Неправильне ім'я користувача або пароль" + "wrongCredentials": "Неправильне ім'я користувача або пароль", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Постійний", "prompts": { diff --git a/filebrowser/frontend/src/i18n/vi.json b/filebrowser/frontend/src/i18n/vi.json index a84ea286bb..380f98ff73 100644 --- a/filebrowser/frontend/src/i18n/vi.json +++ b/filebrowser/frontend/src/i18n/vi.json @@ -101,7 +101,10 @@ "submit": "Đăng nhập", "username": "Tên người dùng", "usernameTaken": "Tên người dùng đã tồn tại", - "wrongCredentials": "Thông tin đăng nhập không đúng" + "wrongCredentials": "Thông tin đăng nhập không đúng", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Vĩnh viễn", "prompts": { diff --git a/filebrowser/frontend/src/i18n/zh-cn.json b/filebrowser/frontend/src/i18n/zh-cn.json index c50e2d4eab..c18c7e98df 100644 --- a/filebrowser/frontend/src/i18n/zh-cn.json +++ b/filebrowser/frontend/src/i18n/zh-cn.json @@ -101,7 +101,10 @@ "submit": "登录", "username": "用户名", "usernameTaken": "用户名已经被使用", - "wrongCredentials": "用户名或密码错误" + "wrongCredentials": "用户名或密码错误", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "永久", "prompts": { diff --git a/filebrowser/frontend/src/i18n/zh-tw.json b/filebrowser/frontend/src/i18n/zh-tw.json index 1522e28d4f..adcfde91bb 100644 --- a/filebrowser/frontend/src/i18n/zh-tw.json +++ b/filebrowser/frontend/src/i18n/zh-tw.json @@ -101,7 +101,10 @@ "submit": "登入", "username": "帳號", "usernameTaken": "用戶名已存在", - "wrongCredentials": "帳號或密碼錯誤" + "wrongCredentials": "帳號或密碼錯誤", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "永久", "prompts": { diff --git a/lede/package/base-files/files/lib/functions.sh b/lede/package/base-files/files/lib/functions.sh index c688ac77ee..2d79d47db4 100644 --- a/lede/package/base-files/files/lib/functions.sh +++ b/lede/package/base-files/files/lib/functions.sh @@ -315,6 +315,11 @@ include() { done } +ipcalc() { + set -- $(ipcalc.sh "$@") + [ $? -eq 0 ] && export -- "$@" +} + find_mtd_index() { local PART="$(grep "\"$1\"" /proc/mtd | awk -F: '{print $1}')" local INDEX="${PART##mtd}" diff --git a/lede/package/libs/openssl/Makefile b/lede/package/libs/openssl/Makefile index dd16a686a6..8a818b4cbb 100644 --- a/lede/package/libs/openssl/Makefile +++ b/lede/package/libs/openssl/Makefile @@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=openssl -PKG_VERSION:=3.5.2 -PKG_RELEASE:=2 +PKG_VERSION:=3.5.3 +PKG_RELEASE:=1 PKG_USE_MIPS16:=0 PKG_BUILD_FLAGS:=gc-sections no-lto @@ -22,7 +22,7 @@ PKG_SOURCE_URL:= \ https://www.openssl.org/source/old/$(PKG_BASE)/ \ https://github.com/openssl/openssl/releases/download/$(PKG_NAME)-$(PKG_VERSION)/ -PKG_HASH:=c53a47e5e441c930c3928cf7bf6fb00e5d129b630e0aa873b08258656e7345ec +PKG_HASH:=c9489d2abcf943cdc8329a57092331c598a402938054dc3a22218aea8a8ec3bf PKG_LICENSE:=Apache-2.0 PKG_LICENSE_FILES:=LICENSE.txt diff --git a/lede/package/libs/openssl/patches/0001-Don-t-keep-the-store-open-in-by_store_ctrl_ex.patch b/lede/package/libs/openssl/patches/0001-Don-t-keep-the-store-open-in-by_store_ctrl_ex.patch deleted file mode 100644 index c1455815dd..0000000000 --- a/lede/package/libs/openssl/patches/0001-Don-t-keep-the-store-open-in-by_store_ctrl_ex.patch +++ /dev/null @@ -1,129 +0,0 @@ -From c4c92f3e8aff38d75047847ded940e1b3f9b688f Mon Sep 17 00:00:00 2001 -From: Matt Caswell -Date: Thu, 7 Aug 2025 17:50:17 +0100 -Subject: [PATCH] Don't keep the store open in by_store_ctrl_ex -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Previously #27529 made a change to `by_store_ctrl_ex` in order to open -the OSSL_STORE early. The reason given in that PR is: - -"This way, we can call OSSL_STORE_open_ex() in by_store_ctrl_ex(), and -get to see possible errors when the URI is loaded" - -That PR then kept the store open until cache_objects is called and then -reused it. Unfortunately by the time cache_objects() is called we could be -in a multi-threaded scenario where the X509_STORE is being shared by -multiple threads. We then get a race condition where multiple threads are -all using (and ultimately closing) the same `OSSL_STORE_CTX`. - -The purpose of keeping the `OSSL_STORE` object between by_store_ctrl_ex() -and `cache_objects` is presumably an optimisation to avoid having to open -the store twice. But this does not work because of the above issue. - -We just take the hit and open it again. - -Fixes #28171 - -Reviewed-by: Saša Nedvědický -Reviewed-by: Tomas Mraz -(Merged from https://github.com/openssl/openssl/pull/28198) - -(cherry picked from commit 08951fb27306ad9b4365103b8616b8545658ffcc) ---- - crypto/x509/by_store.c | 26 +++++++++++++------------- - 1 file changed, 13 insertions(+), 13 deletions(-) - ---- a/crypto/x509/by_store.c -+++ b/crypto/x509/by_store.c -@@ -17,7 +17,6 @@ typedef struct cached_store_st { - char *uri; - OSSL_LIB_CTX *libctx; - char *propq; -- OSSL_STORE_CTX *ctx; - } CACHED_STORE; - - DEFINE_STACK_OF(CACHED_STORE) -@@ -27,14 +26,12 @@ static int cache_objects(X509_LOOKUP *lc - const OSSL_STORE_SEARCH *criterion, int depth) - { - int ok = 0; -- OSSL_STORE_CTX *ctx = store->ctx; -+ OSSL_STORE_CTX *ctx; - X509_STORE *xstore = X509_LOOKUP_get_store(lctx); - -- if (ctx == NULL -- && (ctx = OSSL_STORE_open_ex(store->uri, store->libctx, store->propq, -- NULL, NULL, NULL, NULL, NULL)) == NULL) -+ if ((ctx = OSSL_STORE_open_ex(store->uri, store->libctx, store->propq, -+ NULL, NULL, NULL, NULL, NULL)) == NULL) - return 0; -- store->ctx = ctx; - - /* - * We try to set the criterion, but don't care if it was valid or not. -@@ -79,7 +76,6 @@ static int cache_objects(X509_LOOKUP *lc - substore.uri = (char *)OSSL_STORE_INFO_get0_NAME(info); - substore.libctx = store->libctx; - substore.propq = store->propq; -- substore.ctx = NULL; - ok = cache_objects(lctx, &substore, criterion, depth - 1); - } - } else { -@@ -105,7 +101,6 @@ static int cache_objects(X509_LOOKUP *lc - break; - } - OSSL_STORE_close(ctx); -- store->ctx = NULL; - - return ok; - } -@@ -114,7 +109,6 @@ static int cache_objects(X509_LOOKUP *lc - static void free_store(CACHED_STORE *store) - { - if (store != NULL) { -- OSSL_STORE_close(store->ctx); - OPENSSL_free(store->uri); - OPENSSL_free(store->propq); - OPENSSL_free(store); -@@ -136,6 +130,7 @@ static int by_store_ctrl_ex(X509_LOOKUP - if (argp != NULL) { - STACK_OF(CACHED_STORE) *stores = X509_LOOKUP_get_method_data(ctx); - CACHED_STORE *store = OPENSSL_zalloc(sizeof(*store)); -+ OSSL_STORE_CTX *sctx; - - if (store == NULL) { - return 0; -@@ -145,14 +140,20 @@ static int by_store_ctrl_ex(X509_LOOKUP - store->libctx = libctx; - if (propq != NULL) - store->propq = OPENSSL_strdup(propq); -- store->ctx = OSSL_STORE_open_ex(argp, libctx, propq, NULL, NULL, -- NULL, NULL, NULL); -- if (store->ctx == NULL -+ /* -+ * We open this to check for errors now - so we can report those -+ * errors early. -+ */ -+ sctx = OSSL_STORE_open_ex(argp, libctx, propq, NULL, NULL, -+ NULL, NULL, NULL); -+ if (sctx == NULL - || (propq != NULL && store->propq == NULL) - || store->uri == NULL) { -+ OSSL_STORE_close(sctx); - free_store(store); - return 0; - } -+ OSSL_STORE_close(sctx); - - if (stores == NULL) { - stores = sk_CACHED_STORE_new_null(); -@@ -174,7 +175,6 @@ static int by_store_ctrl_ex(X509_LOOKUP - store.uri = (char *)argp; - store.libctx = libctx; - store.propq = (char *)propq; -- store.ctx = NULL; - return cache_objects(ctx, &store, NULL, 0); - } - default: diff --git a/lede/package/network/services/dnsmasq/Makefile b/lede/package/network/services/dnsmasq/Makefile index d2fe1e51e7..aabac5d3ee 100644 --- a/lede/package/network/services/dnsmasq/Makefile +++ b/lede/package/network/services/dnsmasq/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2006-2022 OpenWrt.org +# Copyright (C) 2006-2016 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dnsmasq PKG_UPSTREAM_VERSION:=2.91 PKG_VERSION:=$(subst test,~~test,$(subst rc,~rc,$(PKG_UPSTREAM_VERSION))) -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_UPSTREAM_VERSION).tar.xz PKG_SOURCE_URL:=https://thekelleys.org.uk/dnsmasq/ @@ -24,6 +24,7 @@ PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_UPSTR PKG_INSTALL:=1 PKG_BUILD_PARALLEL:=1 +PKG_BUILD_FLAGS:=lto PKG_ASLR_PIE_REGULAR:=1 PKG_CONFIG_DEPENDS:= CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcp \ CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcpv6 \ @@ -108,16 +109,16 @@ define Package/dnsmasq-full/config default n config PACKAGE_dnsmasq_full_auth bool "Build with the facility to act as an authoritative DNS server." - default n + default y config PACKAGE_dnsmasq_full_ipset bool "Build with IPset support." default y config PACKAGE_dnsmasq_full_nftset bool "Build with Nftset support." - default n + default y config PACKAGE_dnsmasq_full_conntrack bool "Build with Conntrack support." - default n + default y config PACKAGE_dnsmasq_full_noid bool "Build with NO_ID. (hide *.bind pseudo domain)" default n @@ -133,9 +134,6 @@ endef Package/dnsmasq-dhcpv6/conffiles = $(Package/dnsmasq/conffiles) Package/dnsmasq-full/conffiles = $(Package/dnsmasq/conffiles) -TARGET_CFLAGS += -flto -TARGET_LDFLAGS += -flto=jobserver - COPTS = -DHAVE_UBUS -DHAVE_POLL_H \ $(if $(CONFIG_IPV6),,-DNO_IPV6) diff --git a/lede/package/network/services/dnsmasq/files/dhcp-script.sh b/lede/package/network/services/dnsmasq/files/dhcp-script.sh index 470097bf6b..f0c8b50902 100755 --- a/lede/package/network/services/dnsmasq/files/dhcp-script.sh +++ b/lede/package/network/services/dnsmasq/files/dhcp-script.sh @@ -8,6 +8,15 @@ json_init json_add_array env hotplugobj="" +oldIFS=$IFS +IFS=$'\n' +for var in $(env); do + if [ "${var}" != "${var#DNSMASQ_}" ]; then + json_add_string "" "${var%%=*}=${var#*=}" + fi +done +IFS=$oldIFS + case "$1" in add | del | old | arp-add | arp-del) json_add_string "" "MACADDR=$2" diff --git a/lede/package/network/services/dnsmasq/files/dhcp.conf b/lede/package/network/services/dnsmasq/files/dhcp.conf index 3f054f5feb..d5b9dfa018 100644 --- a/lede/package/network/services/dnsmasq/files/dhcp.conf +++ b/lede/package/network/services/dnsmasq/files/dhcp.conf @@ -10,7 +10,7 @@ config dnsmasq option domain 'lan' option expandhosts 1 option nonegcache 0 - option cachesize 8192 + option cachesize 1000 option authoritative 1 option readethers 1 option leasefile '/tmp/dhcp.leases' diff --git a/lede/package/network/services/dnsmasq/files/dnsmasq.init b/lede/package/network/services/dnsmasq/files/dnsmasq.init index 7fa50803f9..6f31636a0d 100755 --- a/lede/package/network/services/dnsmasq/files/dnsmasq.init +++ b/lede/package/network/services/dnsmasq/files/dnsmasq.init @@ -12,6 +12,7 @@ ADD_WAN_FQDN=0 ADD_LOCAL_FQDN="" BASECONFIGFILE="/var/etc/dnsmasq.conf" +EXTRACONFFILE="extraconfig.conf" BASEHOSTFILE="/tmp/hosts/dhcp" TRUSTANCHORSFILE="/usr/share/dnsmasq/trust-anchors.conf" TIMEVALIDFILE="/var/state/dnsmasqsec" @@ -19,7 +20,7 @@ BASEDHCPSTAMPFILE="/var/run/dnsmasq" DHCPBOGUSHOSTNAMEFILE="/usr/share/dnsmasq/dhcpbogushostname.conf" RFC6761FILE="/usr/share/dnsmasq/rfc6761.conf" DHCPSCRIPT="/usr/lib/dnsmasq/dhcp-script.sh" -DHCPSCRIPT_DEPENDS="/usr/share/libubox/jshn.sh /usr/bin/jshn /bin/ubus" +DHCPSCRIPT_DEPENDS="/usr/share/libubox/jshn.sh /usr/bin/jshn /bin/ubus /usr/bin/env" DNSMASQ_DHCP_VER=4 @@ -33,6 +34,7 @@ dnsmasq_ignore_opt() { [ "${dnsmasq_features#* DNSSEC }" = "$dnsmasq_features" ] || dnsmasq_has_dnssec=1 [ "${dnsmasq_features#* TFTP }" = "$dnsmasq_features" ] || dnsmasq_has_tftp=1 [ "${dnsmasq_features#* ipset }" = "$dnsmasq_features" ] || dnsmasq_has_ipset=1 + [ "${dnsmasq_features#* nftset }" = "$dnsmasq_features" ] || dnsmasq_has_nftset=1 fi case "$opt" in @@ -55,6 +57,8 @@ dnsmasq_ignore_opt() { [ -z "$dnsmasq_has_tftp" ] ;; ipset) [ -z "$dnsmasq_has_ipset" ] ;; + nftset) + [ -z "$dnsmasq_has_nftset" ] ;; *) return 1 esac @@ -65,7 +69,7 @@ xappend() { local opt="${value%%=*}" if ! dnsmasq_ignore_opt "$opt"; then - echo "$value" >>$CONFIGFILE_TMP + echo "$value" >>"$CONFIGFILE_TMP" fi } @@ -169,10 +173,6 @@ append_address() { xappend "--address=$1" } -append_ipset() { - xappend "--ipset=$1" -} - append_connmark_allowlist() { xappend "--connmark-allowlist=$1" } @@ -205,8 +205,12 @@ ismounted() { return 1 } -append_addnhosts() { +append_extramount() { ismounted "$1" || append EXTRA_MOUNT "$1" +} + +append_addnhosts() { + append_extramount "$1" xappend "--addn-hosts=$1" } @@ -222,6 +226,14 @@ append_interface_name() { xappend "--interface-name=$1,$2" } +append_filter_rr() { + xappend "--filter-rr=$1" +} + +append_cache_rr() { + xappend "--cache-rr=$1" +} + filter_dnsmasq() { local cfg="$1" func="$2" match_cfg="$3" found_cfg @@ -350,7 +362,7 @@ dhcp_host_add() { config_get_bool dns "$cfg" dns 0 [ "$dns" = "1" ] && [ -n "$ip" ] && [ -n "$name" ] && { - echo "$ip $name${DOMAIN:+.$DOMAIN}" >> $HOSTFILE_TMP + echo "$ip $name${DOMAIN:+.$DOMAIN}" >> "$HOSTFILE_TMP" } config_get mac "$cfg" mac @@ -499,14 +511,13 @@ dhcp_boot_add() { [ -n "$serveraddress" ] && [ ! -n "$servername" ] && return 0 - xappend "--dhcp-boot=${networkid:+net:$networkid,}${filename}${servername:+,$servername}${serveraddress:+,$serveraddress}" + xappend "--dhcp-boot=${networkid:+tag:$networkid,}${filename}${servername:+,$servername}${serveraddress:+,$serveraddress}" config_get_bool force "$cfg" force 0 dhcp_option_add "$cfg" "$networkid" "$force" } - dhcp_add() { local cfg="$1" local dhcp6range="::" @@ -537,8 +548,13 @@ dhcp_add() { # Do not support non-static interfaces for now [ static = "$proto" ] || return 0 + ipaddr="${subnet%%/*}" + prefix_or_netmask="${subnet##*/}" + # Override interface netmask with dhcp config if applicable - config_get netmask "$cfg" netmask "${subnet##*/}" + config_get netmask "$cfg" netmask + + [ -n "$netmask" ] && prefix_or_netmask="$netmask" #check for an already active dhcp server on the interface, unless 'force' is set config_get_bool force "$cfg" force 0 @@ -554,6 +570,8 @@ dhcp_add() { config_get leasetime "$cfg" leasetime 12h config_get options "$cfg" options config_get_bool dynamicdhcp "$cfg" dynamicdhcp 1 + config_get_bool dynamicdhcpv4 "$cfg" dynamicdhcpv4 $dynamicdhcp + config_get_bool dynamicdhcpv6 "$cfg" dynamicdhcpv6 $dynamicdhcp config_get dhcpv4 "$cfg" dhcpv4 config_get dhcpv6 "$cfg" dhcpv6 @@ -578,25 +596,30 @@ dhcp_add() { nettag="${networkid:+set:${networkid},}" - if [ "$limit" -gt 0 ] ; then - limit=$((limit-1)) + # make sure the DHCP range is not empty + if [ "$dhcpv4" != "disabled" ]; then + unset START + unset END + unset NETMASK + ipcalc "$ipaddr/$prefix_or_netmask" "$start" "$limit" + + if [ -z "$START" ] || [ -z "$END" ] || [ -z "$NETMASK" ]; then + logger -t dnsmasq \ + "unable to set dhcp-range for dhcp uci config section '$cfg'" \ + "on interface '$ifname', please check your config" + else + [ "$dynamicdhcpv4" = "0" ] && END="static" + xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}" + fi fi - eval "$(ipcalc.sh "${subnet%%/*}" $netmask $start $limit)" - - if [ "$dynamicdhcp" = "0" ] ; then - END="static" + if [ "$dynamicdhcpv6" = "0" ] ; then dhcp6range="::,static" else dhcp6range="::1000,::ffff" fi - if [ "$dhcpv4" != "disabled" ] ; then - xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}" - fi - - if [ $DNSMASQ_DHCP_VER -eq 6 ] && [ "$ra" = "server" ] ; then # Note: dnsmasq cannot just be a DHCPv6 server (all-in-1) # and let some other machine(s) send RA pointing to it. @@ -709,7 +732,7 @@ dhcp_domain_add() { record="${record:+$record }$name" done - echo "$ip $record" >> $HOSTFILE_TMP + echo "$ip $record" >> "$HOSTFILE_TMP" } dhcp_srv_add() { @@ -783,6 +806,29 @@ dhcp_hostrecord_add() { xappend "--host-record=$record" } +dhcp_dnsrr_add() { + #This adds arbitrary resource record types (of IN class) whose optional data must be hex + local cfg="$1" + local rrname rrnumber hexdata + + config_get rrname "$cfg" rrname + [ -n "$rrname" ] || return 0 + + config_get rrnumber "$cfg" rrnumber + [ -n "$rrnumber" ] && [ "$rrnumber" -gt 0 ] || return 0 + + config_get hexdata "$cfg" hexdata + + # dnsmasq accepts colon XX:XX:.., space XX XX .., or contiguous XXXX.. hex forms or mixtures thereof + if [ -n "${hexdata//[0-9a-fA-F\:\ ]/}" ]; then + # is invalid hex literal + echo "dnsmasq: \"$hexdata\" is malformed hexadecimal (separate hex with colon, space or not at all)." >&2 + return 1 + fi + + xappend "--dns-rr=${rrname},${rrnumber}${hexdata:+,$hexdata}" +} + dhcp_relay_add() { local cfg="$1" local local_addr server_addr interface @@ -804,30 +850,61 @@ dhcp_relay_add() { dnsmasq_ipset_add() { local cfg="$1" - local ipsets + local ipsets nftsets domains add_ipset() { ipsets="${ipsets:+$ipsets,}$1" } - add_domain() { - xappend "--ipset=/$1/$ipsets" + add_nftset() { + local IFS=, + for set in $1; do + local fam="$family" + [ -n "$fam" ] || fam=$(echo "$set" | sed -nre \ + 's#^.*[^0-9]([46])$|^.*[-_]([46])[-_].*$|^([46])[^0-9].*$#\1\2\3#p') + [ -n "$fam" ] || \ + fam=$(nft -t list set "$table_family" "$table" "$set" 2>&1 | sed -nre \ + 's#^\t\ttype .*\bipv([46])_addr\b.*$#\1#p') + + [ -n "$fam" ] || \ + logger -t dnsmasq "Cannot infer address family from non-existent nftables set '$set'" + + nftsets="${nftsets:+$nftsets,}${fam:+$fam#}$table_family#$table#$set" + done } - config_list_foreach "$cfg" "name" add_ipset + add_domain() { + # leading '/' is expected + domains="$domains/$1" + } - if [ -z "$ipsets" ]; then + config_get table "$cfg" table 'fw4' + config_get table_family "$cfg" table_family 'inet' + if [ "$table_family" = "ip" ] ; then + family="4" + elif [ "$table_family" = "ip6" ] ; then + family="6" + else + config_get family "$cfg" family + fi + + config_list_foreach "$cfg" "name" add_ipset + config_list_foreach "$cfg" "name" add_nftset + config_list_foreach "$cfg" "domain" add_domain + + if [ -z "$ipsets" ] || [ -z "$nftsets" ] || [ -z "$domains" ]; then return 0 fi - config_list_foreach "$cfg" "domain" add_domain + xappend "--ipset=$domains/$ipsets" + xappend "--nftset=$domains/$nftsets" } dnsmasq_start() { local cfg="$1" - local disabled user_dhcpscript - local resolvfile resolvdir localuse=0 + local disabled user_dhcpscript logfacility + local resolvfile resolvdir localuse=1 config_get_bool disabled "$cfg" disabled 0 [ "$disabled" -gt 0 ] && return 0 @@ -846,13 +923,13 @@ dnsmasq_start() # before we can call xappend umask u=rwx,g=rx,o=rx mkdir -p /var/run/dnsmasq/ - mkdir -p $(dirname $CONFIGFILE) + mkdir -p "$(dirname "$CONFIGFILE")" mkdir -p "$HOSTFILE_DIR" mkdir -p /var/lib/misc chown dnsmasq:dnsmasq /var/run/dnsmasq - echo "# auto-generated config file from /etc/config/dhcp" > $CONFIGFILE_TMP - echo "# auto-generated config file from /etc/config/dhcp" > $HOSTFILE_TMP + echo "# auto-generated config file from /etc/config/dhcp" > "$CONFIGFILE_TMP" + echo "# auto-generated config file from /etc/config/dhcp" > "$HOSTFILE_TMP" local dnsmasqconffile="/etc/dnsmasq.${cfg}.conf" if [ ! -r "$dnsmasqconffile" ]; then @@ -938,11 +1015,14 @@ dnsmasq_start() append_bool "$cfg" rapidcommit "--dhcp-rapid-commit" append_bool "$cfg" scriptarp "--script-arp" + # deprecate or remove filter-X in favor of filter-rr? append_bool "$cfg" filter_aaaa "--filter-AAAA" append_bool "$cfg" filter_a "--filter-A" + config_list_foreach "$cfg" filter_rr append_filter_rr + config_list_foreach "$cfg" cache_rr append_cache_rr append_parm "$cfg" logfacility "--log-facility" - + config_get logfacility "$cfg" "logfacility" append_parm "$cfg" cachesize "--cache-size" append_parm "$cfg" dnsforwardmax "--dns-forward-max" append_parm "$cfg" port "--port" @@ -957,7 +1037,6 @@ dnsmasq_start() config_list_foreach "$cfg" "server" append_server config_list_foreach "$cfg" "rev_server" append_rev_server config_list_foreach "$cfg" "address" append_address - config_list_foreach "$cfg" "ipset" append_ipset local connmark_allowlist_enable config_get connmark_allowlist_enable "$cfg" connmark_allowlist_enable 0 @@ -981,7 +1060,14 @@ dnsmasq_start() config_list_foreach "$cfg" "addnhosts" append_addnhosts config_list_foreach "$cfg" "bogusnxdomain" append_bogusnxdomain append_parm "$cfg" "leasefile" "--dhcp-leasefile" "/tmp/dhcp.leases" - append_parm "$cfg" "serversfile" "--servers-file" + + local serversfile + config_get serversfile "$cfg" "serversfile" + [ -n "$serversfile" ] && { + xappend "--servers-file=$serversfile" + append EXTRA_MOUNT "$serversfile" + } + append_parm "$cfg" "tftp_root" "--tftp-root" append_parm "$cfg" "dhcp_boot" "--dhcp-boot" append_parm "$cfg" "local_ttl" "--local-ttl" @@ -1018,7 +1104,7 @@ dnsmasq_start() config_get resolvfile "$cfg" resolvfile /tmp/resolv.conf.d/resolv.conf.auto [ -n "$resolvfile" ] && [ ! -e "$resolvfile" ] && touch "$resolvfile" xappend "--resolv-file=$resolvfile" - [ "$resolvfile" = "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=1 + [ "$resolvfile" != "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=0 resolvdir="$(dirname "$resolvfile")" fi config_get_bool localuse "$cfg" localuse "$localuse" @@ -1067,6 +1153,9 @@ dnsmasq_start() [ "$addmac" = "1" ] && addmac= xappend "--add-mac${addmac:+="$addmac"}" } + append_bool "$cfg" stripmac "--strip-mac" + append_parm "$cfg" addsubnet "--add-subnet" + append_bool "$cfg" stripsubnet "--strip-subnet" dhcp_option_add "$cfg" "" 0 dhcp_option_add "$cfg" "" 2 @@ -1080,7 +1169,7 @@ dnsmasq_start() [ ! -d "$dnsmasqconfdir" ] && mkdir -p $dnsmasqconfdir xappend "--user=dnsmasq" xappend "--group=dnsmasq" - echo >> $CONFIGFILE_TMP + echo >> "$CONFIGFILE_TMP" config_get_bool enable_tftp "$cfg" enable_tftp 0 [ "$enable_tftp" -gt 0 ] && { @@ -1089,7 +1178,7 @@ dnsmasq_start() } config_foreach filter_dnsmasq host dhcp_host_add "$cfg" - echo >> $CONFIGFILE_TMP + echo >> "$CONFIGFILE_TMP" config_get_bool dhcpbogushostname "$cfg" dhcpbogushostname 1 [ "$dhcpbogushostname" -gt 0 ] && { @@ -1108,12 +1197,13 @@ dnsmasq_start() config_foreach filter_dnsmasq match dhcp_match_add "$cfg" config_foreach filter_dnsmasq domain dhcp_domain_add "$cfg" config_foreach filter_dnsmasq hostrecord dhcp_hostrecord_add "$cfg" + config_foreach filter_dnsmasq dnsrr dhcp_dnsrr_add "$cfg" [ -n "$BOOT" ] || config_foreach filter_dnsmasq relay dhcp_relay_add "$cfg" - echo >> $CONFIGFILE_TMP + echo >> "$CONFIGFILE_TMP" config_foreach filter_dnsmasq srvhost dhcp_srv_add "$cfg" config_foreach filter_dnsmasq mxhost dhcp_mx_add "$cfg" - echo >> $CONFIGFILE_TMP + echo >> "$CONFIGFILE_TMP" config_get_bool boguspriv "$cfg" boguspriv 1 [ "$boguspriv" -gt 0 ] && { @@ -1135,16 +1225,16 @@ dnsmasq_start() fi - echo >> $CONFIGFILE_TMP + echo >> "$CONFIGFILE_TMP" config_foreach filter_dnsmasq cname dhcp_cname_add "$cfg" - echo >> $CONFIGFILE_TMP + echo >> "$CONFIGFILE_TMP" - echo >> $CONFIGFILE_TMP + echo >> "$CONFIGFILE_TMP" config_foreach filter_dnsmasq ipset dnsmasq_ipset_add "$cfg" - echo >> $CONFIGFILE_TMP + echo >> "$CONFIGFILE_TMP" - mv -f $CONFIGFILE_TMP $CONFIGFILE - mv -f $HOSTFILE_TMP $HOSTFILE + mv -f "$CONFIGFILE_TMP" "$CONFIGFILE" + mv -f "$HOSTFILE_TMP" "$HOSTFILE" [ "$localuse" -gt 0 ] && { rm -f /tmp/resolv.conf @@ -1158,18 +1248,30 @@ dnsmasq_start() done } + config_list_foreach "$cfg" addnmount append_extramount + procd_open_instance $cfg procd_set_param command $PROG -C $CONFIGFILE -k -x /var/run/dnsmasq/dnsmasq."${cfg}".pid procd_set_param file $CONFIGFILE [ -n "$user_dhcpscript" ] && procd_set_param env USER_DHCPSCRIPT="$user_dhcpscript" procd_set_param respawn + local instance_ifc instance_netdev + config_get instance_ifc "$cfg" interface + [ -n "$instance_ifc" ] && network_get_device instance_netdev "$instance_ifc" && + [ -n "$instance_netdev" ] && procd_set_param netdev $instance_netdev + procd_add_jail dnsmasq ubus log procd_add_jail_mount $CONFIGFILE $DHCPBOGUSHOSTNAMEFILE $DHCPSCRIPT $DHCPSCRIPT_DEPENDS procd_add_jail_mount $EXTRA_MOUNT $RFC6761FILE $TRUSTANCHORSFILE procd_add_jail_mount $dnsmasqconffile $dnsmasqconfdir $resolvdir $user_dhcpscript procd_add_jail_mount /etc/passwd /etc/group /etc/TZ /etc/hosts /etc/ethers procd_add_jail_mount_rw /var/run/dnsmasq/ $leasefile + case "$logfacility" in */*) + [ ! -e "$logfacility" ] && touch "$logfacility" + procd_add_jail_mount_rw "$logfacility" + esac + [ -e "$hostsfile" ] && procd_add_jail_mount $hostsfile procd_close_instance } @@ -1177,12 +1279,12 @@ dnsmasq_start() dnsmasq_stop() { local cfg="$1" - local noresolv resolvfile localuse=0 + local noresolv resolvfile localuse=1 config_get_bool noresolv "$cfg" noresolv 0 config_get resolvfile "$cfg" "resolvfile" - [ "$noresolv" = 0 ] && [ "$resolvfile" = "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=1 + [ "$noresolv" = 0 ] && [ "$resolvfile" != "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=0 config_get_bool localuse "$cfg" localuse "$localuse" [ "$localuse" -gt 0 ] && ln -sf "/tmp/resolv.conf.d/resolv.conf.auto" /tmp/resolv.conf @@ -1191,10 +1293,11 @@ dnsmasq_stop() add_interface_trigger() { - local interface ignore + local interface ifname ignore config_get interface "$1" interface config_get_bool ignore "$1" ignore 0 + network_get_device ifname "$interface" || ignore=0 [ -n "$interface" ] && [ $ignore -eq 0 ] && procd_add_interface_trigger "interface.*" "$interface" /etc/init.d/dnsmasq reload } diff --git a/lede/package/network/services/dnsmasq/patches/200-ubus_dns.patch b/lede/package/network/services/dnsmasq/patches/200-ubus_dns.patch index 21e9e57c9c..a1a668818e 100644 --- a/lede/package/network/services/dnsmasq/patches/200-ubus_dns.patch +++ b/lede/package/network/services/dnsmasq/patches/200-ubus_dns.patch @@ -275,4 +275,4 @@ + void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface) { - struct ubus_context *ubus = (struct ubus_context *)daemon->ubus; \ No newline at end of file + struct ubus_context *ubus = (struct ubus_context *)daemon->ubus; diff --git a/lede/target/linux/generic/backport-6.12/801-02-v6.13-clk-clk-gpio-update-documentation-for-gpio-gate-cloc.patch b/lede/target/linux/generic/backport-6.12/801-02-v6.13-clk-clk-gpio-update-documentation-for-gpio-gate-cloc.patch new file mode 100644 index 0000000000..99e41a1e99 --- /dev/null +++ b/lede/target/linux/generic/backport-6.12/801-02-v6.13-clk-clk-gpio-update-documentation-for-gpio-gate-cloc.patch @@ -0,0 +1,27 @@ +From 6cb137c7e99f8307f1f0fcccb1896f2d3b0651d3 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 6 Sep 2024 10:25:08 +0200 +Subject: clk: clk-gpio: update documentation for gpio-gate clock + +The main documentation block seems to be from a time before the driver +handled sleeping and non-sleeping gpios and with that change it seems +updating the doc was overlooked. So do that now. + +Signed-off-by: Heiko Stuebner +Link: https://lore.kernel.org/r/20240906082511.2963890-3-heiko@sntech.de +Signed-off-by: Stephen Boyd + +--- a/drivers/clk/clk-gpio.c ++++ b/drivers/clk/clk-gpio.c +@@ -22,8 +22,9 @@ + * DOC: basic gpio gated clock which can be enabled and disabled + * with gpio output + * Traits of this clock: +- * prepare - clk_(un)prepare only ensures parent is (un)prepared +- * enable - clk_enable and clk_disable are functional & control gpio ++ * prepare - clk_(un)prepare are functional and control a gpio that can sleep ++ * enable - clk_enable and clk_disable are functional & control ++ * non-sleeping gpio + * rate - inherits rate from parent. No clk_set_rate support + * parent - fixed parent. No clk_set_parent support + */ diff --git a/lede/target/linux/generic/backport-6.12/801-03-v6.13-clk-clk-gpio-use-dev_err_probe-for-gpio-get-failure.patch b/lede/target/linux/generic/backport-6.12/801-03-v6.13-clk-clk-gpio-use-dev_err_probe-for-gpio-get-failure.patch new file mode 100644 index 0000000000..1982bb365e --- /dev/null +++ b/lede/target/linux/generic/backport-6.12/801-03-v6.13-clk-clk-gpio-use-dev_err_probe-for-gpio-get-failure.patch @@ -0,0 +1,44 @@ +From 36abe81d9c3fa200a57ef2363e93a2991e387e19 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 6 Sep 2024 10:25:09 +0200 +Subject: clk: clk-gpio: use dev_err_probe for gpio-get failure + +This is a real driver and dev_err_probe will hide the distinction between +EPROBE_DEFER and other errors automatically, so there is no need to +open-code this. + +Signed-off-by: Heiko Stuebner +Link: https://lore.kernel.org/r/20240906082511.2963890-4-heiko@sntech.de +Signed-off-by: Stephen Boyd + +--- a/drivers/clk/clk-gpio.c ++++ b/drivers/clk/clk-gpio.c +@@ -200,7 +200,6 @@ static int gpio_clk_driver_probe(struct + struct gpio_desc *gpiod; + struct clk_hw *hw; + bool is_mux; +- int ret; + + is_mux = of_device_is_compatible(node, "gpio-mux-clock"); + +@@ -212,17 +211,9 @@ static int gpio_clk_driver_probe(struct + + gpio_name = is_mux ? "select" : "enable"; + gpiod = devm_gpiod_get(dev, gpio_name, GPIOD_OUT_LOW); +- if (IS_ERR(gpiod)) { +- ret = PTR_ERR(gpiod); +- if (ret == -EPROBE_DEFER) +- pr_debug("%pOFn: %s: GPIOs not yet available, retry later\n", +- node, __func__); +- else +- pr_err("%pOFn: %s: Can't get '%s' named GPIO property\n", +- node, __func__, +- gpio_name); +- return ret; +- } ++ if (IS_ERR(gpiod)) ++ return dev_err_probe(dev, PTR_ERR(gpiod), ++ "Can't get '%s' named GPIO property\n", gpio_name); + + if (is_mux) + hw = clk_hw_register_gpio_mux(dev, gpiod); diff --git a/lede/target/linux/generic/backport-6.12/801-04-v6.13-clk-clk-gpio-add-driver-for-gated-fixed-clocks.patch b/lede/target/linux/generic/backport-6.12/801-04-v6.13-clk-clk-gpio-add-driver-for-gated-fixed-clocks.patch new file mode 100644 index 0000000000..44da746fdc --- /dev/null +++ b/lede/target/linux/generic/backport-6.12/801-04-v6.13-clk-clk-gpio-add-driver-for-gated-fixed-clocks.patch @@ -0,0 +1,229 @@ +From 4940071d962827467f7297be3b874c96186ca0b7 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 6 Sep 2024 10:25:10 +0200 +Subject: clk: clk-gpio: add driver for gated-fixed-clocks + +In contrast to fixed clocks that are described as ungateable, boards +sometimes use additional oscillators for things like PCIe reference +clocks, that need actual supplies to get enabled and enable-gpios to be +toggled for them to work. + +This adds a driver for those generic gated-fixed-clocks +that can show up in schematics looking like + + ---------------- +Enable - | 100MHz,3.3V, | - VDD + | 3225 | + GND - | | - OUT + ---------------- + +The new driver gets grouped together with the existing gpio-gate and +gpio-mux, as it for one re-uses a lot of the gpio-gate functions +and also in its core it's just another gpio-controlled clock, just +with a fixed rate and a regulator-supply added in. + +The regulator-API provides function stubs for the !CONFIG_REGULATOR case, +so no special handling is necessary. + +Signed-off-by: Heiko Stuebner +Link: https://lore.kernel.org/r/20240906082511.2963890-5-heiko@sntech.de +Signed-off-by: Stephen Boyd + +--- a/drivers/clk/clk-gpio.c ++++ b/drivers/clk/clk-gpio.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + /** + * DOC: basic gpio gated clock which can be enabled and disabled +@@ -239,3 +240,187 @@ static struct platform_driver gpio_clk_d + }, + }; + builtin_platform_driver(gpio_clk_driver); ++ ++/** ++ * DOC: gated fixed clock, controlled with a gpio output and a regulator ++ * Traits of this clock: ++ * prepare - clk_prepare and clk_unprepare are function & control regulator ++ * optionally a gpio that can sleep ++ * enable - clk_enable and clk_disable are functional & control gpio ++ * rate - rate is fixed and set on clock registration ++ * parent - fixed clock is a root clock and has no parent ++ */ ++ ++/** ++ * struct clk_gated_fixed - Gateable fixed rate clock ++ * @clk_gpio: instance of clk_gpio for gate-gpio ++ * @supply: supply regulator ++ * @rate: fixed rate ++ */ ++struct clk_gated_fixed { ++ struct clk_gpio clk_gpio; ++ struct regulator *supply; ++ unsigned long rate; ++}; ++ ++#define to_clk_gated_fixed(_clk_gpio) container_of(_clk_gpio, struct clk_gated_fixed, clk_gpio) ++ ++static unsigned long clk_gated_fixed_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ return to_clk_gated_fixed(to_clk_gpio(hw))->rate; ++} ++ ++static int clk_gated_fixed_prepare(struct clk_hw *hw) ++{ ++ struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); ++ ++ if (!clk->supply) ++ return 0; ++ ++ return regulator_enable(clk->supply); ++} ++ ++static void clk_gated_fixed_unprepare(struct clk_hw *hw) ++{ ++ struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); ++ ++ if (!clk->supply) ++ return; ++ ++ regulator_disable(clk->supply); ++} ++ ++static int clk_gated_fixed_is_prepared(struct clk_hw *hw) ++{ ++ struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); ++ ++ if (!clk->supply) ++ return true; ++ ++ return regulator_is_enabled(clk->supply); ++} ++ ++/* ++ * Fixed gated clock with non-sleeping gpio. ++ * ++ * Prepare operation turns on the supply regulator ++ * and the enable operation switches the enable-gpio. ++ */ ++static const struct clk_ops clk_gated_fixed_ops = { ++ .prepare = clk_gated_fixed_prepare, ++ .unprepare = clk_gated_fixed_unprepare, ++ .is_prepared = clk_gated_fixed_is_prepared, ++ .enable = clk_gpio_gate_enable, ++ .disable = clk_gpio_gate_disable, ++ .is_enabled = clk_gpio_gate_is_enabled, ++ .recalc_rate = clk_gated_fixed_recalc_rate, ++}; ++ ++static int clk_sleeping_gated_fixed_prepare(struct clk_hw *hw) ++{ ++ int ret; ++ ++ ret = clk_gated_fixed_prepare(hw); ++ if (ret) ++ return ret; ++ ++ ret = clk_sleeping_gpio_gate_prepare(hw); ++ if (ret) ++ clk_gated_fixed_unprepare(hw); ++ ++ return ret; ++} ++ ++static void clk_sleeping_gated_fixed_unprepare(struct clk_hw *hw) ++{ ++ clk_gated_fixed_unprepare(hw); ++ clk_sleeping_gpio_gate_unprepare(hw); ++} ++ ++/* ++ * Fixed gated clock with non-sleeping gpio. ++ * ++ * Enabling the supply regulator and switching the enable-gpio happens ++ * both in the prepare step. ++ * is_prepared only needs to check the gpio state, as toggling the ++ * gpio is the last step when preparing. ++ */ ++static const struct clk_ops clk_sleeping_gated_fixed_ops = { ++ .prepare = clk_sleeping_gated_fixed_prepare, ++ .unprepare = clk_sleeping_gated_fixed_unprepare, ++ .is_prepared = clk_sleeping_gpio_gate_is_prepared, ++ .recalc_rate = clk_gated_fixed_recalc_rate, ++}; ++ ++static int clk_gated_fixed_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct clk_gated_fixed *clk; ++ const struct clk_ops *ops; ++ const char *clk_name; ++ u32 rate; ++ int ret; ++ ++ clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); ++ if (!clk) ++ return -ENOMEM; ++ ++ ret = device_property_read_u32(dev, "clock-frequency", &rate); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to get clock-frequency\n"); ++ clk->rate = rate; ++ ++ ret = device_property_read_string(dev, "clock-output-names", &clk_name); ++ if (ret) ++ clk_name = fwnode_get_name(dev->fwnode); ++ ++ clk->supply = devm_regulator_get_optional(dev, "vdd"); ++ if (IS_ERR(clk->supply)) { ++ if (PTR_ERR(clk->supply) != -ENODEV) ++ return dev_err_probe(dev, PTR_ERR(clk->supply), ++ "Failed to get regulator\n"); ++ clk->supply = NULL; ++ } ++ ++ clk->clk_gpio.gpiod = devm_gpiod_get_optional(dev, "enable", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(clk->clk_gpio.gpiod)) ++ return dev_err_probe(dev, PTR_ERR(clk->clk_gpio.gpiod), ++ "Failed to get gpio\n"); ++ ++ if (gpiod_cansleep(clk->clk_gpio.gpiod)) ++ ops = &clk_sleeping_gated_fixed_ops; ++ else ++ ops = &clk_gated_fixed_ops; ++ ++ clk->clk_gpio.hw.init = CLK_HW_INIT_NO_PARENT(clk_name, ops, 0); ++ ++ /* register the clock */ ++ ret = devm_clk_hw_register(dev, &clk->clk_gpio.hw); ++ if (ret) ++ return dev_err_probe(dev, ret, ++ "Failed to register clock\n"); ++ ++ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, ++ &clk->clk_gpio.hw); ++ if (ret) ++ return dev_err_probe(dev, ret, ++ "Failed to register clock provider\n"); ++ ++ return 0; ++} ++ ++static const struct of_device_id gated_fixed_clk_match_table[] = { ++ { .compatible = "gated-fixed-clock" }, ++ { /* sentinel */ } ++}; ++ ++static struct platform_driver gated_fixed_clk_driver = { ++ .probe = clk_gated_fixed_probe, ++ .driver = { ++ .name = "gated-fixed-clk", ++ .of_match_table = gated_fixed_clk_match_table, ++ }, ++}; ++builtin_platform_driver(gated_fixed_clk_driver); diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt index 397aab0a8d..8fe0a2944c 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt @@ -738,7 +738,7 @@ fun buildConfig( } } - _hack_custom_config = DataStore.globalCustomConfig + if (!forTest) _hack_custom_config = DataStore.globalCustomConfig }.let { val configMap = it.asMap() Util.mergeJSON(configMap, proxy.requireBean().customConfigJson) diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowsocks/ShadowsocksFmt.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowsocks/ShadowsocksFmt.kt index 04506abdc8..b1d0bb9c1b 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowsocks/ShadowsocksFmt.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowsocks/ShadowsocksFmt.kt @@ -117,6 +117,10 @@ fun buildSingBoxOutboundShadowsocksBean(bean: ShadowsocksBean): SingBoxOptions.O if (bean.plugin.isNotBlank()) { plugin = bean.plugin.substringBefore(";") plugin_opts = bean.plugin.substringAfter(";") + if (plugin == "none") { + plugin = null + plugin_opts = null + } } } } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt index 436151aae0..107b27e3d9 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt @@ -287,17 +287,6 @@ class AppListActivity : ThemedActivity() { } Snackbar.make(binding.list, R.string.action_import_err, Snackbar.LENGTH_LONG).show() } - - R.id.uninstall_all -> { - runOnDefaultDispatcher { - proxiedUids.clear() - DataStore.routePackages = "" - apps = apps.sortedWith(compareBy({ !isProxiedApp(it) }, { it.name.toString() })) - onMainDispatcher { - appsAdapter.notifyItemRangeChanged(0, appsAdapter.itemCount, SWITCH) - } - } - } } return super.onOptionsItemSelected(item) } diff --git a/nekobox-android/app/src/main/res/menu/app_list_neko_menu.xml b/nekobox-android/app/src/main/res/menu/app_list_neko_menu.xml deleted file mode 100644 index 94cbd0782f..0000000000 --- a/nekobox-android/app/src/main/res/menu/app_list_neko_menu.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/nekobox-android/buildScript/lib/core/get_source_env.sh b/nekobox-android/buildScript/lib/core/get_source_env.sh index e946e7e2b4..af7fd845ce 100644 --- a/nekobox-android/buildScript/lib/core/get_source_env.sh +++ b/nekobox-android/buildScript/lib/core/get_source_env.sh @@ -1,2 +1,2 @@ -export COMMIT_SING_BOX="cc3a8000fdc0c9ddf9aa1ab4d6aacdfec91d8e73" +export COMMIT_SING_BOX="f39bce4d939a35749aab6ea598b7ff3faf740645" export COMMIT_LIBNEKO="1c47a3af71990a7b2192e03292b4d246c308ef0b" diff --git a/nekobox-android/libcore/go.mod b/nekobox-android/libcore/go.mod index 42ea05b48b..477fe2b5d1 100644 --- a/nekobox-android/libcore/go.mod +++ b/nekobox-android/libcore/go.mod @@ -9,9 +9,9 @@ require ( github.com/miekg/dns v1.1.67 github.com/oschwald/maxminddb-golang v1.13.1 github.com/sagernet/quic-go v0.52.0-beta.1 - github.com/sagernet/sing v0.7.6-0.20250825114712-2aeec120ce28 + github.com/sagernet/sing v0.7.10 github.com/sagernet/sing-box v1.0.0 // replaced - github.com/sagernet/sing-tun v0.7.0-beta.1 + github.com/sagernet/sing-tun v0.7.2 github.com/ulikunitz/xz v0.5.11 golang.org/x/mobile v0.0.0-20231108233038-35478a0c49da golang.org/x/sys v0.35.0 @@ -53,7 +53,7 @@ require ( github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect github.com/sagernet/sing-mux v0.3.3 // indirect - github.com/sagernet/sing-quic v0.5.0 // indirect + github.com/sagernet/sing-quic v0.5.2-0.20250909083218-00a55617c0fb // indirect github.com/sagernet/sing-shadowsocks v0.2.8 // indirect github.com/sagernet/sing-shadowsocks2 v0.2.1 // indirect github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 // indirect diff --git a/nekobox-android/libcore/go.sum b/nekobox-android/libcore/go.sum index 9ba6bf7989..94ea9e2f24 100644 --- a/nekobox-android/libcore/go.sum +++ b/nekobox-android/libcore/go.sum @@ -89,20 +89,20 @@ github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/l github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs= github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4= github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= -github.com/sagernet/sing v0.7.6-0.20250825114712-2aeec120ce28 h1:C8Lnqd0Q+C15kwaMiDsfq5S45rhhaQMBG91TT+6oFVo= -github.com/sagernet/sing v0.7.6-0.20250825114712-2aeec120ce28/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.7.10 h1:2yPhZFx+EkyHPH8hXNezgyRSHyGY12CboId7CtwLROw= +github.com/sagernet/sing v0.7.10/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw= github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA= -github.com/sagernet/sing-quic v0.5.0 h1:jNLIyVk24lFPvu8A4x+ZNEnZdI+Tg1rp7eCJ6v0Csak= -github.com/sagernet/sing-quic v0.5.0/go.mod h1:SAv/qdeDN+75msGG5U5ZIwG+3Ua50jVIKNrRSY8pkx0= +github.com/sagernet/sing-quic v0.5.2-0.20250909083218-00a55617c0fb h1:5Wx3XeTiKrrrcrAky7Hc1bO3CGxrvho2Vu5b/adlEIM= +github.com/sagernet/sing-quic v0.5.2-0.20250909083218-00a55617c0fb/go.mod h1:evP1e++ZG8TJHVV5HudXV4vWeYzGfCdF4HwSJZcdqkI= github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE= github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI= github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo= github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w= github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA= -github.com/sagernet/sing-tun v0.7.0-beta.1 h1:mBIFXYAnGO5ey/HcCYanqnBx61E7yF8zTFGRZonGYmY= -github.com/sagernet/sing-tun v0.7.0-beta.1/go.mod h1:AHJuRrLbNRJuivuFZ2VhXwDj4ViYp14szG5EkkKAqRQ= +github.com/sagernet/sing-tun v0.7.2 h1:uJkAZM0KBqIYzrq077QGqdvj/+4i/pMOx6Pnx0jYqAs= +github.com/sagernet/sing-tun v0.7.2/go.mod h1:pUEjh9YHQ2gJT6Lk0TYDklh3WJy7lz+848vleGM3JPM= github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk= github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs= github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4= diff --git a/nekobox-android/libcore/init.sh b/nekobox-android/libcore/init.sh index 22ad72d044..50bf4cfbd7 100755 --- a/nekobox-android/libcore/init.sh +++ b/nekobox-android/libcore/init.sh @@ -10,8 +10,9 @@ fi # Install gomobile if [ ! -f "$GOPATH/bin/gomobile-matsuri" ]; then git clone https://github.com/MatsuriDayo/gomobile.git + pushd gomobile git checkout origin/master2 - pushd gomobile/cmd + pushd cmd pushd gomobile go install -v popd diff --git a/nekobox-android/nb4a.properties b/nekobox-android/nb4a.properties index 22c97eb417..32c2b93045 100644 --- a/nekobox-android/nb4a.properties +++ b/nekobox-android/nb4a.properties @@ -1,4 +1,4 @@ PACKAGE_NAME=moe.nb4a -VERSION_NAME=1.3.9 -PRE_VERSION_NAME=pre-1.4.0-20250907-1 -VERSION_CODE=43 +VERSION_NAME=1.4.0 +PRE_VERSION_NAME=pre-1.4.0-20250914-1 +VERSION_CODE=44 diff --git a/openwrt-passwall/.github/workflows/Auto compile with openwrt sdk.yml b/openwrt-passwall/.github/workflows/Auto compile with openwrt sdk.yml index e47a3479b1..1e75322cc8 100644 --- a/openwrt-passwall/.github/workflows/Auto compile with openwrt sdk.yml +++ b/openwrt-passwall/.github/workflows/Auto compile with openwrt sdk.yml @@ -137,6 +137,9 @@ jobs: rm -rf temp_resp git clone -b master --single-branch https://github.com/openwrt/packages.git temp_resp + cd temp_resp + git checkout 2b99cd7d7637da0f152da378994f699aaf0dd44d + cd .. echo "update golang version" rm -rf feeds/packages/lang/golang cp -r temp_resp/lang/golang feeds/packages/lang @@ -321,6 +324,9 @@ jobs: rm -rf temp_resp git clone -b master --single-branch https://github.com/openwrt/packages.git temp_resp + cd temp_resp + git checkout 2b99cd7d7637da0f152da378994f699aaf0dd44d + cd .. echo "update golang version" rm -rf feeds/packages/lang/golang cp -r temp_resp/lang/golang feeds/packages/lang diff --git a/openwrt-passwall2/.github/workflows/Auto compile with openwrt sdk.yml b/openwrt-passwall2/.github/workflows/Auto compile with openwrt sdk.yml index 526e15a20b..c77f5d5bfe 100644 --- a/openwrt-passwall2/.github/workflows/Auto compile with openwrt sdk.yml +++ b/openwrt-passwall2/.github/workflows/Auto compile with openwrt sdk.yml @@ -136,6 +136,9 @@ jobs: rm -rf temp_resp git clone -b master --single-branch https://github.com/openwrt/packages.git temp_resp + cd temp_resp + git checkout 2b99cd7d7637da0f152da378994f699aaf0dd44d + cd .. echo "update golang version" rm -rf feeds/packages/lang/golang cp -r temp_resp/lang/golang feeds/packages/lang @@ -320,6 +323,9 @@ jobs: rm -rf temp_resp git clone -b master --single-branch https://github.com/openwrt/packages.git temp_resp + cd temp_resp + git checkout 2b99cd7d7637da0f152da378994f699aaf0dd44d + cd .. echo "update golang version" rm -rf feeds/packages/lang/golang cp -r temp_resp/lang/golang feeds/packages/lang diff --git a/small/README.md b/small/README.md index 419ec21d13..27c910c372 100644 --- a/small/README.md +++ b/small/README.md @@ -51,9 +51,9 @@ make menuconfig ``` #### 注意 -编译新版Sing-box和hysteria,尽量使用golang版本1.22以上版本 ,可以用以下命令 +编译新版Sing-box和hysteria,尽量使用golang版本1.25版本 ,可以用以下命令 ```yaml rm -rf feeds/packages/lang/golang -git clone https://github.com/kenzok8/golang feeds/packages/lang/golang +git clone https://github.com/kenzok8/golang -b 1.25 feeds/packages/lang/golang ``` diff --git a/small/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js b/small/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js index 48dd4ee371..3b4eaead44 100644 --- a/small/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js +++ b/small/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js @@ -64,6 +64,14 @@ const dashrepos_urlparams = { 'metacubex/razord-meta': '?host=%s&port=%s&secret=%s' }; +const log_levels = [ + ['silent', _('Silent')], + ['error', _('Error')], + ['warning', _('Warning')], + ['info', _('Info')], + ['debug', _('Debug')] +]; + const glossary = { proxy_group: { prefmt: 'group_%s', @@ -970,7 +978,7 @@ function renderResDownload(section_id) { E('button', { class: 'cbi-button cbi-button-add', disabled: (type !== 'http') || null, - click: ui.createHandlerFn(this, function(section_type, section_id, type, url, header) { + click: ui.createHandlerFn(this, (section_type, section_id, type, url, header) => { if (type === 'http') { return downloadFile(section_type, section_id, url, header).then((res) => { ui.addNotification(null, E('p', _('Download successful.'))); @@ -1070,7 +1078,7 @@ function handleRemoveIdles() { E('button', { class: 'cbi-button cbi-button-negative important', id: 'rmidles.' + filename + '.button', - click: ui.createHandlerFn(this, function(filename) { + click: ui.createHandlerFn(this, (filename) => { return removeFile(section_type, filename).then((res) => { let node = document.getElementById('rmidles.' + filename + '.label'); node.innerHTML = '%s'.format(node.innerHTML); @@ -1422,6 +1430,7 @@ return baseclass.extend({ stunserver, dashrepos, dashrepos_urlparams, + log_levels, glossary, health_checkurls, inbound_type, diff --git a/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/global.js b/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/global.js index bc116da386..5f65a4a21d 100644 --- a/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/global.js +++ b/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/global.js @@ -145,7 +145,7 @@ return view.extend({ const playButton = mapEl.querySelector('.cbi-map-descr > img'); const audio = mapEl.querySelector('.cbi-map-descr > audio'); - playButton.addEventListener('click', function() { + playButton.addEventListener('click', () => { if (audio.paused) audio.play(); }); @@ -208,7 +208,7 @@ return view.extend({ return E([ E('button', { 'class': 'cbi-button cbi-button-apply', - 'click': ui.createHandlerFn(this, function() { + 'click': ui.createHandlerFn(this, () => { let weight = document.getElementById(ElId); weight.innerHTML = ''; @@ -257,7 +257,7 @@ return view.extend({ ]), E('button', { 'class': 'cbi-button cbi-button-apply', - 'click': ui.createHandlerFn(this, function() { + 'click': ui.createHandlerFn(this, () => { const stun = this.formvalue(this.section.section); const l4proto = document.getElementById('_status_nattest_l4proto').value; @@ -404,12 +404,10 @@ return view.extend({ so.default = 'off'; so = ss.option(form.ListValue, 'log_level', _('Log level')); - so.value('silent', _('Silent')); - so.value('error', _('Error')); - so.value('warning', _('Warning')); - so.value('info', _('Info')); - so.value('debug', _('Debug')); so.default = 'warning'; + hm.log_levels.forEach((res) => { + so.value.apply(so, res); + }); so = ss.option(form.Flag, 'etag_support', _('ETag support')); so.default = so.enabled; @@ -570,7 +568,7 @@ return view.extend({ }), E('button', { class: 'cbi-button cbi-button-add', - click: ui.createHandlerFn(this, function() { + click: ui.createHandlerFn(this, () => { this.hm_options.params = document.getElementById(cbid).value; return hm.handleGenKey.call(this, this.hm_options); diff --git a/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/log.js b/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/log.js index 6398c95234..5207ce1167 100644 --- a/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/log.js +++ b/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/log.js @@ -5,9 +5,12 @@ 'require fs'; 'require poll'; 'require rpc'; +'require uci'; 'require ui'; 'require view'; +'require fchomo as hm'; + /* Thanks to luci-app-aria2 */ const css = ' \ #log_textarea { \ @@ -25,7 +28,49 @@ const css = ' \ const hm_dir = '/var/run/fchomo'; -function getRuntimeLog(name, filename) { +function getRuntimeLog(name, option_index, section_id, in_table) { + const filename = this.option.split('_')[1]; + + let section, option, log_level_el; + switch (filename) { + case 'fchomo': + section = null; + option = null; + break; + case 'mihomo-c': + section = 'global'; + option = 'log_level'; + break; + case 'mihomo-s': + section = 'global'; + option = 'server_log_level'; + break; + } + + if (section) { + const selected = uci.get('fchomo', section, option) || 'warning'; + const choices = Object.fromEntries(hm.log_levels); + + log_level_el = E('select', { + 'id': this.cbid(section_id), + 'class': 'cbi-input-select', + 'style': 'margin-left: 4px; width: 6em;', + 'change': ui.createHandlerFn(this, (ev) => { + uci.set('fchomo', section, option, ev.target.value); + return this.map.save(null, true).then(() => { + ui.changes.apply(true); + }); + }) + }); + + Object.keys(choices).forEach((v) => { + log_level_el.appendChild(E('option', { + 'value': v, + 'selected': (v === selected) ? '' : null + }, [ choices[v] ])); + }); + } + const callLogClean = rpc.declare({ object: 'luci.fchomo', method: 'log_clean', @@ -33,7 +78,7 @@ function getRuntimeLog(name, filename) { expect: { '': {} } }); - let log_textarea = E('div', { 'id': 'log_textarea' }, + const log_textarea = E('div', { 'id': 'log_textarea' }, E('pre', { 'class': 'spinning' }, _('Collecting data...')) @@ -65,12 +110,13 @@ function getRuntimeLog(name, filename) { return E([ E('style', [ css ]), E('div', {'class': 'cbi-map'}, [ - E('h3', {'name': 'content'}, [ + E('h3', {'name': 'content', 'style': 'align-items: center; display: flex;'}, [ _('%s log').format(name), - ' ', + log_level_el || '', E('button', { 'class': 'btn cbi-button cbi-button-action', - 'click': ui.createHandlerFn(this, function() { + 'style': 'margin-left: 4px;', + 'click': ui.createHandlerFn(this, () => { return L.resolveDefault(callLogClean(filename), {}); }) }, [ _('Clean log') ]) @@ -99,7 +145,7 @@ return view.extend({ ss = o.subsection; so = ss.option(form.DummyValue, '_fchomo_logview'); - so.render = L.bind(getRuntimeLog, so, _('FullCombo Shark!'), 'fchomo'); + so.render = L.bind(getRuntimeLog, so, _('FullCombo Shark!')); /* FullCombo Shark! END */ /* Mihomo client START */ @@ -108,7 +154,7 @@ return view.extend({ ss = o.subsection; so = ss.option(form.DummyValue, '_mihomo-c_logview'); - so.render = L.bind(getRuntimeLog, so, _('Mihomo client'), 'mihomo-c'); + so.render = L.bind(getRuntimeLog, so, _('Mihomo client')); /* Mihomo client END */ /* Mihomo server START */ @@ -117,7 +163,7 @@ return view.extend({ ss = o.subsection; so = ss.option(form.DummyValue, '_mihomo-s_logview'); - so.render = L.bind(getRuntimeLog, so, _('Mihomo server'), 'mihomo-s'); + so.render = L.bind(getRuntimeLog, so, _('Mihomo server')); /* Mihomo server END */ return m.render(); diff --git a/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/ruleset.js b/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/ruleset.js index fdb8596f17..b5db959a41 100644 --- a/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/ruleset.js +++ b/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/ruleset.js @@ -297,11 +297,11 @@ return view.extend({ } o.textvalue = function(section_id) { let cval = this.cfgvalue(section_id) || this.default; - let inline = L.bind(function() { + let inline = function() { let cval = this.cfgvalue(section_id) || this.default; return (cval === 'inline') ? true : false; - }, s.getOption('type')); - return inline() ? _('none') : cval; + }.call(s.getOption('type')); + return inline ? _('none') : cval; }; o.depends({'type': 'inline', '!reverse': true}); diff --git a/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/server.js b/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/server.js index 3444eb3b08..4ddb0f51b5 100644 --- a/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/server.js +++ b/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/server.js @@ -392,7 +392,7 @@ return view.extend({ }), E('button', { class: 'cbi-button cbi-button-add', - click: ui.createHandlerFn(this, function() { + click: ui.createHandlerFn(this, () => { this.hm_options.params = document.getElementById(cbid).value; return hm.handleGenKey.call(this, this.hm_options); diff --git a/small/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/client.js b/small/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/client.js index 68394ce0fe..dcbb05c539 100644 --- a/small/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/client.js +++ b/small/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/client.js @@ -1020,6 +1020,7 @@ return view.extend({ _('The domain strategy for resolving the domain name in the address.')); for (let i in hp.dns_strategy) so.value(i, hp.dns_strategy[i]); + so.depends({'address_resolver': '', '!reverse': true}); so.modalonly = true; so = ss.option(form.ListValue, 'outbound', _('Outbound'), diff --git a/small/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/node.js b/small/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/node.js index 4423efc1ba..c41a2c908f 100644 --- a/small/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/node.js +++ b/small/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/node.js @@ -1235,7 +1235,7 @@ return view.extend({ '', E('button', { class: 'btn cbi-button-action', - click: ui.createHandlerFn(this, function() { + click: ui.createHandlerFn(this, () => { let input_links = textarea.getValue().trim().split('\n'); if (input_links && input_links[0]) { /* Remove duplicate lines */ @@ -1272,7 +1272,7 @@ return view.extend({ .then(L.bind(this.map.load, this.map)) .then(L.bind(this.map.reset, this.map)) .then(L.ui.hideModal) - .catch(function() {}); + .catch(() => {}); } else { return ui.hideModal(); } diff --git a/small/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/server.js b/small/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/server.js index ecaa2e3d65..b7167f7a73 100644 --- a/small/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/server.js +++ b/small/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/server.js @@ -46,7 +46,7 @@ function renderStatus(isRunning, version) { function handleGenKey(option) { let section_id = this.section.section; let type = this.section.getOption('type')?.formvalue(section_id); - let widget = L.bind(function(option) { + let widget = L.bind((option) => { return this.map.findElement('id', 'widget.' + this.cbid(section_id).replace(/\.[^\.]+$/, '.') + option); }, this); @@ -85,10 +85,10 @@ function handleGenKey(option) { break; } /* AEAD */ - (function(length) { + ((length) => { if (length && length > 0) password = hp.generateRand('base64', length); - }(hp.shadowsocks_encrypt_length[required_method])); + })(hp.shadowsocks_encrypt_length[required_method]); return widget(option).value = password; } @@ -110,8 +110,8 @@ return view.extend({ _('The modern ImmortalWrt proxy platform for ARM64/AMD64.')); s = m.section(form.TypedSection); - s.render = function () { - poll.add(function () { + s.render = function() { + poll.add(() => { return L.resolveDefault(getServiceStatus()).then((res) => { let view = document.getElementById('service_status'); view.innerHTML = renderStatus(res, features.version); @@ -807,7 +807,7 @@ return view.extend({ }), E('button', { class: 'cbi-button cbi-button-add', - click: ui.createHandlerFn(this, function() { + click: ui.createHandlerFn(this, () => { this.hp_options.params = document.getElementById(cbid).value; return handleGenKey.call(this, this.hp_options); diff --git a/small/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_client.uc b/small/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_client.uc index a8797b67f7..58555f8e74 100755 --- a/small/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_client.uc +++ b/small/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_client.uc @@ -754,18 +754,18 @@ if (!isEmpty(main_node)) { push(config.endpoints, generate_endpoint(outbound)); config.endpoints[length(config.endpoints)-1].bind_interface = cfg.bind_interface; config.endpoints[length(config.endpoints)-1].detour = get_outbound(cfg.outbound); - if (cfg.domain_resolver || cfg.domain_strategy) + if (cfg.domain_resolver) config.endpoints[length(config.endpoints)-1].domain_resolver = { - server: get_resolver(cfg.domain_resolver || default_outbound_dns), + server: get_resolver(cfg.domain_resolver), strategy: cfg.domain_strategy }; } else { push(config.outbounds, generate_outbound(outbound)); config.outbounds[length(config.outbounds)-1].bind_interface = cfg.bind_interface; config.outbounds[length(config.outbounds)-1].detour = get_outbound(cfg.outbound); - if (cfg.domain_resolver || cfg.domain_strategy) + if (cfg.domain_resolver) config.outbounds[length(config.outbounds)-1].domain_resolver = { - server: get_resolver(cfg.domain_resolver || default_outbound_dns), + server: get_resolver(cfg.domain_resolver), strategy: cfg.domain_strategy }; } diff --git a/small/luci-app-homeproxy/root/usr/share/rpcd/ucode/luci.homeproxy b/small/luci-app-homeproxy/root/usr/share/rpcd/ucode/luci.homeproxy index 217e1a358b..68fad464b3 100644 --- a/small/luci-app-homeproxy/root/usr/share/rpcd/ucode/luci.homeproxy +++ b/small/luci-app-homeproxy/root/usr/share/rpcd/ucode/luci.homeproxy @@ -59,7 +59,7 @@ const methods = { certificate_write: { args: { filename: 'filename' }, call: function(req) { - const writeCertificate = function(filename, priv) { + const writeCertificate = (filename, priv) => { const tmpcert = '/tmp/homeproxy_certificate.tmp'; const filestat = lstat(tmpcert); diff --git a/small/luci-app-passwall2/Makefile b/small/luci-app-passwall2/Makefile index bdf1f36896..ef30315bf6 100644 --- a/small/luci-app-passwall2/Makefile +++ b/small/luci-app-passwall2/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 -PKG_VERSION:=25.9.4 +PKG_VERSION:=25.9.20 PKG_RELEASE:=1 PKG_CONFIG_DEPENDS:= \ @@ -83,7 +83,7 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria config PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy bool "Include NaiveProxy" - depends on !(arc||(arm&&TARGET_gemini)||armeb||mips||mips64||powerpc) + depends on !(arc||armeb||loongarch64||mips||mips64||powerpc||TARGET_gemini) select PACKAGE_naiveproxy default n @@ -100,13 +100,13 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client bool "Include Shadowsocks Rust Client" - depends on aarch64||arm||i386||mips||mipsel||x86_64 + depends on !i386 select PACKAGE_shadowsocks-rust-sslocal - default y if aarch64 + default y if aarch64||x86_64 config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server bool "Include Shadowsocks Rust Server" - depends on aarch64||arm||i386||mips||mipsel||x86_64 + depends on !i386 select PACKAGE_shadowsocks-rust-ssserver default n @@ -150,7 +150,6 @@ define Package/$(PKG_NAME)/conffiles /etc/config/passwall2 /etc/config/passwall2_server /usr/share/passwall2/domains_excluded -/www/luci-static/resources/qrcode.min.js endef include $(TOPDIR)/feeds/luci/luci.mk diff --git a/small/luci-app-passwall2/htdocs/luci-static/resources/qrcode.min.js b/small/luci-app-passwall2/htdocs/luci-static/resources/view/passwall2/qrcode.min.js similarity index 100% rename from small/luci-app-passwall2/htdocs/luci-static/resources/qrcode.min.js rename to small/luci-app-passwall2/htdocs/luci-static/resources/view/passwall2/qrcode.min.js diff --git a/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua b/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua index 9881ef15ae..b4c811fd6b 100644 --- a/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua +++ b/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua @@ -43,7 +43,9 @@ o:value("socks", translate("Socks")) o:value("shadowsocks", translate("Shadowsocks")) o:value("trojan", translate("Trojan")) o:value("wireguard", translate("WireGuard")) -o:value("_balancing", translate("Balancing")) +if api.compare_versions(xray_version, ">=", "1.8.12") then + o:value("_balancing", translate("Balancing")) +end o:value("_shunt", translate("Shunt")) o:value("_iface", translate("Custom Interface")) @@ -99,80 +101,86 @@ m.uci:foreach(appname, "socks", function(s) end) -- 负载均衡列表 -local o = s:option(DynamicList, _n("balancing_node"), translate("Load balancing node list"), translate("Load balancing node list, document")) +o = s:option(DynamicList, _n("balancing_node"), translate("Load balancing node list"), translate("Load balancing node list, document")) o:depends({ [_n("protocol")] = "_balancing" }) -for k, v in pairs(nodes_table) do o:value(v.id, v.remark) end +local valid_ids = {} +for k, v in pairs(nodes_table) do + o:value(v.id, v.remark) + valid_ids[v.id] = true +end +-- 去重并禁止自定义非法输入 +function o.custom_write(self, section, value) + local result = {} + if type(value) == "table" then + local seen = {} + for _, v in ipairs(value) do + if v and not seen[v] and valid_ids[v] then + table.insert(result, v) + seen[v] = true + end + end + else + result = { value } + end + api.uci:set_list(appname, section, "balancing_node", result) +end -local o = s:option(ListValue, _n("balancingStrategy"), translate("Balancing Strategy")) +o = s:option(ListValue, _n("balancingStrategy"), translate("Balancing Strategy")) o:depends({ [_n("protocol")] = "_balancing" }) o:value("random") o:value("roundRobin") o:value("leastPing") o:value("leastLoad") -o.default = "leastLoad" +o.default = "random" -- Fallback Node -if api.compare_versions(xray_version, ">=", "1.8.10") then - local o = s:option(ListValue, _n("fallback_node"), translate("Fallback Node")) - if api.compare_versions(xray_version, ">=", "1.8.12") then - o:depends({ [_n("protocol")] = "_balancing" }) - else - o:depends({ [_n("balancingStrategy")] = "leastPing" }) - end - local function check_fallback_chain(fb) - for k, v in pairs(fallback_table) do - if v.fallback == fb then - fallback_table[k] = nil - check_fallback_chain(v.id) - end +o = s:option(ListValue, _n("fallback_node"), translate("Fallback Node")) +o:value("", translate("Close(Not use)")) +o:depends({ [_n("protocol")] = "_balancing" }) +local function check_fallback_chain(fb) + for k, v in pairs(fallback_table) do + if v.fallback == fb then + fallback_table[k] = nil + check_fallback_chain(v.id) end end - -- 检查fallback链,去掉会形成闭环的balancer节点 - if is_balancer then - check_fallback_chain(arg[1]) - end - for k, v in pairs(fallback_table) do o:value(v.id, v.remark) end - for k, v in pairs(nodes_table) do o:value(v.id, v.remark) end end +-- 检查fallback链,去掉会形成闭环的balancer节点 +if is_balancer then + check_fallback_chain(arg[1]) +end +for k, v in pairs(fallback_table) do o:value(v.id, v.remark) end +for k, v in pairs(nodes_table) do o:value(v.id, v.remark) end -- 探测地址 -local ucpu = s:option(Flag, _n("useCustomProbeUrl"), translate("Use Custom Probe URL"), translate("By default the built-in probe URL will be used, enable this option to use a custom probe URL.")) -ucpu:depends({ [_n("balancingStrategy")] = "leastPing" }) -ucpu:depends({ [_n("balancingStrategy")] = "leastLoad" }) +o = s:option(Flag, _n("useCustomProbeUrl"), translate("Use Custom Probe URL"), translate("By default the built-in probe URL will be used, enable this option to use a custom probe URL.")) +o:depends({ [_n("protocol")] = "_balancing" }) -local pu = s:option(Value, _n("probeUrl"), translate("Probe URL")) -pu:depends({ [_n("useCustomProbeUrl")] = true }) -pu:value("https://cp.cloudflare.com/", "Cloudflare") -pu:value("https://www.gstatic.com/generate_204", "Gstatic") -pu:value("https://www.google.com/generate_204", "Google") -pu:value("https://www.youtube.com/generate_204", "YouTube") -pu:value("https://connect.rom.miui.com/generate_204", "MIUI (CN)") -pu:value("https://connectivitycheck.platform.hicloud.com/generate_204", "HiCloud (CN)") -pu.default = "https://www.google.com/generate_204" -pu.description = translate("The URL used to detect the connection status.") +o = s:option(Value, _n("probeUrl"), translate("Probe URL")) +o:depends({ [_n("useCustomProbeUrl")] = true }) +o:value("https://cp.cloudflare.com/", "Cloudflare") +o:value("https://www.gstatic.com/generate_204", "Gstatic") +o:value("https://www.google.com/generate_204", "Google") +o:value("https://www.youtube.com/generate_204", "YouTube") +o:value("https://connect.rom.miui.com/generate_204", "MIUI (CN)") +o:value("https://connectivitycheck.platform.hicloud.com/generate_204", "HiCloud (CN)") +o.default = "https://www.google.com/generate_204" +o.description = translate("The URL used to detect the connection status.") -- 探测间隔 -local pi = s:option(Value, _n("probeInterval"), translate("Probe Interval")) -pi:depends({ [_n("balancingStrategy")] = "leastPing" }) -pi:depends({ [_n("balancingStrategy")] = "leastLoad" }) -pi.default = "1m" -pi.placeholder = "1m" -pi.description = translate("The interval between initiating probes.") .. "
" .. +o = s:option(Value, _n("probeInterval"), translate("Probe Interval")) +o:depends({ [_n("protocol")] = "_balancing" }) +o.default = "1m" +o.placeholder = "1m" +o.description = translate("The interval between initiating probes.") .. "
" .. translate("The time format is numbers + units, such as '10s', '2h45m', and the supported time units are s, m, h, which correspond to seconds, minutes, and hours, respectively.") .. "
" .. translate("When the unit is not filled in, it defaults to seconds.") -if api.compare_versions(xray_version, ">=", "1.8.12") then - ucpu:depends({ [_n("protocol")] = "_balancing" }) - pi:depends({ [_n("protocol")] = "_balancing" }) -else - ucpu:depends({ [_n("balancingStrategy")] = "leastPing" }) - pi:depends({ [_n("balancingStrategy")] = "leastPing" }) -end - o = s:option(Value, _n("expected"), translate("Preferred Node Count")) o:depends({ [_n("balancingStrategy")] = "leastLoad" }) o.datatype = "uinteger" o.default = "2" +o.placeholder = "2" o.description = translate("The load balancer selects the optimal number of nodes, and traffic is randomly distributed among them.") @@ -311,7 +319,7 @@ o:depends({ [_n("protocol")] = "vmess" }) o = s:option(Value, _n("encryption"), translate("Encrypt Method") .. " (encryption)") o.default = "none" -o:value("none") +o.placeholder = "none" o:depends({ [_n("protocol")] = "vless" }) o = s:option(ListValue, _n("ss_method"), translate("Encrypt Method")) @@ -353,7 +361,6 @@ o = s:option(Flag, _n("reality"), translate("REALITY")) o.default = 0 o:depends({ [_n("tls")] = true, [_n("transport")] = "raw" }) o:depends({ [_n("tls")] = true, [_n("transport")] = "ws" }) -o:depends({ [_n("tls")] = true, [_n("transport")] = "quic" }) o:depends({ [_n("tls")] = true, [_n("transport")] = "grpc" }) o:depends({ [_n("tls")] = true, [_n("transport")] = "httpupgrade" }) o:depends({ [_n("tls")] = true, [_n("transport")] = "xhttp" }) @@ -367,7 +374,7 @@ o:value("h3,h2") o:value("http/1.1") o:value("h2,http/1.1") o:value("h3,h2,http/1.1") -o:depends({ [_n("tls")] = true }) +o:depends({ [_n("tls")] = true, [_n("reality")] = false }) -- o = s:option(Value, _n("minversion"), translate("minversion")) -- o.default = "1.3" @@ -448,11 +455,9 @@ o = s:option(ListValue, _n("transport"), translate("Transport")) o:value("raw", "RAW (TCP)") o:value("mkcp", "mKCP") o:value("ws", "WebSocket") -o:value("ds", "DomainSocket") -o:value("quic", "QUIC") o:value("grpc", "gRPC") o:value("httpupgrade", "HttpUpgrade") -o:value("xhttp", "XHTTP (SplitHTTP)") +o:value("xhttp", "XHTTP") o:depends({ [_n("protocol")] = "vmess" }) o:depends({ [_n("protocol")] = "vless" }) o:depends({ [_n("protocol")] = "socks" }) @@ -552,24 +557,6 @@ o = s:option(Value, _n("ws_heartbeatPeriod"), translate("HeartbeatPeriod(second) o.datatype = "integer" o:depends({ [_n("transport")] = "ws" }) --- [[ DomainSocket部分 ]]-- -o = s:option(Value, _n("ds_path"), "Path", translate("A legal file path. This file must not exist before running.")) -o:depends({ [_n("transport")] = "ds" }) - --- [[ QUIC部分 ]]-- -o = s:option(ListValue, _n("quic_security"), translate("Encrypt Method")) -o:value("none") -o:value("aes-128-gcm") -o:value("chacha20-poly1305") -o:depends({ [_n("transport")] = "quic" }) - -o = s:option(Value, _n("quic_key"), translate("Encrypt Method") .. translate("Key")) -o:depends({ [_n("transport")] = "quic" }) - -o = s:option(ListValue, _n("quic_guise"), translate("Camouflage Type")) -for a, t in ipairs(header_type_list) do o:value(t) end -o:depends({ [_n("transport")] = "quic" }) - -- [[ gRPC部分 ]]-- o = s:option(Value, _n("grpc_serviceName"), "ServiceName") o:depends({ [_n("transport")] = "grpc" }) @@ -637,6 +624,7 @@ o.custom_write = function(self, section, value) local address = (data.extra and data.extra.downloadSettings and data.extra.downloadSettings.address) or (data.downloadSettings and data.downloadSettings.address) if address and address ~= "" then + address = address:gsub("^%[", ""):gsub("%]$", "") m:set(section, "download_address", address) else m:del(section, "download_address") @@ -660,34 +648,27 @@ end -- [[ Mux.Cool ]]-- o = s:option(Flag, _n("mux"), "Mux", translate("Enable Mux.Cool")) o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless", [_n("flow")] = "" }) +o:depends({ [_n("protocol")] = "vless", [_n("transport")] = "raw" }) +o:depends({ [_n("protocol")] = "vless", [_n("transport")] = "ws" }) +o:depends({ [_n("protocol")] = "vless", [_n("transport")] = "grpc" }) +o:depends({ [_n("protocol")] = "vless", [_n("transport")] = "httpupgrade" }) o:depends({ [_n("protocol")] = "http" }) o:depends({ [_n("protocol")] = "socks" }) o:depends({ [_n("protocol")] = "shadowsocks" }) o:depends({ [_n("protocol")] = "trojan" }) o = s:option(Value, _n("mux_concurrency"), translate("Mux concurrency")) -o.default = 8 +o.default = -1 o:depends({ [_n("mux")] = true }) --- [[ XUDP Mux ]]-- -o = s:option(Flag, _n("xmux"), "XUDP Mux") -o.default = 1 -o:depends({ [_n("protocol")] = "vless", [_n("flow")] = "xtls-rprx-vision" }) -o:depends({ [_n("protocol")] = "vless", [_n("flow")] = "xtls-rprx-vision-udp443" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) - o = s:option(Value, _n("xudp_concurrency"), translate("XUDP Mux concurrency")) o.default = 8 -o:depends({ [_n("xmux")] = true }) +o:depends({ [_n("mux")] = true }) --[[tcpMptcp]] o = s:option(Flag, _n("tcpMptcp"), "tcpMptcp", translate("Enable Multipath TCP, need to be enabled in both server and client configuration.")) o.default = 0 -o = s:option(Flag, _n("tcpNoDelay"), "tcpNoDelay") -o.default = 0 - o = s:option(ListValue, _n("chain_proxy"), translate("Chain Proxy")) o:value("", translate("Close(Not use)")) o:value("1", translate("Preproxy Node")) @@ -714,7 +695,6 @@ end for i, v in ipairs(s.fields[_n("protocol")].keylist) do if not v:find("_") then s.fields[_n("tcpMptcp")]:depends({ [_n("protocol")] = v }) - s.fields[_n("tcpNoDelay")]:depends({ [_n("protocol")] = v }) s.fields[_n("chain_proxy")]:depends({ [_n("protocol")] = v }) end end diff --git a/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua b/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua index baa73a0efb..c8dc18c7b9 100644 --- a/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua +++ b/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua @@ -113,7 +113,27 @@ end) --[[ URLTest ]] o = s:option(DynamicList, _n("urltest_node"), translate("URLTest node list"), translate("List of nodes to test, document")) o:depends({ [_n("protocol")] = "_urltest" }) -for k, v in pairs(nodes_table) do o:value(v.id, v.remark) end +local valid_ids = {} +for k, v in pairs(nodes_table) do + o:value(v.id, v.remark) + valid_ids[v.id] = true +end +-- 去重并禁止自定义非法输入 +function o.custom_write(self, section, value) + local result = {} + if type(value) == "table" then + local seen = {} + for _, v in ipairs(value) do + if v and not seen[v] and valid_ids[v] then + table.insert(result, v) + seen[v] = true + end + end + else + result = { value } + end + api.uci:set_list(appname, section, "urltest_node", result) +end o = s:option(Value, _n("urltest_url"), translate("Probe URL")) o:depends({ [_n("protocol")] = "_urltest" }) diff --git a/small/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua b/small/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua index 4c4ace5655..028bf39204 100644 --- a/small/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua +++ b/small/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua @@ -181,13 +181,13 @@ end o = s:option(ListValue, _n("alpn"), translate("alpn")) o.default = "h2,http/1.1" -o:value("h3,h2,http/1.1") -o:value("h3,h2") -o:value("h2,http/1.1") o:value("h3") o:value("h2") +o:value("h3,h2") o:value("http/1.1") -o:depends({ [_n("tls")] = true }) +o:value("h2,http/1.1") +o:value("h3,h2,http/1.1") +o:depends({ [_n("tls")] = true, [_n("reality")] = false }) o = s:option(Flag, _n("use_mldsa65Seed"), translate("ML-DSA-65")) o.default = "0" @@ -255,8 +255,6 @@ o = s:option(ListValue, _n("transport"), translate("Transport")) o:value("raw", "RAW") o:value("mkcp", "mKCP") o:value("ws", "WebSocket") -o:value("ds", "DomainSocket") -o:value("quic", "QUIC") o:value("grpc", "gRPC") o:value("httpupgrade", "HttpUpgrade") o:value("xhttp", "XHTTP") @@ -281,7 +279,7 @@ o = s:option(Value, _n("httpupgrade_path"), translate("HttpUpgrade Path")) o.placeholder = "/" o:depends({ [_n("transport")] = "httpupgrade" }) --- [[ SplitHTTP部分 ]]-- +-- [[ XHTTP部分 ]]-- o = s:option(Value, _n("xhttp_host"), translate("XHTTP Host")) o:depends({ [_n("transport")] = "xhttp" }) @@ -360,24 +358,6 @@ o:depends({ [_n("transport")] = "mkcp" }) o = s:option(Value, _n("mkcp_seed"), translate("KCP Seed")) o:depends({ [_n("transport")] = "mkcp" }) --- [[ DomainSocket部分 ]]-- -o = s:option(Value, _n("ds_path"), "Path", translate("A legal file path. This file must not exist before running.")) -o:depends({ [_n("transport")] = "ds" }) - --- [[ QUIC部分 ]]-- -o = s:option(ListValue, _n("quic_security"), translate("Encrypt Method")) -o:value("none") -o:value("aes-128-gcm") -o:value("chacha20-poly1305") -o:depends({ [_n("transport")] = "quic" }) - -o = s:option(Value, _n("quic_key"), translate("Encrypt Key")) -o:depends({ [_n("transport")] = "quic" }) - -o = s:option(ListValue, _n("quic_guise"), translate("Camouflage Type")) -for a, t in ipairs(header_type_list) do o:value(t) end -o:depends({ [_n("transport")] = "quic" }) - -- [[ gRPC部分 ]]-- o = s:option(Value, _n("grpc_serviceName"), "ServiceName") o:depends({ [_n("transport")] = "grpc" }) diff --git a/small/luci-app-passwall2/luasrc/passwall2/api.lua b/small/luci-app-passwall2/luasrc/passwall2/api.lua index e73d030e74..033dfe92d7 100644 --- a/small/luci-app-passwall2/luasrc/passwall2/api.lua +++ b/small/luci-app-passwall2/luasrc/passwall2/api.lua @@ -1005,7 +1005,7 @@ function to_download(app_name, url, size) end local _curl_args = clone(curl_args) - table.insert(_curl_args, "-m 60") + table.insert(_curl_args, "--speed-limit 51200 --speed-time 15 --max-time 300") local return_code, result = curl_logic(url, tmp_file, _curl_args) result = return_code == 0 diff --git a/small/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/small/luci-app-passwall2/luasrc/passwall2/util_xray.lua index 420e40d630..6bc1ae18d3 100644 --- a/small/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/small/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -95,14 +95,11 @@ function gen_outbound(flag, node, tag, proxy_table) node.port = new_port node.stream_security = "none" else - if node.flow == "xtls-rprx-vision" then - else - if proxy_tag then - node.proxySettings = { - tag = proxy_tag, - transportLayer = true - } - end + if proxy_tag then + node.proxySettings = { + tag = proxy_tag, + transportLayer = true + } end end @@ -138,16 +135,15 @@ function gen_outbound(flag, node, tag, proxy_table) proxySettings = node.proxySettings or nil, protocol = node.protocol, mux = { - enabled = (node.mux == "1" or node.xmux == "1") and true or false, - concurrency = (node.mux == "1" and ((node.mux_concurrency) and tonumber(node.mux_concurrency) or 8)) or ((node.xmux == "1") and -1) or nil, - xudpConcurrency = (node.xmux == "1" and ((node.xudp_concurrency) and tonumber(node.xudp_concurrency) or 8)) or nil + enabled = (node.mux == "1") and true or false, + concurrency = (node.mux == "1" and ((node.mux_concurrency) and tonumber(node.mux_concurrency) or -1)) or nil, + xudpConcurrency = (node.mux == "1" and ((node.xudp_concurrency) and tonumber(node.xudp_concurrency) or 8)) or nil } or nil, -- 底层传输配置 streamSettings = (node.streamSettings or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan") and { sockopt = { mark = 255, tcpMptcp = (node.tcpMptcp == "1") and true or nil, - tcpNoDelay = (node.tcpNoDelay == "1") and true or nil, dialerProxy = (fragment or noise) and "dialerproxy" or nil }, network = node.transport, @@ -199,13 +195,6 @@ function gen_outbound(flag, node, tag, proxy_table) earlyDataHeaderName = (node.ws_earlyDataHeaderName) and node.ws_earlyDataHeaderName or nil, heartbeatPeriod = tonumber(node.ws_heartbeatPeriod) or nil } or nil, - dsSettings = (node.transport == "ds") and - {path = node.ds_path} or nil, - quicSettings = (node.transport == "quic") and { - security = node.quic_security, - key = node.quic_key, - header = {type = node.quic_guise} - } or nil, grpcSettings = (node.transport == "grpc") and { serviceName = node.grpc_serviceName, multiMode = (node.grpc_mode == "multi") and true or nil, @@ -218,10 +207,10 @@ function gen_outbound(flag, node, tag, proxy_table) path = node.httpupgrade_path or "/", host = node.httpupgrade_host } or nil, - xhttpSettings = (node.transport == "xhttp" or node.transport == "splithttp") and { + xhttpSettings = (node.transport == "xhttp") and { mode = node.xhttp_mode or "auto", - path = node.xhttp_path or node.splithttp_path or "/", - host = node.xhttp_host or node.splithttp_host, + path = node.xhttp_path or "/", + host = node.xhttp_host, -- 如果包含 "extra" 节,取 "extra" 内的内容,否则直接赋值给 extra extra = node.xhttp_extra and (function() local success, parsed = pcall(jsonc.parse, node.xhttp_extra) @@ -496,14 +485,6 @@ function gen_config_server(node) host = node.ws_host or nil, path = node.ws_path } or nil, - dsSettings = (node.transport == "ds") and { - path = node.ds_path - } or nil, - quicSettings = (node.transport == "quic") and { - security = node.quic_security, - key = node.quic_key, - header = {type = node.quic_guise} - } or nil, grpcSettings = (node.transport == "grpc") and { serviceName = node.grpc_serviceName } or nil, @@ -928,7 +909,7 @@ function gen_config(var) table.insert(outbounds, copied_outbound) return copied_outbound.tag, nil else - if use_proxy and (_node.type ~= "Xray" or _node.flow == "xtls-rprx-vision") then + if use_proxy and _node.type ~= "Xray" then new_port = get_new_port() table.insert(inbounds, { tag = "proxy_" .. rule_name, @@ -1574,8 +1555,7 @@ function gen_config(var) }, streamSettings = { sockopt = { - mark = 255, - tcpNoDelay = true + mark = 255 } } }) diff --git a/small/luci-app-passwall2/luasrc/view/passwall2/global/backup.htm b/small/luci-app-passwall2/luasrc/view/passwall2/global/backup.htm index c96acda2c4..c10c6ce81e 100644 --- a/small/luci-app-passwall2/luasrc/view/passwall2/global/backup.htm +++ b/small/luci-app-passwall2/luasrc/view/passwall2/global/backup.htm @@ -37,55 +37,57 @@ local api = require "luci.passwall2.api"