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) -> 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 = Lazy::new(|| { format!("https://{}/ap/actor", *DOMAIN) .parse::() .unwrap() }); static ICON_URL: Lazy = Lazy::new(|| format!("https://{}/shadowfacts.png", *DOMAIN)); static INBOX: Lazy = Lazy::new(|| { format!("https://{}/ap/inbox", *DOMAIN) .parse::() .unwrap() }); pub static FOLLOWERS: Lazy = Lazy::new(|| { format!("https://{}/ap/actor/followers", *DOMAIN) .parse::() .unwrap() }); pub static KEY_ID: Lazy = Lazy::new(|| { format!("https://{}/ap/actor#main-key", *DOMAIN) .parse::() .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 }