fix: report legacy TLS subscription failures

This commit is contained in:
Tunglies
2026-05-25 22:22:24 +08:00
parent 8ccb0b9abd
commit ec9ef0f85e
5 changed files with 39 additions and 8 deletions
+1
View File
@@ -3,6 +3,7 @@
### 🐞 修复问题
- macOS 托盘速率可能的样式错误
- 订阅导入 TLS 1.0/1.1 等过旧协议时显示更明确错误原因
<details>
<summary><strong> ✨ 新增功能 </strong></summary>
+9 -1
View File
@@ -24,6 +24,14 @@ use std::time::Duration;
static CURRENT_SWITCHING_PROFILE: AtomicBool = AtomicBool::new(false);
fn profile_import_error(err: &anyhow::Error) -> std::string::String {
if let Some(cause) = err.chain().find(|cause| cause.to_string().contains("TLS 1.0/1.1")) {
return cause.to_string();
}
format!("导入订阅失败: {err:#}")
}
#[tauri::command]
pub async fn get_profiles() -> CmdResult<SharedDraft<IProfiles>> {
logging!(debug, Type::Cmd, "获取配置文件列表");
@@ -70,7 +78,7 @@ pub async fn import_profile(url: std::string::String, option: Option<PrfOption>)
}
Err(e) => {
logging!(error, Type::Cmd, "[导入订阅] 下载失败: {}", e);
return Err(format!("导入订阅失败: {}", e).into());
return Err(profile_import_error(&e).into());
}
};
+1 -1
View File
@@ -297,7 +297,7 @@ impl PrfItem {
Ok(r) => r,
Err(e) => {
tokio::time::sleep(Duration::from_millis(100)).await;
bail!("failed to fetch remote profile: {}", e);
return Err(e).context("failed to fetch remote profile");
}
};
+23 -5
View File
@@ -121,6 +121,10 @@ impl NetworkManager {
}
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();
[
@@ -141,6 +145,22 @@ impl NetworkManager {
})
}
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);
if legacy_tls {
err.context("Subscription server uses legacy TLS; only TLS 1.2/1.3 is supported. TLS 1.0/1.1 is insecure")
} else {
err
}
}
fn is_legacy_tls_protocol_error(err: &(dyn std::error::Error + 'static)) -> bool {
let detail = format!("{err:#?}").to_ascii_lowercase();
detail.contains("protocolversion") || detail.contains("protocol version")
}
pub async fn create_request(
&self,
proxy_type: ProxyType,
@@ -207,7 +227,7 @@ impl NetworkManager {
let response = match request_builder.send().await {
Ok(resp) => resp,
Err(e) => {
return Err(anyhow::Error::new(e).context("Request failed"));
return Err(Self::context_reqwest_error(e, "Request failed"));
}
};
@@ -216,7 +236,7 @@ impl NetworkManager {
let body = match response.text().await {
Ok(text) => text.into(),
Err(e) => {
return Err(anyhow::anyhow!("Failed to read response body: {}", e));
return Err(Self::context_reqwest_error(e, "Failed to read response body"));
}
};
@@ -299,9 +319,7 @@ impl NetworkManager {
)
.await
.map_err(|fallback_err| {
anyhow::anyhow!(
"platform TLS verifier failed: {err}; static webpki roots fallback failed: {fallback_err}"
)
fallback_err.context("static webpki roots fallback failed after platform TLS verifier failed")
}),
Err(err) => Err(err),
}
+5 -1
View File
@@ -292,7 +292,6 @@ const ProfilePage = () => {
setUrl('')
await performRobustRefresh()
}
try {
// 尝试正常导入
await importProfile(url)
@@ -300,6 +299,11 @@ const ProfilePage = () => {
} catch (initialErr) {
console.warn('[订阅导入] 首次导入失败:', initialErr)
if (String(initialErr).toLowerCase().includes('legacy tls')) {
showNotice.error(String(initialErr))
return
}
showNotice.info('profiles.page.feedback.notifications.importRetry')
try {
// 使用自身代理尝试导入