fix(agent): remove SHA-256 verification for driver downloads

R2 CDN cache inconsistency caused hash mismatches when registry
updated before jar files. Remove sha256 verification entirely —
the old field in registry JSON is silently ignored by serde.
This commit is contained in:
t8y2
2026-05-20 00:20:01 +08:00
parent 367037465c
commit b446816bdc
7 changed files with 10 additions and 75 deletions
Generated
-1
View File
@@ -1752,7 +1752,6 @@ dependencies = [
"rustls 0.23.40",
"serde",
"serde_json",
"sha2 0.10.9",
"sqlx",
"tiberius",
"tokio",
-1
View File
@@ -33,4 +33,3 @@ csv = "1"
calamine = "0.30.1"
base64 = "0.22"
async-trait = "0.1"
sha2 = "0.10"
-1
View File
@@ -142,7 +142,6 @@ pub struct DriverInfo {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArtifactInfo {
pub url: String,
pub sha256: String,
pub size: u64,
}
+1 -33
View File
@@ -159,16 +159,7 @@ pub fn download_temp_path(dest: &std::path::Path) -> std::path::PathBuf {
dest.with_file_name(format!("{file_name}.download"))
}
pub fn verify_and_replace_download(
tmp: &std::path::Path,
dest: &std::path::Path,
expected_sha256: &str,
) -> Result<(), String> {
if let Err(err) = verify_file_sha256(tmp, expected_sha256) {
std::fs::remove_file(tmp).ok();
return Err(err);
}
pub fn replace_download(tmp: &std::path::Path, dest: &std::path::Path) -> Result<(), String> {
if let Some(parent) = dest.parent() {
std::fs::create_dir_all(parent).map_err(|e| e.to_string())?;
}
@@ -194,26 +185,3 @@ fn backup_path(dest: &std::path::Path) -> std::path::PathBuf {
let file_name = dest.file_name().and_then(|name| name.to_str()).unwrap_or("download");
dest.with_file_name(format!("{file_name}.backup-{}", uuid::Uuid::new_v4()))
}
pub fn verify_file_sha256(path: &std::path::Path, expected_sha256: &str) -> Result<(), String> {
use sha2::{Digest, Sha256};
let expected = expected_sha256.trim().to_ascii_lowercase();
let mut file =
std::fs::File::open(path).map_err(|e| format!("Failed to open file for SHA-256 verification: {e}"))?;
let mut hasher = Sha256::new();
let mut buffer = [0u8; 8192];
loop {
let n = std::io::Read::read(&mut file, &mut buffer)
.map_err(|e| format!("Failed to read file for SHA-256 verification: {e}"))?;
if n == 0 {
break;
}
hasher.update(&buffer[..n]);
}
let actual = hasher.finalize().iter().map(|byte| format!("{byte:02x}")).collect::<String>();
if actual == expected {
Ok(())
} else {
Err(format!("SHA-256 mismatch for {}: expected {expected}, got {actual}", path.display()))
}
}
+5 -25
View File
@@ -2,7 +2,7 @@ use dbx_core::agent_manager::{
AgentManager, AgentRegistry, ArtifactInfo, DriverInfo, InstalledDriver, DEFAULT_JRE_KEY,
};
use dbx_core::agent_service::{build_agent_list, github_url_to_r2_path, local_agent_jar_candidates};
use dbx_core::agent_service::{is_app_version_compatible, verify_and_replace_download, verify_file_sha256};
use dbx_core::agent_service::{is_app_version_compatible, replace_download};
fn test_manager(name: &str) -> AgentManager {
let dir = std::env::temp_dir().join(format!("dbx-agent-service-{name}-{}", uuid::Uuid::new_v4()));
@@ -18,11 +18,7 @@ fn registry_with_driver(db_type: &str, version: &str, jre: &str) -> AgentRegistr
label: db_type.to_string(),
min_app_version: "0.1.0".to_string(),
jre: jre.to_string(),
jar: ArtifactInfo {
url: format!("https://example.com/dbx-agent-{db_type}.jar"),
sha256: "sha".to_string(),
size: 42,
},
jar: ArtifactInfo { url: format!("https://example.com/dbx-agent-{db_type}.jar"), size: 42 },
},
);
AgentRegistry { jre: None, jres: std::collections::HashMap::new(), drivers }
@@ -104,20 +100,7 @@ fn accepts_current_app_when_min_version_is_not_newer() {
}
#[test]
fn verifies_file_sha256() {
let path = test_path("sha256");
std::fs::write(&path, b"dbx").unwrap();
verify_file_sha256(&path, "e4a49ac91ae97a25f60bbe2fa6e25809af94df975aa42d3db29edc17e44e6989").unwrap();
let err =
verify_file_sha256(&path, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap_err();
assert!(err.contains("SHA-256 mismatch"));
std::fs::remove_file(path).ok();
}
#[test]
fn atomic_replace_keeps_existing_destination_when_hash_fails() {
fn atomic_replace_moves_download_into_place() {
let dir = test_path("atomic");
std::fs::create_dir_all(&dir).unwrap();
let dest = dir.join("agent.jar");
@@ -125,12 +108,9 @@ fn atomic_replace_keeps_existing_destination_when_hash_fails() {
std::fs::write(&dest, b"old").unwrap();
std::fs::write(&tmp, b"new").unwrap();
let err =
verify_and_replace_download(&tmp, &dest, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
.unwrap_err();
replace_download(&tmp, &dest).unwrap();
assert!(err.contains("SHA-256 mismatch"));
assert_eq!(std::fs::read(&dest).unwrap(), b"old");
assert_eq!(std::fs::read(&dest).unwrap(), b"new");
assert!(!tmp.exists());
std::fs::remove_dir_all(dir).ok();
}
+2 -6
View File
@@ -9,7 +9,7 @@ use dbx_core::agent_manager::{
};
use dbx_core::agent_service::{
build_agent_list, download_temp_path, fetch_registry, find_local_agent_jar, github_url_to_r2_path,
install_local_agent, invalidate_registry_cache, verify_and_replace_download,
install_local_agent, invalidate_registry_cache, replace_download,
};
use futures::Stream;
use serde::Deserialize;
@@ -233,7 +233,6 @@ async fn install_agent_from_registry(
&platform_jre.url,
&github_url_to_r2_path(&platform_jre.url, "jre"),
&jre_archive,
&platform_jre.sha256,
platform_jre.size,
Some(db_type),
current,
@@ -253,7 +252,6 @@ async fn install_agent_from_registry(
&driver.jar.url,
&github_url_to_r2_path(&driver.jar.url, "driver"),
&jar_path,
&driver.jar.sha256,
driver.jar.size,
Some(db_type),
current,
@@ -293,7 +291,6 @@ async fn reinstall_jre_core(am: &AgentManager, jre_key: &str, tx: &broadcast::Se
&platform_jre.url,
&github_url_to_r2_path(&platform_jre.url, "jre"),
&jre_archive,
&platform_jre.sha256,
platform_jre.size,
None,
None,
@@ -319,7 +316,6 @@ async fn download_with_progress(
url: &str,
r2_path: &str,
dest: &std::path::Path,
expected_sha256: &str,
total_size: u64,
db_type: Option<&str>,
current: Option<u32>,
@@ -346,7 +342,7 @@ async fn download_with_progress(
}
std::io::Write::flush(&mut file).map_err(|err| format!("Failed to flush temp file: {err}"))?;
drop(file);
verify_and_replace_download(&tmp, dest, expected_sha256)
replace_download(&tmp, dest)
}
fn send_install_progress(
+2 -8
View File
@@ -7,7 +7,7 @@ use dbx_core::agent_manager::{
};
use dbx_core::agent_service::{
build_agent_list, download_temp_path, fetch_registry, find_local_agent_jar, github_url_to_r2_path,
install_local_agent, invalidate_registry_cache, verify_and_replace_download,
install_local_agent, invalidate_registry_cache, replace_download,
};
use dbx_core::connection::AppState;
@@ -73,7 +73,6 @@ pub async fn install_agent(
&platform_jre.url,
&github_url_to_r2_path(&platform_jre.url, "jre"),
&jre_archive,
&platform_jre.sha256,
platform_jre.size,
)
.await?;
@@ -100,7 +99,6 @@ pub async fn install_agent(
&driver.jar.url,
&github_url_to_r2_path(&driver.jar.url, "driver"),
&jar_path,
&driver.jar.sha256,
driver.jar.size,
)
.await?;
@@ -162,7 +160,6 @@ pub async fn upgrade_all_agents(app: tauri::AppHandle, state: State<'_, Arc<AppS
&platform_jre.url,
&github_url_to_r2_path(&platform_jre.url, "jre"),
&jre_archive,
&platform_jre.sha256,
platform_jre.size,
)
.await?;
@@ -191,7 +188,6 @@ pub async fn upgrade_all_agents(app: tauri::AppHandle, state: State<'_, Arc<AppS
&driver.jar.url,
&github_url_to_r2_path(&driver.jar.url, "driver"),
&jar_path,
&driver.jar.sha256,
driver.jar.size,
)
.await?;
@@ -312,7 +308,6 @@ pub async fn reinstall_jre(
&platform_jre.url,
&github_url_to_r2_path(&platform_jre.url, "jre"),
&jre_archive,
&platform_jre.sha256,
platform_jre.size,
)
.await?;
@@ -335,7 +330,6 @@ async fn download_with_progress(
url: &str,
r2_path: &str,
dest: &std::path::Path,
expected_sha256: &str,
total_size: u64,
) -> Result<(), String> {
if let Some(parent) = dest.parent() {
@@ -365,7 +359,7 @@ async fn download_with_progress(
}
std::io::Write::flush(&mut file).map_err(|e| format!("Failed to flush temp file: {e}"))?;
drop(file);
verify_and_replace_download(&tmp, dest, expected_sha256)
replace_download(&tmp, dest)
}
fn extract_archive(archive: &std::path::Path, dest: &std::path::Path) -> Result<(), String> {