diff --git a/CHANGELOG.md b/CHANGELOG.md index fc12d3d..03c3d44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## UNRELEASED (YYYY-MM-DD) +### Breaking changes + +- `MagnetLink` now refuses to parse strings that contain a newline (`\n`), producing + a `MagnetLinkError::InvalidURINewLine` error + ## Version 0.3.2 (2025-08-29) ### Added diff --git a/src/magnet.rs b/src/magnet.rs index 1bca96d..035ec25 100644 --- a/src/magnet.rs +++ b/src/magnet.rs @@ -7,6 +7,8 @@ use crate::{InfoHash, InfoHashError, TorrentID}; pub enum MagnetLinkError { /// The URI was not valid according to [`Url::parse`](url::Url::parse). InvalidURI { source: url::ParseError }, + /// The URI contains a newline + InvalidURINewLine, /// The URI scheme was not `magnet` InvalidScheme { scheme: String }, /// No Bittorrent v1/v2 hash was found in the magnet URI @@ -29,6 +31,9 @@ impl std::fmt::Display for MagnetLinkError { MagnetLinkError::InvalidURI { source } => { write!(f, "Invalid URI: {source}") } + MagnetLinkError::InvalidURINewLine => { + write!(f, "Invalid URI: newlines are not allowed in magnet links") + } MagnetLinkError::InvalidScheme { scheme } => { write!(f, "Invalid URI scheme: {scheme}") } @@ -87,6 +92,11 @@ impl MagnetLink { /// Generates a new MagnetLink from a string. Will fail if the string is not a valid URL, and /// in the conditions defined in [`MagnetLink::from_url`](crate::magnet::MagnetLink::from_url). pub fn new(s: &str) -> Result { + // The error returned by Uri::parse when there is a newline is not very obvious, so we + // sacrifice performance to save neurons from fellow developers. + if s.contains('\n') { + return Err(MagnetLinkError::InvalidURINewLine); + } let u = Url::parse(s)?; MagnetLink::from_url(&u) } @@ -329,4 +339,15 @@ mod tests { } ); } + + #[test] + fn fails_newline_in_magnet() { + let mut magnet_url = std::fs::read_to_string("tests/bittorrent-v2-test.magnet").unwrap(); + magnet_url.push('\n'); + + let res = MagnetLink::new(&magnet_url); + assert!(res.is_err()); + + assert_eq!(res.unwrap_err(), MagnetLinkError::InvalidURINewLine,); + } } diff --git a/tests/bittorrent-v1-emma-goldman.magnet b/tests/bittorrent-v1-emma-goldman.magnet index 9a5753e..4194aae 100644 --- a/tests/bittorrent-v1-emma-goldman.magnet +++ b/tests/bittorrent-v1-emma-goldman.magnet @@ -1 +1 @@ -magnet:?xt=urn:btih:C811B41641A09D192B8ED81B14064FFF55D85CE3&dn=Emma+Goldman+-+Essential+Works+of+Anarchism+%2816+books%29&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Fexodus.desync.com%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=http%3A%2F%2Ftracker.openbittorrent.com%3A80%2Fannounce&tr=udp%3A%2F%2Fopentracker.i2p.rocks%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.internetwarriors.net%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Fcoppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.zer0day.to%3A1337%2Fannounce +magnet:?xt=urn:btih:C811B41641A09D192B8ED81B14064FFF55D85CE3&dn=Emma+Goldman+-+Essential+Works+of+Anarchism+%2816+books%29&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Fexodus.desync.com%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=http%3A%2F%2Ftracker.openbittorrent.com%3A80%2Fannounce&tr=udp%3A%2F%2Fopentracker.i2p.rocks%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.internetwarriors.net%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Fcoppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.zer0day.to%3A1337%2Fannounce \ No newline at end of file diff --git a/tests/bittorrent-v2-hybrid-test.magnet b/tests/bittorrent-v2-hybrid-test.magnet index 81e877d..32d06f5 100644 --- a/tests/bittorrent-v2-hybrid-test.magnet +++ b/tests/bittorrent-v2-hybrid-test.magnet @@ -1 +1 @@ -magnet:?xt=urn:btih:631a31dd0a46257d5078c0dee4e66e26f73e42ac&xt=urn:btmh:1220d8dd32ac93357c368556af3ac1d95c9d76bd0dff6fa9833ecdac3d53134efabb&dn=bittorrent-v1-v2-hybrid-test +magnet:?xt=urn:btih:631a31dd0a46257d5078c0dee4e66e26f73e42ac&xt=urn:btmh:1220d8dd32ac93357c368556af3ac1d95c9d76bd0dff6fa9833ecdac3d53134efabb&dn=bittorrent-v1-v2-hybrid-test \ No newline at end of file diff --git a/tests/bittorrent-v2-test.magnet b/tests/bittorrent-v2-test.magnet index fc41096..7528b02 100644 --- a/tests/bittorrent-v2-test.magnet +++ b/tests/bittorrent-v2-test.magnet @@ -1 +1 @@ -magnet:?xt=urn:btmh:1220caf1e1c30e81cb361b9ee167c4aa64228a7fa4fa9f6105232b28ad099f3a302e&dn=bittorrent-v2-test +magnet:?xt=urn:btmh:1220caf1e1c30e81cb361b9ee167c4aa64228a7fa4fa9f6105232b28ad099f3a302e&dn=bittorrent-v2-test \ No newline at end of file