Implement webfinger

This commit is contained in:
Evie Viau 2023-07-25 06:20:37 -04:00
parent 25f299986b
commit cb53a719eb
Signed by: evie
GPG key ID: 928652CDFCEC8099

View file

@ -2,9 +2,12 @@ use std::collections::HashMap;
use axum::{Extension, Json};
use axum::extract::Query;
use axum::http::StatusCode;
use axum::response::IntoResponse;
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use slop_common::db::entities::prelude::User;
use slop_common::db::entities::user;
use slop_common::db::get_config;
use slop_common::SlopState;
@ -14,22 +17,25 @@ pub struct WebfingerQuery {
pub resource: String,
}
#[skip_serializing_none]
#[derive(Serialize)]
pub struct WebfingerRes {
pub struct Webfinger {
pub subject: String,
pub aliases: Option<Vec<String>>,
pub aliases: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub properties: Option<HashMap<String, String>>,
pub links: Option<Vec<Link>>,
pub links: Vec<Link>,
}
#[skip_serializing_none]
#[derive(Serialize)]
pub struct Link {
pub rel: String,
pub kind: Option<String>,
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub mime: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub href: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub titles: Option<HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub properties: Option<HashMap<String, String>>,
}
@ -39,18 +45,51 @@ pub async fn webfinger(
) -> impl IntoResponse {
let config = get_config(&state.conn).await;
Json(WebfingerRes {
if !query.resource.starts_with("acct:") {
return (StatusCode::BAD_REQUEST, "Unrecognized prefix").into_response()
}
let subject: String = query.resource.chars().skip(5).collect();
let subject: Vec<&str> = subject.splitn(2, "@").collect();
if subject[1] != config.domain {
return (StatusCode::NOT_FOUND, "Incorrect domain").into_response()
}
let user: Option<user::Model> = User::find()
.filter(user::Column::Username.eq(subject[0]))
.one(&state.conn)
.await
.expect("Failed to access database!");
if user.is_none() {
return (StatusCode::NOT_FOUND, "User not found").into_response()
}
let user = user.unwrap();
Json(Webfinger {
subject: query.resource,
aliases: Some(vec![format!("https://{}/users/b", config.domain)]),
aliases: vec![
format!("https://{}/@{}", config.domain, user.username),
format!("https://{}/users/{}", config.domain, user.id)
],
properties: None,
links: Some(vec![
links: vec![
Link {
rel: "self".to_string(),
kind: Some(String::from("application/activity+json")),
href: Some(format!("https://{}/users/b", config.domain)),
rel: String::from("self"),
mime: Some(String::from("application/activity+json")),
href: Some(format!("https://{}/users/{}", config.domain, user.id)),
titles: None,
properties: None,
},
Link {
rel: String::from("http://webfinger.net/rel/profile-page"),
mime: Some(String::from("text/html")),
href: Some(format!("https://{}/@{}", config.domain, user.username)),
titles: None,
properties: None,
}
]),
})
],
}).into_response()
}