diff options
author | rtkay123 <dev@kanjala.com> | 2025-07-12 17:01:31 +0200 |
---|---|---|
committer | rtkay123 <dev@kanjala.com> | 2025-07-12 17:01:31 +0200 |
commit | 23d86c84e108757951e997d444145b570b72ae62 (patch) | |
tree | fe1f5de75bf69fa9b4ef4eb66d6041350cfc070f | |
parent | a56b12621d9f8c34017995a518e61ef7ee2b0f64 (diff) | |
download | sellershut-23d86c84e108757951e997d444145b570b72ae62.tar.bz2 sellershut-23d86c84e108757951e997d444145b570b72ae62.zip |
feat: webfinger
-rw-r--r-- | contrib/bruno/users/webfinger.bru | 15 | ||||
-rw-r--r-- | src/server/routes/users.rs | 6 | ||||
-rw-r--r-- | src/server/routes/users/get_user.rs | 32 | ||||
-rw-r--r-- | src/server/routes/users/webfinger.rs | 79 |
4 files changed, 125 insertions, 7 deletions
diff --git a/contrib/bruno/users/webfinger.bru b/contrib/bruno/users/webfinger.bru new file mode 100644 index 0000000..14acaab --- /dev/null +++ b/contrib/bruno/users/webfinger.bru @@ -0,0 +1,15 @@ +meta { + name: webfinger + type: http + seq: 2 +} + +get { + url: http://localhost:3000/.well-known/webfinger?resource=acct:sellershut@localhost + body: none + auth: inherit +} + +params:query { + resource: acct:sellershut@localhost +} diff --git a/src/server/routes/users.rs b/src/server/routes/users.rs index ad09c8e..2ef49b2 100644 --- a/src/server/routes/users.rs +++ b/src/server/routes/users.rs @@ -1,6 +1,10 @@ pub mod get_user; +pub mod webfinger; + use axum::{Router, routing::get}; pub fn users_router() -> Router { - Router::new().route("/users/{usernme}", get(get_user::http_get_user)) + Router::new() + .route("/users/{usernme}", get(get_user::http_get_user)) + .route("/.well-known/webfinger", get(webfinger::webfinger)) } diff --git a/src/server/routes/users/get_user.rs b/src/server/routes/users/get_user.rs index 8020923..d86cc26 100644 --- a/src/server/routes/users/get_user.rs +++ b/src/server/routes/users/get_user.rs @@ -10,12 +10,7 @@ pub async fn http_get_user( Path(name): Path<String>, data: Data<AppHandle>, ) -> Result<impl IntoResponse, AppError> { - let read = data.users.read().await; - if let Some(a) = read - .iter() - .find(|value| value.username.eq(&name)) - .map(ToOwned::to_owned) - { + if let Some(a) = read_user(&name, &data).await { let json_user = a.into_json(&data).await?; Ok(( StatusCode::OK, @@ -27,6 +22,13 @@ pub async fn http_get_user( } } +pub async fn read_user(name: &str, data: &Data<AppHandle>) -> Option<crate::entity::user::User> { + let read = data.users.read().await; + read.iter() + .find(|value| value.username.eq(&name)) + .map(ToOwned::to_owned) +} + #[cfg(test)] mod tests { use axum::{ @@ -54,4 +56,22 @@ mod tests { assert_eq!(response.status(), StatusCode::OK); } + + #[tokio::test] + async fn get_user_not_found() { + let state = AppState::new().await.unwrap(); + let app = server::router(state); + + let response = app + .oneshot( + Request::builder() + .uri("/users/selut") + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(response.status(), StatusCode::NOT_FOUND); + } } diff --git a/src/server/routes/users/webfinger.rs b/src/server/routes/users/webfinger.rs new file mode 100644 index 0000000..22975c2 --- /dev/null +++ b/src/server/routes/users/webfinger.rs @@ -0,0 +1,79 @@ +use activitypub_federation::{ + config::Data, + fetch::webfinger::{build_webfinger_response, extract_webfinger_name}, +}; +use axum::{Json, extract::Query, http::StatusCode, response::IntoResponse}; +use serde::Deserialize; + +use crate::{error::AppError, server::routes::users::get_user::read_user, state::AppHandle}; + +#[derive(Deserialize)] +pub struct WebfingerQuery { + resource: String, +} + +pub async fn webfinger( + Query(query): Query<WebfingerQuery>, + data: Data<AppHandle>, +) -> Result<impl IntoResponse, AppError> { + let name = extract_webfinger_name(&query.resource, &data)?; + if let Some(db_user) = read_user(name, &data).await { + Ok(( + StatusCode::OK, + Json(build_webfinger_response( + query.resource, + db_user.ap_id.into_inner(), + )), + ) + .into_response()) + } else { + Ok((StatusCode::NOT_FOUND, "").into_response()) + } +} + +#[cfg(test)] +mod tests { + use axum::{ + body::Body, + http::{Request, StatusCode}, + }; + use tower::ServiceExt; + + use crate::{server, state::AppState}; + + #[tokio::test] + async fn webfinger_ok() { + let state = AppState::new().await.unwrap(); + let app = server::router(state); + + let response = app + .oneshot( + Request::builder() + .uri("/.well-known/webfinger?resource=acct:sellershut@localhost") + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(response.status(), StatusCode::OK); + } + + #[tokio::test] + async fn webfinger_err() { + let state = AppState::new().await.unwrap(); + let app = server::router(state); + + let response = app + .oneshot( + Request::builder() + .uri("/.well-known/webfinger?resource=acct:sst@localhost") + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(response.status(), StatusCode::NOT_FOUND); + } +} |