feat: AP webfinger

This commit is contained in:
aprilthepink 2024-07-17 02:08:39 +02:00
parent f22cae919f
commit b1c78822de
6 changed files with 88 additions and 25 deletions

11
Cargo.lock generated
View file

@ -2091,6 +2091,7 @@ dependencies = [
"url",
"uuid",
"vcpkg",
"webfinger",
]
[[package]]
@ -4173,6 +4174,16 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "webfinger"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f395336b42f1be22490390830ccfe7a735725eef086cd0574bf8759408ecb3af"
dependencies = [
"reqwest 0.11.27",
"serde",
]
[[package]]
name = "webpki-roots"
version = "0.25.4"

View file

@ -34,6 +34,7 @@ serde_derive = "1.0.201"
dotenv = "0.15.0"
async-recursion = "1.1.1"
base64-url = "3.0.0"
webfinger = "0.5.1"
[dependencies.sea-orm]
version = "0.12.0"

View file

@ -2,8 +2,13 @@ use crate::{
database::StateHandle,
entities::user,
error::Error,
lysand::{self, conversion::receive_lysand_note},
lysand::{
self,
conversion::{db_user_from_url, receive_lysand_note},
},
objects::person::{DbUser, PersonAcceptedActivities},
utils::generate_user_id,
API_DOMAIN, LYSAND_DOMAIN,
};
use activitypub_federation::{
actix_web::{inbox::receive_activity, signing_actor},
@ -18,6 +23,7 @@ use anyhow::anyhow;
use serde::Deserialize;
use tracing::info;
use url::Url;
use webfinger::resolve;
pub fn listen(config: &FederationConfig<StateHandle>) -> Result<(), Error> {
let hostname = config.domain();
@ -101,9 +107,18 @@ pub async fn webfinger(
data: Data<StateHandle>,
) -> Result<HttpResponse, Error> {
let name = extract_webfinger_name(&query.resource, &data)?;
let db_user = data.read_user(name).await?;
let db_user = data.read_user(name.clone()).await;
let user;
if db_user.is_ok() {
user = db_user.unwrap();
} else {
let res = resolve("acct:".to_string() + name + "@" + &LYSAND_DOMAIN, true)
.await
.unwrap();
user = db_user_from_url(Url::parse(&res.subject)?).await?;
}
Ok(HttpResponse::Ok().json(build_webfinger_response(
query.resource.clone(),
Url::parse(&db_user.id)?,
generate_user_id(&API_DOMAIN, &user.id)?,
)))
}

View file

@ -1,6 +1,6 @@
use activitypub_federation::{
fetch::{object_id::ObjectId, webfinger::webfinger_resolve_actor},
protocol::context::WithContext,
protocol::{context::WithContext, public_key::PublicKey},
traits::Object,
FEDERATION_CONTENT_TYPE,
};
@ -18,8 +18,8 @@ use crate::{
error,
lysand::conversion::{lysand_post_from_db, lysand_user_from_db},
objects,
utils::{base_url_decode, generate_create_id},
Response, DB, FEDERATION_CONFIG,
utils::{base_url_decode, generate_create_id, generate_user_id},
Response, API_DOMAIN, DB, FEDERATION_CONFIG,
};
#[derive(serde::Deserialize)]
@ -117,6 +117,41 @@ async fn fetch_post(
.json(crate::objects::post::Note::from_db(&post)))
}
#[get("/apbridge/user/{user}")]
async fn fetch_user(
path: web::Path<String>,
state: web::Data<State>,
) -> actix_web::Result<HttpResponse, error::Error> {
let db = DB.get().unwrap();
let user = prelude::User::find()
.filter(post::Column::Id.eq(path.as_str()))
.one(db)
.await?;
let user = match user {
Some(user) => user,
None => return Ok(HttpResponse::NotFound().finish()),
};
Ok(HttpResponse::Ok()
.content_type(FEDERATION_CONTENT_TYPE)
.json(crate::objects::person::Person {
kind: Default::default(),
id: generate_user_id(&API_DOMAIN, &user.id)?.into(),
preferred_username: user.username.clone(),
name: user.name.clone(),
summary: user.summary.clone(),
url: Url::parse(user.url.as_str()).unwrap(),
inbox: Url::parse(user.inbox.as_str()).unwrap(),
public_key: PublicKey {
owner: Url::parse(user.url.as_str()).unwrap(),
public_key_pem: user.public_key,
id: format!("{}#main-key", Url::parse(user.url.as_str()).unwrap()),
},
}))
}
#[get("/apbridge/lysand/object/{post}")]
async fn fetch_lysand_post(
path: web::Path<String>,

View file

@ -15,7 +15,7 @@ use clap::Parser;
use database::Database;
use entities::post;
use http::{http_get_user, http_post_user_inbox, webfinger};
use lysand::http::{create_activity, fetch_lysand_post, fetch_post, query_post};
use lysand::http::{create_activity, fetch_lysand_post, fetch_post, fetch_user, query_post};
use objects::person::DbUser;
use sea_orm::{ActiveModelTrait, DatabaseConnection, Set};
use serde::{Deserialize, Serialize};
@ -259,6 +259,7 @@ async fn main() -> actix_web::Result<(), anyhow::Error> {
.route("/.well-known/webfinger", web::get().to(webfinger))
.service(index)
.service(fetch_post)
.service(fetch_user)
.service(create_activity)
.service(query_post)
.service(fetch_lysand_post)

View file

@ -71,14 +71,14 @@ impl DbUser {
#[serde(rename_all = "camelCase")]
pub struct Person {
#[serde(rename = "type")]
kind: PersonType,
preferred_username: String,
name: String,
summary: Option<String>,
url: Url,
id: ObjectId<user::Model>,
inbox: Url,
public_key: PublicKey,
pub kind: PersonType,
pub preferred_username: String,
pub name: String,
pub summary: Option<String>,
pub url: Url,
pub id: ObjectId<user::Model>,
pub inbox: Url,
pub public_key: PublicKey,
}
#[async_trait::async_trait]