diff --git a/Changelog.md b/Changelog.md
index ffb5b6ff8..e36bd7564 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -15,13 +15,6 @@
-
- 🧹 移除变更
-
-- 移除订阅下载 TLS 校验失败后的静态根证书回退重试
-
-
-
🚀 优化改进
diff --git a/src-tauri/src/utils/network.rs b/src-tauri/src/utils/network.rs
index 37a9011e7..e9463cc99 100644
--- a/src-tauri/src/utils/network.rs
+++ b/src-tauri/src/utils/network.rs
@@ -6,7 +6,7 @@ use reqwest::{
header::{HeaderMap, HeaderValue, USER_AGENT},
};
use smartstring::alias::String;
-use std::time::Duration;
+use std::{sync::Arc, time::Duration};
use sysproxy::Sysproxy;
use tauri::Url;
@@ -42,6 +42,12 @@ pub enum ProxyType {
System,
}
+#[derive(Debug, Clone, Copy)]
+enum TlsRootMode {
+ PlatformVerifier,
+ StaticWebpkiRoots,
+}
+
pub struct NetworkManager;
impl Default for NetworkManager {
@@ -61,6 +67,7 @@ impl NetworkManager {
default_headers: HeaderMap,
accept_invalid_certs: bool,
timeout_secs: Option,
+ tls_root_mode: TlsRootMode,
) -> Result {
let mut builder = Client::builder()
.tls_backend_rustls()
@@ -69,6 +76,10 @@ impl NetworkManager {
.pool_max_idle_per_host(0)
.pool_idle_timeout(None);
+ if matches!(tls_root_mode, TlsRootMode::StaticWebpkiRoots) {
+ builder = builder.tls_backend_preconfigured(Self::build_static_webpki_tls_config()?);
+ }
+
// 设置代理
if let Some(proxy_str) = proxy_url {
let proxy = Proxy::all(proxy_str)?;
@@ -96,6 +107,44 @@ impl NetworkManager {
Ok(builder.build()?)
}
+ fn build_static_webpki_tls_config() -> Result {
+ let root_store = rustls::RootCertStore::from_iter(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
+ let mut config =
+ rustls::ClientConfig::builder_with_provider(Arc::new(rustls::crypto::ring::default_provider()))
+ .with_safe_default_protocol_versions()?
+ .with_root_certificates(root_store)
+ .with_no_client_auth();
+
+ config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
+
+ Ok(config)
+ }
+
+ fn should_retry_with_static_webpki_roots(err: &anyhow::Error) -> bool {
+ if err.chain().any(Self::is_legacy_tls_protocol_error) {
+ return false;
+ }
+
+ err.chain().any(|e| {
+ let msg = e.to_string().to_ascii_lowercase();
+ [
+ "certificate",
+ "cert",
+ "tls",
+ "ssl",
+ "rustls",
+ "webpki",
+ "revocation",
+ "ocsp",
+ "crl",
+ "issuer",
+ "unknownissuer",
+ ]
+ .iter()
+ .any(|kw| msg.contains(kw))
+ })
+ }
+
fn context_reqwest_error(err: reqwest::Error, context: &'static str) -> anyhow::Error {
let legacy_tls = Self::is_legacy_tls_protocol_error(&err);
let err = anyhow::Error::new(err).context(context);
@@ -119,17 +168,24 @@ impl NetworkManager {
user_agent: Option,
accept_invalid_certs: bool,
) -> Result {
- self.create_request_with_tls_mode(proxy_type, timeout_secs, user_agent, accept_invalid_certs)
- .await
+ self.create_request_with_tls_mode(
+ proxy_type,
+ timeout_secs,
+ user_agent,
+ accept_invalid_certs,
+ TlsRootMode::PlatformVerifier,
+ )
+ .await
}
- async fn get(
+ async fn get_with_tls_mode(
&self,
url: &str,
proxy_type: ProxyType,
timeout_secs: Option,
user_agent: Option,
accept_invalid_certs: bool,
+ tls_root_mode: TlsRootMode,
) -> Result {
let mut parsed = Url::parse(url)?;
let mut extra_headers = HeaderMap::new();
@@ -151,7 +207,13 @@ impl NetworkManager {
// 创建请求
let client = self
- .create_request_with_tls_mode(proxy_type, timeout_secs, user_agent, accept_invalid_certs)
+ .create_request_with_tls_mode(
+ proxy_type,
+ timeout_secs,
+ user_agent,
+ accept_invalid_certs,
+ tls_root_mode,
+ )
.await?;
let mut request_builder = client.get(parsed);
@@ -185,6 +247,7 @@ impl NetworkManager {
timeout_secs: Option,
user_agent: Option,
accept_invalid_certs: bool,
+ tls_root_mode: TlsRootMode,
) -> Result {
let proxy_url: Option = match proxy_type {
ProxyType::None => None,
@@ -219,7 +282,7 @@ impl NetworkManager {
);
}
- self.build_client(proxy_url, headers, accept_invalid_certs, timeout_secs)
+ self.build_client(proxy_url, headers, accept_invalid_certs, timeout_secs, tls_root_mode)
}
pub async fn get_with_interrupt(
@@ -230,7 +293,33 @@ impl NetworkManager {
user_agent: Option,
accept_invalid_certs: bool,
) -> Result {
- self.get(url, proxy_type, timeout_secs, user_agent, accept_invalid_certs)
- .await
+ let platform_result = self
+ .get_with_tls_mode(
+ url,
+ proxy_type,
+ timeout_secs,
+ user_agent.clone(),
+ accept_invalid_certs,
+ TlsRootMode::PlatformVerifier,
+ )
+ .await;
+
+ match platform_result {
+ Ok(response) => Ok(response),
+ Err(err) if !accept_invalid_certs && Self::should_retry_with_static_webpki_roots(&err) => self
+ .get_with_tls_mode(
+ url,
+ proxy_type,
+ timeout_secs,
+ user_agent,
+ accept_invalid_certs,
+ TlsRootMode::StaticWebpkiRoots,
+ )
+ .await
+ .map_err(|fallback_err| {
+ fallback_err.context("static webpki roots fallback failed after platform TLS verifier failed")
+ }),
+ Err(err) => Err(err),
+ }
}
}