refactor: move UUID/username routing to application use case — fix handler boundary leak

This commit is contained in:
2026-05-15 03:12:52 +02:00
parent bbf6c97379
commit 6e9b1596d8
2 changed files with 17 additions and 11 deletions

View File

@@ -23,6 +23,21 @@ pub async fn get_user_by_username(
.ok_or(DomainError::NotFound) .ok_or(DomainError::NotFound)
} }
/// Resolve a path segment that is either a UUID (AP actor URL) or a username.
pub async fn get_user_by_id_or_username(
users: &dyn UserRepository,
id_or_username: &str,
) -> Result<User, DomainError> {
if let Ok(uuid) = uuid::Uuid::parse_str(id_or_username) {
users
.find_by_id(&UserId::from_uuid(uuid))
.await?
.ok_or(DomainError::NotFound)
} else {
get_user_by_username(users, id_or_username).await
}
}
pub async fn update_profile( pub async fn update_profile(
users: &dyn UserRepository, users: &dyn UserRepository,
user_id: &UserId, user_id: &UserId,

View File

@@ -9,7 +9,7 @@ use api_types::{
responses::{ErrorResponse, ProfileField, RemoteActorResponse, UserResponse}, responses::{ErrorResponse, ProfileField, RemoteActorResponse, UserResponse},
}; };
use application::use_cases::feed::list_users; use application::use_cases::feed::list_users;
use application::use_cases::profile::{get_user_by_username, update_profile}; use application::use_cases::profile::{get_user_by_id_or_username, update_profile};
use application::use_cases::search::search_users; use application::use_cases::search::search_users;
use axum::{ use axum::{
extract::{Path, Query, State}, extract::{Path, Query, State},
@@ -32,16 +32,7 @@ pub async fn get_user(
OptionalAuthUser(viewer): OptionalAuthUser, OptionalAuthUser(viewer): OptionalAuthUser,
headers: HeaderMap, headers: HeaderMap,
) -> Result<Response, ApiError> { ) -> Result<Response, ApiError> {
// AP actor URLs use the user's UUID (e.g. /users/{uuid}). Fall back to UUID lookup let user = get_user_by_id_or_username(&*s.users, &username).await?;
// so remote servers can fetch the actor JSON for HTTP signature verification.
let user = if let Ok(uuid) = uuid::Uuid::parse_str(&username) {
s.users
.find_by_id(&domain::value_objects::UserId::from_uuid(uuid))
.await?
.ok_or(ApiError::Domain(domain::errors::DomainError::NotFound))?
} else {
get_user_by_username(&*s.users, &username).await?
};
let accept = headers let accept = headers
.get(header::ACCEPT) .get(header::ACCEPT)