Skip to content

Commit

Permalink
feat(api): [torrust#143] axum api. POST /api/key/:seconds_valid endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
josecelano committed Jan 11, 2023
1 parent a58d831 commit 0282e33
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 2 deletions.
18 changes: 18 additions & 0 deletions src/apis/routes.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use std::fmt;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;

use axum::extract::{Path, Query, State};
use axum::http::{header, StatusCode};
use axum::response::{IntoResponse, Json, Response};
use serde::{de, Deserialize, Deserializer, Serialize};
use serde_json::json;

use crate::api::resource::auth_key::AuthKey;
use crate::api::resource::stats::Stats;
use crate::api::resource::torrent::{ListItem, Torrent};
use crate::protocol::info_hash::InfoHash;
Expand Down Expand Up @@ -40,6 +42,15 @@ fn response_err(reason: String) -> Response {
.into_response()
}

fn response_auth_key(auth_key: &AuthKey) -> Response {
(
StatusCode::OK,
[(header::CONTENT_TYPE, "application/json; charset=utf-8")],
serde_json::to_string(auth_key).unwrap(),
)
.into_response()
}

pub async fn get_stats_handler(State(tracker): State<Arc<Tracker>>) -> Json<Stats> {
Json(Stats::from(get_metrics(tracker.clone()).await))
}
Expand Down Expand Up @@ -112,6 +123,13 @@ pub async fn reload_whitelist_handler(State(tracker): State<Arc<Tracker>>) -> Re
}
}

pub async fn generate_auth_key_handler(State(tracker): State<Arc<Tracker>>, Path(seconds_valid): Path<u64>) -> Response {
match tracker.generate_auth_key(Duration::from_secs(seconds_valid)).await {
Ok(auth_key) => response_auth_key(&AuthKey::from(auth_key)),
Err(_) => response_err("failed to generate key".to_string()),
}
}

/// Serde deserialization decorator to map empty Strings to None,
fn empty_string_as_none<'de, D, T>(de: D) -> Result<Option<T>, D::Error>
where
Expand Down
14 changes: 12 additions & 2 deletions src/apis/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use warp::hyper;

use super::middlewares::auth::auth;
use super::routes::{
add_torrent_to_whitelist_handler, delete_torrent_from_whitelist_handler, get_stats_handler, get_torrent_handler,
get_torrents_handler, reload_whitelist_handler,
add_torrent_to_whitelist_handler, delete_torrent_from_whitelist_handler, generate_auth_key_handler, get_stats_handler,
get_torrent_handler, get_torrents_handler, reload_whitelist_handler,
};
use crate::tracker;

Expand All @@ -38,6 +38,11 @@ pub fn start(socket_addr: SocketAddr, tracker: &Arc<tracker::Tracker>) -> impl F
"/whitelist/:info_hash",
get(reload_whitelist_handler).with_state(tracker.clone()),
)
// Keys
.route(
"/key/:seconds_valid",
post(generate_auth_key_handler).with_state(tracker.clone()),
)
.layer(middleware::from_fn_with_state(tracker.config.clone(), auth));

let server = axum::Server::bind(&socket_addr).serve(app.into_make_service());
Expand Down Expand Up @@ -74,6 +79,11 @@ pub fn start_tls(
"/whitelist/:info_hash",
get(reload_whitelist_handler).with_state(tracker.clone()),
)
// Keys
.route(
"/key/:seconds_valid",
post(generate_auth_key_handler).with_state(tracker.clone()),
)
.layer(middleware::from_fn_with_state(tracker.config.clone(), auth));

let handle = Handle::new();
Expand Down
68 changes: 68 additions & 0 deletions tests/tracker_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1123,4 +1123,72 @@ mod tracker_apis {
assert_failed_to_reload_whitelist(response).await;
}
}

mod for_key_resources {
//use std::time::Duration;

use torrust_tracker::api::resource::auth_key::AuthKey;
use torrust_tracker::tracker::auth::Key;

use crate::api::asserts::{assert_failed_to_generate_key, assert_token_not_valid, assert_unauthorized};
/*use crate::api::asserts::{
assert_failed_to_delete_key, assert_failed_to_generate_key, assert_failed_to_reload_keys, assert_token_not_valid,
assert_unauthorized,
};*/
use crate::api::client::Client;
use crate::api::connection_info::{connection_with_invalid_token, connection_with_no_token};
use crate::api::server::start_default_api;
use crate::api::{force_database_error, Version};

#[tokio::test]
async fn should_allow_generating_a_new_auth_key() {
let api_server = start_default_api(&Version::Axum).await;

let seconds_valid = 60;

let response = Client::new(api_server.get_connection_info(), &Version::Axum)
.generate_auth_key(seconds_valid)
.await;

// Verify the key with the tracker
assert!(api_server
.tracker
.verify_auth_key(&Key::from(response.json::<AuthKey>().await.unwrap()))
.await
.is_ok());
}

#[tokio::test]
async fn should_not_allow_generating_a_new_auth_key_for_unauthenticated_users() {
let api_server = start_default_api(&Version::Axum).await;

let seconds_valid = 60;

let response = Client::new(connection_with_invalid_token(&api_server.get_bind_address()), &Version::Axum)
.generate_auth_key(seconds_valid)
.await;

assert_token_not_valid(response).await;

let response = Client::new(connection_with_no_token(&api_server.get_bind_address()), &Version::Axum)
.generate_auth_key(seconds_valid)
.await;

assert_unauthorized(response).await;
}

#[tokio::test]
async fn should_return_an_error_when_the_auth_key_cannot_be_generated() {
let api_server = start_default_api(&Version::Axum).await;

force_database_error(&api_server.tracker);

let seconds_valid = 60;
let response = Client::new(api_server.get_connection_info(), &Version::Axum)
.generate_auth_key(seconds_valid)
.await;

assert_failed_to_generate_key(response).await;
}
}
}

0 comments on commit 0282e33

Please sign in to comment.