1
Fork 0

Create webfinger crate #5

Merged
steffo merged 53 commits from feature/webfinger into main 2024-11-16 06:33:06 +00:00
3 changed files with 125 additions and 4 deletions
Showing only changes of commit 065fa9c80e - Show all commits

View file

@ -5,6 +5,7 @@ edition = "2021"
[dependencies] [dependencies]
acrate-core = { path = "../acrate-core" } acrate-core = { path = "../acrate-core" }
acrate-hostmeta = { path = "../acrate-hostmeta" }
anyhow = "1.0.93" anyhow = "1.0.93"
axum = { version = "0.7.7", features = ["macros"] } axum = { version = "0.7.7", features = ["macros"] }
axum-extra = { version = "0.9.4", features = ["query"] } axum-extra = { version = "0.9.4", features = ["query"] }

View file

@ -1,3 +1,4 @@
micronfig::config!( micronfig::config!(
ACRATE_WEBFINGER_DATABASE_URL: String,
ACRATE_WEBFINGER_BIND_ADDRESS: String, ACRATE_WEBFINGER_BIND_ADDRESS: String,
); );

View file

@ -1,6 +1,11 @@
use axum::http::StatusCode; use axum::body::Body;
use axum::http::{HeaderMap, HeaderValue, StatusCode};
use axum_extra::extract::Query; use axum_extra::extract::Query;
use serde::Deserialize; use serde::Deserialize;
use acrate_core::diesel_async::{AsyncConnection, AsyncPgConnection};
use acrate_hostmeta::jrd::ResourceDescriptorLinkJRD;
use acrate_hostmeta::xrd::{ResourceDescriptorLinkXRD, ResourceDescriptorPropertyXRD};
use crate::config;
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct WebfingerQuery { pub struct WebfingerQuery {
@ -10,13 +15,127 @@ pub struct WebfingerQuery {
pub rel: Vec<String>, pub rel: Vec<String>,
} }
const WEBFINGER_DOC: &str = "/.well-known/webfinger";
#[axum::debug_handler] #[axum::debug_handler]
pub async fn webfinger_handler( pub async fn webfinger_handler(
Query(WebfingerQuery {resource, rel}): Query<WebfingerQuery> Query(WebfingerQuery {resource, rel}): Query<WebfingerQuery>,
) -> StatusCode { headers: HeaderMap,
) -> Result<(Body, HeaderMap), StatusCode> {
log::info!("Handling a WebFinger request!"); log::info!("Handling a WebFinger request!");
log::debug!("Resource is: {resource:#?}"); log::debug!("Resource is: {resource:#?}");
log::debug!("Rel is: {rel:#?}"); log::debug!("Rel is: {rel:#?}");
StatusCode::NO_CONTENT let accept = headers.get("Accept")
.map(|v| v.to_str())
.filter(Result::is_ok)
.map(|v| v.unwrap())
.unwrap_or("application/json")
.to_string();
log::debug!("Accept is: {accept:#?}");
let mut response_headers = HeaderMap::new();
let mut conn = AsyncPgConnection::establish(config::ACRATE_WEBFINGER_DATABASE_URL())
.await
.map_err(|_| StatusCode::BAD_GATEWAY)?;
let aliases = acrate_core::meta::MetaAlias::query_matching(&mut conn, WEBFINGER_DOC, &resource)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let properties = acrate_core::meta::MetaProperty::query_matching(&mut conn, WEBFINGER_DOC, &resource)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let links = acrate_core::meta::MetaLink::query_matching(&mut conn, WEBFINGER_DOC, &resource)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
for mime in accept.split(", ") {
response_headers.insert("Content-Type", mime.parse().unwrap());
match mime {
"application/json" | "application/jrd+json" => {
let subject = Some(resource);
let aliases = aliases
.into_iter()
.map(|alias| alias.alias)
.collect();
let properties = properties
.into_iter()
.map(|prop| (prop.rel, prop.value))
.collect();
let links = links
.into_iter()
.map(|link| ResourceDescriptorLinkJRD {
rel: link.rel,
r#type: link.r#type,
href: link.href,
titles: Default::default(), // TODO: Titles
properties: Default::default(), // TODO: Link properties
template: None, // TODO: Template
})
.collect::<Vec<ResourceDescriptorLinkJRD>>();
let rd = acrate_hostmeta::jrd::ResourceDescriptorJRD {
subject,
aliases,
properties,
links,
};
let body = rd.
return Ok(rd, response_headers)
},
"application/xml" | "application/xrd+xml" => {
let subject = Some(resource);
let aliases = aliases
.into_iter()
.map(|alias| alias.alias)
.collect();
let properties = properties
.into_iter()
.map(|prop| ResourceDescriptorPropertyXRD {
r#type: prop.rel, // TODO: Ah si chiama type?
value: prop.value,
})
.collect();
let links = links
.into_iter()
.map(|link| ResourceDescriptorLinkXRD {
rel: link.rel,
r#type: link.r#type,
href: link.href,
titles: Default::default(), // TODO: Titles
properties: Default::default(), // TODO: Link properties
template: None, // TODO: Template
})
.collect::<Vec<ResourceDescriptorLinkXRD>>();
let rd = acrate_hostmeta::xrd::ResourceDescriptorXRD {
subject,
aliases,
properties,
links,
};
return Ok(StatusCode::OK)
},
_ => {
continue;
}
}
}
Err(StatusCode::NOT_ACCEPTABLE)
} }