diff --git a/src/app.rs b/src/app.rs index 871e6e27..ab9a2066 100644 --- a/src/app.rs +++ b/src/app.rs @@ -130,6 +130,7 @@ pub async fn run(configuration: Configuration, api_version: &Version) -> Running let profile_service = Arc::new(user::ProfileService::new( configuration.clone(), user_authentication_repository.clone(), + authorization_service.clone(), )); let ban_service = Arc::new(user::BanService::new( user_profile_repository.clone(), diff --git a/src/services/authorization.rs b/src/services/authorization.rs index 5d5c8bc7..7448cafd 100644 --- a/src/services/authorization.rs +++ b/src/services/authorization.rs @@ -50,6 +50,7 @@ pub enum ACTION { GetCanonicalInfoHash, GenerateTorrentInfoListing, GetTorrentInfo, + ChangePassword, } pub struct Service { @@ -194,6 +195,7 @@ impl CasbinConfiguration { admin, GetCanonicalInfoHash admin, GenerateTorrentInfoListing admin, GetTorrentInfo + admin, ChangePassword registered, GetCategories registered, GetImageByUrl registered, GetPublicSettings @@ -203,6 +205,7 @@ impl CasbinConfiguration { registered, GetCanonicalInfoHash registered, GenerateTorrentInfoListing registered, GetTorrentInfo + registered, ChangePassword guest, GetCategories guest, GetTags guest, GetAboutPage diff --git a/src/services/user.rs b/src/services/user.rs index 503d8b38..356cc164 100644 --- a/src/services/user.rs +++ b/src/services/user.rs @@ -200,14 +200,20 @@ impl RegistrationService { pub struct ProfileService { configuration: Arc, user_authentication_repository: Arc, + authorization_service: Arc, } impl ProfileService { #[must_use] - pub fn new(configuration: Arc, user_repository: Arc) -> Self { + pub fn new( + configuration: Arc, + user_repository: Arc, + authorization_service: Arc, + ) -> Self { Self { configuration, user_authentication_repository: user_repository, + authorization_service, } } @@ -223,7 +229,16 @@ impl ProfileService { /// * `ServiceError::PasswordTooLong` if the supplied password is too long. /// * An error if unable to successfully hash the password. /// * An error if unable to change the password in the database. - pub async fn change_password(&self, user_id: UserId, change_password_form: &ChangePasswordForm) -> Result<(), ServiceError> { + pub async fn change_password( + &self, + user_id: UserId, + change_password_form: &ChangePasswordForm, + maybe_user_id: Option, + ) -> Result<(), ServiceError> { + self.authorization_service + .authorize(ACTION::ChangePassword, maybe_user_id) + .await?; + info!("changing user password for user ID: {user_id}"); let settings = self.configuration.settings.read().await; diff --git a/src/web/api/server/v1/contexts/user/handlers.rs b/src/web/api/server/v1/contexts/user/handlers.rs index 54b3f229..440c598d 100644 --- a/src/web/api/server/v1/contexts/user/handlers.rs +++ b/src/web/api/server/v1/contexts/user/handlers.rs @@ -10,6 +10,7 @@ use serde::Deserialize; use super::forms::{ChangePasswordForm, JsonWebToken, LoginForm, RegistrationForm}; use super::responses::{self}; use crate::common::AppData; +use crate::web::api::server::v1::extractors::optional_user_id::ExtractOptionalLoggedInUser; use crate::web::api::server::v1::extractors::user_id::ExtractLoggedInUser; use crate::web::api::server::v1::responses::OkResponseData; @@ -133,10 +134,15 @@ pub async fn renew_token_handler( #[allow(clippy::unused_async)] pub async fn change_password_handler( State(app_data): State>, + ExtractOptionalLoggedInUser(maybe_user_id): ExtractOptionalLoggedInUser, ExtractLoggedInUser(user_id): ExtractLoggedInUser, extract::Json(change_password_form): extract::Json, ) -> Response { - match app_data.profile_service.change_password(user_id, &change_password_form).await { + match app_data + .profile_service + .change_password(user_id, &change_password_form, maybe_user_id) + .await + { Ok(()) => Json(OkResponseData { data: format!("Password changed for user with ID: {user_id}"), })