Library now panics! on invalid magnet url

Another helpful redditor warned me about the dangers of not validating
that the URL given is a magnet url. Unfortuanetly, I can't just change
everything to use Options and Errors, so I'm making the fix of having
the library just panic instead, since that would make it still
backwards compatible. This will be changed in version 2.0.0
This commit is contained in:
William Batista 2021-02-17 10:15:02 -05:00
parent f3bf0aeff2
commit d83f888da7
No known key found for this signature in database
GPG Key ID: C6D7973D216F38D3
2 changed files with 48 additions and 25 deletions

View File

@ -1,29 +1,28 @@
[![Build Status](https://www.travis-ci.com/billyb2/parse-magnet-rs.svg?branch=main)](https://www.travis-ci.com/billyb2/parse-magnet-rs) [![Build Status](https://www.travis-ci.com/billyb2/parse-magnet-rs.svg?branch=main)](https://www.travis-ci.com/billyb2/parse-magnet-rs)
# The Rust Magnet URL Parser!
# What is a magnet url # What is a magnet url
A magnet is a URI scheme that identifies files by their hash, A magnet is a URI scheme that identifies files by their hash,
normally used in peer to peer file sharing networks (like normally used in peer to peer file sharing networks (like
Bittorrent). Basically, a magnet link identifies a torrent you Bittorrent). Basically, a magnet link identifies a torrent you
want to download, and tells the torrent client how to download want to download, and tells the torrent client how to download
it. They make it very easy to share files over the internet, it. They make it very easy to share files over the internet,
and use a combination of DHT and trackers to tell your torrent and use a combination of DHT and trackers to tell your torrent
client where other peers who can share the file with you are. client where other peers who can share the file with you are.
# Why is magnet_url # Why is magnet_url
While working on a side project, I realized that I had the While working on a side project, I realized that I had the
misfortune of trying to get the component parts of a magnet-url misfortune of trying to get the component parts of a magnet-url
and then do further processing of them. I quickly wrote some and then do further processing of them. I quickly wrote some
Regex for it, but then I realized that this would be really Regex for it, but then I realized that this would be really
useful for other projects that are dealing with torrents in useful for other projects that are dealing with torrents in
Rust. By making it modifiable, too, it would allow for the Rust. By making it modifiable, too, it would allow for the
creation of custom magnet links, which would also be useful for creation of custom magnet links, which would also be useful for
torrent based projects. torrent based projects.
# Why use magnet_url # Why use magnet_url
magnet_url has the goal of, as you may have guessed, parsing the parts of magnets. It does magnet_url has the goal of, as you may have guessed, parsing the parts of magnets. It does
this using some relatively simple regexes. The crate is designed to be very simple and efficient, this using some relatively simple regexes. The crate is designed to be very simple and efficient,
with a lot of flexibility. It's also designed to be relatively easy to handle errors, and with a lot of flexibility. It's also designed to be relatively easy to handle errors, and
modification of it's source is greatly encouraged through documentation and it's license. modification of it's source is greatly encouraged through documentation and it's license.
## How to use this crate ## How to use this crate
Parsing a magnet is very simple: Parsing a magnet is very simple:
@ -57,7 +56,6 @@ parameters!
``` ```
use magnet_url::Magnet; use magnet_url::Magnet;
let magneturl =
//Note, this magnet won't actually download, sorry :/ //Note, this magnet won't actually download, sorry :/
Magnet { Magnet {
dn: "hello_world".to_string(), dn: "hello_world".to_string(),
@ -67,13 +65,19 @@ parameters!
tr: tr:
{ {
let mut tr_vec = Vec::new(); let mut tr_vec = Vec::new();
tr_vec.push("https://example.com/".to_string()) tr_vec.push("https://example.com/".to_string());
tr_vec tr_vec
}, },
kt: "cool+stuff".to_string(), kt: "cool+stuff".to_string(),
ws: String::new(), ws: String::new(),
acceptable_source: String::new(), acceptable_source: String::new(),
mt: String::new(), mt: String::new(),
xs: String::new(),
}; };
``` ```
Invalid magnet url's will result in a panic! (This will be changed to an error in v2.0.0
```#[should_panic]
use magnet_url::Magnet;
let _magnet_link = Magnet::new("https://example.com");
```

View File

@ -4,6 +4,7 @@ use regex::Regex;
extern crate lazy_static; extern crate lazy_static;
///The regexes used to identify specific parts of the magnet ///The regexes used to identify specific parts of the magnet
const MAGNET_URL_RE_STR: &str = r"^(stratum-|)magnet:\?";
const DISPLAY_NAME_RE_STR: &str = r"dn=([A-Za-z0-9!@#$%^:*<>,?/()_+=.{}\{}\-]*)(&|$|\s)"; const DISPLAY_NAME_RE_STR: &str = r"dn=([A-Za-z0-9!@#$%^:*<>,?/()_+=.{}\{}\-]*)(&|$|\s)";
const EXACT_TOPIC_RE_STR: &str = r"xt=urn:(sha1|btih|ed2k|aich|kzhash|md5|tree:tiger):([A-Fa-f0-9]+|[A-Za-z2-7]+)"; const EXACT_TOPIC_RE_STR: &str = r"xt=urn:(sha1|btih|ed2k|aich|kzhash|md5|tree:tiger):([A-Fa-f0-9]+|[A-Za-z2-7]+)";
const ADDRESS_TRACKER_RE_STR: &str = r"tr=([A-Za-z0-9!@#$%^:*<>,?/()_+=.{}\{}\-]*)(&|$|\s)"; const ADDRESS_TRACKER_RE_STR: &str = r"tr=([A-Za-z0-9!@#$%^:*<>,?/()_+=.{}\{}\-]*)(&|$|\s)";
@ -71,7 +72,6 @@ const MANIFEST_TOPIC_RE_STR: &str = r"mt=((\w+)[A-Za-z0-9!@#$%^:*<>,?/()_+=.{}\\
/// ///
/// ``` /// ```
/// use magnet_url::Magnet; /// use magnet_url::Magnet;
/// let magneturl =
/// //Note, this magnet won't actually download, sorry :/ /// //Note, this magnet won't actually download, sorry :/
/// Magnet { /// Magnet {
/// dn: "hello_world".to_string(), /// dn: "hello_world".to_string(),
@ -91,6 +91,12 @@ const MANIFEST_TOPIC_RE_STR: &str = r"mt=((\w+)[A-Za-z0-9!@#$%^:*<>,?/()_+=.{}\\
/// xs: String::new(), /// xs: String::new(),
/// }; /// };
/// ``` /// ```
///
/// Invalid magnet url's will result in a panic! (This will be changed to an error in v2.0.0
/// ```#[should_panic]
/// use magnet_url::Magnet;
/// let _magnet_link = Magnet::new("https://example.com");
/// ```
pub struct Magnet { pub struct Magnet {
///Display Name of the torrent ///Display Name of the torrent
pub dn: String, pub dn: String,
@ -134,6 +140,7 @@ impl Magnet {
*/ */
pub fn new (magnet_str: &str) -> Magnet { pub fn new (magnet_str: &str) -> Magnet {
lazy_static! { lazy_static! {
static ref MAGNET_URL_RE: Regex = Regex::new(MAGNET_URL_RE_STR).unwrap();
static ref DISPLAY_NAME_RE: Regex = Regex::new(DISPLAY_NAME_RE_STR).unwrap(); static ref DISPLAY_NAME_RE: Regex = Regex::new(DISPLAY_NAME_RE_STR).unwrap();
static ref EXACT_TOPIC_RE: Regex = Regex::new(EXACT_TOPIC_RE_STR).unwrap(); static ref EXACT_TOPIC_RE: Regex = Regex::new(EXACT_TOPIC_RE_STR).unwrap();
static ref EXACT_LENGTH_RE: Regex = Regex::new(EXACT_LENGTH_RE_STR).unwrap(); static ref EXACT_LENGTH_RE: Regex = Regex::new(EXACT_LENGTH_RE_STR).unwrap();
@ -145,6 +152,11 @@ impl Magnet {
static ref MANIFEST_TOPIC_RE: Regex = Regex::new(MANIFEST_TOPIC_RE_STR).unwrap(); static ref MANIFEST_TOPIC_RE: Regex = Regex::new(MANIFEST_TOPIC_RE_STR).unwrap();
} }
// Panicking is a temporary fix, in version 2.0.0 it will instead return an Error
if MAGNET_URL_RE.is_match(magnet_str) == false {
panic!("Invalid magnet url")
}
let validate_regex = |regex: &Regex, re_group_index| -> String { let validate_regex = |regex: &Regex, re_group_index| -> String {
match regex.captures(magnet_str) { match regex.captures(magnet_str) {
Some(m) => m.get(re_group_index).map_or("", |m| m.as_str()).to_string(), Some(m) => m.get(re_group_index).map_or("", |m| m.as_str()).to_string(),
@ -206,4 +218,11 @@ mod tests {
assert_eq!(magnet_link.acceptable_source, String::new()); assert_eq!(magnet_link.acceptable_source, String::new());
assert_eq!(magnet_link.mt, String::new()); assert_eq!(magnet_link.mt, String::new());
} }
#[test]
#[should_panic]
fn invalid_magnet_test() {
let _magnet_link = Magnet::new("https://example.com");
}
} }