Files
k-ap/src/webfinger.rs

70 lines
2.0 KiB
Rust

use activitypub_federation::{config::Data, fetch::webfinger::extract_webfinger_name};
use axum::{
extract::Query,
http::header,
response::{IntoResponse, Response},
};
use serde::{Deserialize, Serialize};
use crate::data::FederationData;
use crate::error::Error;
#[derive(Deserialize)]
pub struct WebfingerQuery {
resource: String,
}
#[derive(Serialize)]
struct WebfingerLink {
rel: String,
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
kind: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
href: Option<String>,
}
#[derive(Serialize)]
struct WebfingerResponse {
subject: String,
/// Canonical URIs for the same account (acct: URI + AP actor URL).
aliases: Vec<String>,
links: Vec<WebfingerLink>,
}
pub async fn webfinger_handler(
Query(query): Query<WebfingerQuery>,
data: Data<FederationData>,
) -> Result<Response, Error> {
let name = extract_webfinger_name(&query.resource, &data)?;
let user = data
.user_repo
.find_by_username(name)
.await
.map_err(Error::from)?
.ok_or_else(|| Error::not_found(anyhow::anyhow!("user not found")))?;
let ap_id = crate::urls::actor_url(&data.base_url, user.id);
let acct_uri = format!("acct:{}@{}", user.username, data.domain);
let wf = WebfingerResponse {
subject: query.resource.clone(),
aliases: vec![acct_uri, ap_id.to_string()],
links: vec![
WebfingerLink {
rel: "http://webfinger.net/rel/profile-page".to_string(),
kind: Some("text/html".to_string()),
href: Some(ap_id.to_string()),
},
WebfingerLink {
rel: "self".to_string(),
kind: Some("application/activity+json".to_string()),
href: Some(ap_id.to_string()),
},
],
};
let body = serde_json::to_string(&wf).map_err(|e| Error::from(anyhow::anyhow!(e)))?;
Ok(([(header::CONTENT_TYPE, "application/jrd+json")], body).into_response())
}