feat: Implement WebFinger discovery and ActivityPub user actor endpoint
- Added a new router for handling well-known endpoints, specifically WebFinger. - Implemented the `webfinger` function to respond to WebFinger queries. - Created a new route for WebFinger in the router. - Refactored user retrieval logic to support both user ID and username in a single endpoint. - Updated user router to use the new `get_user_by_param` function. - Added tests for WebFinger discovery and ActivityPub user actor endpoint. - Updated dependencies in Cargo.toml files to include necessary libraries.
This commit is contained in:
71
thoughts-backend/api/src/routers/well_known.rs
Normal file
71
thoughts-backend/api/src/routers/well_known.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
use app::state::AppState;
|
||||
use axum::{
|
||||
extract::{Query, State},
|
||||
response::{IntoResponse, Json},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct WebFingerQuery {
|
||||
resource: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct WebFingerLink {
|
||||
rel: String,
|
||||
#[serde(rename = "type")]
|
||||
type_: String,
|
||||
href: Url,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct WebFingerResponse {
|
||||
subject: String,
|
||||
links: Vec<WebFingerLink>,
|
||||
}
|
||||
|
||||
pub async fn webfinger(
|
||||
State(state): State<AppState>,
|
||||
Query(query): Query<WebFingerQuery>,
|
||||
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||
if let Some((scheme, account_info)) = query.resource.split_once(':') {
|
||||
if scheme != "acct" {
|
||||
return Err((
|
||||
axum::http::StatusCode::BAD_REQUEST,
|
||||
"Invalid resource scheme",
|
||||
));
|
||||
}
|
||||
|
||||
let account_parts: Vec<&str> = account_info.split('@').collect();
|
||||
let username = account_parts[0];
|
||||
|
||||
let user = match app::persistence::user::get_user_by_username(&state.conn, username).await {
|
||||
Ok(Some(user)) => user,
|
||||
_ => return Err((axum::http::StatusCode::NOT_FOUND, "User not found")),
|
||||
};
|
||||
|
||||
let base_url = "http://localhost:3000";
|
||||
let user_url = Url::parse(&format!("{}/users/{}", base_url, user.username)).unwrap();
|
||||
|
||||
let response = WebFingerResponse {
|
||||
subject: query.resource,
|
||||
links: vec![WebFingerLink {
|
||||
rel: "self".to_string(),
|
||||
type_: "application/activity+json".to_string(),
|
||||
href: user_url,
|
||||
}],
|
||||
};
|
||||
|
||||
Ok(Json(response))
|
||||
} else {
|
||||
Err((
|
||||
axum::http::StatusCode::BAD_REQUEST,
|
||||
"Invalid resource format",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_well_known_router() -> axum::Router<AppState> {
|
||||
axum::Router::new().route("/webfinger", axum::routing::get(webfinger))
|
||||
}
|
Reference in New Issue
Block a user