Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 0 additions & 56 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -909,62 +909,6 @@ impl Tracker {
Ok(())
}

/// It authenticates and authorizes a UDP tracker request.
///
/// # Context: Authentication and Authorization
///
/// # Errors
///
/// Will return a `torrent::Error::PeerKeyNotValid` if the `key` is not valid.
///
/// Will return a `torrent::Error::PeerNotAuthenticated` if the `key` is `None`.
///
/// Will return a `torrent::Error::TorrentNotWhitelisted` if the the Tracker is in listed mode and the `info_hash` is not whitelisted.
#[deprecated(since = "3.0.0", note = "please use `authenticate` and `authorize` instead")]
pub async fn authenticate_request(&self, info_hash: &InfoHash, key: &Option<Key>) -> Result<(), Error> {
// todo: this is a deprecated method.
// We're splitting authentication and authorization responsibilities.
// Use `authenticate` and `authorize` instead.

// Authentication

// no authentication needed in public mode
if self.is_public() {
return Ok(());
}

// check if auth_key is set and valid
if self.is_private() {
match key {
Some(key) => {
if let Err(e) = self.verify_auth_key(key).await {
return Err(Error::PeerKeyNotValid {
key: key.clone(),
source: (Arc::new(e) as Arc<dyn std::error::Error + Send + Sync>).into(),
});
}
}
None => {
return Err(Error::PeerNotAuthenticated {
location: Location::caller(),
});
}
}
}

// Authorization

// check if info_hash is whitelisted
if self.is_whitelisted() && !self.is_info_hash_whitelisted(info_hash).await {
return Err(Error::TorrentNotWhitelisted {
info_hash: *info_hash,
location: Location::caller(),
});
}

Ok(())
}

/// Right now, there is only authorization when the `Tracker` runs in
/// `listed` or `private_listed` modes.
///
Expand Down
4 changes: 4 additions & 0 deletions src/servers/udp/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,8 @@ pub enum Error {
BadRequest {
source: LocatedError<'static, dyn std::error::Error + Send + Sync>,
},

/// Error returned when tracker requires authentication.
#[error("domain tracker requires authentication but is not supported in current UDP implementation. Location: {location}")]
TrackerAuthenticationRequired { location: &'static Location<'static> },
}
48 changes: 19 additions & 29 deletions src/servers/udp/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use aquatic_udp_protocol::{
use log::{debug, info};

use super::connection_cookie::{check, from_connection_id, into_connection_id, make};
use crate::core::{statistics, Tracker};
use crate::core::{statistics, ScrapeData, Tracker};
use crate::servers::udp::error::Error;
use crate::servers::udp::peer_builder;
use crate::servers::udp::request::AnnounceWrapper;
Expand Down Expand Up @@ -99,22 +99,6 @@ pub async fn handle_connect(remote_addr: SocketAddr, request: &ConnectRequest, t
Ok(Response::from(response))
}

/// It authenticates the request. It returns an error if the peer is not allowed
/// to make the request.
///
/// # Errors
///
/// Will return `Error` if unable to `authenticate_request`.
#[allow(deprecated)]
pub async fn authenticate(info_hash: &InfoHash, tracker: &Tracker) -> Result<(), Error> {
tracker
.authenticate_request(info_hash, &None)
.await
.map_err(|e| Error::TrackerError {
source: (Arc::new(e) as Arc<dyn std::error::Error + Send + Sync>).into(),
})
}

/// It handles the `Announce` request. Refer to [`Announce`](crate::servers::udp#announce)
/// request for more information.
///
Expand All @@ -128,14 +112,24 @@ pub async fn handle_announce(
) -> Result<Response, Error> {
debug!("udp announce request: {:#?}", announce_request);

// Authentication
if tracker.requires_authentication() {
return Err(Error::TrackerAuthenticationRequired {
location: Location::caller(),
});
}

check(&remote_addr, &from_connection_id(&announce_request.connection_id))?;

let wrapped_announce_request = AnnounceWrapper::new(announce_request);

let info_hash = wrapped_announce_request.info_hash;
let remote_client_ip = remote_addr.ip();

authenticate(&info_hash, tracker).await?;
// Authorization
tracker.authorize(&info_hash).await.map_err(|e| Error::TrackerError {
source: (Arc::new(e) as Arc<dyn std::error::Error + Send + Sync>).into(),
})?;

info!(target: "UDP", "\"ANNOUNCE TxID {} IH {}\"", announce_request.transaction_id.0, info_hash.to_hex_string());

Expand Down Expand Up @@ -222,28 +216,24 @@ pub async fn handle_scrape(remote_addr: SocketAddr, request: &ScrapeRequest, tra
info_hashes.push(InfoHash(info_hash.0));
}

let scrape_data = tracker.scrape(&info_hashes).await;
let scrape_data = if tracker.requires_authentication() {
ScrapeData::zeroed(&info_hashes)
} else {
tracker.scrape(&info_hashes).await
};

let mut torrent_stats: Vec<TorrentScrapeStatistics> = Vec::new();

for file in &scrape_data.files {
let info_hash = file.0;
let swarm_metadata = file.1;

#[allow(deprecated)]
let scrape_entry = if tracker.authenticate_request(info_hash, &None).await.is_ok() {
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_possible_truncation)]
let scrape_entry = {
TorrentScrapeStatistics {
seeders: NumberOfPeers(i64::from(swarm_metadata.complete) as i32),
completed: NumberOfDownloads(i64::from(swarm_metadata.downloaded) as i32),
leechers: NumberOfPeers(i64::from(swarm_metadata.incomplete) as i32),
}
} else {
TorrentScrapeStatistics {
seeders: NumberOfPeers(0),
completed: NumberOfDownloads(0),
leechers: NumberOfPeers(0),
}
};

torrent_stats.push(scrape_entry);
Expand Down