From 6c331f51a1656e00dd165f72d404ee893fcf1e66 Mon Sep 17 00:00:00 2001 From: fMeow Date: Wed, 22 Jun 2022 13:33:45 +0800 Subject: [PATCH] feat: add support for cargo `auth-required` --- Cargo.toml | 1 + src/delete.rs | 29 ++++++++++------------------- src/get.rs | 18 ++++++++++++++---- src/put.rs | 42 ++++++++++++++---------------------------- src/utils.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 51 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 64c66ba..8a7c556 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ mirroring-dummy = [] db-sled = ["sled"] db-redis = ["redis"] db-mongo = ["mongodb", "bson"] +auth-required = [] [dependencies] tokio = { version = "1.1", features = ["macros", "rt-multi-thread", "fs", "io-util"] } diff --git a/src/delete.rs b/src/delete.rs index d404d1c..795605c 100644 --- a/src/delete.rs +++ b/src/delete.rs @@ -3,8 +3,8 @@ use crate::error::Error; use crate::index_manager::IndexManager; use crate::models::Owners; use crate::utils::{ - authorization_header, ok_json_message, ok_with_msg_json_message, with_db_manager, - with_index_manager, + ok_json_message, ok_with_msg_json_message, with_db_manager, with_index_manager, + with_user_id_from_authorization_header, }; use futures::TryFutureExt; use semver::Version; @@ -26,30 +26,25 @@ fn yank( index_manager: Arc, ) -> impl Filter + Clone { warp::delete() - .and(with_db_manager(db_manager)) + .and(with_db_manager(db_manager.clone())) .and(with_index_manager(index_manager)) - .and(authorization_header()) + .and(with_user_id_from_authorization_header(db_manager)) .and(warp::path!( "api" / "v1" / "crates" / String / Version / "yank" )) .and_then(handle_yank) } -#[tracing::instrument(skip(db_manager, index_manager, token, crate_name, version))] +#[tracing::instrument(skip(db_manager, index_manager, user_id, crate_name, version))] async fn handle_yank( db_manager: Arc>, index_manager: Arc, - token: String, + user_id: u32, crate_name: String, version: Version, ) -> Result { let db_manager = db_manager.write().await; - let user_id = db_manager - .user_id_for_token(&token) - .map_err(warp::reject::custom) - .await?; - let crate_name_cloned = crate_name.clone(); db_manager .can_edit_package(user_id, &crate_name, version.clone()) @@ -80,17 +75,17 @@ fn owners( db_manager: Arc>, ) -> impl Filter + Clone { warp::delete() - .and(with_db_manager(db_manager)) - .and(authorization_header()) + .and(with_db_manager(db_manager.clone())) + .and(with_user_id_from_authorization_header(db_manager)) .and(warp::path!("api" / "v1" / "crates" / String / "owners")) .and(warp::body::json::()) .and_then(handle_owners) } -#[tracing::instrument(skip(db_manager, token, name, owners))] +#[tracing::instrument(skip(db_manager, user_id, name, owners))] async fn handle_owners( db_manager: Arc>, - token: String, + user_id: u32, name: String, owners: Owners, ) -> Result { @@ -100,10 +95,6 @@ async fn handle_owners( let db_manager = db_manager.write().await; - let user_id = db_manager - .user_id_for_token(&token) - .map_err(warp::reject::custom) - .await?; db_manager .can_edit_owners(user_id, &name) .map_err(warp::reject::custom) diff --git a/src/get.rs b/src/get.rs index df833a7..1bd8611 100644 --- a/src/get.rs +++ b/src/get.rs @@ -30,10 +30,15 @@ pub fn apis( dl_dir_path: Arc, path: Vec, ) -> impl Filter + Clone { - download(dl_dir_path, path) + let routes = download(dl_dir_path, path) .or(owners(db_manager.clone())) .or(me()) - .or(search(db_manager)) + .or(search(db_manager)); + + #[cfg(feature = "auth-required")] + let routes = authorization_header_filter(db_manager).and(routes); + + routes } #[cfg(feature = "crates-io-mirroring")] @@ -45,11 +50,16 @@ pub fn apis( cache_dir_path: Arc, path: Vec, ) -> impl Filter + Clone { - download(dl_dir_path, path) + let routes = download(dl_dir_path, path) .or(download_crates_io(http_client, cache_dir_path)) .or(owners(db_manager.clone())) .or(me()) - .or(search(db_manager)) + .or(search(db_manager.clone())); + + #[cfg(feature = "auth-required")] + let routes = authorization_header_filter(db_manager).and(routes); + + routes } #[tracing::instrument(skip(path))] diff --git a/src/put.rs b/src/put.rs index c88d38e..0446741 100644 --- a/src/put.rs +++ b/src/put.rs @@ -3,8 +3,8 @@ use crate::error::Error; use crate::index_manager::IndexManager; use crate::models::{Metadata, Owners}; use crate::utils::{ - authorization_header, empty_json_message, ok_json_message, ok_with_msg_json_message, - with_db_manager, with_dl_dir_path, with_index_manager, + empty_json_message, ok_json_message, ok_with_msg_json_message, with_db_manager, + with_dl_dir_path, with_index_manager, with_user_id_from_authorization_header, }; use bytes::Bytes; use futures::TryFutureExt; @@ -34,30 +34,25 @@ fn new( dl_dir_path: Arc, ) -> impl Filter + Clone { warp::put() - .and(with_db_manager(db_manager)) + .and(with_db_manager(db_manager.clone())) .and(with_index_manager(index_manager)) - .and(authorization_header()) + .and(with_user_id_from_authorization_header(db_manager)) .and(with_dl_dir_path(dl_dir_path)) .and(warp::path!("api" / "v1" / "crates" / "new")) .and(warp::body::bytes()) .and_then(handle_new) } -#[tracing::instrument(skip(db_manager, index_manager, token, dl_dir_path, body))] +#[tracing::instrument(skip(db_manager, index_manager, user_id, dl_dir_path, body))] async fn handle_new( db_manager: Arc>, index_manager: Arc, - token: String, + user_id: u32, dl_dir_path: Arc, body: Bytes, ) -> Result { let db_manager = db_manager.write().await; - let user_id = db_manager - .user_id_for_token(&token) - .map_err(warp::reject::custom) - .await?; - tracing::debug!("user_id: {}", user_id); // body length must be greater than or equals to 4 bytes. @@ -130,30 +125,25 @@ fn unyank( index_manager: Arc, ) -> impl Filter + Clone { warp::put() - .and(with_db_manager(db_manager)) + .and(with_db_manager(db_manager.clone())) .and(with_index_manager(index_manager)) - .and(authorization_header()) + .and(with_user_id_from_authorization_header(db_manager)) .and(warp::path!( "api" / "v1" / "crates" / String / Version / "unyank" )) .and_then(handle_unyank) } -#[tracing::instrument(skip(db_manager, index_manager, token, crate_name, version))] +#[tracing::instrument(skip(db_manager, index_manager, user_id, crate_name, version))] async fn handle_unyank( db_manager: Arc>, index_manager: Arc, - token: String, + user_id: u32, crate_name: String, version: Version, ) -> Result { let db_manager = db_manager.write().await; - let user_id = db_manager - .user_id_for_token(&token) - .map_err(warp::reject::custom) - .await?; - let crate_name_cloned = crate_name.clone(); db_manager .can_edit_package(user_id, &crate_name, version.clone()) @@ -184,17 +174,17 @@ fn owners( db_manager: Arc>, ) -> impl Filter + Clone { warp::put() - .and(with_db_manager(db_manager)) - .and(authorization_header()) + .and(with_db_manager(db_manager.clone())) + .and(with_user_id_from_authorization_header(db_manager)) .and(warp::path!("api" / "v1" / "crates" / String / "owners")) .and(warp::body::json::()) .and_then(handle_owners) } -#[tracing::instrument(skip(db_manager, token, name, owners))] +#[tracing::instrument(skip(db_manager, user_id, name, owners))] async fn handle_owners( db_manager: Arc>, - token: String, + user_id: u32, name: String, owners: Owners, ) -> Result { @@ -204,10 +194,6 @@ async fn handle_owners( let db_manager = db_manager.write().await; - let user_id = db_manager - .user_id_for_token(&token) - .map_err(warp::reject::custom) - .await?; db_manager .can_edit_owners(user_id, &name) .map_err(warp::reject::custom) diff --git a/src/utils.rs b/src/utils.rs index 973b4a6..d1d051d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -111,6 +111,50 @@ pub fn authorization_header() -> impl Filter("Authorization") } +#[tracing::instrument(skip(db_manager))] +pub fn with_user_id_from_authorization_header( + db_manager: Arc>, +) -> impl Filter + Clone { + authorization_header() + .and(with_db_manager(db_manager)) + .and_then(get_user_id_with_token) +} + +#[tracing::instrument(skip(db_manager))] +pub fn authorization_header_filter( + db_manager: Arc>, +) -> impl Filter + Clone { + authorization_header() + .and(with_db_manager(db_manager)) + .and_then(authorize_token) + .and(warp::any()) + .untuple_one() +} + +async fn authorize_token( + token: String, + db_manager: Arc>, +) -> Result<(), Rejection> { + let _user_id = db_manager + .read() + .await + .user_id_for_token(&token) + .map_err(|_| Error::InvalidToken(token.clone())) + .await?; + Ok(()) +} + +async fn get_user_id_with_token( + token: String, + db_manager: Arc>, +) -> Result { + let lock = db_manager.read().await; + Ok(lock + .user_id_for_token(&token) + .map_err(|_| Error::InvalidToken(token.clone())) + .await?) +} + #[cfg(test)] mod tests { use super::package_dir_path;