diff --git a/acrate-webfinger/Cargo.toml b/acrate-webfinger/Cargo.toml index fa9296b..f74ff6b 100644 --- a/acrate-webfinger/Cargo.toml +++ b/acrate-webfinger/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] acrate-core = { path = "../acrate-core" } +acrate-hostmeta = { path = "../acrate-hostmeta" } anyhow = "1.0.93" axum = { version = "0.7.7", features = ["macros"] } axum-extra = { version = "0.9.4", features = ["query"] } diff --git a/acrate-webfinger/src/config.rs b/acrate-webfinger/src/config.rs index 535a5c4..feb7905 100644 --- a/acrate-webfinger/src/config.rs +++ b/acrate-webfinger/src/config.rs @@ -1,3 +1,4 @@ micronfig::config!( + ACRATE_WEBFINGER_DATABASE_URL: String, ACRATE_WEBFINGER_BIND_ADDRESS: String, ); diff --git a/acrate-webfinger/src/route.rs b/acrate-webfinger/src/route.rs index 47aac61..dc98106 100644 --- a/acrate-webfinger/src/route.rs +++ b/acrate-webfinger/src/route.rs @@ -1,6 +1,11 @@ -use axum::http::StatusCode; +use axum::body::Body; +use axum::http::{HeaderMap, HeaderValue, StatusCode}; use axum_extra::extract::Query; 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)] pub struct WebfingerQuery { @@ -10,13 +15,127 @@ pub struct WebfingerQuery { pub rel: Vec, } +const WEBFINGER_DOC: &str = "/.well-known/webfinger"; + #[axum::debug_handler] pub async fn webfinger_handler( - Query(WebfingerQuery {resource, rel}): Query -) -> StatusCode { + Query(WebfingerQuery {resource, rel}): Query, + headers: HeaderMap, +) -> Result<(Body, HeaderMap), StatusCode> { log::info!("Handling a WebFinger request!"); + log::debug!("Resource is: {resource:#?}"); + 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::>(); + + 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::>(); + + let rd = acrate_hostmeta::xrd::ResourceDescriptorXRD { + subject, + aliases, + properties, + links, + }; + + return Ok(StatusCode::OK) + }, + _ => { + continue; + } + } + } + + Err(StatusCode::NOT_ACCEPTABLE) }