From 8b800f679bf1ae39ed8f2198b7e6bcfee24b9dea Mon Sep 17 00:00:00 2001 From: Tunglies Date: Thu, 22 May 2025 14:18:22 +0800 Subject: [PATCH] optimize and enforce external-controller-cors config for all users - Refactored config guard logic to always inject secure defaults for external-controller-cors (allow-origins: ['http://localhost', 'http://127.0.0.1'], allow-private-network: true). - Ensures both new and existing user configs are automatically upgraded for enhanced CORS security. - Improves configuration migration and future maintainability. fix: add http://localhost:3000 to CORS allow-origins for tauri dev server compatibility --- UPDATELOG.md | 1 + src-tauri/src/config/clash.rs | 36 ++++++++++++++++++++-- src/components/home/current-proxy-card.tsx | 10 +++--- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/UPDATELOG.md b/UPDATELOG.md index 0083ca80..72f3d236 100644 --- a/UPDATELOG.md +++ b/UPDATELOG.md @@ -81,6 +81,7 @@ - 优化了随机端口和密钥机制,防止随机时卡死! - 优化了保存机制,使用平滑函数,防止客户端卡死! - 优化端口设置退出和保存机制! + - 强制为 Mihomo 配置补全并覆盖 external-controller-cors 字段,默认不允许跨域和仅本地请求,提升 cors 安全性,升级配置时自动覆盖。 ## v2.2.3 diff --git a/src-tauri/src/config/clash.rs b/src-tauri/src/config/clash.rs index 82307527..faf9f7e2 100644 --- a/src-tauri/src/config/clash.rs +++ b/src-tauri/src/config/clash.rs @@ -32,13 +32,13 @@ impl IClashTemp { pub fn template() -> Self { let mut map = Mapping::new(); let mut tun = Mapping::new(); + let mut cors_map = Mapping::new(); tun.insert("enable".into(), false.into()); tun.insert("stack".into(), "gvisor".into()); tun.insert("auto-route".into(), true.into()); tun.insert("strict-route".into(), false.into()); tun.insert("auto-detect-interface".into(), true.into()); tun.insert("dns-hijack".into(), vec!["any:53"].into()); - #[cfg(not(target_os = "windows"))] map.insert("redir-port".into(), 7895.into()); #[cfg(target_os = "linux")] @@ -51,9 +51,16 @@ impl IClashTemp { map.insert("ipv6".into(), true.into()); map.insert("mode".into(), "rule".into()); map.insert("external-controller".into(), "127.0.0.1:9097".into()); - let mut cors_map = Mapping::new(); cors_map.insert("allow-private-network".into(), true.into()); - cors_map.insert("allow-origins".into(), vec!["*"].into()); + cors_map.insert( + "allow-origins".into(), + vec![ + "http://localhost", + "http://127.0.0.1", + "http://localhost:3000", + ] + .into(), + ); map.insert("secret".into(), "".into()); map.insert("tun".into(), tun.into()); map.insert("external-controller-cors".into(), cors_map.into()); @@ -78,6 +85,21 @@ impl IClashTemp { config.insert("socks-port".into(), socks_port.into()); config.insert("port".into(), port.into()); config.insert("external-controller".into(), ctrl.into()); + + // 强制覆盖 external-controller-cors 字段,允许本地和 tauri 前端 + let mut cors_map = Mapping::new(); + cors_map.insert("allow-private-network".into(), true.into()); + cors_map.insert( + "allow-origins".into(), + vec![ + "http://localhost", + "http://127.0.0.1", + "http://localhost:3000", + ] + .into(), + ); + config.insert("external-controller-cors".into(), cors_map.into()); + config } @@ -317,6 +339,13 @@ fn test_clash_info() { ); } +#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "kebab-case")] +pub struct IClashExternalControllerCors { + pub allow_origins: Option>, + pub allow_private_network: Option, +} + #[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] pub struct IClash { @@ -330,6 +359,7 @@ pub struct IClash { pub dns: Option, pub tun: Option, pub interface_name: Option, + pub external_controller_cors: Option, } #[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] diff --git a/src/components/home/current-proxy-card.tsx b/src/components/home/current-proxy-card.tsx index 849c3756..57a14e1d 100644 --- a/src/components/home/current-proxy-card.tsx +++ b/src/components/home/current-proxy-card.tsx @@ -230,12 +230,12 @@ export const CurrentProxyCard = () => { if (selectorGroup) { newGroup = selectorGroup.name; newProxy = selectorGroup.now || selectorGroup.all[0] || ""; - newDisplayProxy = proxies.records?.[newProxy] || null; + newDisplayProxy = proxies.records?.[newProxy] || null; - if (!isGlobalMode && !isDirectMode) { - localStorage.setItem(STORAGE_KEY_GROUP, newGroup); - if (newProxy) { - localStorage.setItem(STORAGE_KEY_PROXY, newProxy); + if (!isGlobalMode && !isDirectMode) { + localStorage.setItem(STORAGE_KEY_GROUP, newGroup); + if (newProxy) { + localStorage.setItem(STORAGE_KEY_PROXY, newProxy); } } }