setpassword endpoint, misc

This commit is contained in:
2026-03-01 00:31:15 +01:00
parent c8d15f8c6b
commit b2a80ffa58
4 changed files with 34 additions and 6 deletions

View File

@@ -23,6 +23,7 @@ pub fn api_router() -> Router {
.route("/api/users/me", get(users::get_me)) .route("/api/users/me", get(users::get_me))
.route("/api/users/{id}", get(users::get_by_id)) .route("/api/users/{id}", get(users::get_by_id))
.route("/api/users/@{handle}", get(users::get_by_handle)) .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}", get(sessions::get_by_id))
.route("/api/sessions/{id}/revoke", post(sessions::revoke_by_id)) .route("/api/sessions/{id}/revoke", post(sessions::revoke_by_id))
.route("/api/tags/{id}", get(tags::get_by_id)) .route("/api/tags/{id}", get(tags::get_by_id))

View File

@@ -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( pub async fn get_by_id(
Path(id): Path<Uuid>, Path(id): Path<Uuid>,
headers: HeaderMap, headers: HeaderMap,
@@ -48,11 +50,7 @@ pub async fn revoke_by_id(
Ok(Json(s).into_response()) Ok(Json(s).into_response())
} }
false => match u.has_permission(Permission::ListOthersSessions)? { false => match u.has_permission(Permission::ListOthersSessions)? {
true => Ok(( true => Ok((StatusCode::FORBIDDEN, CANT_REVOKE).into_response()),
StatusCode::FORBIDDEN,
"You don't have permission to revoke this session.",
)
.into_response()),
false => Err(SessionError::NoSessionWithId(id))?, false => Err(SessionError::NoSessionWithId(id))?,
}, },
} }

View File

@@ -1,9 +1,10 @@
use axum::{ use axum::{
Json, Json,
extract::Path, extract::Path,
http::HeaderMap, http::{HeaderMap, StatusCode},
response::{IntoResponse, Response}, response::{IntoResponse, Response},
}; };
use serde::Deserialize;
use uuid::Uuid; use uuid::Uuid;
use crate::{ use crate::{
@@ -12,9 +13,13 @@ use crate::{
User, User,
auth::{UserAuthRequired, UserAuthenticate}, auth::{UserAuthRequired, UserAuthenticate},
handle::UserHandle, 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<Response, CompositeError> { pub async fn get_me(headers: HeaderMap) -> Result<Response, CompositeError> {
Ok(Json(User::authenticate(&headers)?.required()?).into_response()) Ok(Json(User::authenticate(&headers)?.required()?).into_response())
} }
@@ -34,3 +39,25 @@ pub async fn get_by_handle(
User::authenticate(&headers)?.required()?; User::authenticate(&headers)?.required()?;
Ok(Json(User::get_by_handle(handle)?).into_response()) Ok(Json(User::get_by_handle(handle)?).into_response())
} }
#[derive(Deserialize)]
pub struct ChangePasswordForm {
password: String,
}
pub async fn change_password(
Path(id): Path<Uuid>,
headers: HeaderMap,
Json(form): Json<ChangePasswordForm>,
) -> Result<Response, CompositeError> {
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())
}

View File

@@ -6,6 +6,8 @@ pub enum Permission {
ListOthersSessions, ListOthersSessions,
// All Users have the right to revoke their own sessions // All Users have the right to revoke their own sessions
RevokeOthersSessions, RevokeOthersSessions,
// All Users have the right to change their own password
ChangeOthersPasswords,
} }
impl User { impl User {