Skip to content

Commit

Permalink
feat(api): [torrust#143] axum api. DELETE /api/key/:key endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
josecelano committed Jan 11, 2023
1 parent 0282e33 commit 6b2e3bc
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 14 deletions.
11 changes: 9 additions & 2 deletions src/apis/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,20 @@ 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 {
pub async fn generate_auth_key_handler(State(tracker): State<Arc<Tracker>>, Path(seconds_valid_or_key): Path<u64>) -> Response {
match tracker.generate_auth_key(Duration::from_secs(seconds_valid_or_key)).await {
Ok(auth_key) => response_auth_key(&AuthKey::from(auth_key)),
Err(_) => response_err("failed to generate key".to_string()),
}
}

pub async fn delete_auth_key_handler(State(tracker): State<Arc<Tracker>>, Path(seconds_valid_or_key): Path<String>) -> Response {
match tracker.remove_auth_key(&seconds_valid_or_key).await {
Ok(_) => response_ok(),
Err(_) => response_err("failed to delete 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
18 changes: 12 additions & 6 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, generate_auth_key_handler, get_stats_handler,
get_torrent_handler, get_torrents_handler, reload_whitelist_handler,
add_torrent_to_whitelist_handler, delete_auth_key_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 Down Expand Up @@ -40,8 +40,11 @@ pub fn start(socket_addr: SocketAddr, tracker: &Arc<tracker::Tracker>) -> impl F
)
// Keys
.route(
"/key/:seconds_valid",
post(generate_auth_key_handler).with_state(tracker.clone()),
"/key/:seconds_valid_or_key",
post(generate_auth_key_handler)
.with_state(tracker.clone())
.delete(delete_auth_key_handler)
.with_state(tracker.clone()),
)
.layer(middleware::from_fn_with_state(tracker.config.clone(), auth));

Expand Down Expand Up @@ -81,8 +84,11 @@ pub fn start_tls(
)
// Keys
.route(
"/key/:seconds_valid",
post(generate_auth_key_handler).with_state(tracker.clone()),
"/key/:seconds_valid_or_key",
post(generate_auth_key_handler)
.with_state(tracker.clone())
.delete(delete_auth_key_handler)
.with_state(tracker.clone()),
)
.layer(middleware::from_fn_with_state(tracker.config.clone(), auth));

Expand Down
6 changes: 6 additions & 0 deletions tests/api/asserts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

use reqwest::Response;

pub async fn assert_ok(response: Response) {
assert_eq!(response.status(), 200);
assert_eq!(response.headers().get("content-type").unwrap(), "text/plain; charset=utf-8");
assert_eq!(response.text().await.unwrap(), "Ok");
}

pub async fn assert_torrent_not_known(response: Response) {
assert_eq!(response.status(), 200);
assert_eq!(response.headers().get("content-type").unwrap(), "application/json");
Expand Down
81 changes: 75 additions & 6 deletions tests/tracker_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1125,16 +1125,14 @@ mod tracker_apis {
}

mod for_key_resources {
//use std::time::Duration;
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::asserts::{
assert_failed_to_delete_key, assert_failed_to_generate_key, assert_ok, 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;
Expand Down Expand Up @@ -1190,5 +1188,76 @@ mod tracker_apis {

assert_failed_to_generate_key(response).await;
}

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

let seconds_valid = 60;
let auth_key = api_server
.tracker
.generate_auth_key(Duration::from_secs(seconds_valid))
.await
.unwrap();

let response = Client::new(api_server.get_connection_info(), &Version::Axum)
.delete_auth_key(&auth_key.key)
.await;

assert_ok(response).await;
}

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

let seconds_valid = 60;
let auth_key = api_server
.tracker
.generate_auth_key(Duration::from_secs(seconds_valid))
.await
.unwrap();

force_database_error(&api_server.tracker);

let response = Client::new(api_server.get_connection_info(), &Version::Warp)
.delete_auth_key(&auth_key.key)
.await;

assert_failed_to_delete_key(response).await;
}

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

let seconds_valid = 60;

// Generate new auth key
let auth_key = api_server
.tracker
.generate_auth_key(Duration::from_secs(seconds_valid))
.await
.unwrap();

let response = Client::new(connection_with_invalid_token(&api_server.get_bind_address()), &Version::Warp)
.delete_auth_key(&auth_key.key)
.await;

assert_token_not_valid(response).await;

// Generate new auth key
let auth_key = api_server
.tracker
.generate_auth_key(Duration::from_secs(seconds_valid))
.await
.unwrap();

let response = Client::new(connection_with_no_token(&api_server.get_bind_address()), &Version::Warp)
.delete_auth_key(&auth_key.key)
.await;

assert_unauthorized(response).await;
}
}
}

0 comments on commit 6b2e3bc

Please sign in to comment.