From df79ed3efb5f9676b4191b49d1455af950544461 Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Mon, 21 Sep 2026 14:54:06 +0800 Subject: [PATCH] Revert "feat(dns): protect provider DNS from unconfirmed overrides (#7902)" This reverts commit 35a2b6c75c5eeed98617fbf8f8779589680f281d. Closes #7994 Closes #7993 --- Changelog.md | 2 +- src-tauri/src/cmd/clash.rs | 13 -- src-tauri/src/cmd/profile.rs | 5 - src-tauri/src/cmd/save_profile.rs | 3 +- src-tauri/src/config/config.rs | 4 +- src-tauri/src/config/dns.rs | 211 ------------------ src-tauri/src/config/mod.rs | 1 - src-tauri/src/config/runtime.rs | 1 - src-tauri/src/config/verge.rs | 4 - src-tauri/src/core/manager/config.rs | 1 - src-tauri/src/enhance/mod.rs | 19 +- src-tauri/src/feat/backup.rs | 3 +- src-tauri/src/feat/dns.rs | 63 ------ src-tauri/src/feat/mod.rs | 2 - src-tauri/src/feat/profile.rs | 9 +- src-tauri/src/lib.rs | 2 - src/components/setting/mods/dns-viewer.tsx | 6 +- src/components/setting/setting-clash.tsx | 71 ++---- src/locales/ar/settings.json | 7 - src/locales/de/settings.json | 7 - src/locales/en/settings.json | 7 - src/locales/es/settings.json | 7 - src/locales/fa/settings.json | 7 - src/locales/id/settings.json | 7 - src/locales/jp/settings.json | 7 - src/locales/ko/settings.json | 7 - src/locales/ru/settings.json | 7 - src/locales/tr/settings.json | 7 - src/locales/tt/settings.json | 7 - src/locales/zh/settings.json | 7 - src/locales/zhtw/settings.json | 7 - .../_layout/hooks/use-layout-events.test.ts | 55 ----- src/pages/_layout/hooks/use-layout-events.ts | 3 +- .../_layout/utils/notification-handlers.ts | 16 +- src/services/cmds.ts | 10 - src/types/generated/i18n-keys.ts | 5 - src/types/generated/i18n-resources.ts | 7 - 37 files changed, 37 insertions(+), 570 deletions(-) delete mode 100644 src-tauri/src/config/dns.rs delete mode 100644 src-tauri/src/feat/dns.rs delete mode 100644 src/pages/_layout/hooks/use-layout-events.test.ts diff --git a/Changelog.md b/Changelog.md index 49b83c155..41de3940e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,7 +3,7 @@
🐞 修复问题 -- 修复 DNS 覆写:空内容报错、初始值覆盖已有设置、已填写字段残留原配置、空字段在高级编辑器中缺失 +- 回退 2.5.4 引入的 DNS 覆写保护,修复重启后开关自动关闭
diff --git a/src-tauri/src/cmd/clash.rs b/src-tauri/src/cmd/clash.rs index c15f06abd..6bba2b789 100644 --- a/src-tauri/src/cmd/clash.rs +++ b/src-tauri/src/cmd/clash.rs @@ -127,18 +127,6 @@ pub async fn save_dns_config(dns_config: Mapping) -> CmdResult { Ok(()) } -#[tauri::command] -pub fn take_dns_override_notice() -> bool { - crate::config::dns::take_dns_override_notice() -} - -#[tauri::command] -pub async fn set_dns_override(enabled: bool, confirmation: Option) -> CmdResult { - feat::set_dns_override(enabled, confirmation) - .await - .map_err(|error| proxy_aware_coded_error(&error, "DNS_OVERRIDE_UPDATE_FAILED")) -} - #[tauri::command] pub async fn apply_dns_config(apply: bool) -> CmdResult { if apply { @@ -181,7 +169,6 @@ pub async fn apply_dns_config(apply: bool) -> CmdResult { logging!(info, Type::Config, "Config regenerated successfully"); } - logging_error!(Type::Config, Config::sync_dns_override().await); handle::Handle::refresh_clash(); Ok(()) } diff --git a/src-tauri/src/cmd/profile.rs b/src-tauri/src/cmd/profile.rs index 2d790e7a3..dcdd4b12b 100644 --- a/src-tauri/src/cmd/profile.rs +++ b/src-tauri/src/cmd/profile.rs @@ -180,10 +180,6 @@ pub async fn delete_profile(index: String) -> CmdResult { drop(config_update_guard); drop(profile_write_guard); - if should_update { - logging_error!(Type::Config, Config::sync_dns_override().await); - } - if let Err(e) = Tray::global().update_tooltip().await { logging!(warn, Type::Cmd, "异步更新托盘提示失败: {e:#}"); } @@ -253,7 +249,6 @@ async fn handle_success(current_value: Option<&String>) -> CmdResult { - logging_error!(Type::Config, Config::sync_dns_override().await); handle::Handle::refresh_clash(); Ok(ValidationOutcome::Valid) } diff --git a/src-tauri/src/config/config.rs b/src-tauri/src/config/config.rs index 4abc64ad2..6e79af60d 100644 --- a/src-tauri/src/config/config.rs +++ b/src-tauri/src/config/config.rs @@ -109,7 +109,6 @@ impl Config { } Self::runtime().await.apply(); - logging_error!(Type::Config, Self::sync_dns_override().await); Ok(()) } @@ -226,7 +225,7 @@ impl Config { } pub(crate) async fn generate_with_profiles(profiles: &IProfiles) -> Result<()> { - let (mut config, exists_keys, logs, dns_override) = enhance::enhance(profiles).await?; + let (mut config, exists_keys, logs) = enhance::enhance(profiles).await?; sanitize_tunnels_proxy(&mut config); // Apply only to generated core config so the saved choice survives the next launch. @@ -237,7 +236,6 @@ impl Config { Self::runtime().await.edit_draft(|d| { *d = IRuntime { config: Some(config), - dns_override: Some(dns_override), exists_keys, chain_logs: logs, } diff --git a/src-tauri/src/config/dns.rs b/src-tauri/src/config/dns.rs deleted file mode 100644 index f752f14d9..000000000 --- a/src-tauri/src/config/dns.rs +++ /dev/null @@ -1,211 +0,0 @@ -use anyhow::Result; -use clash_verge_draft::DraftTransaction; -use serde_yaml_ng::{Mapping, Value}; -use sha2::{Digest as _, Sha256}; -use smartstring::alias::String; -use std::sync::atomic::{AtomicBool, Ordering}; - -use super::{Config, IVerge}; -use crate::core::handle::Handle; - -static PENDING_DNS_OVERRIDE_NOTICE: AtomicBool = AtomicBool::new(false); - -pub(crate) fn take_dns_override_notice() -> bool { - PENDING_DNS_OVERRIDE_NOTICE.swap(false, Ordering::Relaxed) -} - -const PROVIDER_DNS_FIELDS: [&str; 3] = [ - "proxy-server-nameserver", - "proxy-server-nameserver-policy", - "nameserver-policy", -]; - -pub(crate) fn dns_override_source(profile_uid: &str, config: &Mapping) -> Result> { - let Some(dns) = config.get("dns").and_then(Value::as_mapping) else { - return Ok(None); - }; - let fields: Mapping = PROVIDER_DNS_FIELDS - .iter() - .filter_map(|key| { - let value = dns.get(*key)?; - let nonempty = match value { - Value::Sequence(values) => !values.is_empty(), - Value::Mapping(values) => !values.is_empty(), - Value::String(value) => !value.trim().is_empty(), - _ => false, - }; - nonempty.then(|| (Value::from(*key), value.clone())) - }) - .collect(); - if fields.is_empty() { - return Ok(None); - } - - let mut canonical = serde_json::to_value(fields)?; - canonical.sort_all_objects(); - let mut digest = Sha256::new(); - digest.update(profile_uid.as_bytes()); - digest.update([0]); - digest.update(serde_json::to_vec(&canonical)?); - Ok(Some( - digest.finalize().iter().map(|byte| format!("{byte:02x}")).collect(), - )) -} - -#[derive(Debug, Clone)] -pub(crate) struct DnsOverrideState { - pub source: Option, - pub enabled: bool, - requested: bool, - confirmation: Option, -} - -impl DnsOverrideState { - pub fn new(source: Option, requested: bool, confirmation: Option) -> Self { - let enabled = requested && (source.is_none() || source == confirmation); - Self { - source, - enabled, - requested, - confirmation, - } - } - - fn apply_to(&self, verge: &mut IVerge) -> bool { - // A later settings write must not be overwritten by an earlier runtime generation. - if verge.enable_dns_settings.unwrap_or(false) != self.requested - || verge.dns_override_confirmation != self.confirmation - { - return false; - } - let clear_confirmation = self.confirmation.is_some() && self.source != self.confirmation; - if self.enabled == self.requested && !clear_confirmation { - return false; - } - verge.enable_dns_settings = Some(self.enabled); - if clear_confirmation { - verge.dns_override_confirmation = None; - } - true - } -} - -impl Config { - pub(crate) async fn sync_dns_override() -> Result<()> { - let _config_write = Self::lock_config_write().await; - let state = Self::runtime().await.data_arc().dns_override.clone(); - let Some(state) = state else { - return Ok(()); - }; - let verge = Self::verge().await; - let transaction = DraftTransaction::begin(vec![&verge])?; - if !verge.edit_draft(|draft| state.apply_to(draft)) { - return Ok(()); - } - // The runtime is already committed; a disk failure cannot undo its effective settings. - transaction.commit(); - Handle::refresh_verge(); - if state.requested && !state.enabled { - PENDING_DNS_OVERRIDE_NOTICE.store(true, Ordering::Relaxed); - Handle::notice_message("dns_override::auto_disabled", ""); - } - verge.data_arc().save_file().await - } -} - -#[cfg(test)] -#[allow(clippy::expect_used, reason = "tests assert by panicking")] -mod tests { - use super::{DnsOverrideState, dns_override_source}; - use crate::config::IVerge; - use anyhow::Result; - use serde_yaml_ng::Mapping; - - fn mapping(yaml: &str) -> Mapping { - serde_yaml_ng::from_str(yaml).expect("valid fixture") - } - - #[test] - fn dns_override_detects_each_original_field_but_not_empty_placeholders() -> Result<()> { - for field in [ - "proxy-server-nameserver: [https://doh.pub/dns-query]", - "proxy-server-nameserver-policy: {'www.yournode.com': '114.114.114.114'}", - "nameserver-policy: {'+.quandao.com': ['https://doh.dohcore.com:2096/dns-query/#skip-cert-verify=true']}", - ] { - assert!(dns_override_source("profile", &mapping(&format!("dns: {{{field}}}")))?.is_some()); - assert!(dns_override_source("profile", &mapping(field))?.is_none()); - } - for yaml in [ - "{}", - "dns: {nameserver: [1.1.1.1]}", - "dns: {proxy-server-nameserver: [], proxy-server-nameserver-policy: null, nameserver-policy: {}}", - ] { - assert!(dns_override_source("profile", &mapping(yaml))?.is_none()); - } - Ok(()) - } - - #[test] - fn dns_override_confirmation_survives_formatting_but_not_a_different_source() -> Result<()> { - let original = mapping("dns: {nameserver-policy: {a.example: 1.1.1.1, b.example: [8.8.8.8]}}"); - let source = dns_override_source("one", &original)?; - let reordered = - mapping("dns:\n nameserver-policy:\n b.example: [8.8.8.8]\n a.example: 1.1.1.1\nport: 7890"); - assert_eq!(source, dns_override_source("one", &reordered)?); - assert!(DnsOverrideState::new(source.clone(), true, source.clone()).enabled); - assert!(!DnsOverrideState::new(dns_override_source("two", &original)?, true, source.clone()).enabled); - let changed = mapping("dns: {nameserver-policy: {a.example: 9.9.9.9, b.example: [8.8.8.8]}}"); - assert!(!DnsOverrideState::new(dns_override_source("one", &changed)?, true, source).enabled); - Ok(()) - } - - #[test] - fn dns_override_confirmation_expires_on_restart() -> Result<()> { - let source = Some("provider-dns".into()); - let confirmed = IVerge { - enable_dns_settings: Some(true), - dns_override_confirmation: source.clone(), - ..IVerge::default() - }; - assert!(DnsOverrideState::new(source.clone(), true, confirmed.dns_override_confirmation.clone()).enabled); - for saved in [ - serde_yaml_ng::to_string(&confirmed)?, - "enable_dns_settings: true\ndns_override_confirmation: provider-dns".to_owned(), - ] { - let mut restarted: IVerge = serde_yaml_ng::from_str(&saved)?; - let state = DnsOverrideState::new( - source.clone(), - restarted.enable_dns_settings.unwrap_or(false), - restarted.dns_override_confirmation.clone(), - ); - assert!(!state.enabled, "a previous session must not bypass startup protection"); - assert!(state.apply_to(&mut restarted)); - assert_eq!(restarted.enable_dns_settings, Some(false)); - } - Ok(()) - } - - #[test] - fn dns_override_applies_only_to_current_preferences() { - let mut verge = IVerge { - enable_dns_settings: Some(true), - ..IVerge::default() - }; - let state = DnsOverrideState::new(Some("provider-dns".into()), true, None); - assert!(state.apply_to(&mut verge)); - assert_eq!(verge.enable_dns_settings, Some(false)); - assert!(!state.apply_to(&mut verge)); - let disabled = DnsOverrideState::new(None, false, None); - assert!(!disabled.apply_to(&mut verge)); - assert!(!disabled.enabled); - - verge.enable_dns_settings = Some(true); - verge.dns_override_confirmation = Some("provider-dns".into()); - assert!(!state.apply_to(&mut verge)); - assert_eq!(verge.enable_dns_settings, Some(true)); - assert_eq!(verge.dns_override_confirmation.as_deref(), Some("provider-dns")); - let leaving = DnsOverrideState::new(None, true, verge.dns_override_confirmation.clone()); - assert!(leaving.apply_to(&mut verge)); - assert!(verge.dns_override_confirmation.is_none()); - } -} diff --git a/src-tauri/src/config/mod.rs b/src-tauri/src/config/mod.rs index add685f62..259a1bb48 100644 --- a/src-tauri/src/config/mod.rs +++ b/src-tauri/src/config/mod.rs @@ -1,7 +1,6 @@ mod clash; #[allow(clippy::module_inception)] mod config; -pub(crate) mod dns; mod encrypt; mod mixed_port; mod port; diff --git a/src-tauri/src/config/runtime.rs b/src-tauri/src/config/runtime.rs index 105dc8b46..7155989e2 100644 --- a/src-tauri/src/config/runtime.rs +++ b/src-tauri/src/config/runtime.rs @@ -9,7 +9,6 @@ const PATCH_CONFIG_INNER: [&str; 5] = ["allow-lan", "ipv6", "log-level", "unifie #[derive(Default, Clone)] pub struct IRuntime { pub config: Option, - pub(crate) dns_override: Option, // Keys seen in the profile pipeline, including merge and script output. pub exists_keys: HashSet, // TODO 或许可以用 FixMap 来存储以提升效率 diff --git a/src-tauri/src/config/verge.rs b/src-tauri/src/config/verge.rs index 0b04635c0..719bfa073 100644 --- a/src-tauri/src/config/verge.rs +++ b/src-tauri/src/config/verge.rs @@ -83,10 +83,6 @@ pub struct IVerge { /// enable dns settings - this controls whether dns_config.yaml is applied pub enable_dns_settings: Option, - // Force-enable confirmation is valid only for the current app session. - #[serde(skip)] - pub dns_override_confirmation: Option, - pub use_default_bypass: Option, pub system_proxy_bypass: Option, diff --git a/src-tauri/src/core/manager/config.rs b/src-tauri/src/core/manager/config.rs index 2f3e7f7f0..47a31d40f 100644 --- a/src-tauri/src/core/manager/config.rs +++ b/src-tauri/src/core/manager/config.rs @@ -138,7 +138,6 @@ impl CoreManager { Config::runtime().await.edit_draft(|d| { *d = IRuntime { config: Some(clash_config.to_owned()), - dns_override: None, exists_keys: HashSet::new(), chain_logs: Default::default(), } diff --git a/src-tauri/src/enhance/mod.rs b/src-tauri/src/enhance/mod.rs index c62aaf4d8..e97464374 100644 --- a/src-tauri/src/enhance/mod.rs +++ b/src-tauri/src/enhance/mod.rs @@ -13,7 +13,6 @@ use self::{ seq::{SeqMap, use_seq}, tun::use_tun, }; -use crate::config::dns::{DnsOverrideState, dns_override_source}; use crate::utils::dirs; use crate::{ config::{Config, IProfiles, IVerge, PrfItem}, @@ -37,7 +36,6 @@ struct ConfigValues { socks_enabled: bool, http_enabled: bool, enable_dns_settings: bool, - dns_override_confirmation: Option, enable_external_controller: bool, #[cfg(not(target_os = "windows"))] redir_enabled: bool, @@ -123,7 +121,6 @@ async fn get_config_values() -> ConfigValues { .. } = **verge_arc; let enable_external_controller = enable_external_controller.unwrap_or(false); - let dns_override_confirmation = verge_arc.dns_override_confirmation.clone(); let (clash_core, enable_tun, enable_builtin, socks_enabled, http_enabled, enable_dns_settings) = ( Some(verge_arc.get_valid_clash_core()), @@ -151,7 +148,6 @@ async fn get_config_values() -> ConfigValues { socks_enabled, http_enabled, enable_dns_settings, - dns_override_confirmation, enable_external_controller, #[cfg(not(target_os = "windows"))] redir_enabled, @@ -767,10 +763,8 @@ async fn apply_dns_settings(config: Mapping, enable_dns_settings: bool) -> (Mapp (config, false) } -/// Returns the enhanced profile, its original keys, script logs, and DNS override decision. -pub async fn enhance( - profiles: &IProfiles, -) -> Result<(Mapping, HashSet, HashMap, DnsOverrideState)> { +/// Returns the enhanced profile, its original keys, and script logs. +pub async fn enhance(profiles: &IProfiles) -> Result<(Mapping, HashSet, HashMap)> { let cfg_vals = get_config_values().await; let ConfigValues { clash_config, @@ -780,7 +774,6 @@ pub async fn enhance( socks_enabled, http_enabled, enable_dns_settings, - dns_override_confirmation, enable_external_controller, #[cfg(not(target_os = "windows"))] redir_enabled, @@ -789,12 +782,6 @@ pub async fn enhance( } = cfg_vals; let profile = collect_profile_items(profiles).await?; - let dns_override = DnsOverrideState::new( - dns_override_source(profiles.current.as_deref().unwrap_or_default(), &profile.config)?, - enable_dns_settings, - dns_override_confirmation, - ); - let enable_dns_settings = dns_override.enabled; let config = profile.config; let merge_item = profile.merge_item; let script_item = profile.script_item; @@ -851,7 +838,7 @@ pub async fn enhance( let mut exists_keys_set = HashSet::new(); exists_keys_set.extend(exists_keys); - Ok((config, exists_keys_set, result_map, dns_override)) + Ok((config, exists_keys_set, result_map)) } #[cfg(test)] diff --git a/src-tauri/src/feat/backup.rs b/src-tauri/src/feat/backup.rs index 32a6e1de6..414f530b9 100644 --- a/src-tauri/src/feat/backup.rs +++ b/src-tauri/src/feat/backup.rs @@ -9,7 +9,7 @@ use crate::{ }; use anyhow::{Result, anyhow}; use chrono::Utc; -use clash_verge_logging::{Type, logging, logging_error}; +use clash_verge_logging::{Type, logging}; use reqwest_dav::list_cmd::ListFile; use serde::Serialize; use smartstring::alias::String; @@ -85,7 +85,6 @@ async fn finalize_restored_verge_config( return Err(err); } } - logging_error!(Type::Config, Config::sync_dns_override().await); Ok(()) } diff --git a/src-tauri/src/feat/dns.rs b/src-tauri/src/feat/dns.rs deleted file mode 100644 index d711511fb..000000000 --- a/src-tauri/src/feat/dns.rs +++ /dev/null @@ -1,63 +0,0 @@ -use anyhow::Result; -use clash_verge_draft::DraftTransaction; -use serde::Serialize; -use smartstring::alias::String; - -use crate::{ - config::{Config, dns::dns_override_source, profiles::PROFILE_WRITE_LOCK}, - constants::files::DNS_CONFIG, - core::{CoreManager, handle::Handle}, - utils::dirs, -}; - -#[derive(Serialize)] -#[serde(tag = "status", rename_all = "snake_case")] -pub enum DnsOverrideOutcome { - Applied, - ConfirmationRequired { source: String }, -} - -pub async fn set_dns_override(enabled: bool, confirmation: Option) -> Result { - let _profile_write = PROFILE_WRITE_LOCK.lock().await; - let _config_write = Config::lock_config_write().await; - let profiles = Config::profiles().await.data_arc(); - let source = dns_override_source( - profiles.current.as_deref().unwrap_or_default(), - &profiles.current_mapping().await?, - )?; - if enabled && let Some(source) = source.as_ref().filter(|source| Some(*source) != confirmation.as_ref()) { - return Ok(DnsOverrideOutcome::ConfirmationRequired { source: source.clone() }); - } - - if enabled { - let content = tokio::fs::read_to_string(dirs::app_home_dir()?.join(DNS_CONFIG)).await?; - serde_yaml_ng::from_str::(&content)?; - } - - let verge = Config::verge().await; - let transaction = DraftTransaction::begin(vec![&verge])?; - verge.edit_draft(|draft| { - draft.enable_dns_settings = Some(enabled); - draft.dns_override_confirmation = if enabled { source } else { None }; - }); - CoreManager::global().update_config_checked().await?; - - let state = Config::runtime().await.data_arc().dns_override.clone(); - let mut outcome = DnsOverrideOutcome::Applied; - // A subscription update can replace the file while Mihomo is validating it. - if enabled && let Some(state) = state.filter(|state| !state.enabled) { - verge.edit_draft(|draft| { - draft.enable_dns_settings = Some(false); - draft.dns_override_confirmation = None; - }); - if let Some(source) = state.source { - outcome = DnsOverrideOutcome::ConfirmationRequired { source }; - } - } - - transaction.commit(); - Handle::refresh_verge(); - Handle::refresh_clash(); - verge.data_arc().save_file().await?; - Ok(outcome) -} diff --git a/src-tauri/src/feat/mod.rs b/src-tauri/src/feat/mod.rs index 7b4fb4232..17c3abc59 100644 --- a/src-tauri/src/feat/mod.rs +++ b/src-tauri/src/feat/mod.rs @@ -2,7 +2,6 @@ mod backup; mod clash; mod config; mod core_upgrade; -mod dns; mod icon; mod listener; mod profile; @@ -15,7 +14,6 @@ pub use backup::*; pub use clash::*; pub use config::*; pub use core_upgrade::*; -pub use dns::*; pub use icon::*; pub use listener::*; pub use profile::*; diff --git a/src-tauri/src/feat/profile.rs b/src-tauri/src/feat/profile.rs index aa4f206d8..ff9e3f7c3 100644 --- a/src-tauri/src/feat/profile.rs +++ b/src-tauri/src/feat/profile.rs @@ -5,7 +5,7 @@ use crate::{ utils::help::{mask_err, mask_url}, }; use anyhow::{Result, bail}; -use clash_verge_logging::{Type, logging, logging_error}; +use clash_verge_logging::{Type, logging}; use smartstring::alias::String; /// Toggle proxy profile @@ -200,7 +200,6 @@ pub async fn update_profile(uid: &String, option: Option<&PrfOption>, is_mannual logging!(debug, Type::Config, "[订阅更新] 更新内核配置"); match CoreManager::global().update_config_with_force(is_mannual_trigger).await { Ok(outcome) if outcome.is_valid() => { - logging_error!(Type::Config, Config::sync_dns_override().await); handle::Handle::refresh_clash(); } Ok(outcome @ (ValidationOutcome::Skipped { .. } | ValidationOutcome::Busy)) if !is_mannual_trigger => { @@ -229,9 +228,5 @@ pub async fn update_profile(uid: &String, option: Option<&PrfOption>, is_mannual /// 增强配置 pub async fn enhance_profiles() -> Result { - let outcome = CoreManager::global().update_config_forced().await?; - if outcome.is_valid() { - logging_error!(Type::Config, Config::sync_dns_override().await); - } - Ok(outcome) + CoreManager::global().update_config_forced().await } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index a1e4d1a82..7dff71979 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -161,8 +161,6 @@ mod app_init { cmd::forget_selected_node, cmd::save_dns_config, cmd::apply_dns_config, - cmd::set_dns_override, - cmd::take_dns_override_notice, cmd::take_service_fallback_notice, cmd::get_dns_config_content, cmd::validate_dns_config, diff --git a/src/components/setting/mods/dns-viewer.tsx b/src/components/setting/mods/dns-viewer.tsx index c4cd75951..d9eaef28f 100644 --- a/src/components/setting/mods/dns-viewer.tsx +++ b/src/components/setting/mods/dns-viewer.tsx @@ -33,7 +33,6 @@ import { Switch, } from '@/components/base' import { useClash } from '@/hooks/use-clash' -import { useVerge } from '@/hooks/use-verge' import { showNotice } from '@/services/notice-service' import { useThemeMode } from '@/services/states' import type { MonacoEditorInstance } from '@/types/monaco' @@ -184,8 +183,7 @@ const DEFAULT_DNS_CONFIG = { export function DnsViewer({ ref }: { ref?: Ref }) { const { t } = useTranslation() - const { mutateClash } = useClash() - const { verge } = useVerge() + const { clash, mutateClash } = useClash() const themeMode = useThemeMode() const [open, setOpen] = useState(false) @@ -550,7 +548,7 @@ export function DnsViewer({ ref }: { ref?: Ref }) { return } - if (verge?.enable_dns_settings) { + if (clash?.dns?.enable) { await invoke('apply_dns_config', { apply: true }) mutateClash() } diff --git a/src/components/setting/setting-clash.tsx b/src/components/setting/setting-clash.tsx index 73296da76..1ab467ce9 100644 --- a/src/components/setting/setting-clash.tsx +++ b/src/components/setting/setting-clash.tsx @@ -1,16 +1,17 @@ import { LanRounded, SettingsRounded } from '@mui/icons-material' import { MenuItem, Select, TextField, Typography } from '@mui/material' +import { invoke } from '@tauri-apps/api/core' import { useLockFn } from 'ahooks' import { useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { updateGeo, type LogLevel } from 'tauri-plugin-mihomo-api' -import { BaseDialog, DialogRef, Switch, TooltipIcon } from '@/components/base' +import { DialogRef, Switch, TooltipIcon } from '@/components/base' import { useClash } from '@/hooks/use-clash' import { useClashLog } from '@/hooks/use-clash-log' import { useDisplayedMixedPort } from '@/hooks/use-displayed-mixed-port' import { useVerge } from '@/hooks/use-verge' -import { invoke_uwp_tool, setDnsOverride } from '@/services/cmds' +import { invoke_uwp_tool } from '@/services/cmds' import { showNotice } from '@/services/notice-service' import getSystem from '@/utils/get-system' @@ -35,7 +36,7 @@ const SettingClash = ({ onError }: Props) => { const { t } = useTranslation() const { clash, version, mutateClash, patchClash } = useClash() - const { verge, mutateVerge } = useVerge() + const { verge, patchVerge } = useVerge() const displayedMixedPort = useDisplayedMixedPort() const [, setClashLog] = useClashLog() @@ -46,8 +47,10 @@ const SettingClash = ({ onError }: Props) => { 'unified-delay': unifiedDelay, } = clash ?? {} - const [dnsConfirmation, setDnsConfirmation] = useState(null) - const [dnsUpdating, setDnsUpdating] = useState(false) + // 独立跟踪DNS设置开关状态 + const [dnsSettingsEnabled, setDnsSettingsEnabled] = useState(() => { + return verge?.enable_dns_settings ?? false + }) const webRef = useRef(null) const portRef = useRef(null) @@ -71,29 +74,22 @@ const SettingClash = ({ onError }: Props) => { } } - const handleDnsToggle = useLockFn( - async (enable: boolean, confirmation?: string) => { - setDnsUpdating(true) - try { - const outcome = await setDnsOverride(enable, confirmation) - if (outcome.status === 'confirmation_required') { - setDnsConfirmation(outcome.source) - } else { - setDnsConfirmation(null) - } - mutateVerge() + // 实现DNS设置开关处理函数 + const handleDnsToggle = useLockFn(async (enable: boolean) => { + try { + setDnsSettingsEnabled(enable) + await patchVerge({ enable_dns_settings: enable }) + await invoke('apply_dns_config', { apply: enable }) + setTimeout(() => { mutateClash() - } catch (err: any) { - showNotice.error(err) - } finally { - setDnsUpdating(false) - } - }, - ) - - const closeDnsConfirmation = () => { - if (!dnsUpdating) setDnsConfirmation(null) - } + }, 500) + } catch (err: any) { + setDnsSettingsEnabled(!enable) + showNotice.error(err) + await patchVerge({ enable_dns_settings: !enable }).catch(() => {}) + throw err + } + }) return ( @@ -103,24 +99,6 @@ const SettingClash = ({ onError }: Props) => { - { - if (dnsConfirmation) void handleDnsToggle(true, dnsConfirmation) - }} - > - - {t('settings.modals.dns.protection.message')} - - { > handleDnsToggle(checked)} /> diff --git a/src/locales/ar/settings.json b/src/locales/ar/settings.json index 4fd6792cb..2080d61d6 100644 --- a/src/locales/ar/settings.json +++ b/src/locales/ar/settings.json @@ -510,13 +510,6 @@ "title": "DNS Overwrite", "warning": "If you are not familiar with these settings, please do not modify them and keep DNS Overwrite disabled" }, - "protection": { - "title": "Enable DNS Overwrite?", - "message": "This subscription contains custom DNS settings. DNS Overwrite may replace them, preventing nodes from connecting or some websites from loading. Enable it anyway?", - "enableAnyway": "Enable anyway", - "keepDisabled": "Keep disabled", - "autoDisabled": "DNS Overwrite was disabled to preserve the custom DNS settings in the current subscription." - }, "sections": { "general": "DNS Settings", "fallbackFilter": "Fallback Filter Settings", diff --git a/src/locales/de/settings.json b/src/locales/de/settings.json index e6d16ec5b..2d05ea8a3 100644 --- a/src/locales/de/settings.json +++ b/src/locales/de/settings.json @@ -510,13 +510,6 @@ "title": "DNS-Überschreibung", "warning": "Wenn Sie sich nicht mit diesen Einstellungen auskennen, ändern Sie sie nicht und lassen Sie die DNS-Überschreibung deaktiviert." }, - "protection": { - "title": "Enable DNS Overwrite?", - "message": "This subscription contains custom DNS settings. DNS Overwrite may replace them, preventing nodes from connecting or some websites from loading. Enable it anyway?", - "enableAnyway": "Enable anyway", - "keepDisabled": "Keep disabled", - "autoDisabled": "DNS Overwrite was disabled to preserve the custom DNS settings in the current subscription." - }, "sections": { "general": "DNS-Einstellungen", "fallbackFilter": "Rückfallfilter-Einstellungen", diff --git a/src/locales/en/settings.json b/src/locales/en/settings.json index 24450ae3f..5a1ac094d 100644 --- a/src/locales/en/settings.json +++ b/src/locales/en/settings.json @@ -510,13 +510,6 @@ "title": "DNS Overwrite", "warning": "If you are not familiar with these settings, please do not modify them and keep DNS Overwrite disabled" }, - "protection": { - "title": "Enable DNS Overwrite?", - "message": "This subscription contains custom DNS settings. DNS Overwrite may replace them, preventing nodes from connecting or some websites from loading. Enable it anyway?", - "enableAnyway": "Enable anyway", - "keepDisabled": "Keep disabled", - "autoDisabled": "DNS Overwrite was disabled to preserve the custom DNS settings in the current subscription." - }, "sections": { "general": "DNS Settings", "fallbackFilter": "Fallback Filter Settings", diff --git a/src/locales/es/settings.json b/src/locales/es/settings.json index c686037e3..f10b24627 100644 --- a/src/locales/es/settings.json +++ b/src/locales/es/settings.json @@ -510,13 +510,6 @@ "title": "Sobrescritura de DNS", "warning": "Si no está seguro de cómo configurar esto, no realice cambios y mantenga deshabilitada la sobrescritura de DNS." }, - "protection": { - "title": "Enable DNS Overwrite?", - "message": "This subscription contains custom DNS settings. DNS Overwrite may replace them, preventing nodes from connecting or some websites from loading. Enable it anyway?", - "enableAnyway": "Enable anyway", - "keepDisabled": "Keep disabled", - "autoDisabled": "DNS Overwrite was disabled to preserve the custom DNS settings in the current subscription." - }, "sections": { "general": "Configuración de DNS", "fallbackFilter": "Configuración de filtrado de respaldo", diff --git a/src/locales/fa/settings.json b/src/locales/fa/settings.json index 32cf0e447..6b381a61b 100644 --- a/src/locales/fa/settings.json +++ b/src/locales/fa/settings.json @@ -510,13 +510,6 @@ "title": "بازنویسی DNS", "warning": "اگر با این تنظیمات آشنا نیستید، لطفاً آنها را تغییر ندهید و DNS Overwrite را غیرفعال نگه دارید." }, - "protection": { - "title": "Enable DNS Overwrite?", - "message": "This subscription contains custom DNS settings. DNS Overwrite may replace them, preventing nodes from connecting or some websites from loading. Enable it anyway?", - "enableAnyway": "Enable anyway", - "keepDisabled": "Keep disabled", - "autoDisabled": "DNS Overwrite was disabled to preserve the custom DNS settings in the current subscription." - }, "sections": { "general": "تنظیمات DNS", "fallbackFilter": "Fallback Filter Settings", diff --git a/src/locales/id/settings.json b/src/locales/id/settings.json index aefc26171..1696fd185 100644 --- a/src/locales/id/settings.json +++ b/src/locales/id/settings.json @@ -510,13 +510,6 @@ "title": "DNS Overwrite", "warning": "If you are not familiar with these settings, please do not modify them and keep DNS Overwrite disabled" }, - "protection": { - "title": "Enable DNS Overwrite?", - "message": "This subscription contains custom DNS settings. DNS Overwrite may replace them, preventing nodes from connecting or some websites from loading. Enable it anyway?", - "enableAnyway": "Enable anyway", - "keepDisabled": "Keep disabled", - "autoDisabled": "DNS Overwrite was disabled to preserve the custom DNS settings in the current subscription." - }, "sections": { "general": "DNS Settings", "fallbackFilter": "Fallback Filter Settings", diff --git a/src/locales/jp/settings.json b/src/locales/jp/settings.json index b39537ecf..f390a8c52 100644 --- a/src/locales/jp/settings.json +++ b/src/locales/jp/settings.json @@ -510,13 +510,6 @@ "title": "DNS上書き", "warning": "ここの設定がわからない場合は、変更しないでください。DNS上書きを無効にしたままにしてください。" }, - "protection": { - "title": "Enable DNS Overwrite?", - "message": "This subscription contains custom DNS settings. DNS Overwrite may replace them, preventing nodes from connecting or some websites from loading. Enable it anyway?", - "enableAnyway": "Enable anyway", - "keepDisabled": "Keep disabled", - "autoDisabled": "DNS Overwrite was disabled to preserve the custom DNS settings in the current subscription." - }, "sections": { "general": "DNS設定", "fallbackFilter": "フォールバックフィルター設定", diff --git a/src/locales/ko/settings.json b/src/locales/ko/settings.json index 6aadcdc98..ee05f3923 100644 --- a/src/locales/ko/settings.json +++ b/src/locales/ko/settings.json @@ -510,13 +510,6 @@ "title": "DNS 덮어쓰기", "warning": "이 설정에 익숙하지 않다면 수정하지 말고 DNS 덮어쓰기를 비활성화 상태로 유지하세요" }, - "protection": { - "title": "Enable DNS Overwrite?", - "message": "This subscription contains custom DNS settings. DNS Overwrite may replace them, preventing nodes from connecting or some websites from loading. Enable it anyway?", - "enableAnyway": "Enable anyway", - "keepDisabled": "Keep disabled", - "autoDisabled": "DNS Overwrite was disabled to preserve the custom DNS settings in the current subscription." - }, "sections": { "general": "DNS 설정", "fallbackFilter": "폴백 필터 설정", diff --git a/src/locales/ru/settings.json b/src/locales/ru/settings.json index cf5be05dd..4bd759255 100644 --- a/src/locales/ru/settings.json +++ b/src/locales/ru/settings.json @@ -510,13 +510,6 @@ "title": "Переопределение настроек DNS", "warning": "Если вы не знакомы с этими настройками, пожалуйста, не изменяйте их и оставьте переопределение DNS отключённым" }, - "protection": { - "title": "Enable DNS Overwrite?", - "message": "This subscription contains custom DNS settings. DNS Overwrite may replace them, preventing nodes from connecting or some websites from loading. Enable it anyway?", - "enableAnyway": "Enable anyway", - "keepDisabled": "Keep disabled", - "autoDisabled": "DNS Overwrite was disabled to preserve the custom DNS settings in the current subscription." - }, "sections": { "general": "Настройки DNS", "fallbackFilter": "Настройки фильтра fallback", diff --git a/src/locales/tr/settings.json b/src/locales/tr/settings.json index 498a1075a..58755ff71 100644 --- a/src/locales/tr/settings.json +++ b/src/locales/tr/settings.json @@ -510,13 +510,6 @@ "title": "DNS Üzerine Yazma", "warning": "Bu ayarlarla ilgili bilginiz yoksa, lütfen bunları değiştirmeyin ve DNS Üzerine Yazma'yı devre dışı tutun" }, - "protection": { - "title": "DNS Üzerine Yazma etkinleştirilsin mi?", - "message": "Bu abonelik özel DNS ayarları içeriyor. DNS Üzerine Yazma bunların yerine geçebilir; bu da düğümlerin bağlanmasını veya bazı web sitelerinin yüklenmesini engelleyebilir. Yine de etkinleştirilsin mi?", - "enableAnyway": "Yine de etkinleştir", - "keepDisabled": "Devre dışı bırak", - "autoDisabled": "Geçerli abonelikteki özel DNS ayarlarını korumak için DNS Üzerine Yazma devre dışı bırakıldı." - }, "sections": { "general": "DNS Ayarları", "fallbackFilter": "Yedek Filtre Ayarları", diff --git a/src/locales/tt/settings.json b/src/locales/tt/settings.json index 97c5e3abe..810b07466 100644 --- a/src/locales/tt/settings.json +++ b/src/locales/tt/settings.json @@ -510,13 +510,6 @@ "title": "DNS Overwrite", "warning": "If you are not familiar with these settings, please do not modify them and keep DNS Overwrite disabled" }, - "protection": { - "title": "Enable DNS Overwrite?", - "message": "This subscription contains custom DNS settings. DNS Overwrite may replace them, preventing nodes from connecting or some websites from loading. Enable it anyway?", - "enableAnyway": "Enable anyway", - "keepDisabled": "Keep disabled", - "autoDisabled": "DNS Overwrite was disabled to preserve the custom DNS settings in the current subscription." - }, "sections": { "general": "DNS Settings", "fallbackFilter": "Fallback Filter Settings", diff --git a/src/locales/zh/settings.json b/src/locales/zh/settings.json index 090e6fff0..8ced533af 100644 --- a/src/locales/zh/settings.json +++ b/src/locales/zh/settings.json @@ -510,13 +510,6 @@ "title": "DNS 覆写", "warning": "如果你不清楚这里的设置请不要修改,并保持 DNS 覆写关闭" }, - "protection": { - "title": "是否开启 DNS 覆写?", - "message": "当前订阅包含自定义 DNS 配置。开启 DNS 覆写可能覆盖这些配置,导致节点无法连接或部分网站无法访问。是否仍要开启?", - "enableAnyway": "仍然开启", - "keepDisabled": "保持关闭", - "autoDisabled": "检测到当前订阅包含自定义 DNS 配置,已自动关闭 DNS 覆写。" - }, "sections": { "general": "DNS 设置", "fallbackFilter": "回退过滤设置", diff --git a/src/locales/zhtw/settings.json b/src/locales/zhtw/settings.json index 89eb9689e..250e0286c 100644 --- a/src/locales/zhtw/settings.json +++ b/src/locales/zhtw/settings.json @@ -510,13 +510,6 @@ "title": "DNS 覆寫", "warning": "如果你不清楚這裡的設定請不要修改,並保持 DNS 覆寫關閉" }, - "protection": { - "title": "是否開啟 DNS 覆寫?", - "message": "目前訂閱包含自訂 DNS 設定。開啟 DNS 覆寫可能覆蓋這些設定,導致節點無法連線或部分網站無法存取。是否仍要開啟?", - "enableAnyway": "仍然開啟", - "keepDisabled": "保持關閉", - "autoDisabled": "偵測到目前訂閱包含自訂 DNS 設定,已自動關閉 DNS 覆寫。" - }, "sections": { "general": "DNS 設定", "fallbackFilter": "備援篩選設定", diff --git a/src/pages/_layout/hooks/use-layout-events.test.ts b/src/pages/_layout/hooks/use-layout-events.test.ts deleted file mode 100644 index 0a3f50f4d..000000000 --- a/src/pages/_layout/hooks/use-layout-events.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { beforeEach, expect, it, vi } from 'vitest' - -import { takeDnsOverrideNotice } from '@/services/cmds' -import { subscribeVergeEvents } from '@/services/events' -import { showNotice } from '@/services/notice-service' -import { revalidateQueries } from '@/services/query-client' - -import { handleNoticeMessage } from '../utils/notification-handlers' - -import { useLayoutEvents } from './use-layout-events' - -vi.mock('react', () => ({ useEffect: (effect: () => void) => effect() })) -vi.mock('@/hooks/use-profiles', () => ({ revalidateProfiles: vi.fn() })) -vi.mock('@/hooks/use-system-state', () => ({ runStateQueryKey: ['state'] })) -vi.mock('@/services/events', () => ({ subscribeVergeEvents: vi.fn() })) -vi.mock('@/services/cmds', () => ({ - takeDnsOverrideNotice: vi.fn(), - takeServiceFallbackNotice: vi.fn().mockResolvedValue(false), -})) -vi.mock('@/services/notice-service', () => ({ - showNotice: { info: vi.fn() }, -})) -vi.mock('@/services/query-client', () => ({ - revalidateQueries: vi.fn(), - setCacheData: vi.fn(), -})) - -beforeEach(() => { - vi.clearAllMocks() -}) - -it('drains a DNS notice after listeners mount without duplicating its live event', async () => { - vi.mocked(takeDnsOverrideNotice) - .mockResolvedValueOnce(true) - .mockResolvedValue(false) - - useLayoutEvents(([status, message]) => { - handleNoticeMessage(status, message, (key) => key, vi.fn()) - }) - - expect(takeDnsOverrideNotice).not.toHaveBeenCalled() - const [handlers, onSubscribed] = vi.mocked(subscribeVergeEvents).mock.calls[0] - onSubscribed?.() - expect(takeDnsOverrideNotice).toHaveBeenCalledOnce() - handlers['verge://notice-message']?.(['dns_override::auto_disabled', '']) - await new Promise((resolve) => setTimeout(resolve, 0)) - - expect(showNotice.info).toHaveBeenCalledExactlyOnceWith( - 'settings.modals.dns.protection.autoDisabled', - ) - expect(revalidateQueries).toHaveBeenCalledWith([ - ['getRuntimeState'], - ['getVergeConfig'], - ]) -}) diff --git a/src/pages/_layout/hooks/use-layout-events.ts b/src/pages/_layout/hooks/use-layout-events.ts index eddf2318f..3e6fa760b 100644 --- a/src/pages/_layout/hooks/use-layout-events.ts +++ b/src/pages/_layout/hooks/use-layout-events.ts @@ -62,8 +62,7 @@ export const useLayoutEvents = ( }, // Re-read event-only state after subscribing to close the initial race window. () => { - revalidateKeys(['getRuntimeState', 'getVergeConfig']) - handleNotice(['dns_override::auto_disabled', '']) + revalidateKeys(['getRuntimeState']) handleNotice(['service_core::sidecar_fallback', '']) }, ) diff --git a/src/pages/_layout/utils/notification-handlers.ts b/src/pages/_layout/utils/notification-handlers.ts index cff425e8e..cd4c031ab 100644 --- a/src/pages/_layout/utils/notification-handlers.ts +++ b/src/pages/_layout/utils/notification-handlers.ts @@ -1,7 +1,4 @@ -import { - takeDnsOverrideNotice, - takeServiceFallbackNotice, -} from '@/services/cmds' +import { takeServiceFallbackNotice } from '@/services/cmds' import { showNotice } from '@/services/notice-service' type NavigateFunction = (path: string, options?: any) => void @@ -44,17 +41,6 @@ export const handleNoticeMessage = ( ) }) }, - 'dns_override::auto_disabled': () => { - void takeDnsOverrideNotice() - .then((pending) => { - if (pending) { - showNotice.info('settings.modals.dns.protection.autoDisabled') - } - }) - .catch((error) => { - console.error('Failed to read the pending DNS override notice', error) - }) - }, 'tun_mode::auto_disabled': () => showNotice.info( 'settings.sections.system.notifications.tunMode.autoDisabled', diff --git a/src/services/cmds.ts b/src/services/cmds.ts index 034d77efa..b14ede15d 100644 --- a/src/services/cmds.ts +++ b/src/services/cmds.ts @@ -172,16 +172,6 @@ export async function patchVergeConfig(payload: IVergeConfig) { return invoke('patch_verge_config', { payload }) } -export async function setDnsOverride(enabled: boolean, confirmation?: string) { - return invoke< - { status: 'applied' } | { status: 'confirmation_required'; source: string } - >('set_dns_override', { enabled, confirmation }) -} - -export async function takeDnsOverrideNotice() { - return invoke('take_dns_override_notice') -} - export async function takeServiceFallbackNotice() { return invoke('take_service_fallback_notice') } diff --git a/src/types/generated/i18n-keys.ts b/src/types/generated/i18n-keys.ts index 972d28812..d4e3c7fa1 100644 --- a/src/types/generated/i18n-keys.ts +++ b/src/types/generated/i18n-keys.ts @@ -698,11 +698,6 @@ export const translationKeys = [ 'settings.modals.tun.messages.routeExcludeAddressHint', 'settings.modals.dns.dialog.title', 'settings.modals.dns.dialog.warning', - 'settings.modals.dns.protection.title', - 'settings.modals.dns.protection.message', - 'settings.modals.dns.protection.enableAnyway', - 'settings.modals.dns.protection.keepDisabled', - 'settings.modals.dns.protection.autoDisabled', 'settings.modals.dns.sections.general', 'settings.modals.dns.sections.fallbackFilter', 'settings.modals.dns.sections.hosts', diff --git a/src/types/generated/i18n-resources.ts b/src/types/generated/i18n-resources.ts index ad39b14ff..9260a913d 100644 --- a/src/types/generated/i18n-resources.ts +++ b/src/types/generated/i18n-resources.ts @@ -1041,13 +1041,6 @@ export interface TranslationResources { configError: string saved: string } - protection: { - autoDisabled: string - enableAnyway: string - keepDisabled: string - message: string - title: string - } sections: { fallbackFilter: string general: string