From ea249733f4f74ae1c35e47fda965d97b83681f11 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 1 Mar 2023 11:20:20 +0000 Subject: [PATCH 1/2] refactor(http): [#200] move function to Tracker --- src/http/axum_implementation/handlers/announce.rs | 2 +- src/http/axum_implementation/handlers/auth.rs | 15 +-------------- src/http/axum_implementation/handlers/scrape.rs | 2 +- src/tracker/mod.rs | 11 +++++++++++ 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/http/axum_implementation/handlers/announce.rs b/src/http/axum_implementation/handlers/announce.rs index b9b964605..9f39a5bdf 100644 --- a/src/http/axum_implementation/handlers/announce.rs +++ b/src/http/axum_implementation/handlers/announce.rs @@ -55,7 +55,7 @@ pub async fn handle_with_key( .into_response() }; - match auth::authenticate(&key_id, &tracker).await { + match tracker.authenticate(&key_id).await { Ok(_) => (), Err(error) => return responses::error::Error::from(error).into_response(), } diff --git a/src/http/axum_implementation/handlers/auth.rs b/src/http/axum_implementation/handlers/auth.rs index 3b9aebc23..366526664 100644 --- a/src/http/axum_implementation/handlers/auth.rs +++ b/src/http/axum_implementation/handlers/auth.rs @@ -1,12 +1,10 @@ use std::panic::Location; -use std::sync::Arc; use serde::Deserialize; use thiserror::Error; use crate::http::axum_implementation::responses; -use crate::tracker::auth::{self, KeyId}; -use crate::tracker::Tracker; +use crate::tracker::auth; #[derive(Deserialize)] pub struct KeyIdParam(String); @@ -26,17 +24,6 @@ pub enum Error { InvalidKeyFormat { location: &'static Location<'static> }, } -/// # Errors -/// -/// Will return an error if the the authentication key cannot be verified. -pub async fn authenticate(key_id: &KeyId, tracker: &Arc) -> Result<(), auth::Error> { - if tracker.is_private() { - tracker.verify_auth_key(key_id).await - } else { - Ok(()) - } -} - impl From for responses::error::Error { fn from(err: Error) -> Self { responses::error::Error { diff --git a/src/http/axum_implementation/handlers/scrape.rs b/src/http/axum_implementation/handlers/scrape.rs index 814cdbfa4..6edf2fdb8 100644 --- a/src/http/axum_implementation/handlers/scrape.rs +++ b/src/http/axum_implementation/handlers/scrape.rs @@ -47,7 +47,7 @@ pub async fn handle_with_key( .into_response() }; - match auth::authenticate(&key_id, &tracker).await { + match tracker.authenticate(&key_id).await { Ok(_) => (), Err(_) => return handle_fake_scrape(&tracker, &scrape_request, &remote_client_ip).await, } diff --git a/src/tracker/mod.rs b/src/tracker/mod.rs index 2604c5045..31eeef6dc 100644 --- a/src/tracker/mod.rs +++ b/src/tracker/mod.rs @@ -334,6 +334,17 @@ impl Tracker { Ok(()) } + /// # Errors + /// + /// Will return an error if the the authentication key cannot be verified. + pub async fn authenticate(&self, key_id: &KeyId) -> Result<(), auth::Error> { + if self.is_private() { + self.verify_auth_key(key_id).await + } else { + Ok(()) + } + } + /// Loading the torrents from database into memory /// /// # Errors From cd14c6b334c4a129ebf997f7095f3fe0cdd9e62b Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 1 Mar 2023 11:58:13 +0000 Subject: [PATCH 2/2] feat(http): [#200] announce request in listed mode --- .../axum_implementation/handlers/announce.rs | 8 +++++- src/http/axum_implementation/handlers/mod.rs | 11 ++++++++ .../axum_implementation/handlers/scrape.rs | 3 ++- src/tracker/mod.rs | 25 +++++++++++++++++++ tests/http_tracker.rs | 6 ++--- 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/http/axum_implementation/handlers/announce.rs b/src/http/axum_implementation/handlers/announce.rs index 9f39a5bdf..e4cd476fa 100644 --- a/src/http/axum_implementation/handlers/announce.rs +++ b/src/http/axum_implementation/handlers/announce.rs @@ -28,7 +28,7 @@ pub async fn handle_without_key( ) -> Response { debug!("http announce request: {:#?}", announce_request); - if tracker.is_private() { + if tracker.requires_authentication() { return responses::error::Error::from(auth::Error::MissingAuthKey { location: Location::caller(), }) @@ -47,6 +47,7 @@ pub async fn handle_with_key( ) -> Response { debug!("http announce request: {:#?}", announce_request); + // todo: extract to Axum extractor. Duplicate code in `scrape` handler. let Ok(key_id) = key_id_param.value().parse::() else { return responses::error::Error::from( auth::Error::InvalidKeyFormat { @@ -64,6 +65,11 @@ pub async fn handle_with_key( } async fn handle(tracker: &Arc, announce_request: &Announce, remote_client_ip: &RemoteClientIp) -> Response { + match tracker.authorize(&announce_request.info_hash).await { + Ok(_) => (), + Err(error) => return responses::error::Error::from(error).into_response(), + } + let peer_ip = match peer_ip::resolve(tracker.config.on_reverse_proxy, remote_client_ip) { Ok(peer_ip) => peer_ip, Err(err) => return err, diff --git a/src/http/axum_implementation/handlers/mod.rs b/src/http/axum_implementation/handlers/mod.rs index 0d8aa7f52..7cc5022e6 100644 --- a/src/http/axum_implementation/handlers/mod.rs +++ b/src/http/axum_implementation/handlers/mod.rs @@ -1,4 +1,15 @@ +use super::responses; +use crate::tracker::error::Error; + pub mod announce; pub mod auth; pub mod scrape; pub mod status; + +impl From for responses::error::Error { + fn from(err: Error) -> Self { + responses::error::Error { + failure_reason: format!("Tracker error: {err}"), + } + } +} diff --git a/src/http/axum_implementation/handlers/scrape.rs b/src/http/axum_implementation/handlers/scrape.rs index 6edf2fdb8..649d630b0 100644 --- a/src/http/axum_implementation/handlers/scrape.rs +++ b/src/http/axum_implementation/handlers/scrape.rs @@ -23,7 +23,7 @@ pub async fn handle_without_key( ) -> Response { debug!("http scrape request: {:#?}", &scrape_request); - if tracker.is_private() { + if tracker.requires_authentication() { return handle_fake_scrape(&tracker, &scrape_request, &remote_client_ip).await; } @@ -39,6 +39,7 @@ pub async fn handle_with_key( ) -> Response { debug!("http scrape request: {:#?}", &scrape_request); + // todo: extract to Axum extractor. Duplicate code in `announce` handler. let Ok(key_id) = key_id_param.value().parse::() else { return responses::error::Error::from( auth::Error::InvalidKeyFormat { diff --git a/src/tracker/mod.rs b/src/tracker/mod.rs index 31eeef6dc..7733940c9 100644 --- a/src/tracker/mod.rs +++ b/src/tracker/mod.rs @@ -107,6 +107,10 @@ impl Tracker { self.mode == mode::Mode::Listed || self.mode == mode::Mode::PrivateListed } + pub fn requires_authentication(&self) -> bool { + self.is_private() + } + /// It handles an announce request. /// /// BEP 03: [The `BitTorrent` Protocol Specification](https://www.bittorrent.org/beps/bep_0003.html). @@ -345,6 +349,27 @@ impl Tracker { } } + /// The only authorization process is the whitelist. + /// + /// # Errors + /// + /// Will return an error if the tracker is running in `listed` mode + /// and the infohash is not whitelisted. + pub async fn authorize(&self, info_hash: &InfoHash) -> Result<(), Error> { + if !self.is_whitelisted() { + return Ok(()); + } + + if self.is_info_hash_whitelisted(info_hash).await { + return Ok(()); + } + + return Err(Error::TorrentNotWhitelisted { + info_hash: *info_hash, + location: Location::caller(), + }); + } + /// Loading the torrents from database into memory /// /// # Errors diff --git a/tests/http_tracker.rs b/tests/http_tracker.rs index 0536ab0b7..60ccae06b 100644 --- a/tests/http_tracker.rs +++ b/tests/http_tracker.rs @@ -2403,8 +2403,7 @@ mod axum_http_tracker_server { use crate::http::requests::announce::QueryBuilder; use crate::http::server::start_whitelisted_http_tracker; - //#[tokio::test] - #[allow(dead_code)] + #[tokio::test] async fn should_fail_if_the_torrent_is_not_in_the_whitelist() { let http_tracker_server = start_whitelisted_http_tracker(Version::Axum).await; @@ -2417,8 +2416,7 @@ mod axum_http_tracker_server { assert_torrent_not_in_whitelist_error_response(response).await; } - //#[tokio::test] - #[allow(dead_code)] + #[tokio::test] async fn should_allow_announcing_a_whitelisted_torrent() { let http_tracker_server = start_whitelisted_http_tracker(Version::Axum).await;