diff --git a/crates/adapters/activitypub/src/instance_actor.rs b/crates/adapters/activitypub/src/instance_actor.rs new file mode 100644 index 0000000..77192f0 --- /dev/null +++ b/crates/adapters/activitypub/src/instance_actor.rs @@ -0,0 +1,57 @@ +use std::sync::Arc; + +use async_trait::async_trait; +use k_ap::{ApActorType, ApUser, ApUserRepository}; + +pub const INSTANCE_ACTOR_ID: uuid::Uuid = + uuid::Uuid::from_bytes([0, 0, 0, 0, 0, 0, 0x40, 0, 0x80, 0, 0, 0, 0, 0, 0, 0]); + +pub struct InstanceActorUserRepo { + inner: Arc, + base_url: String, +} + +impl InstanceActorUserRepo { + pub fn new(inner: Arc, base_url: String) -> Self { + Self { inner, base_url } + } +} + +fn instance_ap_user(base_url: &str) -> ApUser { + ApUser { + id: INSTANCE_ACTOR_ID, + username: "instance".to_string(), + display_name: None, + bio: None, + avatar_url: None, + banner_url: None, + also_known_as: vec![], + profile_url: url::Url::parse(base_url).ok(), + attachment: vec![], + manually_approves_followers: false, + discoverable: false, + actor_type: ApActorType::Service, + featured_url: None, + } +} + +#[async_trait] +impl ApUserRepository for InstanceActorUserRepo { + async fn find_by_id(&self, id: uuid::Uuid) -> anyhow::Result> { + if id == INSTANCE_ACTOR_ID { + return Ok(Some(instance_ap_user(&self.base_url))); + } + self.inner.find_by_id(id).await + } + + async fn find_by_username(&self, username: &str) -> anyhow::Result> { + if username == "instance" { + return Ok(Some(instance_ap_user(&self.base_url))); + } + self.inner.find_by_username(username).await + } + + async fn count_users(&self) -> anyhow::Result { + self.inner.count_users().await + } +} diff --git a/crates/adapters/activitypub/src/lib.rs b/crates/adapters/activitypub/src/lib.rs index 749aa65..af65e9e 100644 --- a/crates/adapters/activitypub/src/lib.rs +++ b/crates/adapters/activitypub/src/lib.rs @@ -1,6 +1,7 @@ pub mod composite_handler; pub mod event_handler; pub mod federation_event_bridge; +pub mod instance_actor; pub mod objects; pub mod port; pub mod remote_review_repository; @@ -96,16 +97,18 @@ pub async fn wire(deps: ActivityPubDeps) -> anyhow::Result { federation_event_bridge::FederationEventBridge::new(event_publisher), ); + let user_repo = std::sync::Arc::new(instance_actor::InstanceActorUserRepo::new( + std::sync::Arc::new(DomainUserRepoAdapter::new(user_repo, base_url.clone())), + base_url.clone(), + )); let concrete = std::sync::Arc::new( ActivityPubService::builder(base_url.clone()) .activity_repo(activity_repo) .follow_repo(follow_repo) .actor_repo(actor_repo) .blocklist_repo(blocklist_repo) - .user_repo(std::sync::Arc::new(DomainUserRepoAdapter::new( - user_repo, - base_url.clone(), - ))) + .user_repo(user_repo) + .signed_fetch_actor_id(instance_actor::INSTANCE_ACTOR_ID) .content_reader(composite.clone() as std::sync::Arc) .object_handler(composite as std::sync::Arc) .event_publisher(fed_event_bridge)