v6/src/activitypub/actor.rs

106 lines
3.4 KiB
Rust

use super::types::{ActorExt, PublicKey, PublicKeyInner};
use super::util::accept;
use super::{keys, DOMAIN};
use crate::activitypub::db;
use crate::activitypub::types::{ImageExt, ImageExtData};
use activitystreams::actor::{ApActor, Person};
use activitystreams::base::AnyBase;
use activitystreams::collection::UnorderedCollection;
use activitystreams::object::Image;
use activitystreams::prelude::{ApActorExt, ObjectExt};
use activitystreams::{context, iri_string::types::IriString, prelude::*, security};
use axum::http::HeaderMap;
use axum::response::{IntoResponse, Redirect, Response};
use axum::{Extension, Json};
use hyper::{StatusCode, Uri};
use log::error;
use once_cell::sync::Lazy;
use sqlx::SqlitePool;
pub async fn handle(headers: HeaderMap, uri: Uri) -> Response {
let json = uri
.query()
.unwrap_or("")
.split("&")
.any(|p| p.split("=").next() == Some("json"));
if accept::accepts_html(&headers) && !json {
Redirect::permanent("/").into_response()
} else {
(
[("Content-Type", "application/activity+json")],
Json(actor()),
)
.into_response()
}
}
pub async fn handle_followers(Extension(pool): Extension<SqlitePool>) -> Response {
match db::get_followers(&pool).await {
Ok(followers) => {
let mut collection = UnorderedCollection::new();
collection.add_context(context());
collection.set_id(FOLLOWERS.clone());
collection.set_total_items(followers.len() as u64);
collection.set_many_items(
followers
.into_iter()
.map(|actor| AnyBase::from_xsd_string(actor.id)),
);
Json(collection).into_response()
}
Err(e) => {
error!("Error fetching followers: {:?}", e);
(
StatusCode::INTERNAL_SERVER_ERROR,
"Unable to fetch followers",
)
.into_response()
}
}
}
pub static ID: Lazy<IriString> = Lazy::new(|| {
format!("https://{}/ap/actor", *DOMAIN)
.parse::<IriString>()
.unwrap()
});
static ICON_URL: Lazy<String> = Lazy::new(|| format!("https://{}/shadowfacts.png", *DOMAIN));
static INBOX: Lazy<IriString> = Lazy::new(|| {
format!("https://{}/ap/inbox", *DOMAIN)
.parse::<IriString>()
.unwrap()
});
pub static FOLLOWERS: Lazy<IriString> = Lazy::new(|| {
format!("https://{}/ap/actor/followers", *DOMAIN)
.parse::<IriString>()
.unwrap()
});
pub static KEY_ID: Lazy<IriString> = Lazy::new(|| {
format!("https://{}/ap/actor#main-key", *DOMAIN)
.parse::<IriString>()
.unwrap()
});
fn actor() -> ActorExt {
let key = PublicKey {
public_key: PublicKeyInner {
id: KEY_ID.clone(),
owner: ID.clone(),
public_key_pem: keys::PUB_KEY_PEM.clone(),
},
};
let mut actor = ActorExt::new(ApActor::new(INBOX.clone(), Person::new()), key);
actor.add_context(context());
actor.add_context(security());
actor.set_id(ID.clone());
actor.set_preferred_username("blog");
actor.set_name("shadowfacts' blog");
let image = ImageExt::new(
Image::new(),
ImageExtData::new("image/png".into(), ICON_URL.clone()),
);
actor.set_icon(image.into_any_base().unwrap());
actor.set_followers(FOLLOWERS.clone());
actor
}