From 1274ba232499bbdb1ce188fb326ca4ada07470fd Mon Sep 17 00:00:00 2001 From: coolcoala Date: Thu, 10 Jul 2025 20:50:12 +0300 Subject: [PATCH] HWID implementation --- src-tauri/Cargo.lock | 32 ++++++++++++++++++++++++++++++++ src-tauri/Cargo.toml | 2 ++ src-tauri/src/config/prfitem.rs | 6 ++++++ src-tauri/src/feat/clash.rs | 2 +- src-tauri/src/lib.rs | 2 +- src-tauri/src/utils/mod.rs | 1 + src-tauri/src/utils/network.rs | 18 ++++++++++++++++-- src-tauri/src/utils/resolve.rs | 31 +++++++++++++++++++------------ src-tauri/src/utils/sys_info.rs | 22 ++++++++++++++++++++++ 9 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 src-tauri/src/utils/sys_info.rs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 65f5da01..189debf1 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1085,11 +1085,13 @@ dependencies = [ "libc", "log", "log4rs", + "machine-uid", "mihomo_api", "nanoid", "network-interface", "once_cell", "open", + "os_info", "parking_lot", "percent-encoding", "port_scanner", @@ -3882,6 +3884,15 @@ dependencies = [ "time", ] +[[package]] +name = "machine-uid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f1595709b0a7386bcd56ba34d250d626e5503917d05d32cdccddcd68603e212" +dependencies = [ + "winreg 0.6.2", +] + [[package]] name = "malloc_buf" version = "0.0.6" @@ -4792,6 +4803,18 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "os_info" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0e1ac5fde8d43c34139135df8ea9ee9465394b2d8d20f032d38998f64afffc3" +dependencies = [ + "log", + "plist", + "serde", + "windows-sys 0.52.0", +] + [[package]] name = "os_pipe" version = "1.2.2" @@ -9299,6 +9322,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +dependencies = [ + "winapi", +] + [[package]] name = "winreg" version = "0.10.1" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index b66203d3..1ca5b722 100755 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -16,6 +16,8 @@ identifier = "io.github.clash-verge-rev.clash-verge-rev" tauri-build = { version = "2.3.0", features = [] } [dependencies] +os_info = "3.0" +machine-uid = "0.2" warp = "0.3.7" anyhow = "1.0.98" dirs = "6.0" diff --git a/src-tauri/src/config/prfitem.rs b/src-tauri/src/config/prfitem.rs index 76a86a8f..3671e64b 100644 --- a/src-tauri/src/config/prfitem.rs +++ b/src-tauri/src/config/prfitem.rs @@ -113,6 +113,9 @@ pub struct PrfOption { pub proxies: Option, pub groups: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub use_hwid: Option, } impl PrfOption { @@ -132,6 +135,7 @@ impl PrfOption { a.proxies = b.proxies.or(a.proxies); a.groups = b.groups.or(a.groups); a.timeout_seconds = b.timeout_seconds.or(a.timeout_seconds); + a.use_hwid = b.use_hwid.or(a.use_hwid); Some(a) } t => t.0.or(t.1), @@ -251,6 +255,7 @@ impl PrfItem { let user_agent = opt_ref.and_then(|o| o.user_agent.clone()); let update_interval = opt_ref.and_then(|o| o.update_interval); let timeout = opt_ref.and_then(|o| o.timeout_seconds).unwrap_or(20); + let use_hwid = opt_ref.is_some_and(|o| o.use_hwid.unwrap_or(true)); let mut merge = opt_ref.and_then(|o| o.merge.clone()); let mut script = opt_ref.and_then(|o| o.script.clone()); let mut rules = opt_ref.and_then(|o| o.rules.clone()); @@ -274,6 +279,7 @@ impl PrfItem { Some(timeout), user_agent.clone(), accept_invalid_certs, + use_hwid, ) .await { diff --git a/src-tauri/src/feat/clash.rs b/src-tauri/src/feat/clash.rs index 8aa6d72f..5be7be99 100644 --- a/src-tauri/src/feat/clash.rs +++ b/src-tauri/src/feat/clash.rs @@ -108,7 +108,7 @@ pub async fn test_delay(url: String) -> anyhow::Result { let start = Instant::now(); let response = NetworkManager::global() - .get_with_interrupt(&url, proxy_type, Some(10), user_agent, false) + .get_with_interrupt(&url, proxy_type, Some(10), user_agent, false, false) .await; match response { diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 712e852d..5751785d 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -343,7 +343,7 @@ pub fn run() { .get_webview_window("main") { logging!(info, Type::Window, true, "设置macOS窗口标题"); - let _ = window.set_title("Clash Verge"); + let _ = window.set_title("Clash Verge Rev Lite"); } } } diff --git a/src-tauri/src/utils/mod.rs b/src-tauri/src/utils/mod.rs index 0cb644b4..4989c94c 100644 --- a/src-tauri/src/utils/mod.rs +++ b/src-tauri/src/utils/mod.rs @@ -10,3 +10,4 @@ pub mod resolve; pub mod server; pub mod tmpl; pub mod window_manager; +pub mod sys_info; diff --git a/src-tauri/src/utils/network.rs b/src-tauri/src/utils/network.rs index 9ac0fe75..af7a3e58 100644 --- a/src-tauri/src/utils/network.rs +++ b/src-tauri/src/utils/network.rs @@ -7,7 +7,7 @@ use std::{ }; use tokio::runtime::{Builder, Runtime}; -use crate::{config::Config, logging, utils::logging::Type}; +use crate::{config::Config, logging, utils::logging::Type, utils::sys_info}; // HTTP2 相关 const H2_CONNECTION_WINDOW_SIZE: u32 = 1024 * 1024; @@ -248,6 +248,7 @@ impl NetworkManager { timeout_secs: Option, user_agent: Option, accept_invalid_certs: bool, + use_hwid: bool, ) -> RequestBuilder { if self.should_reset_clients() { self.reset_clients(); @@ -331,7 +332,18 @@ impl NetworkManager { let client = builder.build().expect("Failed to build custom HTTP client"); - client.get(url) + let mut request_builder = client.get(url); + + if use_hwid { + let sys_info = sys_info::get_system_info(); + logging!(info, Type::Network, true, "Adding HWID headers to request"); + request_builder = request_builder + .header("x-hwid", &sys_info.hwid) + .header("x-device-os", &sys_info.os_type) + .header("x-ver-os", &sys_info.os_ver); + } + + request_builder } /* /// 执行GET请求,添加错误跟踪 @@ -378,6 +390,7 @@ impl NetworkManager { timeout_secs: Option, user_agent: Option, accept_invalid_certs: bool, + use_hwid: bool, ) -> Result { let request = self.create_request( url, @@ -385,6 +398,7 @@ impl NetworkManager { timeout_secs, user_agent, accept_invalid_certs, + use_hwid, ); let timeout_duration = timeout_secs.unwrap_or(20); diff --git a/src-tauri/src/utils/resolve.rs b/src-tauri/src/utils/resolve.rs index ad28365c..bda25f8c 100644 --- a/src-tauri/src/utils/resolve.rs +++ b/src-tauri/src/utils/resolve.rs @@ -23,6 +23,7 @@ use tauri::{AppHandle, Manager}; use tokio::net::TcpListener; use tauri::Url; +use crate::config::PrfOption; //#[cfg(not(target_os = "linux"))] // use window_shadows::set_shadow; @@ -549,19 +550,25 @@ pub async fn resolve_scheme(param: String) -> Result<()> { }; if link_parsed.scheme() == "clash" || link_parsed.scheme() == "clash-verge" { - let name = link_parsed - .query_pairs() - .find(|(key, _)| key == "name") - .map(|(_, value)| value.into_owned()); + let mut name: Option = None; + let mut url_param: Option = None; + let mut use_hwid = true; - let url_param = if let Some(query) = link_parsed.query() { - let prefix = "url="; - if let Some(pos) = query.find(prefix) { - let raw_url = &query[pos + prefix.len()..]; - Some(percent_decode_str(raw_url).decode_utf8_lossy().to_string()) - } else { - None + for (key, value) in link_parsed.query_pairs() { + match key.as_ref() { + "name" => name = Some(value.into_owned()), + "url" => url_param = Some(percent_decode_str(&value).decode_utf8_lossy().to_string()), + "hwid" => use_hwid = value == "1" || value == "true", + _ => {} } + } + + let option = if use_hwid { + log::info!(target:"app", "HWID usage requested via deep link"); + Some(PrfOption { + use_hwid: Some(true), + ..Default::default() + }) } else { None }; @@ -571,7 +578,7 @@ pub async fn resolve_scheme(param: String) -> Result<()> { log::info!(target:"app", "decoded subscription url: {url}"); create_window(false); - match PrfItem::from_url(url.as_ref(), name, None, None).await { + match PrfItem::from_url(url.as_ref(), name, None, option).await { Ok(item) => { let uid = item.uid.clone().unwrap(); let _ = wrap_err!(Config::profiles().data().append_item(item)); diff --git a/src-tauri/src/utils/sys_info.rs b/src-tauri/src/utils/sys_info.rs new file mode 100644 index 00000000..bb57cbd7 --- /dev/null +++ b/src-tauri/src/utils/sys_info.rs @@ -0,0 +1,22 @@ +use once_cell::sync::Lazy; +use serde::Serialize; + +#[derive(Serialize, Debug, Clone)] +pub struct SystemInfo { + pub hwid: String, + pub os_type: String, + pub os_ver: String, +} + +pub static SYSTEM_INFO: Lazy = Lazy::new(|| { + let os_info = os_info::get(); + SystemInfo { + hwid: machine_uid::get().unwrap_or_else(|_| "unknown_hwid".to_string()), + os_type: os_info.os_type().to_string(), + os_ver: os_info.version().to_string(), + } +}); + +pub fn get_system_info() -> &'static SystemInfo { + &SYSTEM_INFO +}