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
55 changes: 55 additions & 0 deletions src/http/axum_implementation/extractors/key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use std::panic::Location;

use axum::async_trait;
use axum::extract::{FromRequestParts, Path};
use axum::http::request::Parts;
use axum::response::{IntoResponse, Response};

use crate::http::axum_implementation::handlers::auth::{self, KeyIdParam};
use crate::http::axum_implementation::responses;
use crate::tracker::auth::KeyId;

pub struct ExtractKeyId(pub KeyId);

#[async_trait]
impl<S> FromRequestParts<S> for ExtractKeyId
where
S: Send + Sync,
{
type Rejection = Response;

async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
match Path::<KeyIdParam>::from_request_parts(parts, state).await {
Ok(key_id_param) => {
let Ok(key_id) = key_id_param.0.value().parse::<KeyId>() else {
return Err(responses::error::Error::from(
auth::Error::InvalidKeyFormat {
location: Location::caller()
})
.into_response())
};
Ok(ExtractKeyId(key_id))
}
Err(rejection) => match rejection {
axum::extract::rejection::PathRejection::FailedToDeserializePathParams(_) => {
return Err(responses::error::Error::from(auth::Error::InvalidKeyFormat {
location: Location::caller(),
})
.into_response())
}
axum::extract::rejection::PathRejection::MissingPathParams(_) => {
return Err(responses::error::Error::from(auth::Error::MissingAuthKey {
location: Location::caller(),
})
.into_response())
}
_ => {
return Err(responses::error::Error::from(auth::Error::CannotExtractKeyParam {
location: Location::caller(),
})
.into_response())
}
},
}
}
}
1 change: 1 addition & 0 deletions src/http/axum_implementation/extractors/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod announce_request;
pub mod key;
pub mod peer_ip;
pub mod remote_client_ip;
pub mod scrape_request;
16 changes: 3 additions & 13 deletions src/http/axum_implementation/handlers/announce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@ use std::panic::Location;
use std::sync::Arc;

use aquatic_udp_protocol::{AnnounceEvent, NumberOfBytes};
use axum::extract::{Path, State};
use axum::extract::State;
use axum::response::{IntoResponse, Response};
use log::debug;

use super::auth::KeyIdParam;
use crate::http::axum_implementation::extractors::announce_request::ExtractRequest;
use crate::http::axum_implementation::extractors::key::ExtractKeyId;
use crate::http::axum_implementation::extractors::peer_ip;
use crate::http::axum_implementation::extractors::remote_client_ip::RemoteClientIp;
use crate::http::axum_implementation::handlers::auth;
use crate::http::axum_implementation::requests::announce::{Announce, Compact, Event};
use crate::http::axum_implementation::responses::{self, announce};
use crate::http::axum_implementation::services;
use crate::protocol::clock::{Current, Time};
use crate::tracker::auth::KeyId;
use crate::tracker::peer::Peer;
use crate::tracker::Tracker;

Expand All @@ -42,20 +41,11 @@ pub async fn handle_without_key(
pub async fn handle_with_key(
State(tracker): State<Arc<Tracker>>,
ExtractRequest(announce_request): ExtractRequest,
Path(key_id_param): Path<KeyIdParam>,
ExtractKeyId(key_id): ExtractKeyId,
remote_client_ip: RemoteClientIp,
) -> 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::<KeyId>() else {
return responses::error::Error::from(
auth::Error::InvalidKeyFormat {
location: Location::caller()
})
.into_response()
};

match tracker.authenticate(&key_id).await {
Ok(_) => (),
Err(error) => return responses::error::Error::from(error).into_response(),
Expand Down
6 changes: 4 additions & 2 deletions src/http/axum_implementation/handlers/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ impl KeyIdParam {

#[derive(Debug, Error)]
pub enum Error {
#[error("Missing authentication key for private tracker. Error in {location}")]
#[error("Missing authentication key param for private tracker. Error in {location}")]
MissingAuthKey { location: &'static Location<'static> },
#[error("Invalid format authentication key. Error in {location}")]
#[error("Invalid format for authentication key param. Error in {location}")]
InvalidKeyFormat { location: &'static Location<'static> },
#[error("Cannot extract authentication key param from URL path. Error in {location}")]
CannotExtractKeyParam { location: &'static Location<'static> },
}

impl From<Error> for responses::error::Error {
Expand Down
18 changes: 3 additions & 15 deletions src/http/axum_implementation/handlers/scrape.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
use std::panic::Location;
use std::sync::Arc;

use axum::extract::{Path, State};
use axum::extract::State;
use axum::response::{IntoResponse, Response};
use log::debug;

use super::auth::KeyIdParam;
use crate::http::axum_implementation::extractors::key::ExtractKeyId;
use crate::http::axum_implementation::extractors::peer_ip;
use crate::http::axum_implementation::extractors::remote_client_ip::RemoteClientIp;
use crate::http::axum_implementation::extractors::scrape_request::ExtractRequest;
use crate::http::axum_implementation::handlers::auth;
use crate::http::axum_implementation::requests::scrape::Scrape;
use crate::http::axum_implementation::{responses, services};
use crate::tracker::auth::KeyId;
use crate::tracker::Tracker;

#[allow(clippy::unused_async)]
Expand All @@ -34,20 +31,11 @@ pub async fn handle_without_key(
pub async fn handle_with_key(
State(tracker): State<Arc<Tracker>>,
ExtractRequest(scrape_request): ExtractRequest,
Path(key_id_param): Path<KeyIdParam>,
ExtractKeyId(key_id): ExtractKeyId,
remote_client_ip: RemoteClientIp,
) -> 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::<KeyId>() else {
return responses::error::Error::from(
auth::Error::InvalidKeyFormat {
location: Location::caller()
})
.into_response()
};

match tracker.authenticate(&key_id).await {
Ok(_) => (),
Err(_) => return handle_fake_scrape(&tracker, &scrape_request, &remote_client_ip).await,
Expand Down