tirocinio-canali-steffo-acrate/acrate-webfinger/src/route.rs

213 lines
5.4 KiB
Rust
Raw Normal View History

use axum::http::{HeaderMap, Response, StatusCode};
use axum_extra::extract::Query;
use serde::Deserialize;
use acrate_core::diesel::GroupedBy;
2024-11-15 05:50:51 +00:00
use acrate_core::diesel_async::{AsyncConnection, AsyncPgConnection};
use acrate_core::meta::{MetaAlias, MetaLink, MetaLinkProperty, MetaLinkTitle, MetaProperty};
2024-11-15 05:50:51 +00:00
use acrate_hostmeta::jrd::ResourceDescriptorLinkJRD;
use acrate_hostmeta::xrd::{ResourceDescriptorLinkXRD, ResourceDescriptorPropertyXRD, ResourceDescriptorTitleXRD};
2024-11-15 05:50:51 +00:00
use crate::config;
#[derive(Debug, Clone, Deserialize)]
pub struct WebfingerQuery {
pub resource: Option<String>,
#[serde(default)]
pub rel: Vec<String>,
}
2024-11-15 05:50:51 +00:00
const WEBFINGER_DOC: &str = "/.well-known/webfinger";
2024-11-14 03:16:12 +00:00
#[axum::debug_handler]
pub async fn webfinger_handler(
2024-11-15 05:50:51 +00:00
Query(WebfingerQuery {resource, rel}): Query<WebfingerQuery>,
headers: HeaderMap,
) -> Result<Response<String>, StatusCode> {
2024-11-14 03:16:12 +00:00
log::info!("Handling a WebFinger request!");
2024-11-15 05:50:51 +00:00
let resource = resource.unwrap_or_else(|| "".to_string());
2024-11-14 03:16:12 +00:00
log::debug!("Resource is: {resource:#?}");
2024-11-15 05:50:51 +00:00
2024-11-14 03:16:12 +00:00
log::debug!("Rel is: {rel:#?}");
2024-11-15 05:50:51 +00:00
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 = Response::new("".to_string());
2024-11-15 05:50:51 +00:00
let mut conn = AsyncPgConnection::establish(config::ACRATE_WEBFINGER_DATABASE_URL())
.await
.map_err(|_| StatusCode::BAD_GATEWAY)?;
let aliases = MetaAlias::query_matching(&mut conn, WEBFINGER_DOC, &resource)
2024-11-15 05:50:51 +00:00
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let properties = MetaProperty::query_matching(&mut conn, WEBFINGER_DOC, &resource)
2024-11-15 05:50:51 +00:00
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let links = MetaLink::query_matching(&mut conn, WEBFINGER_DOC, &resource)
2024-11-15 05:50:51 +00:00
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let link_properties = MetaLinkProperty::query_by_link(&mut conn, &links)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
.grouped_by(&links);
let link_titles = MetaLinkTitle::query_by_link(&mut conn, &links)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
.grouped_by(&links);
let links_full: Vec<(MetaLink, Vec<MetaLinkProperty>, Vec<MetaLinkTitle>)> = links
.into_iter()
.zip(link_properties)
.zip(link_titles)
.map(|((link, properties), titles)| (link, properties, titles))
.collect();
{
let headers = response.headers_mut();
headers.insert(
"Access-Control-Allow-Origin",
"*".parse().unwrap()
);
}
for mime in accept.split(",") {
{
let headers = response.headers_mut();
headers.insert(
"Content-Type",
mime.parse().map_err(|_| StatusCode::BAD_REQUEST)?
);
}
let (mime, _params) = match mime.trim().split_once(";") {
Some((mime, params)) => (mime, Some(params)),
None => (mime, None),
};
2024-11-15 05:50:51 +00:00
match mime {
"*/*" | "application/json" | "application/jrd+json" => {
2024-11-15 05:50:51 +00:00
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_full
2024-11-15 05:50:51 +00:00
.into_iter()
.map(|(link, properties, titles)| ResourceDescriptorLinkJRD {
2024-11-15 05:50:51 +00:00
rel: link.rel,
2024-11-16 00:35:30 +00:00
r#type: link.type_,
2024-11-15 05:50:51 +00:00
href: link.href,
template: link.template,
properties: properties
.into_iter()
.map(|property| (property.rel, property.value))
.collect(),
titles: titles
.into_iter()
.map(|title| (title.language, title.value))
.collect(),
2024-11-15 05:50:51 +00:00
})
.collect::<Vec<ResourceDescriptorLinkJRD>>();
let rd = acrate_hostmeta::jrd::ResourceDescriptorJRD {
subject,
aliases,
properties,
links,
};
let json = serde_json::to_string_pretty(&rd)
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
2024-11-15 05:50:51 +00:00
{
let body = response.body_mut();
body.push_str(&json);
}
return Ok(response)
2024-11-15 05:50:51 +00:00
},
"application/xml" | "application/xrd+xml" => {
let subject = Some(resource);
let aliases = aliases
.into_iter()
.map(|alias| alias.alias)
.collect();
let properties: Vec<ResourceDescriptorPropertyXRD> = properties
2024-11-15 05:50:51 +00:00
.into_iter()
.map(|prop| ResourceDescriptorPropertyXRD {
rel: prop.rel,
2024-11-15 05:50:51 +00:00
value: prop.value,
})
.collect();
let links = links_full
2024-11-15 05:50:51 +00:00
.into_iter()
.map(|(link, properties, titles)| ResourceDescriptorLinkXRD {
2024-11-15 05:50:51 +00:00
rel: link.rel,
2024-11-16 00:35:30 +00:00
r#type: link.type_,
2024-11-15 05:50:51 +00:00
href: link.href,
template: link.template,
properties: properties
.into_iter()
.map(|property| ResourceDescriptorPropertyXRD {
rel: property.rel,
value: property.value,
})
.collect(),
titles: titles
.into_iter()
.map(|title| ResourceDescriptorTitleXRD {
language: title.language,
value: title.value,
})
.collect(),
2024-11-15 05:50:51 +00:00
})
.collect::<Vec<ResourceDescriptorLinkXRD>>();
let rd = acrate_hostmeta::xrd::ResourceDescriptorXRD {
subject,
aliases,
properties,
links,
};
let xml = quick_xml::se::to_string(&rd)
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
{
let body = response.body_mut();
body.push_str("<?xml version='1.0' encoding='UTF-8'?>");
body.push_str(&xml);
}
return Ok(response)
2024-11-15 05:50:51 +00:00
},
_ => {
continue;
}
}
}
Err(StatusCode::NOT_ACCEPTABLE)
}