From 87d682709e1248d4efccf52192a3bdc986a72f3f Mon Sep 17 00:00:00 2001 From: NimBold Date: Sat, 1 Aug 2026 22:36:37 +0330 Subject: [PATCH] fix(torrents): preserve metadata retention on malformed records --- src-tauri/src/lib.rs | 65 +++++++++++++++++++++++++++++++----------- src-tauri/src/queue.rs | 2 ++ 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 61b81e8..d69d825 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -7003,6 +7003,22 @@ fn db_get_all_downloads( crate::db::load_downloads(&connection) } +fn retained_torrent_id_from_persisted_record(record: &str) -> Option { + let value = serde_json::from_str::(record).ok()?; + let object = value.as_object()?; + if object.get("isTorrent").and_then(serde_json::Value::as_bool) != Some(true) + || object.get("torrentPath").is_none_or(serde_json::Value::is_null) + { + return None; + } + object + .get("id") + .and_then(serde_json::Value::as_str) + .map(str::trim) + .filter(|id| !id.is_empty()) + .map(ToOwned::to_owned) +} + #[tauri::command] fn db_replace_downloads( state: tauri::State<'_, crate::db::DbState>, @@ -7446,6 +7462,7 @@ mod tests { parse_media_playlist_metadata, normalize_media_connections, validate_enqueue_url, validate_enqueue_uris, validate_keychain_grant_request_id, + retained_torrent_id_from_persisted_record, }; #[cfg(target_os = "macos")] use super::should_apply_dock_badge_update; @@ -7479,6 +7496,27 @@ mod tests { ); } + #[test] + fn retained_torrent_metadata_survives_unrelated_persisted_field_corruption() { + let record = json!({ + "id": "retained-torrent", + "isTorrent": true, + "torrentPath": "/tmp/retained-torrent.torrent", + "torrentMaxPeers": "corrupted" + }) + .to_string(); + + assert_eq!( + retained_torrent_id_from_persisted_record(&record).as_deref(), + Some("retained-torrent") + ); + assert!(retained_torrent_id_from_persisted_record("not-json").is_none()); + assert!(retained_torrent_id_from_persisted_record( + &json!({ "id": "ordinary", "isTorrent": false }).to_string() + ) + .is_none()); + } + #[test] fn aria2_active_connection_count_uses_only_nonnegative_daemon_values() { assert_eq!( @@ -9921,25 +9959,20 @@ pub fn run() { let retained_torrent_ids = database .lock() .and_then(|connection| crate::db::load_downloads(&connection)) - .and_then(|records| { + .map(|records| { records .into_iter() - .map(|record| { - serde_json::from_str::(&record) - .map_err(|error| { - format!("could not decode persisted download metadata: {error}") - }) + .filter_map(|record| { + let retained = retained_torrent_id_from_persisted_record(&record); + if retained.is_none() { + if serde_json::from_str::(&record).is_err() { + log::warn!( + "skipping malformed persisted download during torrent metadata retention" + ); + } + } + retained }) - .collect::, _>>() - }) - .map(|downloads| { - downloads - .into_iter() - .filter(|download| { - download.is_torrent.unwrap_or(false) - && download.torrent_path.is_some() - }) - .map(|download| download.id) .collect::>() }); match retained_torrent_ids { diff --git a/src-tauri/src/queue.rs b/src-tauri/src/queue.rs index 8fc5f2c..b870801 100644 --- a/src-tauri/src/queue.rs +++ b/src-tauri/src/queue.rs @@ -3928,6 +3928,8 @@ mod tests { #[test] fn torrent_options_reject_invalid_peer_values() { + assert!(normalize_torrent_max_peers(Some(-1)).is_err()); + let mut options = serde_json::Map::new(); let payload = SpawnPayload { is_torrent: true,