Create webfinger
crate #5
3 changed files with 125 additions and 4 deletions
|
@ -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"] }
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
micronfig::config!(
|
||||
ACRATE_WEBFINGER_DATABASE_URL: String,
|
||||
ACRATE_WEBFINGER_BIND_ADDRESS: String,
|
||||
);
|
||||
|
|
|
@ -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<String>,
|
||||
}
|
||||
|
||||
const WEBFINGER_DOC: &str = "/.well-known/webfinger";
|
||||
|
||||
#[axum::debug_handler]
|
||||
pub async fn webfinger_handler(
|
||||
Query(WebfingerQuery {resource, rel}): Query<WebfingerQuery>
|
||||
) -> StatusCode {
|
||||
Query(WebfingerQuery {resource, rel}): Query<WebfingerQuery>,
|
||||
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::<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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue