HWID implementation

This commit is contained in:
coolcoala
2025-07-10 20:50:12 +03:00
parent d6014865d6
commit 1274ba2324
9 changed files with 100 additions and 16 deletions

32
src-tauri/Cargo.lock generated
View File

@@ -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"

View File

@@ -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"

View File

@@ -113,6 +113,9 @@ pub struct PrfOption {
pub proxies: Option<String>,
pub groups: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub use_hwid: Option<bool>,
}
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
{

View File

@@ -108,7 +108,7 @@ pub async fn test_delay(url: String) -> anyhow::Result<u32> {
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 {

View File

@@ -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");
}
}
}

View File

@@ -10,3 +10,4 @@ pub mod resolve;
pub mod server;
pub mod tmpl;
pub mod window_manager;
pub mod sys_info;

View File

@@ -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<u64>,
user_agent: Option<String>,
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<u64>,
user_agent: Option<String>,
accept_invalid_certs: bool,
use_hwid: bool,
) -> Result<Response> {
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);

View File

@@ -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<String> = None;
let mut url_param: Option<String> = 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));

View File

@@ -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<SystemInfo> = 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
}