From b2a80ffa580aaf6595fb8854ab3d24f11b628c36 Mon Sep 17 00:00:00 2001 From: jakubmanczak Date: Sun, 1 Mar 2026 00:31:15 +0100 Subject: [PATCH] setpassword endpoint, misc --- src/api/mod.rs | 1 + src/api/sessions.rs | 8 +++----- src/api/users.rs | 29 ++++++++++++++++++++++++++++- src/users/permissions.rs | 2 ++ 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index 0e3126a..dc27492 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -23,6 +23,7 @@ pub fn api_router() -> Router { .route("/api/users/me", get(users::get_me)) .route("/api/users/{id}", get(users::get_by_id)) .route("/api/users/@{handle}", get(users::get_by_handle)) + .route("/api/users/{id}/setpassw", get(users::change_password)) .route("/api/sessions/{id}", get(sessions::get_by_id)) .route("/api/sessions/{id}/revoke", post(sessions::revoke_by_id)) .route("/api/tags/{id}", get(tags::get_by_id)) diff --git a/src/api/sessions.rs b/src/api/sessions.rs index cc1b8f8..b7bf472 100644 --- a/src/api/sessions.rs +++ b/src/api/sessions.rs @@ -16,6 +16,8 @@ use crate::{ }, }; +const CANT_REVOKE: &str = "You don't have permission to change this user's password."; + pub async fn get_by_id( Path(id): Path, headers: HeaderMap, @@ -48,11 +50,7 @@ pub async fn revoke_by_id( Ok(Json(s).into_response()) } false => match u.has_permission(Permission::ListOthersSessions)? { - true => Ok(( - StatusCode::FORBIDDEN, - "You don't have permission to revoke this session.", - ) - .into_response()), + true => Ok((StatusCode::FORBIDDEN, CANT_REVOKE).into_response()), false => Err(SessionError::NoSessionWithId(id))?, }, } diff --git a/src/api/users.rs b/src/api/users.rs index 99f1003..1ae2ebf 100644 --- a/src/api/users.rs +++ b/src/api/users.rs @@ -1,9 +1,10 @@ use axum::{ Json, extract::Path, - http::HeaderMap, + http::{HeaderMap, StatusCode}, response::{IntoResponse, Response}, }; +use serde::Deserialize; use uuid::Uuid; use crate::{ @@ -12,9 +13,13 @@ use crate::{ User, auth::{UserAuthRequired, UserAuthenticate}, handle::UserHandle, + permissions::Permission, }, }; +const CANT_CHANGE_OTHERS_PASSW: &str = "You don't have permission to change this user's password."; +const PASSW_CHANGED_SUCCESS: &str = "Password changed successfully."; + pub async fn get_me(headers: HeaderMap) -> Result { Ok(Json(User::authenticate(&headers)?.required()?).into_response()) } @@ -34,3 +39,25 @@ pub async fn get_by_handle( User::authenticate(&headers)?.required()?; Ok(Json(User::get_by_handle(handle)?).into_response()) } + +#[derive(Deserialize)] +pub struct ChangePasswordForm { + password: String, +} +pub async fn change_password( + Path(id): Path, + headers: HeaderMap, + Json(form): Json, +) -> Result { + let u = User::authenticate(&headers)?.required()?; + let mut target = if u.id == id { + u + } else { + if u.has_permission(Permission::ChangeOthersPasswords)? == false { + return Ok((StatusCode::FORBIDDEN, CANT_CHANGE_OTHERS_PASSW).into_response()); + } + User::get_by_id(id)? + }; + target.set_password(Some(&form.password))?; + Ok(PASSW_CHANGED_SUCCESS.into_response()) +} diff --git a/src/users/permissions.rs b/src/users/permissions.rs index 5b1a6f5..73dc146 100644 --- a/src/users/permissions.rs +++ b/src/users/permissions.rs @@ -6,6 +6,8 @@ pub enum Permission { ListOthersSessions, // All Users have the right to revoke their own sessions RevokeOthersSessions, + // All Users have the right to change their own password + ChangeOthersPasswords, } impl User {