]> Untitled Git - lemmy.git/commitdiff
Activitypub crate rewrite (#2782)
authorNutomic <me@nutomic.com>
Tue, 21 Mar 2023 15:03:05 +0000 (16:03 +0100)
committerGitHub <noreply@github.com>
Tue, 21 Mar 2023 15:03:05 +0000 (16:03 +0100)
* update activitypub-federation crate to 0.4.0

* fixes

* apub compiles!

* everything compiling!

* almost done, federated follow failing

* some test fixes

* use release

* add code back in

113 files changed:
Cargo.lock
Cargo.toml
crates/api_common/src/context.rs
crates/api_common/src/request.rs
crates/api_common/src/site.rs
crates/api_common/src/utils.rs
crates/api_crud/src/community/create.rs
crates/api_crud/src/site/create.rs
crates/api_crud/src/user/create.rs
crates/apub/Cargo.toml
crates/apub/src/activities/block/block_user.rs
crates/apub/src/activities/block/mod.rs
crates/apub/src/activities/block/undo_block_user.rs
crates/apub/src/activities/community/announce.rs
crates/apub/src/activities/community/collection_add.rs
crates/apub/src/activities/community/collection_remove.rs
crates/apub/src/activities/community/lock_page.rs
crates/apub/src/activities/community/mod.rs
crates/apub/src/activities/community/report.rs
crates/apub/src/activities/community/update.rs
crates/apub/src/activities/create_or_update/comment.rs
crates/apub/src/activities/create_or_update/mod.rs
crates/apub/src/activities/create_or_update/post.rs
crates/apub/src/activities/create_or_update/private_message.rs
crates/apub/src/activities/deletion/delete.rs
crates/apub/src/activities/deletion/delete_user.rs
crates/apub/src/activities/deletion/mod.rs
crates/apub/src/activities/deletion/undo_delete.rs
crates/apub/src/activities/following/accept.rs
crates/apub/src/activities/following/follow.rs
crates/apub/src/activities/following/mod.rs
crates/apub/src/activities/following/undo_follow.rs
crates/apub/src/activities/mod.rs
crates/apub/src/activities/voting/mod.rs
crates/apub/src/activities/voting/undo_vote.rs
crates/apub/src/activities/voting/vote.rs
crates/apub/src/activity_lists.rs
crates/apub/src/api/list_comments.rs
crates/apub/src/api/list_posts.rs
crates/apub/src/api/mod.rs
crates/apub/src/api/read_community.rs
crates/apub/src/api/read_person.rs
crates/apub/src/api/resolve_object.rs
crates/apub/src/api/search.rs
crates/apub/src/collections/community_featured.rs
crates/apub/src/collections/community_moderators.rs
crates/apub/src/collections/community_outbox.rs
crates/apub/src/collections/mod.rs
crates/apub/src/fetcher/mod.rs
crates/apub/src/fetcher/post_or_comment.rs
crates/apub/src/fetcher/search.rs
crates/apub/src/fetcher/user_or_community.rs
crates/apub/src/fetcher/webfinger.rs [deleted file]
crates/apub/src/http/comment.rs
crates/apub/src/http/community.rs
crates/apub/src/http/mod.rs
crates/apub/src/http/person.rs
crates/apub/src/http/post.rs
crates/apub/src/http/site.rs
crates/apub/src/lib.rs
crates/apub/src/mentions.rs
crates/apub/src/objects/comment.rs
crates/apub/src/objects/community.rs
crates/apub/src/objects/instance.rs
crates/apub/src/objects/mod.rs
crates/apub/src/objects/person.rs
crates/apub/src/objects/post.rs
crates/apub/src/objects/private_message.rs
crates/apub/src/protocol/activities/block/block_user.rs
crates/apub/src/protocol/activities/block/undo_block_user.rs
crates/apub/src/protocol/activities/community/announce.rs
crates/apub/src/protocol/activities/community/collection_add.rs
crates/apub/src/protocol/activities/community/collection_remove.rs
crates/apub/src/protocol/activities/community/lock_page.rs
crates/apub/src/protocol/activities/community/report.rs
crates/apub/src/protocol/activities/community/update.rs
crates/apub/src/protocol/activities/create_or_update/chat_message.rs
crates/apub/src/protocol/activities/create_or_update/note.rs
crates/apub/src/protocol/activities/create_or_update/page.rs
crates/apub/src/protocol/activities/deletion/delete.rs
crates/apub/src/protocol/activities/deletion/delete_user.rs
crates/apub/src/protocol/activities/deletion/undo_delete.rs
crates/apub/src/protocol/activities/following/accept.rs
crates/apub/src/protocol/activities/following/follow.rs
crates/apub/src/protocol/activities/following/undo_follow.rs
crates/apub/src/protocol/activities/voting/undo_vote.rs
crates/apub/src/protocol/activities/voting/vote.rs
crates/apub/src/protocol/collections/empty_outbox.rs
crates/apub/src/protocol/collections/group_featured.rs
crates/apub/src/protocol/collections/group_followers.rs
crates/apub/src/protocol/collections/group_moderators.rs
crates/apub/src/protocol/collections/group_outbox.rs
crates/apub/src/protocol/mod.rs
crates/apub/src/protocol/objects/chat_message.rs
crates/apub/src/protocol/objects/group.rs
crates/apub/src/protocol/objects/instance.rs
crates/apub/src/protocol/objects/note.rs
crates/apub/src/protocol/objects/page.rs
crates/apub/src/protocol/objects/person.rs
crates/apub/src/protocol/objects/tombstone.rs
crates/db_schema/src/impls/activity.rs
crates/db_schema/src/newtypes.rs
crates/db_schema/src/traits.rs
crates/db_schema/src/utils.rs
crates/routes/Cargo.toml
crates/routes/src/webfinger.rs
crates/utils/src/lib.rs
docker/Dockerfile
docker/docker_update.sh
src/api_routes_http.rs
src/api_routes_websocket.rs
src/code_migrations.rs
src/lib.rs

index 909893932319a52316d3d9ef46e2a51c97425646..3dc23a462e20261c215509e4690d0f6ca4e1699d 100644 (file)
@@ -4,26 +4,33 @@ version = 3
 
 [[package]]
 name = "activitypub_federation"
-version = "0.3.5"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59fbd2b7fb0aea9bdd738fc1441d34d3e7b585d60b42ed63deeac289c872f119"
+checksum = "b52228e706f380074b0722dae97f9c8274264026dbd3aa16d20466758995b6f4"
 dependencies = [
+ "activitystreams-kinds",
+ "actix-rt",
  "actix-web",
  "anyhow",
  "async-trait",
  "background-jobs",
  "base64",
+ "bytes",
  "chrono",
- "derive_builder 0.11.2",
+ "derive_builder 0.12.0",
+ "displaydoc",
  "dyn-clone",
  "enum_delegate",
+ "futures-core",
  "http",
- "http-signature-normalization-actix",
+ "http-signature-normalization",
  "http-signature-normalization-reqwest",
  "httpdate",
  "itertools",
  "once_cell",
  "openssl",
+ "pin-project-lite",
+ "regex",
  "reqwest",
  "reqwest-middleware",
  "serde",
@@ -695,9 +702,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 
 [[package]]
 name = "bytes"
-version = "1.2.1"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
+checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
 
 [[package]]
 name = "bytestring"
@@ -1232,11 +1239,11 @@ dependencies = [
 
 [[package]]
 name = "derive_builder"
-version = "0.11.2"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3"
+checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8"
 dependencies = [
- "derive_builder_macro 0.11.2",
+ "derive_builder_macro 0.12.0",
 ]
 
 [[package]]
@@ -1253,9 +1260,9 @@ dependencies = [
 
 [[package]]
 name = "derive_builder_core"
-version = "0.11.2"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4"
+checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f"
 dependencies = [
  "darling 0.14.1",
  "proc-macro2 1.0.47",
@@ -1275,11 +1282,11 @@ dependencies = [
 
 [[package]]
 name = "derive_builder_macro"
-version = "0.11.2"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68"
+checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"
 dependencies = [
- "derive_builder_core 0.11.2",
+ "derive_builder_core 0.12.0",
  "syn 1.0.103",
 ]
 
@@ -1418,6 +1425,17 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "displaydoc"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886"
+dependencies = [
+ "proc-macro2 1.0.47",
+ "quote 1.0.21",
+ "syn 1.0.103",
+]
+
 [[package]]
 name = "dlv-list"
 version = "0.3.0"
@@ -2451,7 +2469,6 @@ name = "lemmy_apub"
 version = "0.17.1"
 dependencies = [
  "activitypub_federation",
- "activitystreams-kinds",
  "actix-rt",
  "actix-web",
  "anyhow",
@@ -2557,6 +2574,7 @@ dependencies = [
 name = "lemmy_routes"
 version = "0.17.1"
 dependencies = [
+ "activitypub_federation",
  "actix-web",
  "anyhow",
  "chrono",
@@ -3998,9 +4016,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.6.0"
+version = "1.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
+checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
 dependencies = [
  "aho-corasick",
  "memchr",
index 6fcccc4d653c5e8100bb7c46e7ff67fc6f4b4a83..970ebb75d4e1583f1ab345cc8e572d638180ee0c 100644 (file)
@@ -59,7 +59,7 @@ lemmy_routes = { version = "=0.17.1", path = "./crates/routes" }
 lemmy_db_views = { version = "=0.17.1", path = "./crates/db_views" }
 lemmy_db_views_actor = { version = "=0.17.1", path = "./crates/db_views_actor" }
 lemmy_db_views_moderator = { version = "=0.17.1", path = "./crates/db_views_moderator" }
-activitypub_federation = "0.3.5"
+activitypub_federation = { version = "0.4.0", default-features = false, features = ["actix-web"] }
 diesel = "2.0.2"
 diesel_migrations = "2.0.0"
 diesel-async = "0.1.1"
index eb53b2af3109567807851102df99bdd6da25d12c..4c91c2c5bcd9412b03bbd54ce82843f3f85b2692 100644 (file)
@@ -7,12 +7,12 @@ use lemmy_utils::{
 use reqwest_middleware::ClientWithMiddleware;
 use std::sync::Arc;
 
+#[derive(Clone)]
 pub struct LemmyContext {
   pool: DbPool,
   chat_server: Arc<ChatServer>,
-  client: ClientWithMiddleware,
-  settings: Settings,
-  secret: Secret,
+  client: Arc<ClientWithMiddleware>,
+  secret: Arc<Secret>,
   rate_limit_cell: RateLimitCell,
 }
 
@@ -21,16 +21,14 @@ impl LemmyContext {
     pool: DbPool,
     chat_server: Arc<ChatServer>,
     client: ClientWithMiddleware,
-    settings: Settings,
     secret: Secret,
     rate_limit_cell: RateLimitCell,
   ) -> LemmyContext {
     LemmyContext {
       pool,
       chat_server,
-      client,
-      settings,
-      secret,
+      client: Arc::new(client),
+      secret: Arc::new(secret),
       rate_limit_cell,
     }
   }
@@ -53,16 +51,3 @@ impl LemmyContext {
     &self.rate_limit_cell
   }
 }
-
-impl Clone for LemmyContext {
-  fn clone(&self) -> Self {
-    LemmyContext {
-      pool: self.pool.clone(),
-      chat_server: self.chat_server.clone(),
-      client: self.client.clone(),
-      settings: self.settings.clone(),
-      secret: self.secret.clone(),
-      rate_limit_cell: self.rate_limit_cell.clone(),
-    }
-  }
-}
index 260abce1bb0649ee9061a3b30e0103e9afa5c49a..c6f71b868a3ff000621b0b75e568f0f872e4640e 100644 (file)
@@ -39,7 +39,6 @@ fn html_to_site_metadata(html_bytes: &[u8]) -> Result<SiteMetadata, LemmyError>
   let first_line = html
     .trim_start()
     .lines()
-    .into_iter()
     .next()
     .ok_or_else(|| LemmyError::from_message("No lines in html"))?
     .to_lowercase();
index 920cc6ec62d248b7e4af76734b568a58433e674a..524d102047b5d0ab7ae7a028efbb5a93ce7da964 100644 (file)
@@ -73,7 +73,7 @@ pub struct SearchResponse {
 #[derive(Debug, Serialize, Deserialize, Clone, Default)]
 pub struct ResolveObject {
   pub q: String,
-  pub auth: Option<Sensitive<String>>,
+  pub auth: Sensitive<String>,
 }
 
 #[derive(Debug, Serialize, Deserialize, Default)]
index c4828d352a8dfb40172b2bb47048a293516218f7..27f34c02f76edec21357b184c89e5ad558c5360b 100644 (file)
@@ -142,6 +142,7 @@ pub async fn mark_post_as_unread(
     .map_err(|e| LemmyError::from_error_message(e, "couldnt_mark_post_as_read"))
 }
 
+// TODO: this should simply take LemmyContext as param
 #[tracing::instrument(skip_all)]
 pub async fn get_local_user_view_from_jwt(
   jwt: &str,
index 7eb81067d3f7589fccef9b62dc56a2b281e342cf..8aaeb8f6aa568898da12ebe2ef80fa9674e0c747 100644 (file)
@@ -1,5 +1,5 @@
 use crate::PerformCrud;
-use activitypub_federation::core::signatures::generate_actor_keypair;
+use activitypub_federation::http_signatures::generate_actor_keypair;
 use actix_web::web::Data;
 use lemmy_api_common::{
   community::{CommunityResponse, CreateCommunity},
index 90b5dd8c931f128ffe88774b91c5e2c2c5535791..bda7eadc9fb03b2e7946b42db9b03bc67517e559 100644 (file)
@@ -1,5 +1,5 @@
 use crate::{site::check_application_question, PerformCrud};
-use activitypub_federation::core::signatures::generate_actor_keypair;
+use activitypub_federation::http_signatures::generate_actor_keypair;
 use actix_web::web::Data;
 use lemmy_api_common::{
   context::LemmyContext,
index c9539200195a7094cfb63ced84b2ca2e311aa84b..bf48b5f57b3a973f703a6df948ed16dff5f93462 100644 (file)
@@ -1,5 +1,5 @@
 use crate::PerformCrud;
-use activitypub_federation::core::signatures::generate_actor_keypair;
+use activitypub_federation::http_signatures::generate_actor_keypair;
 use actix_web::web::Data;
 use lemmy_api_common::{
   context::LemmyContext,
index 3a4db66dc421bd31e4d676941d161669010e62c4..9ac447c98f9aaf7ff8585b0d50f6559bcb827884 100644 (file)
@@ -41,7 +41,6 @@ once_cell = { workspace = true }
 tokio = { workspace = true }
 html2md = "0.2.13"
 serde_with = "1.14.0"
-activitystreams-kinds = "0.2.1"
 http-signature-normalization-actix = { version = "0.6.1", default-features = false, features = ["server", "sha-2"] }
 enum_delegate = "0.2.0"
 
index a2f96fd5d458506db28206e24c694eb9a69b7bc2..46f9b7940ca45f651850dbb394f344db1d525c36 100644 (file)
@@ -9,18 +9,16 @@ use crate::{
     verify_person_in_community,
   },
   activity_lists::AnnouncableActivities,
-  local_instance,
+  insert_activity,
   objects::{instance::remote_instance_inboxes, person::ApubPerson},
   protocol::activities::block::block_user::BlockUser,
-  ActorType,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
+  config::Data,
+  kinds::{activity::BlockType, public},
+  protocol::verification::verify_domains_match,
   traits::{ActivityHandler, Actor},
-  utils::verify_domains_match,
 };
-use activitystreams_kinds::{activity::BlockType, public};
 use anyhow::anyhow;
 use chrono::NaiveDateTime;
 use lemmy_api_common::{
@@ -51,17 +49,17 @@ impl BlockUser {
     remove_data: Option<bool>,
     reason: Option<String>,
     expires: Option<NaiveDateTime>,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<BlockUser, LemmyError> {
     let audience = if let SiteOrCommunity::Community(c) = target {
-      Some(ObjectId::new(c.actor_id()))
+      Some(c.id().into())
     } else {
       None
     };
     Ok(BlockUser {
-      actor: ObjectId::new(mod_.actor_id()),
+      actor: mod_.id().into(),
       to: vec![public()],
-      object: ObjectId::new(user.actor_id()),
+      object: user.id().into(),
       cc: generate_cc(target, context.pool()).await?,
       target: target.id(),
       kind: BlockType::Block,
@@ -84,7 +82,7 @@ impl BlockUser {
     remove_data: bool,
     reason: Option<String>,
     expires: Option<NaiveDateTime>,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let block = BlockUser::new(
       target,
@@ -111,7 +109,7 @@ impl BlockUser {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for BlockUser {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -125,17 +123,9 @@ impl ActivityHandler for BlockUser {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn verify(&self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
     verify_is_public(&self.to, &self.cc)?;
-    match self
-      .target
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?
-    {
+    match self.target.dereference(context).await? {
       SiteOrCommunity::Site(site) => {
         let domain = self.object.inner().domain().expect("url needs domain");
         if context.settings().hostname == domain {
@@ -144,43 +134,24 @@ impl ActivityHandler for BlockUser {
           );
         }
         // site ban can only target a user who is on the same instance as the actor (admin)
-        verify_domains_match(&site.actor_id(), self.actor.inner())?;
-        verify_domains_match(&site.actor_id(), self.object.inner())?;
+        verify_domains_match(&site.id(), self.actor.inner())?;
+        verify_domains_match(&site.id(), self.object.inner())?;
       }
       SiteOrCommunity::Community(community) => {
-        verify_person_in_community(&self.actor, &community, context, request_counter).await?;
-        verify_mod_action(
-          &self.actor,
-          self.object.inner(),
-          community.id,
-          context,
-          request_counter,
-        )
-        .await?;
+        verify_person_in_community(&self.actor, &community, context).await?;
+        verify_mod_action(&self.actor, self.object.inner(), community.id, context).await?;
       }
     }
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, false, context).await?;
     let expires = self.expires.map(|u| u.naive_local());
-    let mod_person = self
-      .actor
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
-    let blocked_person = self
-      .object
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
-    let target = self
-      .target
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+    let mod_person = self.actor.dereference(context).await?;
+    let blocked_person = self.object.dereference(context).await?;
+    let target = self.target.dereference(context).await?;
     match target {
       SiteOrCommunity::Site(_site) => {
         let blocked_person = Person::update(
index 9a5b9fcb160bcfa62f34bb5283487adb34100867..a1315bb78facfa3f6acece87752943854f759d49 100644 (file)
@@ -4,10 +4,13 @@ use crate::{
     activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
     objects::{group::Group, instance::Instance},
   },
-  ActorType,
   SendActivity,
 };
-use activitypub_federation::{core::object_id::ObjectId, traits::ApubObject};
+use activitypub_federation::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  traits::{Actor, Object},
+};
 use chrono::NaiveDateTime;
 use lemmy_api_common::{
   community::{BanFromCommunity, BanFromCommunityResponse},
@@ -41,11 +44,10 @@ pub enum InstanceOrGroup {
   Group(Group),
 }
 
-#[async_trait::async_trait(?Send)]
-impl ApubObject for SiteOrCommunity {
+#[async_trait::async_trait]
+impl Object for SiteOrCommunity {
   type DataType = LemmyContext;
-  type ApubType = InstanceOrGroup;
-  type DbType = ();
+  type Kind = InstanceOrGroup;
   type Error = LemmyError;
 
   #[tracing::instrument(skip_all)]
@@ -57,62 +59,51 @@ impl ApubObject for SiteOrCommunity {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn read_from_apub_id(
+  async fn read_from_id(
     object_id: Url,
-    data: &Self::DataType,
+    data: &Data<Self::DataType>,
   ) -> Result<Option<Self>, LemmyError>
   where
     Self: Sized,
   {
-    let site = ApubSite::read_from_apub_id(object_id.clone(), data).await?;
+    let site = ApubSite::read_from_id(object_id.clone(), data).await?;
     Ok(match site {
       Some(o) => Some(SiteOrCommunity::Site(o)),
-      None => ApubCommunity::read_from_apub_id(object_id, data)
+      None => ApubCommunity::read_from_id(object_id, data)
         .await?
         .map(SiteOrCommunity::Community),
     })
   }
 
-  async fn delete(self, _data: &Self::DataType) -> Result<(), LemmyError> {
+  async fn delete(self, _data: &Data<Self::DataType>) -> Result<(), LemmyError> {
     unimplemented!()
   }
 
-  async fn into_apub(self, _data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
+  async fn into_json(self, _data: &Data<Self::DataType>) -> Result<Self::Kind, LemmyError> {
     unimplemented!()
   }
 
   #[tracing::instrument(skip_all)]
   async fn verify(
-    apub: &Self::ApubType,
+    apub: &Self::Kind,
     expected_domain: &Url,
-    data: &Self::DataType,
-    request_counter: &mut i32,
+    data: &Data<Self::DataType>,
   ) -> Result<(), LemmyError> {
     match apub {
-      InstanceOrGroup::Instance(i) => {
-        ApubSite::verify(i, expected_domain, data, request_counter).await
-      }
-      InstanceOrGroup::Group(g) => {
-        ApubCommunity::verify(g, expected_domain, data, request_counter).await
-      }
+      InstanceOrGroup::Instance(i) => ApubSite::verify(i, expected_domain, data).await,
+      InstanceOrGroup::Group(g) => ApubCommunity::verify(g, expected_domain, data).await,
     }
   }
 
   #[tracing::instrument(skip_all)]
-  async fn from_apub(
-    apub: Self::ApubType,
-    data: &Self::DataType,
-    request_counter: &mut i32,
-  ) -> Result<Self, LemmyError>
+  async fn from_json(apub: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, LemmyError>
   where
     Self: Sized,
   {
     Ok(match apub {
-      InstanceOrGroup::Instance(p) => {
-        SiteOrCommunity::Site(ApubSite::from_apub(p, data, request_counter).await?)
-      }
+      InstanceOrGroup::Instance(p) => SiteOrCommunity::Site(ApubSite::from_json(p, data).await?),
       InstanceOrGroup::Group(n) => {
-        SiteOrCommunity::Community(ApubCommunity::from_apub(n, data, request_counter).await?)
+        SiteOrCommunity::Community(ApubCommunity::from_json(n, data).await?)
       }
     })
   }
@@ -121,8 +112,8 @@ impl ApubObject for SiteOrCommunity {
 impl SiteOrCommunity {
   fn id(&self) -> ObjectId<SiteOrCommunity> {
     match self {
-      SiteOrCommunity::Site(s) => ObjectId::new(s.actor_id.clone()),
-      SiteOrCommunity::Community(c) => ObjectId::new(c.actor_id.clone()),
+      SiteOrCommunity::Site(s) => ObjectId::from(s.actor_id.clone()),
+      SiteOrCommunity::Community(c) => ObjectId::from(c.actor_id.clone()),
     }
   }
 }
@@ -134,18 +125,18 @@ async fn generate_cc(target: &SiteOrCommunity, pool: &DbPool) -> Result<Vec<Url>
       .into_iter()
       .map(|s| s.actor_id.into())
       .collect(),
-    SiteOrCommunity::Community(c) => vec![c.actor_id()],
+    SiteOrCommunity::Community(c) => vec![c.id()],
   })
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for BanPerson {
   type Response = BanPersonResponse;
 
   async fn send_activity(
     request: &Self,
     _response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
@@ -182,14 +173,14 @@ impl SendActivity for BanPerson {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for BanFromCommunity {
   type Response = BanFromCommunityResponse;
 
   async fn send_activity(
     request: &Self,
     _response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
index 315667ac6c565738c3d254ff6996b89e738c5992..43bc73523df7c4b83fdbadafc3ffbce3861160bb 100644 (file)
@@ -7,18 +7,16 @@ use crate::{
     verify_is_public,
   },
   activity_lists::AnnouncableActivities,
-  local_instance,
+  insert_activity,
   objects::{instance::remote_instance_inboxes, person::ApubPerson},
   protocol::activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
-  ActorType,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
+  config::Data,
+  kinds::{activity::UndoType, public},
+  protocol::verification::verify_domains_match,
   traits::{ActivityHandler, Actor},
-  utils::verify_domains_match,
 };
-use activitystreams_kinds::{activity::UndoType, public};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::{
   source::{
@@ -38,11 +36,11 @@ impl UndoBlockUser {
     user: &ApubPerson,
     mod_: &ApubPerson,
     reason: Option<String>,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let block = BlockUser::new(target, user, mod_, None, reason, None, context).await?;
     let audience = if let SiteOrCommunity::Community(c) = target {
-      Some(ObjectId::new(c.actor_id()))
+      Some(c.id().into())
     } else {
       None
     };
@@ -52,7 +50,7 @@ impl UndoBlockUser {
       &context.settings().get_protocol_and_hostname(),
     )?;
     let undo = UndoBlockUser {
-      actor: ObjectId::new(mod_.actor_id()),
+      actor: mod_.id().into(),
       to: vec![public()],
       object: block,
       cc: generate_cc(target, context.pool()).await?,
@@ -75,7 +73,7 @@ impl UndoBlockUser {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for UndoBlockUser {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -89,40 +87,20 @@ impl ActivityHandler for UndoBlockUser {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn verify(&self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
     verify_is_public(&self.to, &self.cc)?;
     verify_domains_match(self.actor.inner(), self.object.actor.inner())?;
-    self.object.verify(context, request_counter).await?;
+    self.object.verify(context).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let instance = local_instance(context).await;
+  async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, false, context).await?;
     let expires = self.object.expires.map(|u| u.naive_local());
-    let mod_person = self
-      .actor
-      .dereference(context, instance, request_counter)
-      .await?;
-    let blocked_person = self
-      .object
-      .object
-      .dereference(context, instance, request_counter)
-      .await?;
-    match self
-      .object
-      .target
-      .dereference(context, instance, request_counter)
-      .await?
-    {
+    let mod_person = self.actor.dereference(context).await?;
+    let blocked_person = self.object.object.dereference(context).await?;
+    match self.object.target.dereference(context).await? {
       SiteOrCommunity::Site(_site) => {
         let blocked_person = Person::update(
           context.pool(),
index 306913aa6682c0864d8263b00fea57ab598ba98a..116b027269b1d13c4e9bcf0e61f4d319d6e2811e 100644 (file)
@@ -14,17 +14,18 @@ use crate::{
     IdOrNestedObject,
     InCommunity,
   },
-  ActorType,
 };
-use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
-use activitystreams_kinds::{activity::AnnounceType, public};
+use activitypub_federation::{
+  config::Data,
+  kinds::{activity::AnnounceType, public},
+  traits::{ActivityHandler, Actor},
+};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_utils::error::LemmyError;
 use serde_json::Value;
-use tracing::debug;
 use url::Url;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for RawAnnouncableActivities {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -38,35 +39,27 @@ impl ActivityHandler for RawAnnouncableActivities {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    _data: &Data<Self::DataType>,
-    _request_counter: &mut i32,
-  ) -> Result<(), Self::Error> {
+  async fn verify(&self, _data: &Data<Self::DataType>) -> Result<(), Self::Error> {
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    data: &Data<Self::DataType>,
-    request_counter: &mut i32,
-  ) -> Result<(), Self::Error> {
+  async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> {
     let activity: AnnouncableActivities = self.clone().try_into()?;
     // This is only for sending, not receiving so we reject it.
     if let AnnouncableActivities::Page(_) = activity {
       return Err(LemmyError::from_message("Cant receive page"));
     }
-    let community = activity.community(data, &mut 0).await?;
-    let actor_id = ObjectId::new(activity.actor().clone());
+    let community = activity.community(data).await?;
+    let actor_id = activity.actor().clone().into();
 
     // verify and receive activity
-    activity.verify(data, request_counter).await?;
-    activity.receive(data, request_counter).await?;
+    activity.verify(data).await?;
+    activity.receive(data).await?;
 
     // send to community followers
     if community.local {
-      verify_person_in_community(&actor_id, &community, data, &mut 0).await?;
+      verify_person_in_community(&actor_id, &community, data).await?;
       AnnounceActivity::send(self, &community, data).await?;
     }
     Ok(())
@@ -77,10 +70,10 @@ impl AnnounceActivity {
   pub(crate) fn new(
     object: RawAnnouncableActivities,
     community: &ApubCommunity,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<AnnounceActivity, LemmyError> {
     Ok(AnnounceActivity {
-      actor: ObjectId::new(community.actor_id()),
+      actor: community.id().into(),
       to: vec![public()],
       object: IdOrNestedObject::NestedObject(object),
       cc: vec![community.followers_url.clone().into()],
@@ -96,7 +89,7 @@ impl AnnounceActivity {
   pub async fn send(
     object: RawAnnouncableActivities,
     community: &ApubCommunity,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let announce = AnnounceActivity::new(object.clone(), community, context)?;
     let inboxes = community.get_follower_inboxes(context).await?;
@@ -109,7 +102,10 @@ impl AnnounceActivity {
       // Hack: need to convert Page into a format which can be sent as activity, which requires
       //       adding actor field.
       let announcable_page = RawAnnouncableActivities {
-        id: c.object.id.clone().into_inner(),
+        id: generate_activity_id(
+          AnnounceType::Announce,
+          &context.settings().get_protocol_and_hostname(),
+        )?,
         actor: c.actor.clone().into_inner(),
         other: serde_json::to_value(c.object)?
           .as_object()
@@ -123,7 +119,7 @@ impl AnnounceActivity {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for AnnounceActivity {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -137,44 +133,23 @@ impl ActivityHandler for AnnounceActivity {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    _context: &Data<LemmyContext>,
-    _request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn verify(&self, _context: &Data<Self::DataType>) -> Result<(), LemmyError> {
     verify_is_public(&self.to, &self.cc)?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let object: AnnouncableActivities = self
-      .object
-      .object(context, request_counter)
-      .await?
-      .try_into()?;
+  async fn receive(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, false, context).await?;
+    let object: AnnouncableActivities = self.object.object(context).await?.try_into()?;
     // This is only for sending, not receiving so we reject it.
     if let AnnouncableActivities::Page(_) = object {
       return Err(LemmyError::from_message("Cant receive page"));
     }
 
-    // we have to verify this here in order to avoid fetching the object twice over http
-    object.verify(context, request_counter).await?;
-
-    let object_value = serde_json::to_value(&object)?;
-    let insert = insert_activity(object.id(), object_value, false, true, context.pool()).await?;
-    if !insert {
-      debug!(
-        "Received duplicate activity in announce {}",
-        object.id().to_string()
-      );
-      return Ok(());
-    }
-    object.receive(context, request_counter).await
+    // verify here in order to avoid fetching the object twice over http
+    object.verify(context).await?;
+    object.receive(context).await
   }
 }
 
index b45fa278ee933185265d1f45848a3458702cbb75..dfab0baf6637c18f4325f29b4cb00d2969af2454 100644 (file)
@@ -7,7 +7,7 @@ use crate::{
     verify_person_in_community,
   },
   activity_lists::AnnouncableActivities,
-  local_instance,
+  insert_activity,
   objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
   protocol::{
     activities::{
@@ -17,15 +17,14 @@ use crate::{
     },
     InCommunity,
   },
-  ActorType,
   SendActivity,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::{activity::AddType, public},
   traits::{ActivityHandler, Actor},
 };
-use activitystreams_kinds::{activity::AddType, public};
 use lemmy_api_common::{
   community::{AddModToCommunity, AddModToCommunityResponse},
   context::LemmyContext,
@@ -51,21 +50,21 @@ impl CollectionAdd {
     community: &ApubCommunity,
     added_mod: &ApubPerson,
     actor: &ApubPerson,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let id = generate_activity_id(
       AddType::Add,
       &context.settings().get_protocol_and_hostname(),
     )?;
     let add = CollectionAdd {
-      actor: ObjectId::new(actor.actor_id()),
+      actor: actor.id().into(),
       to: vec![public()],
-      object: added_mod.actor_id(),
+      object: added_mod.id(),
       target: generate_moderators_url(&community.actor_id)?.into(),
-      cc: vec![community.actor_id()],
+      cc: vec![community.id()],
       kind: AddType::Add,
       id: id.clone(),
-      audience: Some(ObjectId::new(community.actor_id())),
+      audience: Some(community.id().into()),
     };
 
     let activity = AnnouncableActivities::CollectionAdd(add);
@@ -77,28 +76,28 @@ impl CollectionAdd {
     community: &ApubCommunity,
     featured_post: &ApubPost,
     actor: &ApubPerson,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let id = generate_activity_id(
       AddType::Add,
       &context.settings().get_protocol_and_hostname(),
     )?;
     let add = CollectionAdd {
-      actor: ObjectId::new(actor.actor_id()),
+      actor: actor.id().into(),
       to: vec![public()],
       object: featured_post.ap_id.clone().into(),
       target: generate_featured_url(&community.actor_id)?.into(),
-      cc: vec![community.actor_id()],
+      cc: vec![community.id()],
       kind: AddType::Add,
       id: id.clone(),
-      audience: Some(ObjectId::new(community.actor_id())),
+      audience: Some(community.id().into()),
     };
     let activity = AnnouncableActivities::CollectionAdd(add);
     send_activity_in_community(activity, actor, community, vec![], true, context).await
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for CollectionAdd {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -112,37 +111,23 @@ impl ActivityHandler for CollectionAdd {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
     verify_is_public(&self.to, &self.cc)?;
-    let community = self.community(context, request_counter).await?;
-    verify_person_in_community(&self.actor, &community, context, request_counter).await?;
-    verify_mod_action(
-      &self.actor,
-      &self.object,
-      community.id,
-      context,
-      request_counter,
-    )
-    .await?;
+    let community = self.community(context).await?;
+    verify_person_in_community(&self.actor, &community, context).await?;
+    verify_mod_action(&self.actor, &self.object, community.id, context).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn receive(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, false, context).await?;
     let (community, collection_type) =
       Community::get_by_collection_url(context.pool(), &self.target.into()).await?;
     match collection_type {
       CollectionType::Moderators => {
-        let new_mod = ObjectId::<ApubPerson>::new(self.object)
-          .dereference(context, local_instance(context).await, request_counter)
+        let new_mod = ObjectId::<ApubPerson>::from(self.object)
+          .dereference(context)
           .await?;
 
         // If we had to refetch the community while parsing the activity, then the new mod has already
@@ -158,10 +143,7 @@ impl ActivityHandler for CollectionAdd {
           CommunityModerator::join(context.pool(), &form).await?;
 
           // write mod log
-          let actor = self
-            .actor
-            .dereference(context, local_instance(context).await, request_counter)
-            .await?;
+          let actor = self.actor.dereference(context).await?;
           let form = ModAddCommunityForm {
             mod_person_id: actor.id,
             other_person_id: new_mod.id,
@@ -173,8 +155,8 @@ impl ActivityHandler for CollectionAdd {
         // TODO: send websocket notification about added mod
       }
       CollectionType::Featured => {
-        let post = ObjectId::<ApubPost>::new(self.object)
-          .dereference(context, local_instance(context).await, request_counter)
+        let post = ObjectId::<ApubPost>::from(self.object)
+          .dereference(context)
           .await?;
         let form = PostUpdateForm::builder()
           .featured_community(Some(true))
@@ -186,14 +168,14 @@ impl ActivityHandler for CollectionAdd {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for AddModToCommunity {
   type Response = AddModToCommunityResponse;
 
   async fn send_activity(
     request: &Self,
     _response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
@@ -223,14 +205,14 @@ impl SendActivity for AddModToCommunity {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for FeaturePost {
   type Response = PostResponse;
 
   async fn send_activity(
     request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
index d804e65db017ed76e6dd299daad5e2bb18105652..8f920cf24522b36ce8db2a4e0dc2d1cc47305333 100644 (file)
@@ -7,17 +7,16 @@ use crate::{
     verify_person_in_community,
   },
   activity_lists::AnnouncableActivities,
-  local_instance,
+  insert_activity,
   objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
   protocol::{activities::community::collection_remove::CollectionRemove, InCommunity},
-  ActorType,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::{activity::RemoveType, public},
   traits::{ActivityHandler, Actor},
 };
-use activitystreams_kinds::{activity::RemoveType, public};
 use lemmy_api_common::{
   context::LemmyContext,
   utils::{generate_featured_url, generate_moderators_url},
@@ -40,21 +39,21 @@ impl CollectionRemove {
     community: &ApubCommunity,
     removed_mod: &ApubPerson,
     actor: &ApubPerson,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let id = generate_activity_id(
       RemoveType::Remove,
       &context.settings().get_protocol_and_hostname(),
     )?;
     let remove = CollectionRemove {
-      actor: ObjectId::new(actor.actor_id()),
+      actor: actor.id().into(),
       to: vec![public()],
-      object: ObjectId::new(removed_mod.actor_id()),
+      object: removed_mod.id(),
       target: generate_moderators_url(&community.actor_id)?.into(),
       id: id.clone(),
-      cc: vec![community.actor_id()],
+      cc: vec![community.id()],
       kind: RemoveType::Remove,
-      audience: Some(ObjectId::new(community.actor_id())),
+      audience: Some(community.id().into()),
     };
 
     let activity = AnnouncableActivities::CollectionRemove(remove);
@@ -66,28 +65,28 @@ impl CollectionRemove {
     community: &ApubCommunity,
     featured_post: &ApubPost,
     actor: &ApubPerson,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let id = generate_activity_id(
       RemoveType::Remove,
       &context.settings().get_protocol_and_hostname(),
     )?;
     let remove = CollectionRemove {
-      actor: ObjectId::new(actor.actor_id()),
+      actor: actor.id().into(),
       to: vec![public()],
       object: featured_post.ap_id.clone().into(),
       target: generate_featured_url(&community.actor_id)?.into(),
-      cc: vec![community.actor_id()],
+      cc: vec![community.id()],
       kind: RemoveType::Remove,
       id: id.clone(),
-      audience: Some(ObjectId::new(community.actor_id())),
+      audience: Some(community.id().into()),
     };
     let activity = AnnouncableActivities::CollectionRemove(remove);
     send_activity_in_community(activity, actor, community, vec![], true, context).await
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for CollectionRemove {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -101,38 +100,23 @@ impl ActivityHandler for CollectionRemove {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
     verify_is_public(&self.to, &self.cc)?;
-    let community = self.community(context, request_counter).await?;
-    verify_person_in_community(&self.actor, &community, context, request_counter).await?;
-    verify_mod_action(
-      &self.actor,
-      self.object.inner(),
-      community.id,
-      context,
-      request_counter,
-    )
-    .await?;
+    let community = self.community(context).await?;
+    verify_person_in_community(&self.actor, &community, context).await?;
+    verify_mod_action(&self.actor, &self.object, community.id, context).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn receive(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, false, context).await?;
     let (community, collection_type) =
       Community::get_by_collection_url(context.pool(), &self.target.into()).await?;
     match collection_type {
       CollectionType::Moderators => {
-        let remove_mod = self
-          .object
-          .dereference(context, local_instance(context).await, request_counter)
+        let remove_mod = ObjectId::<ApubPerson>::from(self.object)
+          .dereference(context)
           .await?;
 
         let form = CommunityModeratorForm {
@@ -142,10 +126,7 @@ impl ActivityHandler for CollectionRemove {
         CommunityModerator::leave(context.pool(), &form).await?;
 
         // write mod log
-        let actor = self
-          .actor
-          .dereference(context, local_instance(context).await, request_counter)
-          .await?;
+        let actor = self.actor.dereference(context).await?;
         let form = ModAddCommunityForm {
           mod_person_id: actor.id,
           other_person_id: remove_mod.id,
@@ -157,8 +138,8 @@ impl ActivityHandler for CollectionRemove {
         // TODO: send websocket notification about removed mod
       }
       CollectionType::Featured => {
-        let post = ObjectId::<ApubPost>::new(self.object)
-          .dereference(context, local_instance(context).await, request_counter)
+        let post = ObjectId::<ApubPost>::from(self.object)
+          .dereference(context)
           .await?;
         let form = PostUpdateForm::builder()
           .featured_community(Some(false))
index 8caf3bfb182f5864c503de9210e8ee578de1cc80..498c3a324983b0028396a89b65ecd5da82a123ea 100644 (file)
@@ -8,7 +8,7 @@ use crate::{
     verify_person_in_community,
   },
   activity_lists::AnnouncableActivities,
-  local_instance,
+  insert_activity,
   protocol::{
     activities::{
       community::lock_page::{LockPage, LockType, UndoLockPage},
@@ -19,8 +19,11 @@ use crate::{
   },
   SendActivity,
 };
-use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
-use activitystreams_kinds::{activity::UndoType, public};
+use activitypub_federation::{
+  config::Data,
+  kinds::{activity::UndoType, public},
+  traits::ActivityHandler,
+};
 use lemmy_api_common::{
   context::LemmyContext,
   post::{LockPost, PostResponse},
@@ -36,7 +39,7 @@ use lemmy_db_schema::{
 use lemmy_utils::error::LemmyError;
 use url::Url;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for LockPage {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -49,42 +52,24 @@ impl ActivityHandler for LockPage {
     self.actor.inner()
   }
 
-  async fn verify(
-    &self,
-    context: &Data<Self::DataType>,
-    request_counter: &mut i32,
-  ) -> Result<(), Self::Error> {
+  async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
     verify_is_public(&self.to, &self.cc)?;
-    let community = self.community(context, request_counter).await?;
-    verify_person_in_community(&self.actor, &community, context, request_counter).await?;
+    let community = self.community(context).await?;
+    verify_person_in_community(&self.actor, &community, context).await?;
     check_community_deleted_or_removed(&community)?;
-    verify_mod_action(
-      &self.actor,
-      self.object.inner(),
-      community.id,
-      context,
-      request_counter,
-    )
-    .await?;
+    verify_mod_action(&self.actor, self.object.inner(), community.id, context).await?;
     Ok(())
   }
 
-  async fn receive(
-    self,
-    context: &Data<Self::DataType>,
-    request_counter: &mut i32,
-  ) -> Result<(), Self::Error> {
+  async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
     let form = PostUpdateForm::builder().locked(Some(true)).build();
-    let post = self
-      .object
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+    let post = self.object.dereference(context).await?;
     Post::update(context.pool(), post.id, &form).await?;
     Ok(())
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for UndoLockPage {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -97,50 +82,38 @@ impl ActivityHandler for UndoLockPage {
     self.actor.inner()
   }
 
-  async fn verify(
-    &self,
-    context: &Data<Self::DataType>,
-    request_counter: &mut i32,
-  ) -> Result<(), Self::Error> {
+  async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
     verify_is_public(&self.to, &self.cc)?;
-    let community = self.community(context, request_counter).await?;
-    verify_person_in_community(&self.actor, &community, context, request_counter).await?;
+    let community = self.community(context).await?;
+    verify_person_in_community(&self.actor, &community, context).await?;
     check_community_deleted_or_removed(&community)?;
     verify_mod_action(
       &self.actor,
       self.object.object.inner(),
       community.id,
       context,
-      request_counter,
     )
     .await?;
     Ok(())
   }
 
-  async fn receive(
-    self,
-    context: &Data<Self::DataType>,
-    request_counter: &mut i32,
-  ) -> Result<(), Self::Error> {
+  async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
+    insert_activity(&self.id, &self, false, false, context).await?;
     let form = PostUpdateForm::builder().locked(Some(false)).build();
-    let post = self
-      .object
-      .object
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+    let post = self.object.object.dereference(context).await?;
     Post::update(context.pool(), post.id, &form).await?;
     Ok(())
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for LockPost {
   type Response = PostResponse;
 
   async fn send_activity(
     request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
@@ -156,16 +129,16 @@ impl SendActivity for LockPost {
       LockType::Lock,
       &context.settings().get_protocol_and_hostname(),
     )?;
-    let community_id: Url = response.post_view.community.actor_id.clone().into();
-    let actor = ObjectId::new(local_user_view.person.actor_id.clone());
+    let community_id = response.post_view.community.actor_id.clone();
+    let actor = local_user_view.person.actor_id.clone().into();
     let lock = LockPage {
       actor,
       to: vec![public()],
-      object: ObjectId::new(response.post_view.post.ap_id.clone()),
-      cc: vec![community_id.clone()],
+      object: response.post_view.post.ap_id.clone().into(),
+      cc: vec![community_id.clone().into()],
       kind: LockType::Lock,
       id,
-      audience: Some(ObjectId::new(community_id)),
+      audience: Some(community_id.into()),
     };
     let activity = if request.locked {
       AnnouncableActivities::LockPost(lock)
index 226d5d64310b927652f5d95a46c1e0f5f5b08085..b770c47ac6a09c60fac83f7386b6b5774d28a11c 100644 (file)
@@ -4,7 +4,7 @@ use crate::{
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::activities::community::announce::AnnounceActivity,
 };
-use activitypub_federation::traits::Actor;
+use activitypub_federation::{config::Data, traits::Actor};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::source::person::PersonFollower;
 use lemmy_utils::error::LemmyError;
@@ -36,29 +36,30 @@ pub(crate) async fn send_activity_in_community(
   community: &ApubCommunity,
   extra_inboxes: Vec<Url>,
   is_mod_action: bool,
-  context: &LemmyContext,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
-  // send to extra_inboxes
-  send_lemmy_activity(context, activity.clone(), actor, extra_inboxes, false).await?;
+  // send to any users which are mentioned or affected directly
+  let mut inboxes = extra_inboxes;
+
+  // send to user followers
+  if !is_mod_action {
+    inboxes.append(
+      &mut PersonFollower::list_followers(context.pool(), actor.id)
+        .await?
+        .into_iter()
+        .map(|p| ApubPerson(p).shared_inbox_or_inbox())
+        .collect(),
+    );
+  }
 
   if community.local {
     // send directly to community followers
     AnnounceActivity::send(activity.clone().try_into()?, community, context).await?;
   } else {
     // send to the community, which will then forward to followers
-    let inbox = vec![community.shared_inbox_or_inbox()];
-    send_lemmy_activity(context, activity.clone(), actor, inbox, false).await?;
-  }
-
-  // send to those who follow `actor`
-  if !is_mod_action {
-    let inboxes = PersonFollower::list_followers(context.pool(), actor.id)
-      .await?
-      .into_iter()
-      .map(|p| ApubPerson(p).shared_inbox_or_inbox())
-      .collect();
-    send_lemmy_activity(context, activity, actor, inboxes, false).await?;
+    inboxes.push(community.shared_inbox_or_inbox());
   }
 
+  send_lemmy_activity(context, activity.clone(), actor, inboxes, false).await?;
   Ok(())
 }
index dfd0a83c8086361ef2c10ee6b23009cf9cb0a0f8..a5fab8a01a9d5c4081dbc593057b4a8a57a186b7 100644 (file)
@@ -1,18 +1,17 @@
 use crate::{
   activities::{generate_activity_id, send_lemmy_activity, verify_person_in_community},
-  local_instance,
+  insert_activity,
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::{activities::community::report::Report, InCommunity},
-  ActorType,
   PostOrComment,
   SendActivity,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::activity::FlagType,
   traits::{ActivityHandler, Actor},
 };
-use activitystreams_kinds::activity::FlagType;
 use lemmy_api_common::{
   comment::{CommentReportResponse, CreateCommentReport},
   context::LemmyContext,
@@ -31,21 +30,21 @@ use lemmy_db_views::structs::{CommentReportView, PostReportView};
 use lemmy_utils::error::LemmyError;
 use url::Url;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for CreatePostReport {
   type Response = PostReportResponse;
 
   async fn send_activity(
     request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
     Report::send(
-      ObjectId::new(response.post_report_view.post.ap_id.clone()),
+      ObjectId::from(response.post_report_view.post.ap_id.clone()),
       &local_user_view.person.into(),
-      ObjectId::new(response.post_report_view.community.actor_id.clone()),
+      ObjectId::from(response.post_report_view.community.actor_id.clone()),
       request.reason.to_string(),
       context,
     )
@@ -53,21 +52,21 @@ impl SendActivity for CreatePostReport {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for CreateCommentReport {
   type Response = CommentReportResponse;
 
   async fn send_activity(
     request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
     Report::send(
-      ObjectId::new(response.comment_report_view.comment.ap_id.clone()),
+      ObjectId::from(response.comment_report_view.comment.ap_id.clone()),
       &local_user_view.person.into(),
-      ObjectId::new(response.comment_report_view.community.actor_id.clone()),
+      ObjectId::from(response.comment_report_view.community.actor_id.clone()),
       request.reason.to_string(),
       context,
     )
@@ -82,7 +81,7 @@ impl Report {
     actor: &ApubPerson,
     community_id: ObjectId<ApubCommunity>,
     reason: String,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let community = community_id.dereference_local(context).await?;
     let kind = FlagType::Flag;
@@ -91,13 +90,13 @@ impl Report {
       &context.settings().get_protocol_and_hostname(),
     )?;
     let report = Report {
-      actor: ObjectId::new(actor.actor_id()),
-      to: [ObjectId::new(community.actor_id())],
+      actor: actor.id().into(),
+      to: [community.id().into()],
       object: object_id,
       summary: reason,
       kind,
       id: id.clone(),
-      audience: Some(ObjectId::new(community.actor_id())),
+      audience: Some(community.id().into()),
     };
 
     let inbox = vec![community.shared_inbox_or_inbox()];
@@ -105,7 +104,7 @@ impl Report {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for Report {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -119,31 +118,17 @@ impl ActivityHandler for Report {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let community = self.community(context, request_counter).await?;
-    verify_person_in_community(&self.actor, &community, context, request_counter).await?;
+  async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
+    let community = self.community(context).await?;
+    verify_person_in_community(&self.actor, &community, context).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let actor = self
-      .actor
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
-    match self
-      .object
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?
-    {
+  async fn receive(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, true, context).await?;
+    let actor = self.actor.dereference(context).await?;
+    match self.object.dereference(context).await? {
       PostOrComment::Post(post) => {
         let report_form = PostReportForm {
           creator_id: actor.id,
index 969741ef66f97f686ee88f41450296c2e923f1e6..f0eaa09c6230ebbad94a129adbead246168bd580 100644 (file)
@@ -7,17 +7,16 @@ use crate::{
     verify_person_in_community,
   },
   activity_lists::AnnouncableActivities,
+  insert_activity,
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::{activities::community::update::UpdateCommunity, InCommunity},
-  ActorType,
   SendActivity,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
-  traits::{ActivityHandler, ApubObject},
+  config::Data,
+  kinds::{activity::UpdateType, public},
+  traits::{ActivityHandler, Actor, Object},
 };
-use activitystreams_kinds::{activity::UpdateType, public};
 use lemmy_api_common::{
   community::{CommunityResponse, EditCommunity, HideCommunity},
   context::LemmyContext,
@@ -28,14 +27,14 @@ use lemmy_db_schema::{source::community::Community, traits::Crud};
 use lemmy_utils::error::LemmyError;
 use url::Url;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for EditCommunity {
   type Response = CommunityResponse;
 
   async fn send_activity(
     request: &Self,
     _response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
@@ -49,20 +48,20 @@ impl UpdateCommunity {
   pub async fn send(
     community: ApubCommunity,
     actor: &ApubPerson,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let id = generate_activity_id(
       UpdateType::Update,
       &context.settings().get_protocol_and_hostname(),
     )?;
     let update = UpdateCommunity {
-      actor: ObjectId::new(actor.actor_id()),
+      actor: actor.id().into(),
       to: vec![public()],
-      object: Box::new(community.clone().into_apub(context).await?),
-      cc: vec![community.actor_id()],
+      object: Box::new(community.clone().into_json(context).await?),
+      cc: vec![community.id()],
       kind: UpdateType::Update,
       id: id.clone(),
-      audience: Some(ObjectId::new(community.actor_id())),
+      audience: Some(community.id().into()),
     };
 
     let activity = AnnouncableActivities::UpdateCommunity(update);
@@ -70,7 +69,7 @@ impl UpdateCommunity {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for UpdateCommunity {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -84,39 +83,19 @@ impl ActivityHandler for UpdateCommunity {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
     verify_is_public(&self.to, &self.cc)?;
-    let community = self.community(context, request_counter).await?;
-    verify_person_in_community(&self.actor, &community, context, request_counter).await?;
-    verify_mod_action(
-      &self.actor,
-      self.object.id.inner(),
-      community.id,
-      context,
-      request_counter,
-    )
-    .await?;
-    ApubCommunity::verify(
-      &self.object,
-      &community.actor_id.clone().into(),
-      context,
-      request_counter,
-    )
-    .await?;
+    let community = self.community(context).await?;
+    verify_person_in_community(&self.actor, &community, context).await?;
+    verify_mod_action(&self.actor, self.object.id.inner(), community.id, context).await?;
+    ApubCommunity::verify(&self.object, &community.actor_id.clone().into(), context).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let community = self.community(context, request_counter).await?;
+  async fn receive(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, false, context).await?;
+    let community = self.community(context).await?;
 
     let community_update_form = self.object.into_update_form();
 
@@ -135,14 +114,14 @@ impl ActivityHandler for UpdateCommunity {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for HideCommunity {
   type Response = CommunityResponse;
 
   async fn send_activity(
     request: &Self,
     _response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
index 4177f71feef4efc82fe97f9190273f7460a9879e..55d5e3f0201754d4d525f3b1e29c972589a9b444 100644 (file)
@@ -8,23 +8,22 @@ use crate::{
     verify_person_in_community,
   },
   activity_lists::AnnouncableActivities,
-  local_instance,
+  insert_activity,
   mentions::MentionOrValue,
   objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson},
   protocol::{
     activities::{create_or_update::note::CreateOrUpdateNote, CreateOrUpdateType},
     InCommunity,
   },
-  ActorType,
   SendActivity,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
-  traits::{ActivityHandler, Actor, ApubObject},
-  utils::verify_domains_match,
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::public,
+  protocol::verification::verify_domains_match,
+  traits::{ActivityHandler, Actor, Object},
 };
-use activitystreams_kinds::public;
 use lemmy_api_common::{
   comment::{CommentResponse, CreateComment, EditComment},
   context::LemmyContext,
@@ -44,14 +43,14 @@ use lemmy_db_schema::{
 use lemmy_utils::error::LemmyError;
 use url::Url;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for CreateComment {
   type Response = CommentResponse;
 
   async fn send_activity(
     _request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     CreateOrUpdateNote::send(
       &response.comment_view.comment,
@@ -63,14 +62,14 @@ impl SendActivity for CreateComment {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for EditComment {
   type Response = CommentResponse;
 
   async fn send_activity(
     _request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     CreateOrUpdateNote::send(
       &response.comment_view.comment,
@@ -88,7 +87,7 @@ impl CreateOrUpdateNote {
     comment: &Comment,
     person_id: PersonId,
     kind: CreateOrUpdateType,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     // TODO: might be helpful to add a comment method to retrieve community directly
     let post_id = comment.post_id;
@@ -101,17 +100,17 @@ impl CreateOrUpdateNote {
       kind.clone(),
       &context.settings().get_protocol_and_hostname(),
     )?;
-    let note = ApubComment(comment.clone()).into_apub(context).await?;
+    let note = ApubComment(comment.clone()).into_json(context).await?;
 
     let create_or_update = CreateOrUpdateNote {
-      actor: ObjectId::new(person.actor_id()),
+      actor: person.id().into(),
       to: vec![public()],
       cc: note.cc.clone(),
       tag: note.tag.clone(),
       object: note,
       kind,
       id: id.clone(),
-      audience: Some(ObjectId::new(community.actor_id())),
+      audience: Some(community.id().into()),
     };
 
     let tagged_users: Vec<ObjectId<ApubPerson>> = create_or_update
@@ -125,13 +124,11 @@ impl CreateOrUpdateNote {
         }
       })
       .map(|t| t.href.clone())
-      .map(ObjectId::new)
+      .map(ObjectId::from)
       .collect();
     let mut inboxes = vec![];
     for t in tagged_users {
-      let person = t
-        .dereference(context, local_instance(context).await, &mut 0)
-        .await?;
+      let person = t.dereference(context).await?;
       inboxes.push(person.shared_inbox_or_inbox());
     }
 
@@ -140,7 +137,7 @@ impl CreateOrUpdateNote {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for CreateOrUpdateNote {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -154,47 +151,37 @@ impl ActivityHandler for CreateOrUpdateNote {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
     verify_is_public(&self.to, &self.cc)?;
-    let post = self.object.get_parents(context, request_counter).await?.0;
-    let community = self.community(context, request_counter).await?;
+    let post = self.object.get_parents(context).await?.0;
+    let community = self.community(context).await?;
 
-    verify_person_in_community(&self.actor, &community, context, request_counter).await?;
+    verify_person_in_community(&self.actor, &community, context).await?;
     verify_domains_match(self.actor.inner(), self.object.id.inner())?;
     check_community_deleted_or_removed(&community)?;
     check_post_deleted_or_removed(&post)?;
 
-    ApubComment::verify(&self.object, self.actor.inner(), context, request_counter).await?;
+    ApubComment::verify(&self.object, self.actor.inner(), context).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    // Need to do this check here instead of Note::from_apub because we need the person who
+  async fn receive(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, false, context).await?;
+    // Need to do this check here instead of Note::from_json because we need the person who
     // send the activity, not the comment author.
     let existing_comment = self.object.id.dereference_local(context).await.ok();
     if let (Some(distinguished), Some(existing_comment)) =
       (self.object.distinguished, existing_comment)
     {
       if distinguished != existing_comment.distinguished {
-        let creator = self
-          .actor
-          .dereference(context, local_instance(context).await, request_counter)
-          .await?;
-        let (post, _) = self.object.get_parents(context, request_counter).await?;
+        let creator = self.actor.dereference(context).await?;
+        let (post, _) = self.object.get_parents(context).await?;
         is_mod_or_admin(context.pool(), creator.id, post.community_id).await?;
       }
     }
 
-    let comment = ApubComment::from_apub(self.object, context, request_counter).await?;
+    let comment = ApubComment::from_json(self.object, context).await?;
 
     // author likes their own comment by default
     let like_form = CommentLikeForm {
@@ -206,14 +193,8 @@ impl ActivityHandler for CreateOrUpdateNote {
     CommentLike::like(context.pool(), &like_form).await?;
 
     let do_send_email = self.kind == CreateOrUpdateType::Create;
-    let recipients = get_comment_notif_recipients(
-      &self.actor,
-      &comment,
-      do_send_email,
-      context,
-      request_counter,
-    )
-    .await?;
+    let recipients =
+      get_comment_notif_recipients(&self.actor, &comment, do_send_email, context).await?;
     let notif_type = match self.kind {
       CreateOrUpdateType::Create => UserOperationCrud::CreateComment,
       CreateOrUpdateType::Update => UserOperationCrud::EditComment,
index 1f8ae79c99e472d35d482a9355e6e5e33e703572..b1fcfb6ee112f48937d35ed6693d223dac2d11dc 100644 (file)
@@ -1,5 +1,5 @@
-use crate::{local_instance, objects::person::ApubPerson};
-use activitypub_federation::core::object_id::ObjectId;
+use crate::objects::person::ApubPerson;
+use activitypub_federation::{config::Data, fetch::object_id::ObjectId};
 use lemmy_api_common::{context::LemmyContext, websocket::send::send_local_notifs};
 use lemmy_db_schema::{
   newtypes::LocalUserId,
@@ -17,14 +17,11 @@ async fn get_comment_notif_recipients(
   actor: &ObjectId<ApubPerson>,
   comment: &Comment,
   do_send_email: bool,
-  context: &LemmyContext,
-  request_counter: &mut i32,
+  context: &Data<LemmyContext>,
 ) -> Result<Vec<LocalUserId>, LemmyError> {
   let post_id = comment.post_id;
   let post = Post::read(context.pool(), post_id).await?;
-  let actor = actor
-    .dereference(context, local_instance(context).await, request_counter)
-    .await?;
+  let actor = actor.dereference(context).await?;
 
   // Note:
   // Although mentions could be gotten from the post tags (they are included there), or the ccs,
index d2e8e76c74f582049146755c0503b79bceb4e3e0..169db5eabef174136033a23efc7c86d6f04f59c1 100644 (file)
@@ -8,21 +8,20 @@ use crate::{
     verify_person_in_community,
   },
   activity_lists::AnnouncableActivities,
+  insert_activity,
   objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
   protocol::{
     activities::{create_or_update::page::CreateOrUpdatePage, CreateOrUpdateType},
     InCommunity,
   },
-  ActorType,
   SendActivity,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
-  traits::{ActivityHandler, ApubObject},
-  utils::{verify_domains_match, verify_urls_match},
+  config::Data,
+  kinds::public,
+  protocol::verification::{verify_domains_match, verify_urls_match},
+  traits::{ActivityHandler, Actor, Object},
 };
-use activitystreams_kinds::public;
 use lemmy_api_common::{
   context::LemmyContext,
   post::{CreatePost, EditPost, PostResponse},
@@ -40,14 +39,14 @@ use lemmy_db_schema::{
 use lemmy_utils::error::LemmyError;
 use url::Url;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for CreatePost {
   type Response = PostResponse;
 
   async fn send_activity(
     _request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     CreateOrUpdatePage::send(
       &response.post_view.post,
@@ -59,14 +58,14 @@ impl SendActivity for CreatePost {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for EditPost {
   type Response = PostResponse;
 
   async fn send_activity(
     _request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     CreateOrUpdatePage::send(
       &response.post_view.post,
@@ -84,20 +83,20 @@ impl CreateOrUpdatePage {
     actor: &ApubPerson,
     community: &ApubCommunity,
     kind: CreateOrUpdateType,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<CreateOrUpdatePage, LemmyError> {
     let id = generate_activity_id(
       kind.clone(),
       &context.settings().get_protocol_and_hostname(),
     )?;
     Ok(CreateOrUpdatePage {
-      actor: ObjectId::new(actor.actor_id()),
+      actor: actor.id().into(),
       to: vec![public()],
-      object: post.into_apub(context).await?,
-      cc: vec![community.actor_id()],
+      object: post.into_json(context).await?,
+      cc: vec![community.id()],
       kind,
       id: id.clone(),
-      audience: Some(ObjectId::new(community.actor_id())),
+      audience: Some(community.id().into()),
     })
   }
 
@@ -106,7 +105,7 @@ impl CreateOrUpdatePage {
     post: &Post,
     person_id: PersonId,
     kind: CreateOrUpdateType,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let post = ApubPost(post.clone());
     let community_id = post.community_id;
@@ -130,7 +129,7 @@ impl CreateOrUpdatePage {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for CreateOrUpdatePage {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -144,14 +143,10 @@ impl ActivityHandler for CreateOrUpdatePage {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn verify(&self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
     verify_is_public(&self.to, &self.cc)?;
-    let community = self.community(context, request_counter).await?;
-    verify_person_in_community(&self.actor, &community, context, request_counter).await?;
+    let community = self.community(context).await?;
+    verify_person_in_community(&self.actor, &community, context).await?;
     check_community_deleted_or_removed(&community)?;
 
     match self.kind {
@@ -173,31 +168,21 @@ impl ActivityHandler for CreateOrUpdatePage {
       CreateOrUpdateType::Update => {
         let is_mod_action = self.object.is_mod_action(context).await?;
         if is_mod_action {
-          verify_mod_action(
-            &self.actor,
-            self.object.id.inner(),
-            community.id,
-            context,
-            request_counter,
-          )
-          .await?;
+          verify_mod_action(&self.actor, self.object.id.inner(), community.id, context).await?;
         } else {
           verify_domains_match(self.actor.inner(), self.object.id.inner())?;
           verify_urls_match(self.actor.inner(), self.object.creator()?.inner())?;
         }
       }
     }
-    ApubPost::verify(&self.object, self.actor.inner(), context, request_counter).await?;
+    ApubPost::verify(&self.object, self.actor.inner(), context).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let post = ApubPost::from_apub(self.object, context, request_counter).await?;
+  async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, false, context).await?;
+    let post = ApubPost::from_json(self.object, context).await?;
 
     // author likes their own post by default
     let like_form = PostLikeForm {
index 071209c349bf1d5235ed6457590d3893fcb7b5f5..cacfc1a8dece1d76d8735d0c377ee800a66177ed 100644 (file)
@@ -1,18 +1,17 @@
 use crate::{
   activities::{generate_activity_id, send_lemmy_activity, verify_person},
+  insert_activity,
   objects::{person::ApubPerson, private_message::ApubPrivateMessage},
   protocol::activities::{
     create_or_update::chat_message::CreateOrUpdateChatMessage,
     CreateOrUpdateType,
   },
-  ActorType,
   SendActivity,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
-  traits::{ActivityHandler, Actor, ApubObject},
-  utils::verify_domains_match,
+  config::Data,
+  protocol::verification::verify_domains_match,
+  traits::{ActivityHandler, Actor, Object},
 };
 use lemmy_api_common::{
   context::LemmyContext,
@@ -27,14 +26,14 @@ use lemmy_db_schema::{
 use lemmy_utils::error::LemmyError;
 use url::Url;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for CreatePrivateMessage {
   type Response = PrivateMessageResponse;
 
   async fn send_activity(
     _request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     CreateOrUpdateChatMessage::send(
       &response.private_message_view.private_message,
@@ -45,14 +44,14 @@ impl SendActivity for CreatePrivateMessage {
     .await
   }
 }
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for EditPrivateMessage {
   type Response = PrivateMessageResponse;
 
   async fn send_activity(
     _request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     CreateOrUpdateChatMessage::send(
       &response.private_message_view.private_message,
@@ -70,7 +69,7 @@ impl CreateOrUpdateChatMessage {
     private_message: &PrivateMessage,
     sender_id: PersonId,
     kind: CreateOrUpdateType,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let recipient_id = private_message.recipient_id;
     let sender: ApubPerson = Person::read(context.pool(), sender_id).await?.into();
@@ -82,10 +81,10 @@ impl CreateOrUpdateChatMessage {
     )?;
     let create_or_update = CreateOrUpdateChatMessage {
       id: id.clone(),
-      actor: ObjectId::new(sender.actor_id()),
-      to: [ObjectId::new(recipient.actor_id())],
+      actor: sender.id().into(),
+      to: [recipient.id().into()],
       object: ApubPrivateMessage(private_message.clone())
-        .into_apub(context)
+        .into_json(context)
         .await?,
       kind,
     };
@@ -94,7 +93,7 @@ impl CreateOrUpdateChatMessage {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for CreateOrUpdateChatMessage {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -108,26 +107,18 @@ impl ActivityHandler for CreateOrUpdateChatMessage {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    verify_person(&self.actor, context, request_counter).await?;
+  async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
+    verify_person(&self.actor, context).await?;
     verify_domains_match(self.actor.inner(), self.object.id.inner())?;
     verify_domains_match(self.to[0].inner(), self.object.to[0].inner())?;
-    ApubPrivateMessage::verify(&self.object, self.actor.inner(), context, request_counter).await?;
+    ApubPrivateMessage::verify(&self.object, self.actor.inner(), context).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let private_message =
-      ApubPrivateMessage::from_apub(self.object, context, request_counter).await?;
+  async fn receive(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, true, context).await?;
+    let private_message = ApubPrivateMessage::from_json(self.object, context).await?;
 
     let notif_type = match self.kind {
       CreateOrUpdateType::Create => UserOperationCrud::CreatePrivateMessage,
index 138a1fae1788bb454eb93792fc8050beb31c3283..337ba9e8afa271c37388ec1bdd63bacbc96e194c 100644 (file)
@@ -3,12 +3,11 @@ use crate::{
     deletion::{receive_delete_action, verify_delete_activity, DeletableObjects},
     generate_activity_id,
   },
-  local_instance,
-  objects::{community::ApubCommunity, person::ApubPerson},
+  insert_activity,
+  objects::person::ApubPerson,
   protocol::{activities::deletion::delete::Delete, IdOrNestedObject},
 };
-use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
-use activitystreams_kinds::activity::DeleteType;
+use activitypub_federation::{config::Data, kinds::activity::DeleteType, traits::ActivityHandler};
 use lemmy_api_common::{
   context::LemmyContext,
   websocket::{
@@ -35,7 +34,7 @@ use lemmy_db_schema::{
 use lemmy_utils::error::LemmyError;
 use url::Url;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for Delete {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -49,21 +48,14 @@ impl ActivityHandler for Delete {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    verify_delete_activity(self, self.summary.is_some(), context, request_counter).await?;
+  async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
+    verify_delete_activity(self, self.summary.is_some(), context).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, false, context).await?;
     if let Some(reason) = self.summary {
       // We set reason to empty string if it doesn't exist, to distinguish between delete and
       // remove. Here we change it back to option, so we don't write it to db.
@@ -73,24 +65,14 @@ impl ActivityHandler for Delete {
         Some(reason)
       };
       receive_remove_action(
-        &self
-          .actor
-          .dereference(context, local_instance(context).await, request_counter)
-          .await?,
+        &self.actor.dereference(context).await?,
         self.object.id(),
         reason,
         context,
       )
       .await
     } else {
-      receive_delete_action(
-        self.object.id(),
-        &self.actor,
-        true,
-        context,
-        request_counter,
-      )
-      .await
+      receive_delete_action(self.object.id(), &self.actor, true, context).await
     }
   }
 }
@@ -102,7 +84,7 @@ impl Delete {
     to: Url,
     community: Option<&Community>,
     summary: Option<String>,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<Delete, LemmyError> {
     let id = generate_activity_id(
       DeleteType::Delete,
@@ -110,14 +92,14 @@ impl Delete {
     )?;
     let cc: Option<Url> = community.map(|c| c.actor_id.clone().into());
     Ok(Delete {
-      actor: ObjectId::new(actor.actor_id.clone()),
+      actor: actor.actor_id.clone().into(),
       to: vec![to],
       object: IdOrNestedObject::Id(object.id()),
       cc: cc.into_iter().collect(),
       kind: DeleteType::Delete,
       summary,
       id,
-      audience: community.map(|c| ObjectId::<ApubCommunity>::new(c.actor_id.clone())),
+      audience: community.map(|c| c.actor_id.clone().into()),
     })
   }
 }
@@ -127,7 +109,7 @@ pub(in crate::activities) async fn receive_remove_action(
   actor: &ApubPerson,
   object: &Url,
   reason: Option<String>,
-  context: &LemmyContext,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
   use UserOperationCrud::*;
   match DeletableObjects::read_from_db(object, context).await? {
index 4ace431e67f7d8f7679591fcfc1a1c60bb16d4ff..e5c1021ccd547a10fc2b0b3b26ab4d92d726ca99 100644 (file)
@@ -1,17 +1,16 @@
 use crate::{
   activities::{generate_activity_id, send_lemmy_activity, verify_is_public, verify_person},
-  local_instance,
+  insert_activity,
   objects::{instance::remote_instance_inboxes, person::ApubPerson},
   protocol::activities::deletion::delete_user::DeleteUser,
   SendActivity,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
-  traits::ActivityHandler,
-  utils::verify_urls_match,
+  config::Data,
+  kinds::{activity::DeleteType, public},
+  protocol::verification::verify_urls_match,
+  traits::{ActivityHandler, Actor},
 };
-use activitystreams_kinds::{activity::DeleteType, public};
 use lemmy_api_common::{
   context::LemmyContext,
   person::{DeleteAccount, DeleteAccountResponse},
@@ -20,14 +19,14 @@ use lemmy_api_common::{
 use lemmy_utils::error::LemmyError;
 use url::Url;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for DeleteAccount {
   type Response = DeleteAccountResponse;
 
   async fn send_activity(
     request: &Self,
     _response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
@@ -40,15 +39,14 @@ impl SendActivity for DeleteAccount {
     )
     .await?;
 
-    let actor_id = ObjectId::new(actor.actor_id.clone());
     let id = generate_activity_id(
       DeleteType::Delete,
       &context.settings().get_protocol_and_hostname(),
     )?;
     let delete = DeleteUser {
-      actor: actor_id.clone(),
+      actor: actor.id().into(),
       to: vec![public()],
-      object: actor_id,
+      object: actor.id().into(),
       kind: DeleteType::Delete,
       id: id.clone(),
       cc: vec![],
@@ -62,7 +60,7 @@ impl SendActivity for DeleteAccount {
 
 /// This can be separate from Delete activity because it doesn't need to be handled in shared inbox
 /// (cause instance actor doesn't have shared inbox).
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for DeleteUser {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -75,26 +73,16 @@ impl ActivityHandler for DeleteUser {
     self.actor.inner()
   }
 
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
     verify_is_public(&self.to, &[])?;
-    verify_person(&self.actor, context, request_counter).await?;
+    verify_person(&self.actor, context).await?;
     verify_urls_match(self.actor.inner(), self.object.inner())?;
     Ok(())
   }
 
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let actor = self
-      .actor
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+  async fn receive(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, false, context).await?;
+    let actor = self.actor.dereference(context).await?;
     delete_user_account(
       actor.id,
       context.pool(),
index c17dcbfc2c41be13a5253e2287339cfafa473089..7f901d596ea183479830b1455133655936787e66 100644 (file)
@@ -8,7 +8,6 @@ use crate::{
     verify_person_in_community,
   },
   activity_lists::AnnouncableActivities,
-  local_instance,
   objects::{
     comment::ApubComment,
     community::ApubCommunity,
@@ -20,15 +19,15 @@ use crate::{
     activities::deletion::{delete::Delete, undo_delete::UndoDelete},
     InCommunity,
   },
-  ActorType,
   SendActivity,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  traits::{Actor, ApubObject},
-  utils::verify_domains_match,
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::public,
+  protocol::verification::verify_domains_match,
+  traits::{Actor, Object},
 };
-use activitystreams_kinds::public;
 use lemmy_api_common::{
   comment::{CommentResponse, DeleteComment, RemoveComment},
   community::{CommunityResponse, DeleteCommunity, RemoveCommunity},
@@ -64,14 +63,14 @@ pub mod delete;
 pub mod delete_user;
 pub mod undo_delete;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for DeletePost {
   type Response = PostResponse;
 
   async fn send_activity(
     request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
@@ -89,14 +88,14 @@ impl SendActivity for DeletePost {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for RemovePost {
   type Response = PostResponse;
 
   async fn send_activity(
     request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
@@ -114,14 +113,14 @@ impl SendActivity for RemovePost {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for DeleteComment {
   type Response = CommentResponse;
 
   async fn send_activity(
     request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let community_id = response.comment_view.community.id;
     let community = Community::read(context.pool(), community_id).await?;
@@ -132,14 +131,14 @@ impl SendActivity for DeleteComment {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for RemoveComment {
   type Response = CommentResponse;
 
   async fn send_activity(
     request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
@@ -158,14 +157,14 @@ impl SendActivity for RemoveComment {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for DeletePrivateMessage {
   type Response = PrivateMessageResponse;
 
   async fn send_activity(
     request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
@@ -179,14 +178,14 @@ impl SendActivity for DeletePrivateMessage {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for DeleteCommunity {
   type Response = CommunityResponse;
 
   async fn send_activity(
     request: &Self,
     _response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
@@ -204,14 +203,14 @@ impl SendActivity for DeleteCommunity {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for RemoveCommunity {
   type Response = CommunityResponse;
 
   async fn send_activity(
     request: &Self,
     _response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
@@ -238,7 +237,7 @@ async fn send_apub_delete_in_community(
   object: DeletableObjects,
   reason: Option<String>,
   deleted: bool,
-  context: &LemmyContext,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
   let actor = ApubPerson::from(actor);
   let is_mod_action = reason.is_some();
@@ -265,7 +264,7 @@ async fn send_apub_delete_private_message(
   actor: &ApubPerson,
   pm: PrivateMessage,
   deleted: bool,
-  context: &LemmyContext,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
   let recipient_id = pm.recipient_id;
   let recipient: ApubPerson = Person::read(context.pool(), recipient_id).await?.into();
@@ -273,10 +272,10 @@ async fn send_apub_delete_private_message(
   let deletable = DeletableObjects::PrivateMessage(pm.into());
   let inbox = vec![recipient.shared_inbox_or_inbox()];
   if deleted {
-    let delete = Delete::new(actor, deletable, recipient.actor_id(), None, None, context)?;
+    let delete = Delete::new(actor, deletable, recipient.id(), None, None, context)?;
     send_lemmy_activity(context, delete, actor, inbox, true).await?;
   } else {
-    let undo = UndoDelete::new(actor, deletable, recipient.actor_id(), None, None, context)?;
+    let undo = UndoDelete::new(actor, deletable, recipient.id(), None, None, context)?;
     send_lemmy_activity(context, undo, actor, inbox, true).await?;
   };
   Ok(())
@@ -293,18 +292,18 @@ impl DeletableObjects {
   #[tracing::instrument(skip_all)]
   pub(crate) async fn read_from_db(
     ap_id: &Url,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<DeletableObjects, LemmyError> {
-    if let Some(c) = ApubCommunity::read_from_apub_id(ap_id.clone(), context).await? {
+    if let Some(c) = ApubCommunity::read_from_id(ap_id.clone(), context).await? {
       return Ok(DeletableObjects::Community(c));
     }
-    if let Some(p) = ApubPost::read_from_apub_id(ap_id.clone(), context).await? {
+    if let Some(p) = ApubPost::read_from_id(ap_id.clone(), context).await? {
       return Ok(DeletableObjects::Post(p));
     }
-    if let Some(c) = ApubComment::read_from_apub_id(ap_id.clone(), context).await? {
+    if let Some(c) = ApubComment::read_from_id(ap_id.clone(), context).await? {
       return Ok(DeletableObjects::Comment(c));
     }
-    if let Some(p) = ApubPrivateMessage::read_from_apub_id(ap_id.clone(), context).await? {
+    if let Some(p) = ApubPrivateMessage::read_from_id(ap_id.clone(), context).await? {
       return Ok(DeletableObjects::PrivateMessage(p));
     }
     Err(diesel::NotFound.into())
@@ -312,7 +311,7 @@ impl DeletableObjects {
 
   pub(crate) fn id(&self) -> Url {
     match self {
-      DeletableObjects::Community(c) => c.actor_id(),
+      DeletableObjects::Community(c) => c.id(),
       DeletableObjects::Comment(c) => c.ap_id.clone().into(),
       DeletableObjects::Post(p) => p.ap_id.clone().into(),
       DeletableObjects::PrivateMessage(p) => p.ap_id.clone().into(),
@@ -324,8 +323,7 @@ impl DeletableObjects {
 pub(in crate::activities) async fn verify_delete_activity(
   activity: &Delete,
   is_mod_action: bool,
-  context: &LemmyContext,
-  request_counter: &mut i32,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
   let object = DeletableObjects::read_from_db(activity.object.id(), context).await?;
   match object {
@@ -334,27 +332,19 @@ pub(in crate::activities) async fn verify_delete_activity(
       if community.local {
         // can only do this check for local community, in remote case it would try to fetch the
         // deleted community (which fails)
-        verify_person_in_community(&activity.actor, &community, context, request_counter).await?;
+        verify_person_in_community(&activity.actor, &community, context).await?;
       }
       // community deletion is always a mod (or admin) action
-      verify_mod_action(
-        &activity.actor,
-        activity.object.id(),
-        community.id,
-        context,
-        request_counter,
-      )
-      .await?;
+      verify_mod_action(&activity.actor, activity.object.id(), community.id, context).await?;
     }
     DeletableObjects::Post(p) => {
       verify_is_public(&activity.to, &[])?;
       verify_delete_post_or_comment(
         &activity.actor,
         &p.ap_id.clone().into(),
-        &activity.community(context, request_counter).await?,
+        &activity.community(context).await?,
         is_mod_action,
         context,
-        request_counter,
       )
       .await?;
     }
@@ -363,15 +353,14 @@ pub(in crate::activities) async fn verify_delete_activity(
       verify_delete_post_or_comment(
         &activity.actor,
         &c.ap_id.clone().into(),
-        &activity.community(context, request_counter).await?,
+        &activity.community(context).await?,
         is_mod_action,
         context,
-        request_counter,
       )
       .await?;
     }
     DeletableObjects::PrivateMessage(_) => {
-      verify_person(&activity.actor, context, request_counter).await?;
+      verify_person(&activity.actor, context).await?;
       verify_domains_match(activity.actor.inner(), activity.object.id())?;
     }
   }
@@ -384,12 +373,11 @@ async fn verify_delete_post_or_comment(
   object_id: &Url,
   community: &ApubCommunity,
   is_mod_action: bool,
-  context: &LemmyContext,
-  request_counter: &mut i32,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
-  verify_person_in_community(actor, community, context, request_counter).await?;
+  verify_person_in_community(actor, community, context).await?;
   if is_mod_action {
-    verify_mod_action(actor, object_id, community.id, context, request_counter).await?;
+    verify_mod_action(actor, object_id, community.id, context).await?;
   } else {
     // domain of post ap_id and post.creator ap_id are identical, so we just check the former
     verify_domains_match(actor.inner(), object_id)?;
@@ -403,17 +391,12 @@ async fn receive_delete_action(
   object: &Url,
   actor: &ObjectId<ApubPerson>,
   deleted: bool,
-  context: &LemmyContext,
-  request_counter: &mut i32,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
   match DeletableObjects::read_from_db(object, context).await? {
     DeletableObjects::Community(community) => {
       if community.local {
-        let mod_: Person = actor
-          .dereference(context, local_instance(context).await, request_counter)
-          .await?
-          .deref()
-          .clone();
+        let mod_: Person = actor.dereference(context).await?.deref().clone();
         let object = DeletableObjects::Community(community.clone());
         let c: Community = community.deref().deref().clone();
         send_apub_delete_in_community(mod_, c, object, None, true, context).await?;
index b3cef38580f72c2d3e82ad0e4abf2902ec0d96eb..d14018382021a28e5585e843aecd7da4caaf4b70 100644 (file)
@@ -3,12 +3,11 @@ use crate::{
     deletion::{receive_delete_action, verify_delete_activity, DeletableObjects},
     generate_activity_id,
   },
-  local_instance,
-  objects::{community::ApubCommunity, person::ApubPerson},
+  insert_activity,
+  objects::person::ApubPerson,
   protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
 };
-use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
-use activitystreams_kinds::activity::UndoType;
+use activitypub_federation::{config::Data, kinds::activity::UndoType, traits::ActivityHandler};
 use lemmy_api_common::{
   context::LemmyContext,
   websocket::{
@@ -35,7 +34,7 @@ use lemmy_db_schema::{
 use lemmy_utils::error::LemmyError;
 use url::Url;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for UndoDelete {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -48,48 +47,24 @@ impl ActivityHandler for UndoDelete {
     self.actor.inner()
   }
 
-  #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    self.object.verify(context, request_counter).await?;
-    verify_delete_activity(
-      &self.object,
-      self.object.summary.is_some(),
-      context,
-      request_counter,
-    )
-    .await?;
+  async fn verify(&self, data: &Data<Self::DataType>) -> Result<(), Self::Error> {
+    self.object.verify(data).await?;
+    verify_delete_activity(&self.object, self.object.summary.is_some(), data).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, false, context).await?;
     if self.object.summary.is_some() {
       UndoDelete::receive_undo_remove_action(
-        &self
-          .actor
-          .dereference(context, local_instance(context).await, request_counter)
-          .await?,
+        &self.actor.dereference(context).await?,
         self.object.object.id(),
         context,
       )
       .await
     } else {
-      receive_delete_action(
-        self.object.object.id(),
-        &self.actor,
-        false,
-        context,
-        request_counter,
-      )
-      .await
+      receive_delete_action(self.object.object.id(), &self.actor, false, context).await
     }
   }
 }
@@ -102,7 +77,7 @@ impl UndoDelete {
     to: Url,
     community: Option<&Community>,
     summary: Option<String>,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<UndoDelete, LemmyError> {
     let object = Delete::new(actor, object, to.clone(), community, summary, context)?;
 
@@ -112,13 +87,13 @@ impl UndoDelete {
     )?;
     let cc: Option<Url> = community.map(|c| c.actor_id.clone().into());
     Ok(UndoDelete {
-      actor: ObjectId::new(actor.actor_id.clone()),
+      actor: actor.actor_id.clone().into(),
       to: vec![to],
       object,
       cc: cc.into_iter().collect(),
       kind: UndoType::Undo,
       id,
-      audience: community.map(|c| ObjectId::<ApubCommunity>::new(c.actor_id.clone())),
+      audience: community.map(|c| c.actor_id.clone().into()),
     })
   }
 
@@ -126,7 +101,7 @@ impl UndoDelete {
   pub(in crate::activities) async fn receive_undo_remove_action(
     actor: &ApubPerson,
     object: &Url,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     use UserOperationCrud::*;
     match DeletableObjects::read_from_db(object, context).await? {
index bd3e5cad2558f3972b7d4f7bc38aa02ff3b7a606..250fbf5454df88a0afdd0d58b4433b9a6d3e94c4 100644 (file)
@@ -1,16 +1,14 @@
 use crate::{
   activities::{generate_activity_id, send_lemmy_activity},
-  local_instance,
+  insert_activity,
   protocol::activities::following::{accept::AcceptFollow, follow::Follow},
-  ActorType,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
+  config::Data,
+  kinds::activity::AcceptType,
+  protocol::verification::verify_urls_match,
   traits::{ActivityHandler, Actor},
-  utils::verify_urls_match,
 };
-use activitystreams_kinds::activity::AcceptType;
 use lemmy_api_common::{
   community::CommunityResponse,
   context::LemmyContext,
@@ -27,19 +25,11 @@ use url::Url;
 
 impl AcceptFollow {
   #[tracing::instrument(skip_all)]
-  pub async fn send(
-    follow: Follow,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  pub async fn send(follow: Follow, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
     let user_or_community = follow.object.dereference_local(context).await?;
-    let person = follow
-      .actor
-      .clone()
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+    let person = follow.actor.clone().dereference(context).await?;
     let accept = AcceptFollow {
-      actor: ObjectId::new(user_or_community.actor_id()),
+      actor: user_or_community.id().into(),
       object: follow,
       kind: AcceptType::Accept,
       id: generate_activity_id(
@@ -53,7 +43,7 @@ impl AcceptFollow {
 }
 
 /// Handle accepted follows
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for AcceptFollow {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -67,31 +57,17 @@ impl ActivityHandler for AcceptFollow {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn verify(&self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
     verify_urls_match(self.actor.inner(), self.object.object.inner())?;
-    self.object.verify(context, request_counter).await?;
+    self.object.verify(context).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let community = self
-      .actor
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
-    let person = self
-      .object
-      .actor
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+  async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, true, context).await?;
+    let community = self.actor.dereference(context).await?;
+    let person = self.object.actor.dereference(context).await?;
     // This will throw an error if no follow was requested
     let community_id = community.id;
     let person_id = person.id;
index 62bd24157f4c6e92aed9b684b3b458ed00b9025c..41d2e71ed7beffa4d29ce1eaa6792df30e4c5147 100644 (file)
@@ -6,22 +6,20 @@ use crate::{
     verify_person_in_community,
   },
   fetcher::user_or_community::UserOrCommunity,
-  local_instance,
+  insert_activity,
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::activities::following::{
     accept::AcceptFollow,
     follow::Follow,
     undo_follow::UndoFollow,
   },
-  ActorType,
   SendActivity,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
+  config::Data,
+  kinds::activity::FollowType,
   traits::{ActivityHandler, Actor},
 };
-use activitystreams_kinds::activity::FollowType;
 use lemmy_api_common::{
   community::{BlockCommunity, BlockCommunityResponse},
   context::LemmyContext,
@@ -41,11 +39,11 @@ impl Follow {
   pub(in crate::activities::following) fn new(
     actor: &ApubPerson,
     community: &ApubCommunity,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<Follow, LemmyError> {
     Ok(Follow {
-      actor: ObjectId::new(actor.actor_id()),
-      object: ObjectId::new(community.actor_id()),
+      actor: actor.id().into(),
+      object: community.id().into(),
       kind: FollowType::Follow,
       id: generate_activity_id(
         FollowType::Follow,
@@ -58,7 +56,7 @@ impl Follow {
   pub async fn send(
     actor: &ApubPerson,
     community: &ApubCommunity,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let community_follower_form = CommunityFollowerForm {
       community_id: community.id,
@@ -75,7 +73,7 @@ impl Follow {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for Follow {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -89,36 +87,20 @@ impl ActivityHandler for Follow {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    verify_person(&self.actor, context, request_counter).await?;
-    let object = self
-      .object
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+  async fn verify(&self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
+    verify_person(&self.actor, context).await?;
+    let object = self.object.dereference(context).await?;
     if let UserOrCommunity::Community(c) = object {
-      verify_person_in_community(&self.actor, &c, context, request_counter).await?;
+      verify_person_in_community(&self.actor, &c, context).await?;
     }
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let actor = self
-      .actor
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
-    let object = self
-      .object
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+  async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, true, context).await?;
+    let actor = self.actor.dereference(context).await?;
+    let object = self.object.dereference(context).await?;
     match object {
       UserOrCommunity::User(u) => {
         let form = PersonFollowerForm {
@@ -138,18 +120,18 @@ impl ActivityHandler for Follow {
       }
     }
 
-    AcceptFollow::send(self, context, request_counter).await
+    AcceptFollow::send(self, context).await
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for BlockCommunity {
   type Response = BlockCommunityResponse;
 
   async fn send_activity(
     request: &Self,
     _response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
index e472dc73a1dd3e9f1339717208c1915cf23270e1..5b9d98b42437d07c37025940e4e5f951bc7755d5 100644 (file)
@@ -3,6 +3,7 @@ use crate::{
   protocol::activities::following::{follow::Follow, undo_follow::UndoFollow},
   SendActivity,
 };
+use activitypub_federation::config::Data;
 use lemmy_api_common::{
   community::{CommunityResponse, FollowCommunity},
   context::LemmyContext,
@@ -15,14 +16,14 @@ pub mod accept;
 pub mod follow;
 pub mod undo_follow;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for FollowCommunity {
   type Response = CommunityResponse;
 
   async fn send_activity(
     request: &Self,
     _response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let local_user_view =
       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
index 436d8a02e84711f7f5f162406bb8dde7e03a27d6..9f1b89dc1a4f9f6c2ad6d7e0027dc72560560974 100644 (file)
@@ -1,18 +1,16 @@
 use crate::{
   activities::{generate_activity_id, send_lemmy_activity, verify_person},
   fetcher::user_or_community::UserOrCommunity,
-  local_instance,
+  insert_activity,
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::activities::following::{follow::Follow, undo_follow::UndoFollow},
-  ActorType,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
+  config::Data,
+  kinds::activity::UndoType,
+  protocol::verification::verify_urls_match,
   traits::{ActivityHandler, Actor},
-  utils::verify_urls_match,
 };
-use activitystreams_kinds::activity::UndoType;
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::{
   source::{
@@ -29,11 +27,11 @@ impl UndoFollow {
   pub async fn send(
     actor: &ApubPerson,
     community: &ApubCommunity,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     let object = Follow::new(actor, community, context)?;
     let undo = UndoFollow {
-      actor: ObjectId::new(actor.actor_id()),
+      actor: actor.id().into(),
       object,
       kind: UndoType::Undo,
       id: generate_activity_id(
@@ -46,7 +44,7 @@ impl UndoFollow {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for UndoFollow {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -60,32 +58,18 @@ impl ActivityHandler for UndoFollow {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
+  async fn verify(&self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
     verify_urls_match(self.actor.inner(), self.object.actor.inner())?;
-    verify_person(&self.actor, context, request_counter).await?;
-    self.object.verify(context, request_counter).await?;
+    verify_person(&self.actor, context).await?;
+    self.object.verify(context).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let person = self
-      .actor
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
-    let object = self
-      .object
-      .object
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+  async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, true, context).await?;
+    let person = self.actor.dereference(context).await?;
+    let object = self.object.object.dereference(context).await?;
 
     match object {
       UserOrCommunity::User(u) => {
index 2896959fc60654e31898094b0564e67fc5e9b8de..4b50c5c835818f3bac937fbb7ed61b2f406a1ba2 100644 (file)
@@ -1,22 +1,19 @@
 use crate::{
   insert_activity,
-  local_instance,
   objects::{community::ApubCommunity, person::ApubPerson},
-  ActorType,
   CONTEXT,
 };
 use activitypub_federation::{
-  core::{activity_queue::send_activity, object_id::ObjectId},
-  deser::context::WithContext,
+  activity_queue::send_activity,
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::public,
+  protocol::context::WithContext,
   traits::{ActivityHandler, Actor},
 };
-use activitystreams_kinds::public;
 use anyhow::anyhow;
 use lemmy_api_common::context::LemmyContext;
-use lemmy_db_schema::{
-  newtypes::CommunityId,
-  source::{community::Community, local_site::LocalSite},
-};
+use lemmy_db_schema::{newtypes::CommunityId, source::community::Community};
 use lemmy_db_views_actor::structs::{CommunityPersonBanView, CommunityView};
 use lemmy_utils::error::LemmyError;
 use serde::Serialize;
@@ -38,12 +35,9 @@ pub mod voting;
 #[tracing::instrument(skip_all)]
 async fn verify_person(
   person_id: &ObjectId<ApubPerson>,
-  context: &LemmyContext,
-  request_counter: &mut i32,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
-  let person = person_id
-    .dereference(context, local_instance(context).await, request_counter)
-    .await?;
+  let person = person_id.dereference(context).await?;
   if person.banned {
     let err = anyhow!("Person {} is banned", person_id);
     return Err(LemmyError::from_error_message(err, "banned"));
@@ -57,12 +51,9 @@ async fn verify_person(
 pub(crate) async fn verify_person_in_community(
   person_id: &ObjectId<ApubPerson>,
   community: &ApubCommunity,
-  context: &LemmyContext,
-  request_counter: &mut i32,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
-  let person = person_id
-    .dereference(context, local_instance(context).await, request_counter)
-    .await?;
+  let person = person_id.dereference(context).await?;
   if person.banned {
     return Err(LemmyError::from_message("Person is banned from site"));
   }
@@ -88,12 +79,9 @@ pub(crate) async fn verify_mod_action(
   mod_id: &ObjectId<ApubPerson>,
   object_id: &Url,
   community_id: CommunityId,
-  context: &LemmyContext,
-  request_counter: &mut i32,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
-  let mod_ = mod_id
-    .dereference(context, local_instance(context).await, request_counter)
-    .await?;
+  let mod_ = mod_id.dereference(context).await?;
 
   let is_mod_or_admin =
     CommunityView::is_mod_or_admin(context.pool(), mod_.id, community_id).await?;
@@ -159,39 +147,22 @@ where
 
 #[tracing::instrument(skip_all)]
 async fn send_lemmy_activity<Activity, ActorT>(
-  context: &LemmyContext,
+  data: &Data<LemmyContext>,
   activity: Activity,
   actor: &ActorT,
   inbox: Vec<Url>,
   sensitive: bool,
 ) -> Result<(), LemmyError>
 where
-  Activity: ActivityHandler + Serialize,
-  ActorT: Actor + ActorType,
+  Activity: ActivityHandler + Serialize + Send + Sync + Clone,
+  ActorT: Actor,
   Activity: ActivityHandler<Error = LemmyError>,
 {
-  let federation_enabled = LocalSite::read(context.pool())
-    .await
-    .map(|l| l.federation_enabled)
-    .unwrap_or(false);
-  if !federation_enabled {
-    return Ok(());
-  }
-
   info!("Sending activity {}", activity.id().to_string());
   let activity = WithContext::new(activity, CONTEXT.deref().clone());
 
-  let object_value = serde_json::to_value(&activity)?;
-  insert_activity(activity.id(), object_value, true, sensitive, context.pool()).await?;
-
-  send_activity(
-    activity,
-    actor.get_public_key(),
-    actor.private_key().expect("actor has private key"),
-    inbox,
-    local_instance(context).await,
-  )
-  .await?;
+  insert_activity(activity.id(), &activity, true, sensitive, data).await?;
+  send_activity(activity, actor, inbox, data).await?;
 
   Ok(())
 }
index 4471fbd920922cae848e80ded5b618c243c78a88..5ab31da5551c6d057c488ef4ad2b29f133fb1714 100644 (file)
@@ -9,7 +9,7 @@ use crate::{
   },
   SendActivity,
 };
-use activitypub_federation::core::object_id::ObjectId;
+use activitypub_federation::{config::Data, fetch::object_id::ObjectId};
 use lemmy_api_common::{
   comment::{CommentResponse, CreateCommentLike},
   context::LemmyContext,
@@ -36,16 +36,16 @@ use lemmy_utils::error::LemmyError;
 pub mod undo_vote;
 pub mod vote;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for CreatePostLike {
   type Response = PostResponse;
 
   async fn send_activity(
     request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
-    let object_id = ObjectId::new(response.post_view.post.ap_id.clone());
+    let object_id = ObjectId::from(response.post_view.post.ap_id.clone());
     let community_id = response.post_view.community.id;
     send_activity(
       object_id,
@@ -58,16 +58,16 @@ impl SendActivity for CreatePostLike {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl SendActivity for CreateCommentLike {
   type Response = CommentResponse;
 
   async fn send_activity(
     request: &Self,
     response: &Self::Response,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
-    let object_id = ObjectId::new(response.comment_view.comment.ap_id.clone());
+    let object_id = ObjectId::from(response.comment_view.comment.ap_id.clone());
     let community_id = response.comment_view.community.id;
     send_activity(
       object_id,
@@ -85,7 +85,7 @@ async fn send_activity(
   community_id: CommunityId,
   score: i16,
   jwt: &Sensitive<String>,
-  context: &LemmyContext,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
   let community = Community::read(context.pool(), community_id).await?.into();
   let local_user_view = get_local_user_view_from_jwt(jwt, context.pool(), context.secret()).await?;
@@ -112,7 +112,7 @@ async fn vote_comment(
   vote_type: &VoteType,
   actor: ApubPerson,
   comment: &ApubComment,
-  context: &LemmyContext,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
   let comment_id = comment.id;
   let like_form = CommentLikeForm {
@@ -134,7 +134,7 @@ async fn vote_post(
   vote_type: &VoteType,
   actor: ApubPerson,
   post: &ApubPost,
-  context: &LemmyContext,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
   let post_id = post.id;
   let like_form = PostLikeForm {
@@ -154,7 +154,7 @@ async fn vote_post(
 async fn undo_vote_comment(
   actor: ApubPerson,
   comment: &ApubComment,
-  context: &LemmyContext,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
   let comment_id = comment.id;
   let person_id = actor.id;
@@ -168,7 +168,7 @@ async fn undo_vote_comment(
 async fn undo_vote_post(
   actor: ApubPerson,
   post: &ApubPost,
-  context: &LemmyContext,
+  context: &Data<LemmyContext>,
 ) -> Result<(), LemmyError> {
   let post_id = post.id;
   let person_id = actor.id;
index 7a419e879b388bc61b6be26af84cd6d1ca6aeded..bcb8ee4068241c22083291feb6d9b2958de0cc37 100644 (file)
@@ -4,22 +4,20 @@ use crate::{
     verify_person_in_community,
     voting::{undo_vote_comment, undo_vote_post},
   },
-  local_instance,
+  insert_activity,
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::{
     activities::voting::{undo_vote::UndoVote, vote::Vote},
     InCommunity,
   },
-  ActorType,
   PostOrComment,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
-  traits::ActivityHandler,
-  utils::verify_urls_match,
+  config::Data,
+  kinds::activity::UndoType,
+  protocol::verification::verify_urls_match,
+  traits::{ActivityHandler, Actor},
 };
-use activitystreams_kinds::activity::UndoType;
 use lemmy_api_common::context::LemmyContext;
 use lemmy_utils::error::LemmyError;
 use url::Url;
@@ -29,22 +27,22 @@ impl UndoVote {
     vote: Vote,
     actor: &ApubPerson,
     community: &ApubCommunity,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<Self, LemmyError> {
     Ok(UndoVote {
-      actor: ObjectId::new(actor.actor_id()),
+      actor: actor.id().into(),
       object: vote,
       kind: UndoType::Undo,
       id: generate_activity_id(
         UndoType::Undo,
         &context.settings().get_protocol_and_hostname(),
       )?,
-      audience: Some(ObjectId::new(community.actor_id())),
+      audience: Some(community.id().into()),
     })
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for UndoVote {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -58,33 +56,19 @@ impl ActivityHandler for UndoVote {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let community = self.community(context, request_counter).await?;
-    verify_person_in_community(&self.actor, &community, context, request_counter).await?;
+  async fn verify(&self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
+    let community = self.community(context).await?;
+    verify_person_in_community(&self.actor, &community, context).await?;
     verify_urls_match(self.actor.inner(), self.object.actor.inner())?;
-    self.object.verify(context, request_counter).await?;
+    self.object.verify(context).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let actor = self
-      .actor
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
-    let object = self
-      .object
-      .object
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+  async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, true, context).await?;
+    let actor = self.actor.dereference(context).await?;
+    let object = self.object.object.dereference(context).await?;
     match object {
       PostOrComment::Post(p) => undo_vote_post(actor, &p, context).await,
       PostOrComment::Comment(c) => undo_vote_comment(actor, &c, context).await,
index e435b682350f5ad1ca2dcbb38888c447a62aa477..7f36ed4710c722ae6dc9489365a45827ff12dc9d 100644 (file)
@@ -4,16 +4,19 @@ use crate::{
     verify_person_in_community,
     voting::{vote_comment, vote_post},
   },
-  local_instance,
+  insert_activity,
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::{
     activities::voting::vote::{Vote, VoteType},
     InCommunity,
   },
-  ActorType,
   PostOrComment,
 };
-use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
+use activitypub_federation::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  traits::{ActivityHandler, Actor},
+};
 use anyhow::anyhow;
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::source::local_site::LocalSite;
@@ -26,19 +29,19 @@ impl Vote {
     actor: &ApubPerson,
     community: &ApubCommunity,
     kind: VoteType,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> Result<Vote, LemmyError> {
     Ok(Vote {
-      actor: ObjectId::new(actor.actor_id()),
+      actor: actor.id().into(),
       object: object_id,
       kind: kind.clone(),
       id: generate_activity_id(kind, &context.settings().get_protocol_and_hostname())?,
-      audience: Some(ObjectId::new(community.actor_id())),
+      audience: Some(community.id().into()),
     })
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for Vote {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -52,13 +55,9 @@ impl ActivityHandler for Vote {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn verify(
-    &self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let community = self.community(context, request_counter).await?;
-    verify_person_in_community(&self.actor, &community, context, request_counter).await?;
+  async fn verify(&self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
+    let community = self.community(context).await?;
+    verify_person_in_community(&self.actor, &community, context).await?;
     let enable_downvotes = LocalSite::read(context.pool())
       .await
       .map(|l| l.enable_downvotes)
@@ -70,19 +69,10 @@ impl ActivityHandler for Vote {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn receive(
-    self,
-    context: &Data<LemmyContext>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let actor = self
-      .actor
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
-    let object = self
-      .object
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+  async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
+    insert_activity(&self.id, &self, false, true, context).await?;
+    let actor = self.actor.dereference(context).await?;
+    let object = self.object.dereference(context).await?;
     match object {
       PostOrComment::Post(p) => vote_post(&self.kind, actor, &p, context).await,
       PostOrComment::Comment(c) => vote_comment(&self.kind, actor, &c, context).await,
index 70ae1bb8ff4c0fc47e4ba8ef5a07e0d3dbf47ddc..705849552263077a3c56abec3f5c3ebdbff2fbf5 100644 (file)
@@ -24,7 +24,11 @@ use crate::{
     InCommunity,
   },
 };
-use activitypub_federation::{data::Data, deser::context::WithContext, traits::ActivityHandler};
+use activitypub_federation::{
+  config::Data,
+  protocol::context::WithContext,
+  traits::ActivityHandler,
+};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_utils::error::LemmyError;
 use serde::{Deserialize, Serialize};
@@ -104,29 +108,25 @@ pub enum SiteInboxActivities {
   DeleteUser(DeleteUser),
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for AnnouncableActivities {
   #[tracing::instrument(skip(self, context))]
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
     use AnnouncableActivities::*;
     match self {
-      CreateOrUpdateComment(a) => a.community(context, request_counter).await,
-      CreateOrUpdatePost(a) => a.community(context, request_counter).await,
-      Vote(a) => a.community(context, request_counter).await,
-      UndoVote(a) => a.community(context, request_counter).await,
-      Delete(a) => a.community(context, request_counter).await,
-      UndoDelete(a) => a.community(context, request_counter).await,
-      UpdateCommunity(a) => a.community(context, request_counter).await,
-      BlockUser(a) => a.community(context, request_counter).await,
-      UndoBlockUser(a) => a.community(context, request_counter).await,
-      CollectionAdd(a) => a.community(context, request_counter).await,
-      CollectionRemove(a) => a.community(context, request_counter).await,
-      LockPost(a) => a.community(context, request_counter).await,
-      UndoLockPost(a) => a.community(context, request_counter).await,
+      CreateOrUpdateComment(a) => a.community(context).await,
+      CreateOrUpdatePost(a) => a.community(context).await,
+      Vote(a) => a.community(context).await,
+      UndoVote(a) => a.community(context).await,
+      Delete(a) => a.community(context).await,
+      UndoDelete(a) => a.community(context).await,
+      UpdateCommunity(a) => a.community(context).await,
+      BlockUser(a) => a.community(context).await,
+      UndoBlockUser(a) => a.community(context).await,
+      CollectionAdd(a) => a.community(context).await,
+      CollectionRemove(a) => a.community(context).await,
+      LockPost(a) => a.community(context).await,
+      UndoLockPost(a) => a.community(context).await,
       Page(_) => unimplemented!(),
     }
   }
index 3d44baf0e9552e4b50e7ae3b0ec3dcc6d4457e36..48ba0ffe98dec36d31e8313cabca7bc3a94e9e27 100644 (file)
@@ -3,7 +3,7 @@ use crate::{
   fetcher::resolve_actor_identifier,
   objects::community::ApubCommunity,
 };
-use actix_web::web::Data;
+use activitypub_federation::config::Data;
 use lemmy_api_common::{
   comment::{GetComments, GetCommentsResponse},
   context::LemmyContext,
@@ -20,7 +20,7 @@ use lemmy_db_schema::{
 use lemmy_db_views::comment_view::CommentQuery;
 use lemmy_utils::{error::LemmyError, ConnectionId};
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl PerformApub for GetComments {
   type Response = GetCommentsResponse;
 
@@ -41,10 +41,10 @@ impl PerformApub for GetComments {
     let listing_type = listing_type_with_site_default(data.type_, &local_site)?;
 
     let community_actor_id = if let Some(name) = &data.community_name {
-      resolve_actor_identifier::<ApubCommunity, Community>(name, context, true)
+      resolve_actor_identifier::<ApubCommunity, Community>(name, context, &None, true)
         .await
         .ok()
-        .map(|c| c.actor_id)
+        .map(|c| c.actor_id.clone())
     } else {
       None
     };
index 2908c4ba76853e9d42221b9ce18f28d6fd67bba3..b1cfa14d4ac253fcff614cf96cd10e78aa838a5a 100644 (file)
@@ -3,7 +3,7 @@ use crate::{
   fetcher::resolve_actor_identifier,
   objects::community::ApubCommunity,
 };
-use actix_web::web::Data;
+use activitypub_federation::config::Data;
 use lemmy_api_common::{
   context::LemmyContext,
   post::{GetPosts, GetPostsResponse},
@@ -18,7 +18,7 @@ use lemmy_db_schema::source::{community::Community, local_site::LocalSite};
 use lemmy_db_views::post_view::PostQuery;
 use lemmy_utils::{error::LemmyError, ConnectionId};
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl PerformApub for GetPosts {
   type Response = GetPostsResponse;
 
@@ -43,10 +43,10 @@ impl PerformApub for GetPosts {
     let limit = data.limit;
     let community_id = data.community_id;
     let community_actor_id = if let Some(name) = &data.community_name {
-      resolve_actor_identifier::<ApubCommunity, Community>(name, context, true)
+      resolve_actor_identifier::<ApubCommunity, Community>(name, context, &None, true)
         .await
         .ok()
-        .map(|c| c.actor_id)
+        .map(|c| c.actor_id.clone())
     } else {
       None
     };
index 233f72f0220ab74a1ad8241b1e7638cd751f039f..8906f3247440d21ab587869633c7f1e8370220ea 100644 (file)
@@ -1,4 +1,4 @@
-use actix_web::web::Data;
+use activitypub_federation::config::Data;
 use lemmy_api_common::context::LemmyContext;
 use lemmy_utils::{error::LemmyError, ConnectionId};
 
@@ -9,7 +9,7 @@ mod read_person;
 mod resolve_object;
 mod search;
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 pub trait PerformApub {
   type Response: serde::ser::Serialize + Send;
 
index 738c8a3f1370e25f476e8984d6e5e3857f8f3a72..ee62275daf912cd855fac476ad3b48d10d81055c 100644 (file)
@@ -3,7 +3,7 @@ use crate::{
   fetcher::resolve_actor_identifier,
   objects::community::ApubCommunity,
 };
-use actix_web::web::Data;
+use activitypub_federation::config::Data;
 use lemmy_api_common::{
   community::{GetCommunity, GetCommunityResponse},
   context::LemmyContext,
@@ -21,7 +21,7 @@ use lemmy_db_schema::{
 use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
 use lemmy_utils::{error::LemmyError, ConnectionId};
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl PerformApub for GetCommunity {
   type Response = GetCommunityResponse;
 
@@ -49,7 +49,7 @@ impl PerformApub for GetCommunity {
       Some(id) => id,
       None => {
         let name = data.name.clone().unwrap_or_else(|| "main".to_string());
-        resolve_actor_identifier::<ApubCommunity, Community>(&name, context, true)
+        resolve_actor_identifier::<ApubCommunity, Community>(&name, context, &local_user_view, true)
           .await
           .map_err(|e| e.with_message("couldnt_find_community"))?
           .id
index a3a5f943d96cd91ec28db194e4b2b62fd4dbdb2e..95d9ecc08b4b1fb9e4fb010db2bf35534adb90fb 100644 (file)
@@ -1,5 +1,5 @@
 use crate::{api::PerformApub, fetcher::resolve_actor_identifier, objects::person::ApubPerson};
-use actix_web::web::Data;
+use activitypub_federation::config::Data;
 use lemmy_api_common::{
   context::LemmyContext,
   person::{GetPersonDetails, GetPersonDetailsResponse},
@@ -13,7 +13,7 @@ use lemmy_db_views::{comment_view::CommentQuery, post_view::PostQuery};
 use lemmy_db_views_actor::structs::{CommunityModeratorView, PersonView};
 use lemmy_utils::{error::LemmyError, ConnectionId};
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl PerformApub for GetPersonDetails {
   type Response = GetPersonDetailsResponse;
 
@@ -42,7 +42,7 @@ impl PerformApub for GetPersonDetails {
       Some(id) => id,
       None => {
         if let Some(username) = &data.username {
-          resolve_actor_identifier::<ApubPerson, Person>(username, context, true)
+          resolve_actor_identifier::<ApubPerson, Person>(username, context, &local_user_view, true)
             .await
             .map_err(|e| e.with_message("couldnt_find_that_username_or_email"))?
             .id
index cd5ee47c0afe1c73bb334a00437a02e83ce67911..f0cb15e36e6929a21c7c87161e4bd8317f53733f 100644 (file)
@@ -2,19 +2,19 @@ use crate::{
   api::PerformApub,
   fetcher::search::{search_query_to_object_id, SearchableObjects},
 };
-use actix_web::web::Data;
+use activitypub_federation::config::Data;
 use diesel::NotFound;
 use lemmy_api_common::{
   context::LemmyContext,
   site::{ResolveObject, ResolveObjectResponse},
-  utils::{check_private_instance, get_local_user_view_from_jwt_opt},
+  utils::{check_private_instance, get_local_user_view_from_jwt},
 };
 use lemmy_db_schema::{newtypes::PersonId, source::local_site::LocalSite, utils::DbPool};
 use lemmy_db_views::structs::{CommentView, PostView};
 use lemmy_db_views_actor::structs::{CommunityView, PersonView};
 use lemmy_utils::{error::LemmyError, ConnectionId};
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl PerformApub for ResolveObject {
   type Response = ResolveObjectResponse;
 
@@ -25,17 +25,15 @@ impl PerformApub for ResolveObject {
     _websocket_id: Option<ConnectionId>,
   ) -> Result<ResolveObjectResponse, LemmyError> {
     let local_user_view =
-      get_local_user_view_from_jwt_opt(self.auth.as_ref(), context.pool(), context.secret())
-        .await?;
+      get_local_user_view_from_jwt(&self.auth, context.pool(), context.secret()).await?;
     let local_site = LocalSite::read(context.pool()).await?;
-    check_private_instance(&local_user_view, &local_site)?;
+    let person_id = local_user_view.person.id;
+    check_private_instance(&Some(local_user_view), &local_site)?;
 
-    // In release builds only allow for authenticated users to fetch remote objects
-    let local_only = local_user_view.is_none() && cfg!(not(debug_assertions));
-    let res = search_query_to_object_id(&self.q, local_only, context)
+    let res = search_query_to_object_id(&self.q, context)
       .await
       .map_err(|e| e.with_message("couldnt_find_object"))?;
-    convert_response(res, local_user_view.map(|l| l.person.id), context.pool())
+    convert_response(res, person_id, context.pool())
       .await
       .map_err(|e| e.with_message("couldnt_find_object"))
   }
@@ -43,7 +41,7 @@ impl PerformApub for ResolveObject {
 
 async fn convert_response(
   object: SearchableObjects,
-  user_id: Option<PersonId>,
+  user_id: PersonId,
   pool: &DbPool,
 ) -> Result<ResolveObjectResponse, LemmyError> {
   use SearchableObjects::*;
@@ -56,15 +54,15 @@ async fn convert_response(
     }
     Community(c) => {
       removed_or_deleted = c.deleted || c.removed;
-      res.community = Some(CommunityView::read(pool, c.id, user_id, None).await?)
+      res.community = Some(CommunityView::read(pool, c.id, Some(user_id), None).await?)
     }
     Post(p) => {
       removed_or_deleted = p.deleted || p.removed;
-      res.post = Some(PostView::read(pool, p.id, user_id, None).await?)
+      res.post = Some(PostView::read(pool, p.id, Some(user_id), None).await?)
     }
     Comment(c) => {
       removed_or_deleted = c.deleted || c.removed;
-      res.comment = Some(CommentView::read(pool, c.id, user_id).await?)
+      res.comment = Some(CommentView::read(pool, c.id, Some(user_id)).await?)
     }
   };
   // if the object was deleted from database, dont return it
index dee8c8027bb36862d7f5c40b3abab8986f0f83fd..f02017ad798e8cfd6e46bf72bf8a3948f96dc49e 100644 (file)
@@ -3,7 +3,7 @@ use crate::{
   fetcher::resolve_actor_identifier,
   objects::community::ApubCommunity,
 };
-use actix_web::web::Data;
+use activitypub_federation::config::Data;
 use lemmy_api_common::{
   context::LemmyContext,
   site::{Search, SearchResponse},
@@ -18,7 +18,7 @@ use lemmy_db_views::{comment_view::CommentQuery, post_view::PostQuery};
 use lemmy_db_views_actor::{community_view::CommunityQuery, person_view::PersonQuery};
 use lemmy_utils::{error::LemmyError, ConnectionId};
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl PerformApub for Search {
   type Response = SearchResponse;
 
@@ -39,8 +39,6 @@ impl PerformApub for Search {
 
     let is_admin = local_user_view.as_ref().map(|luv| is_admin(luv).is_ok());
 
-    let local_user = local_user_view.map(|l| l.local_user);
-
     let mut posts = Vec::new();
     let mut comments = Vec::new();
     let mut communities = Vec::new();
@@ -56,14 +54,15 @@ impl PerformApub for Search {
     let search_type = data.type_.unwrap_or(SearchType::All);
     let community_id = data.community_id;
     let community_actor_id = if let Some(name) = &data.community_name {
-      resolve_actor_identifier::<ApubCommunity, Community>(name, context, false)
+      resolve_actor_identifier::<ApubCommunity, Community>(name, context, &local_user_view, false)
         .await
         .ok()
-        .map(|c| c.actor_id)
+        .map(|c| c.actor_id.clone())
     } else {
       None
     };
     let creator_id = data.creator_id;
+    let local_user = local_user_view.map(|l| l.local_user);
     match search_type {
       SearchType::Posts => {
         posts = PostQuery::builder()
index 91abd43b4f83451295584fae39166c3614d08444..0743a9fbd26d7c976f4e4fd908cd27d7ec43828e 100644 (file)
@@ -1,16 +1,15 @@
 use crate::{
-  collections::CommunityContext,
-  objects::post::ApubPost,
+  objects::{community::ApubCommunity, post::ApubPost},
   protocol::collections::group_featured::GroupFeatured,
 };
 use activitypub_federation::{
-  data::Data,
-  traits::{ActivityHandler, ApubObject},
-  utils::verify_domains_match,
+  config::Data,
+  kinds::collection::OrderedCollectionType,
+  protocol::verification::verify_domains_match,
+  traits::{ActivityHandler, Collection, Object},
 };
-use activitystreams_kinds::collection::OrderedCollectionType;
 use futures::future::{join_all, try_join_all};
-use lemmy_api_common::utils::generate_featured_url;
+use lemmy_api_common::{context::LemmyContext, utils::generate_featured_url};
 use lemmy_db_schema::{source::post::Post, utils::FETCH_LIMIT_MAX};
 use lemmy_utils::error::LemmyError;
 use url::Url;
@@ -18,58 +17,46 @@ use url::Url;
 #[derive(Clone, Debug)]
 pub(crate) struct ApubCommunityFeatured(Vec<ApubPost>);
 
-#[async_trait::async_trait(?Send)]
-impl ApubObject for ApubCommunityFeatured {
-  type DataType = CommunityContext;
-  type ApubType = GroupFeatured;
-  type DbType = ();
+#[async_trait::async_trait]
+impl Collection for ApubCommunityFeatured {
+  type Owner = ApubCommunity;
+  type DataType = LemmyContext;
+  type Kind = GroupFeatured;
   type Error = LemmyError;
 
-  async fn read_from_apub_id(
-    _object_id: Url,
-    data: &Self::DataType,
-  ) -> Result<Option<Self>, Self::Error>
-  where
-    Self: Sized,
-  {
-    // Only read from database if its a local community, otherwise fetch over http
-    if data.0.local {
-      let community_id = data.0.id;
-      let post_list: Vec<ApubPost> = Post::list_featured_for_community(data.1.pool(), community_id)
+  async fn read_local(
+    owner: &Self::Owner,
+    data: &Data<Self::DataType>,
+  ) -> Result<Self::Kind, Self::Error> {
+    let ordered_items = try_join_all(
+      Post::list_featured_for_community(data.pool(), owner.id)
         .await?
         .into_iter()
-        .map(Into::into)
-        .collect();
-      Ok(Some(ApubCommunityFeatured(post_list)))
-    } else {
-      Ok(None)
-    }
-  }
-
-  async fn into_apub(self, data: &Self::DataType) -> Result<Self::ApubType, Self::Error> {
-    let ordered_items = try_join_all(self.0.into_iter().map(|p| p.into_apub(&data.1))).await?;
+        .map(ApubPost::from)
+        .map(|p| p.into_json(data)),
+    )
+    .await?;
     Ok(GroupFeatured {
       r#type: OrderedCollectionType::OrderedCollection,
-      id: generate_featured_url(&data.0.actor_id)?.into(),
+      id: generate_featured_url(&owner.actor_id)?.into(),
       total_items: ordered_items.len() as i32,
       ordered_items,
     })
   }
 
   async fn verify(
-    apub: &Self::ApubType,
+    apub: &Self::Kind,
     expected_domain: &Url,
-    _data: &Self::DataType,
-    _request_counter: &mut i32,
+    _data: &Data<Self::DataType>,
   ) -> Result<(), Self::Error> {
     verify_domains_match(expected_domain, &apub.id)?;
     Ok(())
   }
 
-  async fn from_apub(
-    apub: Self::ApubType,
-    data: &Self::DataType,
-    _request_counter: &mut i32,
+  async fn from_json(
+    apub: Self::Kind,
+    _owner: &Self::Owner,
+    data: &Data<Self::DataType>,
   ) -> Result<Self, Self::Error>
   where
     Self: Sized,
@@ -85,16 +72,14 @@ impl ApubObject for ApubCommunityFeatured {
     // We intentionally ignore errors here. This is because the outbox might contain posts from old
     // Lemmy versions, or from other software which we cant parse. In that case, we simply skip the
     // item and only parse the ones that work.
-    let data = Data::new(data.1.clone());
     // process items in parallel, to avoid long delay from fetch_site_metadata() and other processing
     join_all(posts.into_iter().map(|post| {
       async {
         // use separate request counter for each item, otherwise there will be problems with
         // parallel processing
-        let request_counter = &mut 0;
-        let verify = post.verify(&data, request_counter).await;
+        let verify = post.verify(data).await;
         if verify.is_ok() {
-          post.receive(&data, request_counter).await.ok();
+          post.receive(data).await.ok();
         }
       }
     }))
index 5c05258d1e9f35951477f056756c8bef8ec2b1f3..c439da710d23c0ee4d32c8f1a98b45bf44e871a6 100644 (file)
@@ -1,17 +1,15 @@
 use crate::{
-  collections::CommunityContext,
-  local_instance,
-  objects::person::ApubPerson,
+  objects::{community::ApubCommunity, person::ApubPerson},
   protocol::collections::group_moderators::GroupModerators,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  traits::ApubObject,
-  utils::verify_domains_match,
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::collection::OrderedCollectionType,
+  protocol::verification::verify_domains_match,
+  traits::Collection,
 };
-use activitystreams_kinds::collection::OrderedCollectionType;
-use chrono::NaiveDateTime;
-use lemmy_api_common::utils::generate_moderators_url;
+use lemmy_api_common::{context::LemmyContext, utils::generate_moderators_url};
 use lemmy_db_schema::{
   source::community::{CommunityModerator, CommunityModeratorForm},
   traits::Joinable,
@@ -23,46 +21,26 @@ use url::Url;
 #[derive(Clone, Debug)]
 pub(crate) struct ApubCommunityModerators(pub(crate) Vec<CommunityModeratorView>);
 
-#[async_trait::async_trait(?Send)]
-impl ApubObject for ApubCommunityModerators {
-  type DataType = CommunityContext;
-  type ApubType = GroupModerators;
+#[async_trait::async_trait]
+impl Collection for ApubCommunityModerators {
+  type Owner = ApubCommunity;
+  type DataType = LemmyContext;
+  type Kind = GroupModerators;
   type Error = LemmyError;
 
-  fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
-    None
-  }
-
-  #[tracing::instrument(skip_all)]
-  async fn read_from_apub_id(
-    _object_id: Url,
-    data: &Self::DataType,
-  ) -> Result<Option<Self>, LemmyError> {
-    // Only read from database if its a local community, otherwise fetch over http
-    if data.0.local {
-      let cid = data.0.id;
-      let moderators = CommunityModeratorView::for_community(data.1.pool(), cid).await?;
-      Ok(Some(ApubCommunityModerators(moderators)))
-    } else {
-      Ok(None)
-    }
-  }
-
   #[tracing::instrument(skip_all)]
-  async fn delete(self, _data: &Self::DataType) -> Result<(), LemmyError> {
-    unimplemented!()
-  }
-
-  #[tracing::instrument(skip_all)]
-  async fn into_apub(self, data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
-    let ordered_items = self
-      .0
+  async fn read_local(
+    owner: &Self::Owner,
+    data: &Data<Self::DataType>,
+  ) -> Result<Self::Kind, LemmyError> {
+    let moderators = CommunityModeratorView::for_community(data.pool(), owner.id).await?;
+    let ordered_items = moderators
       .into_iter()
-      .map(|m| ObjectId::<ApubPerson>::new(m.moderator.actor_id))
+      .map(|m| ObjectId::<ApubPerson>::from(m.moderator.actor_id))
       .collect();
     Ok(GroupModerators {
       r#type: OrderedCollectionType::OrderedCollection,
-      id: generate_moderators_url(&data.0.actor_id)?.into(),
+      id: generate_moderators_url(&owner.actor_id)?.into(),
       ordered_items,
     })
   }
@@ -71,40 +49,36 @@ impl ApubObject for ApubCommunityModerators {
   async fn verify(
     group_moderators: &GroupModerators,
     expected_domain: &Url,
-    _context: &CommunityContext,
-    _request_counter: &mut i32,
+    _data: &Data<Self::DataType>,
   ) -> Result<(), LemmyError> {
     verify_domains_match(&group_moderators.id, expected_domain)?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn from_apub(
-    apub: Self::ApubType,
-    data: &Self::DataType,
-    request_counter: &mut i32,
+  async fn from_json(
+    apub: Self::Kind,
+    owner: &Self::Owner,
+    data: &Data<Self::DataType>,
   ) -> Result<Self, LemmyError> {
-    let community_id = data.0.id;
+    let community_id = owner.id;
     let current_moderators =
-      CommunityModeratorView::for_community(data.1.pool(), community_id).await?;
+      CommunityModeratorView::for_community(data.pool(), community_id).await?;
     // Remove old mods from database which arent in the moderators collection anymore
     for mod_user in &current_moderators {
-      let mod_id = ObjectId::new(mod_user.moderator.actor_id.clone());
+      let mod_id = ObjectId::from(mod_user.moderator.actor_id.clone());
       if !apub.ordered_items.contains(&mod_id) {
         let community_moderator_form = CommunityModeratorForm {
           community_id: mod_user.community.id,
           person_id: mod_user.moderator.id,
         };
-        CommunityModerator::leave(data.1.pool(), &community_moderator_form).await?;
+        CommunityModerator::leave(data.pool(), &community_moderator_form).await?;
       }
     }
 
     // Add new mods to database which have been added to moderators collection
     for mod_id in apub.ordered_items {
-      let mod_id = ObjectId::new(mod_id);
-      let mod_user: ApubPerson = mod_id
-        .dereference(&data.1, local_instance(&data.1).await, request_counter)
-        .await?;
+      let mod_user: ApubPerson = mod_id.dereference(data).await?;
 
       if !current_moderators
         .iter()
@@ -112,18 +86,16 @@ impl ApubObject for ApubCommunityModerators {
         .any(|x| x == mod_user.actor_id)
       {
         let community_moderator_form = CommunityModeratorForm {
-          community_id: data.0.id,
+          community_id: owner.id,
           person_id: mod_user.id,
         };
-        CommunityModerator::join(data.1.pool(), &community_moderator_form).await?;
+        CommunityModerator::join(data.pool(), &community_moderator_form).await?;
       }
     }
 
     // This return value is unused, so just set an empty vec
     Ok(ApubCommunityModerators(Vec::new()))
   }
-
-  type DbType = ();
 }
 
 #[cfg(test)]
@@ -181,15 +153,13 @@ mod tests {
     let json: GroupModerators =
       file_to_json_object("assets/lemmy/collections/group_moderators.json").unwrap();
     let url = Url::parse("https://enterprise.lemmy.ml/c/tenforward").unwrap();
-    let mut request_counter = 0;
-    let community_context = CommunityContext(community, context.clone());
-    ApubCommunityModerators::verify(&json, &url, &community_context, &mut request_counter)
+    ApubCommunityModerators::verify(&json, &url, &context)
       .await
       .unwrap();
-    ApubCommunityModerators::from_apub(json, &community_context, &mut request_counter)
+    ApubCommunityModerators::from_json(json, &community, &context)
       .await
       .unwrap();
-    assert_eq!(request_counter, 0);
+    assert_eq!(context.request_count(), 0);
 
     let current_moderators = CommunityModeratorView::for_community(context.pool(), community_id)
       .await
@@ -200,7 +170,7 @@ mod tests {
 
     Person::delete(context.pool(), old_mod.id).await.unwrap();
     Person::delete(context.pool(), new_mod.id).await.unwrap();
-    Community::delete(context.pool(), community_context.0.id)
+    Community::delete(context.pool(), community.id)
       .await
       .unwrap();
     Site::delete(context.pool(), site.id).await.unwrap();
index c6d8bb449270221728bcd9ed2a2ccf65ad3127b5..c95b64aab515441e42eb6f950b39ce2f9b6fbeeb 100644 (file)
@@ -1,7 +1,6 @@
 use crate::{
   activity_lists::AnnouncableActivities,
-  collections::CommunityContext,
-  objects::post::ApubPost,
+  objects::{community::ApubCommunity, post::ApubPost},
   protocol::{
     activities::{
       community::announce::AnnounceActivity,
@@ -12,14 +11,13 @@ use crate::{
   },
 };
 use activitypub_federation::{
-  data::Data,
-  traits::{ActivityHandler, ApubObject},
-  utils::verify_domains_match,
+  config::Data,
+  kinds::collection::OrderedCollectionType,
+  protocol::verification::verify_domains_match,
+  traits::{ActivityHandler, Collection},
 };
-use activitystreams_kinds::collection::OrderedCollectionType;
-use chrono::NaiveDateTime;
 use futures::future::join_all;
-use lemmy_api_common::utils::generate_outbox_url;
+use lemmy_api_common::{context::LemmyContext, utils::generate_outbox_url};
 use lemmy_db_schema::{
   source::{person::Person, post::Post},
   traits::Crud,
@@ -31,52 +29,36 @@ use url::Url;
 #[derive(Clone, Debug)]
 pub(crate) struct ApubCommunityOutbox(Vec<ApubPost>);
 
-#[async_trait::async_trait(?Send)]
-impl ApubObject for ApubCommunityOutbox {
-  type DataType = CommunityContext;
-  type ApubType = GroupOutbox;
+#[async_trait::async_trait]
+impl Collection for ApubCommunityOutbox {
+  type Owner = ApubCommunity;
+  type DataType = LemmyContext;
+  type Kind = GroupOutbox;
   type Error = LemmyError;
-  type DbType = ();
-
-  fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
-    None
-  }
-
-  #[tracing::instrument(skip_all)]
-  async fn read_from_apub_id(
-    _object_id: Url,
-    data: &Self::DataType,
-  ) -> Result<Option<Self>, LemmyError> {
-    // Only read from database if its a local community, otherwise fetch over http
-    if data.0.local {
-      let community_id = data.0.id;
-      let post_list: Vec<ApubPost> = Post::list_for_community(data.1.pool(), community_id)
-        .await?
-        .into_iter()
-        .map(Into::into)
-        .collect();
-      Ok(Some(ApubCommunityOutbox(post_list)))
-    } else {
-      Ok(None)
-    }
-  }
 
   #[tracing::instrument(skip_all)]
-  async fn into_apub(self, data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
+  async fn read_local(
+    owner: &Self::Owner,
+    data: &Data<Self::DataType>,
+  ) -> Result<Self::Kind, LemmyError> {
+    let post_list: Vec<ApubPost> = Post::list_for_community(data.pool(), owner.id)
+      .await?
+      .into_iter()
+      .map(Into::into)
+      .collect();
     let mut ordered_items = vec![];
-    for post in self.0 {
-      let person = Person::read(data.1.pool(), post.creator_id).await?.into();
+    for post in post_list {
+      let person = Person::read(data.pool(), post.creator_id).await?.into();
       let create =
-        CreateOrUpdatePage::new(post, &person, &data.0, CreateOrUpdateType::Create, &data.1)
-          .await?;
+        CreateOrUpdatePage::new(post, &person, owner, CreateOrUpdateType::Create, data).await?;
       let announcable = AnnouncableActivities::CreateOrUpdatePost(create);
-      let announce = AnnounceActivity::new(announcable.try_into()?, &data.0, &data.1)?;
+      let announce = AnnounceActivity::new(announcable.try_into()?, owner, data)?;
       ordered_items.push(announce);
     }
 
     Ok(GroupOutbox {
       r#type: OrderedCollectionType::OrderedCollection,
-      id: generate_outbox_url(&data.0.actor_id)?.into(),
+      id: generate_outbox_url(&owner.actor_id)?.into(),
       total_items: ordered_items.len() as i32,
       ordered_items,
     })
@@ -86,18 +68,17 @@ impl ApubObject for ApubCommunityOutbox {
   async fn verify(
     group_outbox: &GroupOutbox,
     expected_domain: &Url,
-    _context: &CommunityContext,
-    _request_counter: &mut i32,
+    _data: &Data<Self::DataType>,
   ) -> Result<(), LemmyError> {
     verify_domains_match(expected_domain, &group_outbox.id)?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn from_apub(
-    apub: Self::ApubType,
-    data: &Self::DataType,
-    _request_counter: &mut i32,
+  async fn from_json(
+    apub: Self::Kind,
+    _owner: &Self::Owner,
+    data: &Data<Self::DataType>,
   ) -> Result<Self, LemmyError> {
     let mut outbox_activities = apub.ordered_items;
     if outbox_activities.len() as i64 > FETCH_LIMIT_MAX {
@@ -110,16 +91,14 @@ impl ApubObject for ApubCommunityOutbox {
     // We intentionally ignore errors here. This is because the outbox might contain posts from old
     // Lemmy versions, or from other software which we cant parse. In that case, we simply skip the
     // item and only parse the ones that work.
-    let data = Data::new(data.1.clone());
     // process items in parallel, to avoid long delay from fetch_site_metadata() and other processing
     join_all(outbox_activities.into_iter().map(|activity| {
       async {
         // use separate request counter for each item, otherwise there will be problems with
         // parallel processing
-        let request_counter = &mut 0;
-        let verify = activity.verify(&data, request_counter).await;
+        let verify = activity.verify(data).await;
         if verify.is_ok() {
-          activity.receive(&data, request_counter).await.ok();
+          activity.receive(data).await.ok();
         }
       }
     }))
index a8d5e136d384b10b312f07a02fd83f7200157825..32922bef8f56c975bd4e5c2b945418903a4959ea 100644 (file)
@@ -1,9 +1,3 @@
-use crate::objects::community::ApubCommunity;
-use lemmy_api_common::context::LemmyContext;
-
 pub(crate) mod community_featured;
 pub(crate) mod community_moderators;
 pub(crate) mod community_outbox;
-
-/// Put community in the data, so we dont have to read it again from the database.
-pub(crate) struct CommunityContext(pub ApubCommunity, pub LemmyContext);
index 0ce4dd8f607e53394de0af1f04ca4432d1d27e0d..de244178e07fdd6d8cf1fa410658b7d77b907fed 100644 (file)
@@ -1,31 +1,38 @@
-use crate::{fetcher::webfinger::webfinger_resolve_actor, ActorType};
-use activitypub_federation::traits::ApubObject;
+use activitypub_federation::{
+  config::Data,
+  fetch::webfinger::webfinger_resolve_actor,
+  traits::{Actor, Object},
+};
+use diesel::NotFound;
 use itertools::Itertools;
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::traits::ApubActor;
+use lemmy_db_views::structs::LocalUserView;
 use lemmy_utils::error::LemmyError;
 
 pub mod post_or_comment;
 pub mod search;
 pub mod user_or_community;
-pub mod webfinger;
 
-/// Resolve actor identifier (eg `!news@example.com`) from local database to avoid network requests.
-/// This only works for local actors, and remote actors which were previously fetched (so it doesnt
-/// trigger any new fetch).
+/// Resolve actor identifier like `!news@example.com` to user or community object.
+///
+/// In case the requesting user is logged in and the object was not found locally, it is attempted
+/// to fetch via webfinger from the original instance.
 #[tracing::instrument(skip_all)]
-pub async fn resolve_actor_identifier<Actor, DbActor>(
+pub async fn resolve_actor_identifier<ActorType, DbActor>(
   identifier: &str,
-  context: &LemmyContext,
+  context: &Data<LemmyContext>,
+  local_user_view: &Option<LocalUserView>,
   include_deleted: bool,
-) -> Result<DbActor, LemmyError>
+) -> Result<ActorType, LemmyError>
 where
-  Actor: ApubObject<DataType = LemmyContext, Error = LemmyError>
-    + ApubObject<DbType = DbActor>
-    + ActorType
+  ActorType: Object<DataType = LemmyContext, Error = LemmyError>
+    + Object
+    + Actor
+    + From<DbActor>
     + Send
     + 'static,
-  for<'de2> <Actor as ApubObject>::ApubType: serde::Deserialize<'de2>,
+  for<'de2> <ActorType as Object>::Kind: serde::Deserialize<'de2>,
   DbActor: ApubActor + Send + 'static,
 {
   // remote actor
@@ -38,19 +45,22 @@ where
     let domain = format!("{}://{}", context.settings().get_protocol_string(), domain);
     let actor = DbActor::read_from_name_and_domain(context.pool(), &name, &domain).await;
     if actor.is_ok() {
-      Ok(actor?)
-    } else {
+      Ok(actor?.into())
+    } else if local_user_view.is_some() {
       // Fetch the actor from its home instance using webfinger
-      let id = webfinger_resolve_actor::<Actor>(identifier, true, context, &mut 0).await?;
-      let actor: DbActor = DbActor::read_from_apub_id(context.pool(), &id)
-        .await?
-        .expect("actor exists as we fetched just before");
+      let actor: ActorType = webfinger_resolve_actor(identifier, context).await?;
       Ok(actor)
+    } else {
+      Err(NotFound.into())
     }
   }
   // local actor
   else {
     let identifier = identifier.to_string();
-    Ok(DbActor::read_from_name(context.pool(), &identifier, include_deleted).await?)
+    Ok(
+      DbActor::read_from_name(context.pool(), &identifier, include_deleted)
+        .await?
+        .into(),
+    )
   }
 }
index c0a42301cb9be7f7ce31d277933c02cf6300112e..651abf7db90bcc41c1fd7676352a07b4f20a642c 100644 (file)
@@ -5,7 +5,7 @@ use crate::{
     InCommunity,
   },
 };
-use activitypub_federation::traits::ApubObject;
+use activitypub_federation::{config::Data, traits::Object};
 use chrono::NaiveDateTime;
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::{
@@ -29,11 +29,10 @@ pub enum PageOrNote {
   Note(Note),
 }
 
-#[async_trait::async_trait(?Send)]
-impl ApubObject for PostOrComment {
+#[async_trait::async_trait]
+impl Object for PostOrComment {
   type DataType = LemmyContext;
-  type ApubType = PageOrNote;
-  type DbType = ();
+  type Kind = PageOrNote;
   type Error = LemmyError;
 
   fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
@@ -41,68 +40,55 @@ impl ApubObject for PostOrComment {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn read_from_apub_id(
+  async fn read_from_id(
     object_id: Url,
-    data: &Self::DataType,
+    data: &Data<Self::DataType>,
   ) -> Result<Option<Self>, LemmyError> {
-    let post = ApubPost::read_from_apub_id(object_id.clone(), data).await?;
+    let post = ApubPost::read_from_id(object_id.clone(), data).await?;
     Ok(match post {
       Some(o) => Some(PostOrComment::Post(o)),
-      None => ApubComment::read_from_apub_id(object_id, data)
+      None => ApubComment::read_from_id(object_id, data)
         .await?
         .map(PostOrComment::Comment),
     })
   }
 
   #[tracing::instrument(skip_all)]
-  async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> {
+  async fn delete(self, data: &Data<Self::DataType>) -> Result<(), LemmyError> {
     match self {
       PostOrComment::Post(p) => p.delete(data).await,
       PostOrComment::Comment(c) => c.delete(data).await,
     }
   }
 
-  async fn into_apub(self, _data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
+  async fn into_json(self, _data: &Data<Self::DataType>) -> Result<Self::Kind, LemmyError> {
     unimplemented!()
   }
 
   #[tracing::instrument(skip_all)]
   async fn verify(
-    apub: &Self::ApubType,
+    apub: &Self::Kind,
     expected_domain: &Url,
-    data: &Self::DataType,
-    request_counter: &mut i32,
+    data: &Data<Self::DataType>,
   ) -> Result<(), LemmyError> {
     match apub {
-      PageOrNote::Page(a) => ApubPost::verify(a, expected_domain, data, request_counter).await,
-      PageOrNote::Note(a) => ApubComment::verify(a, expected_domain, data, request_counter).await,
+      PageOrNote::Page(a) => ApubPost::verify(a, expected_domain, data).await,
+      PageOrNote::Note(a) => ApubComment::verify(a, expected_domain, data).await,
     }
   }
 
   #[tracing::instrument(skip_all)]
-  async fn from_apub(
-    apub: PageOrNote,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<Self, LemmyError> {
+  async fn from_json(apub: PageOrNote, context: &Data<LemmyContext>) -> Result<Self, LemmyError> {
     Ok(match apub {
-      PageOrNote::Page(p) => {
-        PostOrComment::Post(ApubPost::from_apub(*p, context, request_counter).await?)
-      }
-      PageOrNote::Note(n) => {
-        PostOrComment::Comment(ApubComment::from_apub(n, context, request_counter).await?)
-      }
+      PageOrNote::Page(p) => PostOrComment::Post(ApubPost::from_json(*p, context).await?),
+      PageOrNote::Note(n) => PostOrComment::Comment(ApubComment::from_json(n, context).await?),
     })
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for PostOrComment {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    _: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
     let cid = match self {
       PostOrComment::Post(p) => p.community_id,
       PostOrComment::Comment(c) => Post::read(context.pool(), c.post_id).await?.community_id,
index ffc2c96118694191ccf554b43b21c2416b01013f..41bcce375d43d6b026b7a86aa27ae5c7d4f3c926 100644 (file)
@@ -1,10 +1,12 @@
 use crate::{
-  fetcher::webfinger::webfinger_resolve_actor,
-  local_instance,
   objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost},
   protocol::objects::{group::Group, note::Note, page::Page, person::Person},
 };
-use activitypub_federation::{core::object_id::ObjectId, traits::ApubObject};
+use activitypub_federation::{
+  config::Data,
+  fetch::{object_id::ObjectId, webfinger::webfinger_resolve_actor},
+  traits::Object,
+};
 use chrono::NaiveDateTime;
 use lemmy_api_common::context::LemmyContext;
 use lemmy_utils::error::LemmyError;
@@ -17,39 +19,29 @@ use url::Url;
 #[tracing::instrument(skip_all)]
 pub(crate) async fn search_query_to_object_id(
   query: &str,
-  local_only: bool,
-  context: &LemmyContext,
+  context: &Data<LemmyContext>,
 ) -> Result<SearchableObjects, LemmyError> {
-  let request_counter = &mut 0;
-  let object_id = match Url::parse(query) {
-    // its already an url, just go with it
-    Ok(url) => ObjectId::new(url),
+  Ok(match Url::parse(query) {
+    Ok(url) => {
+      // its already an url, just go with it
+      ObjectId::from(url).dereference(context).await?
+    }
     Err(_) => {
       // not an url, try to resolve via webfinger
       let mut chars = query.chars();
       let kind = chars.next();
       let identifier = chars.as_str();
-      let id = match kind {
-        Some('@') => {
-          webfinger_resolve_actor::<ApubPerson>(identifier, local_only, context, request_counter)
-            .await?
-        }
-        Some('!') => {
-          webfinger_resolve_actor::<ApubCommunity>(identifier, local_only, context, request_counter)
-            .await?
-        }
+      match kind {
+        Some('@') => SearchableObjects::Person(
+          webfinger_resolve_actor::<LemmyContext, ApubPerson>(identifier, context).await?,
+        ),
+        Some('!') => SearchableObjects::Community(
+          webfinger_resolve_actor::<LemmyContext, ApubCommunity>(identifier, context).await?,
+        ),
         _ => return Err(LemmyError::from_message("invalid query")),
-      };
-      ObjectId::new(id)
+      }
     }
-  };
-  if local_only {
-    object_id.dereference_local(context).await
-  } else {
-    object_id
-      .dereference(context, local_instance(context).await, request_counter)
-      .await
-  }
+  })
 }
 
 /// The types of ActivityPub objects that can be fetched directly by searching for their ID.
@@ -63,18 +55,17 @@ pub(crate) enum SearchableObjects {
 
 #[derive(Deserialize)]
 #[serde(untagged)]
-pub(crate) enum SearchableApubTypes {
+pub(crate) enum SearchableKinds {
   Group(Group),
   Person(Person),
   Page(Page),
   Note(Note),
 }
 
-#[async_trait::async_trait(?Send)]
-impl ApubObject for SearchableObjects {
+#[async_trait::async_trait]
+impl Object for SearchableObjects {
   type DataType = LemmyContext;
-  type ApubType = SearchableApubTypes;
-  type DbType = ();
+  type Kind = SearchableKinds;
   type Error = LemmyError;
 
   fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
@@ -92,23 +83,23 @@ impl ApubObject for SearchableObjects {
   //       we could skip this and always return an error, but then it would always fetch objects
   //       over http, and not be able to mark objects as deleted that were deleted by remote server.
   #[tracing::instrument(skip_all)]
-  async fn read_from_apub_id(
+  async fn read_from_id(
     object_id: Url,
-    context: &LemmyContext,
+    context: &Data<Self::DataType>,
   ) -> Result<Option<Self>, LemmyError> {
-    let c = ApubCommunity::read_from_apub_id(object_id.clone(), context).await?;
+    let c = ApubCommunity::read_from_id(object_id.clone(), context).await?;
     if let Some(c) = c {
       return Ok(Some(SearchableObjects::Community(c)));
     }
-    let p = ApubPerson::read_from_apub_id(object_id.clone(), context).await?;
+    let p = ApubPerson::read_from_id(object_id.clone(), context).await?;
     if let Some(p) = p {
       return Ok(Some(SearchableObjects::Person(p)));
     }
-    let p = ApubPost::read_from_apub_id(object_id.clone(), context).await?;
+    let p = ApubPost::read_from_id(object_id.clone(), context).await?;
     if let Some(p) = p {
       return Ok(Some(SearchableObjects::Post(p)));
     }
-    let c = ApubComment::read_from_apub_id(object_id, context).await?;
+    let c = ApubComment::read_from_id(object_id, context).await?;
     if let Some(c) = c {
       return Ok(Some(SearchableObjects::Comment(c)));
     }
@@ -116,7 +107,7 @@ impl ApubObject for SearchableObjects {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> {
+  async fn delete(self, data: &Data<Self::DataType>) -> Result<(), LemmyError> {
     match self {
       SearchableObjects::Person(p) => p.delete(data).await,
       SearchableObjects::Community(c) => c.delete(data).await,
@@ -125,46 +116,33 @@ impl ApubObject for SearchableObjects {
     }
   }
 
-  async fn into_apub(self, _data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
+  async fn into_json(self, _data: &Data<Self::DataType>) -> Result<Self::Kind, LemmyError> {
     unimplemented!()
   }
 
   #[tracing::instrument(skip_all)]
   async fn verify(
-    apub: &Self::ApubType,
+    apub: &Self::Kind,
     expected_domain: &Url,
-    data: &Self::DataType,
-    request_counter: &mut i32,
+    data: &Data<Self::DataType>,
   ) -> Result<(), LemmyError> {
     match apub {
-      SearchableApubTypes::Group(a) => {
-        ApubCommunity::verify(a, expected_domain, data, request_counter).await
-      }
-      SearchableApubTypes::Person(a) => {
-        ApubPerson::verify(a, expected_domain, data, request_counter).await
-      }
-      SearchableApubTypes::Page(a) => {
-        ApubPost::verify(a, expected_domain, data, request_counter).await
-      }
-      SearchableApubTypes::Note(a) => {
-        ApubComment::verify(a, expected_domain, data, request_counter).await
-      }
+      SearchableKinds::Group(a) => ApubCommunity::verify(a, expected_domain, data).await,
+      SearchableKinds::Person(a) => ApubPerson::verify(a, expected_domain, data).await,
+      SearchableKinds::Page(a) => ApubPost::verify(a, expected_domain, data).await,
+      SearchableKinds::Note(a) => ApubComment::verify(a, expected_domain, data).await,
     }
   }
 
   #[tracing::instrument(skip_all)]
-  async fn from_apub(
-    apub: Self::ApubType,
-    context: &LemmyContext,
-    rc: &mut i32,
-  ) -> Result<Self, LemmyError> {
-    use SearchableApubTypes as SAT;
+  async fn from_json(apub: Self::Kind, context: &Data<LemmyContext>) -> Result<Self, LemmyError> {
+    use SearchableKinds as SAT;
     use SearchableObjects as SO;
     Ok(match apub {
-      SAT::Group(g) => SO::Community(ApubCommunity::from_apub(g, context, rc).await?),
-      SAT::Person(p) => SO::Person(ApubPerson::from_apub(p, context, rc).await?),
-      SAT::Page(p) => SO::Post(ApubPost::from_apub(p, context, rc).await?),
-      SAT::Note(n) => SO::Comment(ApubComment::from_apub(n, context, rc).await?),
+      SAT::Group(g) => SO::Community(ApubCommunity::from_json(g, context).await?),
+      SAT::Person(p) => SO::Person(ApubPerson::from_json(p, context).await?),
+      SAT::Page(p) => SO::Post(ApubPost::from_json(p, context).await?),
+      SAT::Note(n) => SO::Comment(ApubComment::from_json(n, context).await?),
     })
   }
 }
index 3af86be1a66a13777aaa4f49963dd3dd8d855fa2..d872c4e245db9979da05d69af05550928b70ca36 100644 (file)
@@ -1,9 +1,11 @@
 use crate::{
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::objects::{group::Group, person::Person},
-  ActorType,
 };
-use activitypub_federation::traits::{Actor, ApubObject};
+use activitypub_federation::{
+  config::Data,
+  traits::{Actor, Object},
+};
 use chrono::NaiveDateTime;
 use lemmy_api_common::context::LemmyContext;
 use lemmy_utils::error::LemmyError;
@@ -29,11 +31,10 @@ pub enum PersonOrGroupType {
   Group,
 }
 
-#[async_trait::async_trait(?Send)]
-impl ApubObject for UserOrCommunity {
+#[async_trait::async_trait]
+impl Object for UserOrCommunity {
   type DataType = LemmyContext;
-  type ApubType = PersonOrGroup;
-  type DbType = ();
+  type Kind = PersonOrGroup;
   type Error = LemmyError;
 
   fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
@@ -44,90 +45,77 @@ impl ApubObject for UserOrCommunity {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn read_from_apub_id(
+  async fn read_from_id(
     object_id: Url,
-    data: &Self::DataType,
+    data: &Data<Self::DataType>,
   ) -> Result<Option<Self>, LemmyError> {
-    let person = ApubPerson::read_from_apub_id(object_id.clone(), data).await?;
+    let person = ApubPerson::read_from_id(object_id.clone(), data).await?;
     Ok(match person {
       Some(o) => Some(UserOrCommunity::User(o)),
-      None => ApubCommunity::read_from_apub_id(object_id, data)
+      None => ApubCommunity::read_from_id(object_id, data)
         .await?
         .map(UserOrCommunity::Community),
     })
   }
 
   #[tracing::instrument(skip_all)]
-  async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> {
+  async fn delete(self, data: &Data<Self::DataType>) -> Result<(), LemmyError> {
     match self {
       UserOrCommunity::User(p) => p.delete(data).await,
       UserOrCommunity::Community(p) => p.delete(data).await,
     }
   }
 
-  async fn into_apub(self, _data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
+  async fn into_json(self, _data: &Data<Self::DataType>) -> Result<Self::Kind, LemmyError> {
     unimplemented!()
   }
 
   #[tracing::instrument(skip_all)]
   async fn verify(
-    apub: &Self::ApubType,
+    apub: &Self::Kind,
     expected_domain: &Url,
-    data: &Self::DataType,
-    request_counter: &mut i32,
+    data: &Data<Self::DataType>,
   ) -> Result<(), LemmyError> {
     match apub {
-      PersonOrGroup::Person(a) => {
-        ApubPerson::verify(a, expected_domain, data, request_counter).await
-      }
-      PersonOrGroup::Group(a) => {
-        ApubCommunity::verify(a, expected_domain, data, request_counter).await
-      }
+      PersonOrGroup::Person(a) => ApubPerson::verify(a, expected_domain, data).await,
+      PersonOrGroup::Group(a) => ApubCommunity::verify(a, expected_domain, data).await,
     }
   }
 
   #[tracing::instrument(skip_all)]
-  async fn from_apub(
-    apub: Self::ApubType,
-    data: &Self::DataType,
-    request_counter: &mut i32,
-  ) -> Result<Self, LemmyError> {
+  async fn from_json(apub: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, LemmyError> {
     Ok(match apub {
-      PersonOrGroup::Person(p) => {
-        UserOrCommunity::User(ApubPerson::from_apub(p, data, request_counter).await?)
-      }
+      PersonOrGroup::Person(p) => UserOrCommunity::User(ApubPerson::from_json(p, data).await?),
       PersonOrGroup::Group(p) => {
-        UserOrCommunity::Community(ApubCommunity::from_apub(p, data, request_counter).await?)
+        UserOrCommunity::Community(ApubCommunity::from_json(p, data).await?)
       }
     })
   }
 }
 
 impl Actor for UserOrCommunity {
-  fn public_key(&self) -> &str {
+  fn id(&self) -> Url {
     match self {
-      UserOrCommunity::User(p) => p.public_key(),
-      UserOrCommunity::Community(p) => p.public_key(),
+      UserOrCommunity::User(u) => u.id(),
+      UserOrCommunity::Community(c) => c.id(),
     }
   }
 
-  fn inbox(&self) -> Url {
-    unimplemented!()
-  }
-}
-
-impl ActorType for UserOrCommunity {
-  fn actor_id(&self) -> Url {
+  fn public_key_pem(&self) -> &str {
     match self {
-      UserOrCommunity::User(u) => u.actor_id(),
-      UserOrCommunity::Community(c) => c.actor_id(),
+      UserOrCommunity::User(p) => p.public_key_pem(),
+      UserOrCommunity::Community(p) => p.public_key_pem(),
     }
   }
 
-  fn private_key(&self) -> Option<String> {
+  fn private_key_pem(&self) -> Option<String> {
     match self {
-      UserOrCommunity::User(u) => u.private_key(),
-      UserOrCommunity::Community(c) => c.private_key(),
+      UserOrCommunity::User(p) => p.private_key_pem(),
+      UserOrCommunity::Community(p) => p.private_key_pem(),
     }
   }
+
+  fn inbox(&self) -> Url {
+    unimplemented!()
+  }
 }
diff --git a/crates/apub/src/fetcher/webfinger.rs b/crates/apub/src/fetcher/webfinger.rs
deleted file mode 100644 (file)
index 968a0d7..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-use crate::{local_instance, ActorType, FEDERATION_HTTP_FETCH_LIMIT};
-use activitypub_federation::{core::object_id::ObjectId, traits::ApubObject};
-use anyhow::anyhow;
-use itertools::Itertools;
-use lemmy_api_common::context::LemmyContext;
-use lemmy_db_schema::newtypes::DbUrl;
-use lemmy_utils::{error::LemmyError, WebfingerResponse};
-use tracing::debug;
-use url::Url;
-
-/// Turns a person id like `@name@example.com` into an apub ID, like `https://example.com/user/name`,
-/// using webfinger.
-pub(crate) async fn webfinger_resolve_actor<Kind>(
-  identifier: &str,
-  local_only: bool,
-  context: &LemmyContext,
-  request_counter: &mut i32,
-) -> Result<DbUrl, LemmyError>
-where
-  Kind: ApubObject<DataType = LemmyContext, Error = LemmyError> + ActorType + Send + 'static,
-  for<'de2> <Kind as ApubObject>::ApubType: serde::Deserialize<'de2>,
-{
-  let protocol = context.settings().get_protocol_string();
-  let (_, domain) = identifier
-    .splitn(2, '@')
-    .collect_tuple()
-    .ok_or_else(|| LemmyError::from_message("Invalid webfinger query, missing domain"))?;
-  let fetch_url = format!("{protocol}://{domain}/.well-known/webfinger?resource=acct:{identifier}");
-  debug!("Fetching webfinger url: {}", &fetch_url);
-
-  *request_counter += 1;
-  if *request_counter > FEDERATION_HTTP_FETCH_LIMIT {
-    return Err(LemmyError::from_message("Request retry limit reached"));
-  }
-
-  let response = context.client().get(&fetch_url).send().await?;
-
-  let res: WebfingerResponse = response.json().await.map_err(LemmyError::from)?;
-
-  let links: Vec<Url> = res
-    .links
-    .iter()
-    .filter(|link| {
-      if let Some(type_) = &link.kind {
-        type_.starts_with("application/")
-      } else {
-        false
-      }
-    })
-    .filter_map(|l| l.href.clone())
-    .collect();
-  for l in links {
-    let object_id = ObjectId::<Kind>::new(l);
-    let object = if local_only {
-      object_id.dereference_local(context).await
-    } else {
-      object_id
-        .dereference(context, local_instance(context).await, request_counter)
-        .await
-    };
-    if object.is_ok() {
-      return object.map(|o| o.actor_id().into());
-    }
-  }
-  let err = anyhow!("Failed to resolve actor for {}", identifier);
-  Err(LemmyError::from_error_message(err, "failed_to_resolve"))
-}
index 6753271c791efaa975112686fad3b2e669a086cf..c02bd05450f9561283fa3674cb7c29696cbc0e49 100644 (file)
@@ -2,8 +2,8 @@ use crate::{
   http::{create_apub_response, create_apub_tombstone_response, err_object_not_local},
   objects::comment::ApubComment,
 };
-use activitypub_federation::traits::ApubObject;
-use actix_web::{web, web::Path, HttpResponse};
+use activitypub_federation::{config::Data, traits::Object};
+use actix_web::{web::Path, HttpResponse};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::{newtypes::CommentId, source::comment::Comment, traits::Crud};
 use lemmy_utils::error::LemmyError;
@@ -18,7 +18,7 @@ pub(crate) struct CommentQuery {
 #[tracing::instrument(skip_all)]
 pub(crate) async fn get_apub_comment(
   info: Path<CommentQuery>,
-  context: web::Data<LemmyContext>,
+  context: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
   let id = CommentId(info.comment_id.parse::<i32>()?);
   let comment: ApubComment = Comment::read(context.pool(), id).await?.into();
@@ -27,7 +27,7 @@ pub(crate) async fn get_apub_comment(
   }
 
   if !comment.deleted && !comment.removed {
-    Ok(create_apub_response(&comment.into_apub(&context).await?))
+    Ok(create_apub_response(&comment.into_json(&context).await?))
   } else {
     Ok(create_apub_tombstone_response(comment.ap_id.clone()))
   }
index 9a0d1f02bf1e96fba0eddeb7c3491c6e27e5c1c3..4ae50bb05fcc0b1a6c36061315aedf5c917b3756 100644 (file)
@@ -4,23 +4,19 @@ use crate::{
     community_featured::ApubCommunityFeatured,
     community_moderators::ApubCommunityModerators,
     community_outbox::ApubCommunityOutbox,
-    CommunityContext,
   },
-  http::{create_apub_response, create_apub_tombstone_response, receive_lemmy_activity},
-  local_instance,
+  http::{create_apub_response, create_apub_tombstone_response},
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::collections::group_followers::GroupFollowers,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  deser::context::WithContext,
-  traits::ApubObject,
-};
-use actix_web::{web, HttpRequest, HttpResponse};
-use lemmy_api_common::{
-  context::LemmyContext,
-  utils::{generate_featured_url, generate_outbox_url},
+  actix_web::inbox::receive_activity,
+  config::Data,
+  protocol::context::WithContext,
+  traits::{Collection, Object},
 };
+use actix_web::{web, web::Bytes, HttpRequest, HttpResponse};
+use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::{source::community::Community, traits::ApubActor};
 use lemmy_utils::error::LemmyError;
 use serde::Deserialize;
@@ -34,7 +30,7 @@ pub(crate) struct CommunityQuery {
 #[tracing::instrument(skip_all)]
 pub(crate) async fn get_apub_community_http(
   info: web::Path<CommunityQuery>,
-  context: web::Data<LemmyContext>,
+  context: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
   let community: ApubCommunity =
     Community::read_from_name(context.pool(), &info.community_name, true)
@@ -42,7 +38,7 @@ pub(crate) async fn get_apub_community_http(
       .into();
 
   if !community.deleted && !community.removed {
-    let apub = community.into_apub(&context).await?;
+    let apub = community.into_json(&context).await?;
 
     Ok(create_apub_response(&apub))
   } else {
@@ -54,17 +50,19 @@ pub(crate) async fn get_apub_community_http(
 #[tracing::instrument(skip_all)]
 pub async fn community_inbox(
   request: HttpRequest,
-  payload: String,
-  context: web::Data<LemmyContext>,
+  body: Bytes,
+  data: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
-  receive_lemmy_activity::<WithContext<GroupInboxActivities>, ApubPerson>(request, payload, context)
-    .await
+  receive_activity::<WithContext<GroupInboxActivities>, ApubPerson, LemmyContext>(
+    request, body, &data,
+  )
+  .await
 }
 
 /// Returns an empty followers collection, only populating the size (for privacy).
 pub(crate) async fn get_apub_community_followers(
   info: web::Path<CommunityQuery>,
-  context: web::Data<LemmyContext>,
+  context: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
   let community = Community::read_from_name(context.pool(), &info.community_name, false).await?;
   let followers = GroupFollowers::new(community, &context).await?;
@@ -75,24 +73,23 @@ pub(crate) async fn get_apub_community_followers(
 /// activites like votes or comments).
 pub(crate) async fn get_apub_community_outbox(
   info: web::Path<CommunityQuery>,
-  context: web::Data<LemmyContext>,
+  context: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
-  let community = Community::read_from_name(context.pool(), &info.community_name, false).await?;
+  let community: ApubCommunity =
+    Community::read_from_name(context.pool(), &info.community_name, false)
+      .await?
+      .into();
   if community.deleted || community.removed {
     return Err(LemmyError::from_message("deleted"));
   }
-  let id = ObjectId::new(generate_outbox_url(&community.actor_id)?);
-  let outbox_data = CommunityContext(community.into(), context.get_ref().clone());
-  let outbox: ApubCommunityOutbox = id
-    .dereference(&outbox_data, local_instance(&context).await, &mut 0)
-    .await?;
-  Ok(create_apub_response(&outbox.into_apub(&outbox_data).await?))
+  let outbox = ApubCommunityOutbox::read_local(&community, &context).await?;
+  Ok(create_apub_response(&outbox))
 }
 
 #[tracing::instrument(skip_all)]
 pub(crate) async fn get_apub_community_moderators(
   info: web::Path<CommunityQuery>,
-  context: web::Data<LemmyContext>,
+  context: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
   let community: ApubCommunity =
     Community::read_from_name(context.pool(), &info.community_name, false)
@@ -101,29 +98,22 @@ pub(crate) async fn get_apub_community_moderators(
   if community.deleted || community.removed {
     return Err(LemmyError::from_message("deleted"));
   }
-  let id = ObjectId::new(generate_outbox_url(&community.actor_id)?);
-  let outbox_data = CommunityContext(community, context.get_ref().clone());
-  let moderators: ApubCommunityModerators = id
-    .dereference(&outbox_data, local_instance(&context).await, &mut 0)
-    .await?;
-  Ok(create_apub_response(
-    &moderators.into_apub(&outbox_data).await?,
-  ))
+  let moderators = ApubCommunityModerators::read_local(&community, &context).await?;
+  Ok(create_apub_response(&moderators))
 }
 
 /// Returns collection of featured (stickied) posts.
 pub(crate) async fn get_apub_community_featured(
   info: web::Path<CommunityQuery>,
-  context: web::Data<LemmyContext>,
+  context: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
-  let community = Community::read_from_name(context.pool(), &info.community_name, false).await?;
+  let community: ApubCommunity =
+    Community::read_from_name(context.pool(), &info.community_name, false)
+      .await?
+      .into();
   if community.deleted || community.removed {
     return Err(LemmyError::from_message("deleted"));
   }
-  let id = ObjectId::new(generate_featured_url(&community.actor_id)?);
-  let data = CommunityContext(community.into(), context.get_ref().clone());
-  let featured: ApubCommunityFeatured = id
-    .dereference(&data, local_instance(&context).await, &mut 0)
-    .await?;
-  Ok(create_apub_response(&featured.into_apub(&data).await?))
+  let featured = ApubCommunityFeatured::read_local(&community, &context).await?;
+  Ok(create_apub_response(&featured))
 }
index 8b53991940f10a482deced50a9573de48d56ffb0..72819ccbe39b9752e7ebf20ea77a3339ca7b1591 100644 (file)
@@ -1,28 +1,22 @@
 use crate::{
   activity_lists::SharedInboxActivities,
   fetcher::user_or_community::UserOrCommunity,
-  insert_activity,
-  local_instance,
   protocol::objects::tombstone::Tombstone,
   CONTEXT,
 };
 use activitypub_federation::{
-  core::inbox::receive_activity,
-  data::Data,
-  deser::context::WithContext,
-  traits::{ActivityHandler, Actor, ApubObject},
-  APUB_JSON_CONTENT_TYPE,
+  actix_web::inbox::receive_activity,
+  config::Data,
+  protocol::context::WithContext,
+  FEDERATION_CONTENT_TYPE,
 };
-use actix_web::{web, HttpRequest, HttpResponse};
+use actix_web::{web, web::Bytes, HttpRequest, HttpResponse};
 use http::StatusCode;
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::source::activity::Activity;
 use lemmy_utils::error::LemmyError;
-use once_cell::sync::OnceCell;
-use serde::{de::DeserializeOwned, Deserialize, Serialize};
-use serde_json::Value;
+use serde::{Deserialize, Serialize};
 use std::ops::Deref;
-use tracing::{debug, log::info};
 use url::Url;
 
 mod comment;
@@ -34,45 +28,11 @@ pub mod site;
 
 pub async fn shared_inbox(
   request: HttpRequest,
-  payload: String,
-  context: web::Data<LemmyContext>,
+  body: Bytes,
+  data: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
-  receive_lemmy_activity::<SharedInboxActivities, UserOrCommunity>(request, payload, context).await
-}
-
-pub async fn receive_lemmy_activity<Activity, ActorT>(
-  request: HttpRequest,
-  payload: String,
-  context: web::Data<LemmyContext>,
-) -> Result<HttpResponse, LemmyError>
-where
-  Activity: ActivityHandler<DataType = LemmyContext, Error = LemmyError>
-    + DeserializeOwned
-    + Send
-    + 'static,
-  ActorT: ApubObject<DataType = LemmyContext, Error = LemmyError> + Actor + Send + 'static,
-  for<'de2> <ActorT as ApubObject>::ApubType: serde::Deserialize<'de2>,
-{
-  static DATA: OnceCell<Data<LemmyContext>> = OnceCell::new();
-  let activity_value: Value = serde_json::from_str(&payload)?;
-  debug!("Parsing activity {}", payload);
-  let activity: Activity = serde_json::from_value(activity_value.clone())?;
-  // Log the activity, so we avoid receiving and parsing it twice.
-  let insert = insert_activity(activity.id(), activity_value, false, true, context.pool()).await?;
-  if !insert {
-    debug!("Received duplicate activity {}", activity.id().to_string());
-    return Ok(HttpResponse::BadRequest().finish());
-  }
-  info!("Received activity {}", payload);
-
-  let data = DATA.get_or_init(|| Data::new(context.get_ref().clone()));
-  receive_activity::<Activity, ActorT, LemmyContext>(
-    request,
-    activity,
-    local_instance(&context).await,
-    data,
-  )
-  .await
+  receive_activity::<SharedInboxActivities, UserOrCommunity, LemmyContext>(request, body, &data)
+    .await
 }
 
 /// Convert the data to json and turn it into an HTTP Response with the correct ActivityPub
@@ -82,20 +42,20 @@ where
   T: Serialize,
 {
   HttpResponse::Ok()
-    .content_type(APUB_JSON_CONTENT_TYPE)
+    .content_type(FEDERATION_CONTENT_TYPE)
     .json(WithContext::new(data, CONTEXT.deref().clone()))
 }
 
 fn create_json_apub_response(data: serde_json::Value) -> HttpResponse {
   HttpResponse::Ok()
-    .content_type(APUB_JSON_CONTENT_TYPE)
+    .content_type(FEDERATION_CONTENT_TYPE)
     .json(data)
 }
 
 fn create_apub_tombstone_response<T: Into<Url>>(id: T) -> HttpResponse {
   let tombstone = Tombstone::new(id.into());
   HttpResponse::Gone()
-    .content_type(APUB_JSON_CONTENT_TYPE)
+    .content_type(FEDERATION_CONTENT_TYPE)
     .status(StatusCode::GONE)
     .json(WithContext::new(tombstone, CONTEXT.deref().clone()))
 }
index 6a1bc5b35c52efa8da7c1499c83ea45525d3cae3..79696660ce5bc8e2b8b9ac4a96a304446b8c8949 100644 (file)
@@ -1,12 +1,17 @@
 use crate::{
   activity_lists::PersonInboxActivitiesWithAnnouncable,
   fetcher::user_or_community::UserOrCommunity,
-  http::{create_apub_response, create_apub_tombstone_response, receive_lemmy_activity},
+  http::{create_apub_response, create_apub_tombstone_response},
   objects::person::ApubPerson,
   protocol::collections::empty_outbox::EmptyOutbox,
 };
-use activitypub_federation::{deser::context::WithContext, traits::ApubObject};
-use actix_web::{web, HttpRequest, HttpResponse};
+use activitypub_federation::{
+  actix_web::inbox::receive_activity,
+  config::Data,
+  protocol::context::WithContext,
+  traits::Object,
+};
+use actix_web::{web, web::Bytes, HttpRequest, HttpResponse};
 use lemmy_api_common::{context::LemmyContext, utils::generate_outbox_url};
 use lemmy_db_schema::{source::person::Person, traits::ApubActor};
 use lemmy_utils::error::LemmyError;
@@ -21,7 +26,7 @@ pub struct PersonQuery {
 #[tracing::instrument(skip_all)]
 pub(crate) async fn get_apub_person_http(
   info: web::Path<PersonQuery>,
-  context: web::Data<LemmyContext>,
+  context: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
   let user_name = info.into_inner().user_name;
   // TODO: this needs to be able to read deleted persons, so that it can send tombstones
@@ -30,7 +35,7 @@ pub(crate) async fn get_apub_person_http(
     .into();
 
   if !person.deleted {
-    let apub = person.into_apub(&context).await?;
+    let apub = person.into_json(&context).await?;
 
     Ok(create_apub_response(&apub))
   } else {
@@ -41,11 +46,11 @@ pub(crate) async fn get_apub_person_http(
 #[tracing::instrument(skip_all)]
 pub async fn person_inbox(
   request: HttpRequest,
-  payload: String,
-  context: web::Data<LemmyContext>,
+  body: Bytes,
+  data: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
-  receive_lemmy_activity::<WithContext<PersonInboxActivitiesWithAnnouncable>, UserOrCommunity>(
-    request, payload, context,
+  receive_activity::<WithContext<PersonInboxActivitiesWithAnnouncable>, UserOrCommunity, LemmyContext>(
+    request, body, &data,
   )
   .await
 }
@@ -53,7 +58,7 @@ pub async fn person_inbox(
 #[tracing::instrument(skip_all)]
 pub(crate) async fn get_apub_person_outbox(
   info: web::Path<PersonQuery>,
-  context: web::Data<LemmyContext>,
+  context: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
   let person = Person::read_from_name(context.pool(), &info.user_name, false).await?;
   let outbox_id = generate_outbox_url(&person.actor_id)?.into();
index fc164a549c70e5a2d76c066972bc51f169c1e104..ed1815c075bba7886974d9854ca23ee6ee49d698 100644 (file)
@@ -2,7 +2,7 @@ use crate::{
   http::{create_apub_response, create_apub_tombstone_response, err_object_not_local},
   objects::post::ApubPost,
 };
-use activitypub_federation::traits::ApubObject;
+use activitypub_federation::{config::Data, traits::Object};
 use actix_web::{web, HttpResponse};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::{newtypes::PostId, source::post::Post, traits::Crud};
@@ -18,7 +18,7 @@ pub(crate) struct PostQuery {
 #[tracing::instrument(skip_all)]
 pub(crate) async fn get_apub_post(
   info: web::Path<PostQuery>,
-  context: web::Data<LemmyContext>,
+  context: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
   let id = PostId(info.post_id.parse::<i32>()?);
   let post: ApubPost = Post::read(context.pool(), id).await?.into();
@@ -27,7 +27,7 @@ pub(crate) async fn get_apub_post(
   }
 
   if !post.deleted && !post.removed {
-    Ok(create_apub_response(&post.into_apub(&context).await?))
+    Ok(create_apub_response(&post.into_json(&context).await?))
   } else {
     Ok(create_apub_tombstone_response(post.ap_id.clone()))
   }
index fe6c34f639dc59f0de71abe1129964f757ee12b6..61802eae7b7ef09ac57c0d8dd4b14e8b46a50555 100644 (file)
@@ -1,28 +1,33 @@
 use crate::{
   activity_lists::SiteInboxActivities,
-  http::{create_apub_response, receive_lemmy_activity},
+  http::create_apub_response,
   objects::{instance::ApubSite, person::ApubPerson},
   protocol::collections::empty_outbox::EmptyOutbox,
 };
-use activitypub_federation::{deser::context::WithContext, traits::ApubObject};
-use actix_web::{web, HttpRequest, HttpResponse};
+use activitypub_federation::{
+  actix_web::inbox::receive_activity,
+  config::Data,
+  protocol::context::WithContext,
+  traits::Object,
+};
+use actix_web::{web::Bytes, HttpRequest, HttpResponse};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_views::structs::SiteView;
 use lemmy_utils::error::LemmyError;
 use url::Url;
 
 pub(crate) async fn get_apub_site_http(
-  context: web::Data<LemmyContext>,
+  context: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
   let site: ApubSite = SiteView::read_local(context.pool()).await?.site.into();
 
-  let apub = site.into_apub(&context).await?;
+  let apub = site.into_json(&context).await?;
   Ok(create_apub_response(&apub))
 }
 
 #[tracing::instrument(skip_all)]
 pub(crate) async fn get_apub_site_outbox(
-  context: web::Data<LemmyContext>,
+  context: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
   let outbox_id = format!(
     "{}/site_outbox",
@@ -35,9 +40,11 @@ pub(crate) async fn get_apub_site_outbox(
 #[tracing::instrument(skip_all)]
 pub async fn get_apub_site_inbox(
   request: HttpRequest,
-  payload: String,
-  context: web::Data<LemmyContext>,
+  body: Bytes,
+  data: Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
-  receive_lemmy_activity::<WithContext<SiteInboxActivities>, ApubPerson>(request, payload, context)
-    .await
+  receive_activity::<WithContext<SiteInboxActivities>, ApubPerson, LemmyContext>(
+    request, body, &data,
+  )
+  .await
 }
index d277a3bc80b1d13c5ffb5720e8f68d08c412a9e3..43e26961ccc55580f9132006173cb87e0afc85b9 100644 (file)
@@ -1,20 +1,19 @@
 use crate::fetcher::post_or_comment::PostOrComment;
-use activitypub_federation::{
-  core::signatures::PublicKey,
-  traits::{Actor, ApubObject},
-  InstanceSettings,
-  LocalInstance,
-  UrlVerifier,
-};
+use activitypub_federation::config::{Data, UrlVerifier};
 use async_trait::async_trait;
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::{
-  source::{activity::Activity, instance::Instance, local_site::LocalSite},
+  source::{
+    activity::{Activity, ActivityInsertForm},
+    instance::Instance,
+    local_site::LocalSite,
+  },
+  traits::Crud,
   utils::DbPool,
 };
 use lemmy_utils::{error::LemmyError, settings::structs::Settings};
 use once_cell::sync::Lazy;
-use tokio::sync::OnceCell;
+use serde::Serialize;
 use url::Url;
 
 pub mod activities;
@@ -27,52 +26,23 @@ pub(crate) mod mentions;
 pub mod objects;
 pub mod protocol;
 
-const FEDERATION_HTTP_FETCH_LIMIT: i32 = 25;
+pub const FEDERATION_HTTP_FETCH_LIMIT: u32 = 50;
 
 static CONTEXT: Lazy<Vec<serde_json::Value>> = Lazy::new(|| {
   serde_json::from_str(include_str!("../assets/lemmy/context.json")).expect("parse context")
 });
 
-// TODO: store this in context? but its only used in this crate, no need to expose it elsewhere
-// TODO this singleton needs to be redone to account for live data.
-async fn local_instance(context: &LemmyContext) -> &'static LocalInstance {
-  static LOCAL_INSTANCE: OnceCell<LocalInstance> = OnceCell::const_new();
-  LOCAL_INSTANCE
-    .get_or_init(|| async {
-      // Local site may be missing
-      let local_site = &LocalSite::read(context.pool()).await;
-      let worker_count = local_site
-        .as_ref()
-        .map(|l| l.federation_worker_count)
-        .unwrap_or(64) as u64;
-
-      let settings = InstanceSettings::builder()
-        .http_fetch_retry_limit(FEDERATION_HTTP_FETCH_LIMIT)
-        .worker_count(worker_count)
-        .debug(cfg!(debug_assertions))
-        .http_signature_compat(true)
-        .url_verifier(Box::new(VerifyUrlData(context.clone())))
-        .build()
-        .expect("configure federation");
-      LocalInstance::new(
-        context.settings().hostname.clone(),
-        context.client().clone(),
-        settings,
-      )
-    })
-    .await
-}
-
 #[derive(Clone)]
-struct VerifyUrlData(LemmyContext);
+pub struct VerifyUrlData(pub DbPool);
 
 #[async_trait]
 impl UrlVerifier for VerifyUrlData {
   async fn verify(&self, url: &Url) -> Result<(), &'static str> {
-    let local_site_data = fetch_local_site_data(self.0.pool())
+    let local_site_data = fetch_local_site_data(&self.0)
       .await
       .expect("read local site data");
-    check_apub_id_valid(url, &local_site_data, self.0.settings())
+    check_apub_id_valid(url, &local_site_data)?;
+    Ok(())
   }
 }
 
@@ -86,19 +56,9 @@ impl UrlVerifier for VerifyUrlData {
 ///
 /// `use_strict_allowlist` should be true only when parsing a remote community, or when parsing a
 /// post/comment in a local community.
-#[tracing::instrument(skip(settings, local_site_data))]
-fn check_apub_id_valid(
-  apub_id: &Url,
-  local_site_data: &LocalSiteData,
-  settings: &Settings,
-) -> Result<(), &'static str> {
+#[tracing::instrument(skip(local_site_data))]
+fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> Result<(), &'static str> {
   let domain = apub_id.domain().expect("apud id has domain").to_string();
-  let local_instance = settings
-    .get_hostname_without_port()
-    .expect("local hostname is valid");
-  if domain == local_instance {
-    return Ok(());
-  }
 
   if !local_site_data
     .local_site
@@ -109,10 +69,6 @@ fn check_apub_id_valid(
     return Err("Federation disabled");
   }
 
-  if apub_id.scheme() != settings.get_protocol_string() {
-    return Err("Invalid protocol scheme");
-  }
-
   if let Some(blocked) = local_site_data.blocked_instances.as_ref() {
     if blocked.iter().any(|i| domain.eq(&i.domain)) {
       return Err("Domain is blocked");
@@ -161,7 +117,6 @@ pub(crate) fn check_apub_id_valid_with_strictness(
   local_site_data: &LocalSiteData,
   settings: &Settings,
 ) -> Result<(), LemmyError> {
-  check_apub_id_valid(apub_id, local_site_data, settings).map_err(LemmyError::from_message)?;
   let domain = apub_id.domain().expect("apud id has domain").to_string();
   let local_instance = settings
     .get_hostname_without_port()
@@ -169,6 +124,7 @@ pub(crate) fn check_apub_id_valid_with_strictness(
   if domain == local_instance {
     return Ok(());
   }
+  check_apub_id_valid(apub_id, local_site_data).map_err(LemmyError::from_message)?;
 
   if let Some(allowed) = local_site_data.allowed_instances.as_ref() {
     // Only check allowlist if this is a community
@@ -179,8 +135,12 @@ pub(crate) fn check_apub_id_valid_with_strictness(
         .iter()
         .map(|i| i.domain.clone())
         .collect::<Vec<String>>();
+      let local_instance = settings
+        .get_hostname_without_port()
+        .expect("local hostname is valid");
       allowed_and_local.push(local_instance);
 
+      let domain = apub_id.domain().expect("apud id has domain").to_string();
       if !allowed_and_local.contains(&domain) {
         return Err(LemmyError::from_message(
           "Federation forbidden by strict allowlist",
@@ -191,40 +151,41 @@ pub(crate) fn check_apub_id_valid_with_strictness(
   Ok(())
 }
 
-/// Store a sent or received activity in the database, for logging purposes. These records are not
-/// persistent.
-#[tracing::instrument(skip(pool))]
-async fn insert_activity(
+/// Store a sent or received activity in the database.
+///
+/// Stored activities are served over the HTTP endpoint `GET /activities/{type_}/{id}`. This also
+/// ensures that the same activity cannot be received more than once.
+#[tracing::instrument(skip(data, activity))]
+async fn insert_activity<T>(
   ap_id: &Url,
-  activity: serde_json::Value,
+  activity: &T,
   local: bool,
   sensitive: bool,
-  pool: &DbPool,
-) -> Result<bool, LemmyError> {
+  data: &Data<LemmyContext>,
+) -> Result<(), LemmyError>
+where
+  T: Serialize,
+{
   let ap_id = ap_id.clone().into();
-  Ok(Activity::insert(pool, ap_id, activity, local, Some(sensitive)).await?)
-}
-
-/// Common methods provided by ActivityPub actors (community and person). Not all methods are
-/// implemented by all actors.
-pub trait ActorType: Actor + ApubObject {
-  fn actor_id(&self) -> Url;
-
-  fn private_key(&self) -> Option<String>;
-
-  fn get_public_key(&self) -> PublicKey {
-    PublicKey::new_main_key(self.actor_id(), self.public_key().to_string())
-  }
+  let form = ActivityInsertForm {
+    ap_id,
+    data: serde_json::to_value(activity)?,
+    local: Some(local),
+    sensitive: Some(sensitive),
+    updated: None,
+  };
+  Activity::create(data.pool(), &form).await?;
+  Ok(())
 }
 
-#[async_trait::async_trait(?Send)]
-pub trait SendActivity {
-  type Response;
+#[async_trait::async_trait]
+pub trait SendActivity: Sync {
+  type Response: Sync + Send;
 
   async fn send_activity(
     _request: &Self,
     _response: &Self::Response,
-    _context: &LemmyContext,
+    _context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     Ok(())
   }
index e23b863441dcb605f176a3e2a518cc7c9d25d72a..4de822cc78796d0aeb070ad881927979c6b1aead 100644 (file)
@@ -1,10 +1,10 @@
-use crate::{
-  fetcher::webfinger::webfinger_resolve_actor,
-  objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson},
-  ActorType,
+use crate::objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson};
+use activitypub_federation::{
+  config::Data,
+  fetch::{object_id::ObjectId, webfinger::webfinger_resolve_actor},
+  kinds::link::MentionType,
+  traits::Actor,
 };
-use activitypub_federation::core::object_id::ObjectId;
-use activitystreams_kinds::link::MentionType;
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::{
   source::{comment::Comment, person::Person, post::Post},
@@ -46,11 +46,10 @@ pub struct MentionsAndAddresses {
 pub async fn collect_non_local_mentions(
   comment: &ApubComment,
   community_id: ObjectId<ApubCommunity>,
-  context: &LemmyContext,
-  request_counter: &mut i32,
+  context: &Data<LemmyContext>,
 ) -> Result<MentionsAndAddresses, LemmyError> {
   let parent_creator = get_comment_parent_creator(context.pool(), comment).await?;
-  let mut addressed_ccs: Vec<Url> = vec![community_id.into(), parent_creator.actor_id()];
+  let mut addressed_ccs: Vec<Url> = vec![community_id.into(), parent_creator.id()];
 
   // Add the mention tag
   let parent_creator_tag = Mention {
@@ -58,7 +57,7 @@ pub async fn collect_non_local_mentions(
     name: Some(format!(
       "@{}@{}",
       &parent_creator.name,
-      &parent_creator.actor_id().domain().expect("has domain")
+      &parent_creator.id().domain().expect("has domain")
     )),
     kind: MentionType::Mention,
   };
@@ -73,14 +72,12 @@ pub async fn collect_non_local_mentions(
 
   for mention in &mentions {
     let identifier = format!("{}@{}", mention.name, mention.domain);
-    let actor_id =
-      webfinger_resolve_actor::<ApubPerson>(&identifier, true, context, request_counter).await;
-    if let Ok(actor_id) = actor_id {
-      let actor_id: ObjectId<ApubPerson> = ObjectId::new(actor_id);
-      addressed_ccs.push(actor_id.to_string().parse()?);
+    let person = webfinger_resolve_actor::<LemmyContext, ApubPerson>(&identifier, context).await;
+    if let Ok(person) = person {
+      addressed_ccs.push(person.actor_id.to_string().parse()?);
 
       let mention_tag = Mention {
-        href: actor_id.into(),
+        href: person.id(),
         name: Some(mention.full_name()),
         kind: MentionType::Mention,
       };
index 6021ff36c717e46e2db2a818f82393e29a02efaa..e2a03b8b3f8b69f62be3c8b1fe1ff25ba8f4d106 100644 (file)
@@ -2,7 +2,6 @@ use crate::{
   activities::{verify_is_public, verify_person_in_community},
   check_apub_id_valid_with_strictness,
   fetch_local_site_data,
-  local_instance,
   mentions::collect_non_local_mentions,
   objects::{read_from_string_or_source, verify_is_remote_object},
   protocol::{
@@ -10,15 +9,13 @@ use crate::{
     InCommunity,
     Source,
   },
-  PostOrComment,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  deser::values::MediaTypeMarkdownOrHtml,
-  traits::ApubObject,
-  utils::verify_domains_match,
+  config::Data,
+  kinds::{object::NoteType, public},
+  protocol::{values::MediaTypeMarkdownOrHtml, verification::verify_domains_match},
+  traits::Object,
 };
-use activitystreams_kinds::{object::NoteType, public};
 use chrono::NaiveDateTime;
 use lemmy_api_common::{context::LemmyContext, utils::local_site_opt_to_slur_regex};
 use lemmy_db_schema::{
@@ -54,11 +51,10 @@ impl From<Comment> for ApubComment {
   }
 }
 
-#[async_trait::async_trait(?Send)]
-impl ApubObject for ApubComment {
+#[async_trait::async_trait]
+impl Object for ApubComment {
   type DataType = LemmyContext;
-  type ApubType = Note;
-  type DbType = Comment;
+  type Kind = Note;
   type Error = LemmyError;
 
   fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
@@ -66,9 +62,9 @@ impl ApubObject for ApubComment {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn read_from_apub_id(
+  async fn read_from_id(
     object_id: Url,
-    context: &LemmyContext,
+    context: &Data<Self::DataType>,
   ) -> Result<Option<Self>, LemmyError> {
     Ok(
       Comment::read_from_apub_id(context.pool(), object_id)
@@ -78,7 +74,7 @@ impl ApubObject for ApubComment {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
+  async fn delete(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
     if !self.deleted {
       let form = CommentUpdateForm::builder().deleted(Some(true)).build();
       Comment::update(context.pool(), self.id, &form).await?;
@@ -87,7 +83,7 @@ impl ApubObject for ApubComment {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn into_apub(self, context: &LemmyContext) -> Result<Note, LemmyError> {
+  async fn into_json(self, context: &Data<Self::DataType>) -> Result<Note, LemmyError> {
     let creator_id = self.creator_id;
     let creator = Person::read(context.pool(), creator_id).await?;
 
@@ -98,23 +94,17 @@ impl ApubObject for ApubComment {
 
     let in_reply_to = if let Some(comment_id) = self.parent_comment_id() {
       let parent_comment = Comment::read(context.pool(), comment_id).await?;
-      ObjectId::<PostOrComment>::new(parent_comment.ap_id)
+      parent_comment.ap_id.into()
     } else {
-      ObjectId::<PostOrComment>::new(post.ap_id)
+      post.ap_id.into()
     };
     let language = LanguageTag::new_single(self.language_id, context.pool()).await?;
-    let maa = collect_non_local_mentions(
-      &self,
-      ObjectId::new(community.actor_id.clone()),
-      context,
-      &mut 0,
-    )
-    .await?;
+    let maa = collect_non_local_mentions(&self, community.actor_id.clone().into(), context).await?;
 
     let note = Note {
       r#type: NoteType::Note,
-      id: ObjectId::new(self.ap_id.clone()),
-      attributed_to: ObjectId::new(creator.actor_id),
+      id: self.ap_id.clone().into(),
+      attributed_to: creator.actor_id.into(),
       to: vec![public()],
       cc: maa.ccs,
       content: markdown_to_html(&self.content),
@@ -126,7 +116,7 @@ impl ApubObject for ApubComment {
       tag: maa.tags,
       distinguished: Some(self.distinguished),
       language,
-      audience: Some(ObjectId::new(community.actor_id)),
+      audience: Some(community.actor_id.into()),
     };
 
     Ok(note)
@@ -136,13 +126,12 @@ impl ApubObject for ApubComment {
   async fn verify(
     note: &Note,
     expected_domain: &Url,
-    context: &LemmyContext,
-    request_counter: &mut i32,
+    context: &Data<LemmyContext>,
   ) -> Result<(), LemmyError> {
     verify_domains_match(note.id.inner(), expected_domain)?;
     verify_domains_match(note.attributed_to.inner(), note.id.inner())?;
     verify_is_public(&note.to, &note.cc)?;
-    let community = note.community(context, request_counter).await?;
+    let community = note.community(context).await?;
     let local_site_data = fetch_local_site_data(context.pool()).await?;
 
     check_apub_id_valid_with_strictness(
@@ -152,8 +141,8 @@ impl ApubObject for ApubComment {
       context.settings(),
     )?;
     verify_is_remote_object(note.id.inner(), context.settings())?;
-    verify_person_in_community(&note.attributed_to, &community, context, request_counter).await?;
-    let (post, _) = note.get_parents(context, request_counter).await?;
+    verify_person_in_community(&note.attributed_to, &community, context).await?;
+    let (post, _) = note.get_parents(context).await?;
     if post.locked {
       return Err(LemmyError::from_message("Post is locked"));
     }
@@ -164,16 +153,9 @@ impl ApubObject for ApubComment {
   ///
   /// If the parent community, post and comment(s) are not known locally, these are also fetched.
   #[tracing::instrument(skip_all)]
-  async fn from_apub(
-    note: Note,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubComment, LemmyError> {
-    let creator = note
-      .attributed_to
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
-    let (post, parent_comment) = note.get_parents(context, request_counter).await?;
+  async fn from_json(note: Note, context: &Data<LemmyContext>) -> Result<ApubComment, LemmyError> {
+    let creator = note.attributed_to.dereference(context).await?;
+    let (post, parent_comment) = note.get_parents(context).await?;
 
     let content = read_from_string_or_source(&note.content, &note.media_type, &note.source);
 
@@ -221,17 +203,15 @@ pub(crate) mod tests {
 
   async fn prepare_comment_test(
     url: &Url,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> (ApubPerson, ApubCommunity, ApubPost, ApubSite) {
-    let (person, site) = parse_lemmy_person(context).await;
-    let community = parse_lemmy_community(context).await;
+    // use separate counter so this doesnt affect tests
+    let context2 = context.reset_request_count();
+    let (person, site) = parse_lemmy_person(&context2).await;
+    let community = parse_lemmy_community(&context2).await;
     let post_json = file_to_json_object("assets/lemmy/objects/page.json").unwrap();
-    ApubPost::verify(&post_json, url, context, &mut 0)
-      .await
-      .unwrap();
-    let post = ApubPost::from_apub(post_json, context, &mut 0)
-      .await
-      .unwrap();
+    ApubPost::verify(&post_json, url, &context2).await.unwrap();
+    let post = ApubPost::from_json(post_json, &context2).await.unwrap();
     (person, community, post, site)
   }
 
@@ -251,21 +231,18 @@ pub(crate) mod tests {
     let data = prepare_comment_test(&url, &context).await;
 
     let json: Note = file_to_json_object("assets/lemmy/objects/note.json").unwrap();
-    let mut request_counter = 0;
-    ApubComment::verify(&json, &url, &context, &mut request_counter)
-      .await
-      .unwrap();
-    let comment = ApubComment::from_apub(json.clone(), &context, &mut request_counter)
+    ApubComment::verify(&json, &url, &context).await.unwrap();
+    let comment = ApubComment::from_json(json.clone(), &context)
       .await
       .unwrap();
 
     assert_eq!(comment.ap_id, url.into());
     assert_eq!(comment.content.len(), 14);
     assert!(!comment.local);
-    assert_eq!(request_counter, 0);
+    assert_eq!(context.request_count(), 0);
 
     let comment_id = comment.id;
-    let to_apub = comment.into_apub(&context).await.unwrap();
+    let to_apub = comment.into_json(&context).await.unwrap();
     assert_json_include!(actual: json, expected: to_apub);
 
     Comment::delete(context.pool(), comment_id).await.unwrap();
@@ -283,25 +260,20 @@ pub(crate) mod tests {
       Url::parse("https://queer.hacktivis.me/objects/8d4973f4-53de-49cd-8c27-df160e16a9c2")
         .unwrap();
     let person_json = file_to_json_object("assets/pleroma/objects/person.json").unwrap();
-    ApubPerson::verify(&person_json, &pleroma_url, &context, &mut 0)
-      .await
-      .unwrap();
-    ApubPerson::from_apub(person_json, &context, &mut 0)
+    ApubPerson::verify(&person_json, &pleroma_url, &context)
       .await
       .unwrap();
+    ApubPerson::from_json(person_json, &context).await.unwrap();
     let json = file_to_json_object("assets/pleroma/objects/note.json").unwrap();
-    let mut request_counter = 0;
-    ApubComment::verify(&json, &pleroma_url, &context, &mut request_counter)
-      .await
-      .unwrap();
-    let comment = ApubComment::from_apub(json, &context, &mut request_counter)
+    ApubComment::verify(&json, &pleroma_url, &context)
       .await
       .unwrap();
+    let comment = ApubComment::from_json(json, &context).await.unwrap();
 
     assert_eq!(comment.ap_id, pleroma_url.into());
     assert_eq!(comment.content.len(), 64);
     assert!(!comment.local);
-    assert_eq!(request_counter, 0);
+    assert_eq!(context.request_count(), 1);
 
     Comment::delete(context.pool(), comment.id).await.unwrap();
     cleanup(data, &context).await;
index 7a1583ca09239ee5b107c7623a6df8c32114e50d..396c2af870e45be386f6f0a53d52f83b15ebbdfe 100644 (file)
@@ -1,21 +1,18 @@
 use crate::{
   check_apub_id_valid_with_strictness,
-  collections::CommunityContext,
   fetch_local_site_data,
-  local_instance,
   objects::instance::fetch_instance_actor_for_object,
   protocol::{
     objects::{group::Group, Endpoints, LanguageTag},
     ImageObject,
     Source,
   },
-  ActorType,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  traits::{Actor, ApubObject},
+  config::Data,
+  kinds::actor::GroupType,
+  traits::{Actor, Object},
 };
-use activitystreams_kinds::actor::GroupType;
 use chrono::NaiveDateTime;
 use itertools::Itertools;
 use lemmy_api_common::{
@@ -54,11 +51,10 @@ impl From<Community> for ApubCommunity {
   }
 }
 
-#[async_trait::async_trait(?Send)]
-impl ApubObject for ApubCommunity {
+#[async_trait::async_trait]
+impl Object for ApubCommunity {
   type DataType = LemmyContext;
-  type ApubType = Group;
-  type DbType = Community;
+  type Kind = Group;
   type Error = LemmyError;
 
   fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
@@ -66,9 +62,9 @@ impl ApubObject for ApubCommunity {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn read_from_apub_id(
+  async fn read_from_id(
     object_id: Url,
-    context: &LemmyContext,
+    context: &Data<Self::DataType>,
   ) -> Result<Option<Self>, LemmyError> {
     Ok(
       Community::read_from_apub_id(context.pool(), &object_id.into())
@@ -78,21 +74,21 @@ impl ApubObject for ApubCommunity {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
+  async fn delete(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
     let form = CommunityUpdateForm::builder().deleted(Some(true)).build();
     Community::update(context.pool(), self.id, &form).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn into_apub(self, data: &LemmyContext) -> Result<Group, LemmyError> {
+  async fn into_json(self, data: &Data<Self::DataType>) -> Result<Group, LemmyError> {
     let community_id = self.id;
     let langs = CommunityLanguage::read(data.pool(), community_id).await?;
     let language = LanguageTag::new_multiple(langs, data.pool()).await?;
 
     let group = Group {
       kind: GroupType::Group,
-      id: ObjectId::new(self.actor_id()),
+      id: self.id().into(),
       preferred_username: self.name.clone(),
       name: Some(self.title.clone()),
       summary: self.description.as_ref().map(|b| markdown_to_html(b)),
@@ -103,12 +99,12 @@ impl ApubObject for ApubCommunity {
       moderators: Some(generate_moderators_url(&self.actor_id)?.into()),
       featured: Some(generate_featured_url(&self.actor_id)?.into()),
       inbox: self.inbox_url.clone().into(),
-      outbox: ObjectId::new(generate_outbox_url(&self.actor_id)?),
+      outbox: generate_outbox_url(&self.actor_id)?.into(),
       followers: self.followers_url.clone().into(),
       endpoints: self.shared_inbox_url.clone().map(|s| Endpoints {
         shared_inbox: s.into(),
       }),
-      public_key: self.get_public_key(),
+      public_key: self.public_key(),
       language,
       published: Some(convert_datetime(self.published)),
       updated: self.updated.map(convert_datetime),
@@ -122,20 +118,18 @@ impl ApubObject for ApubCommunity {
   async fn verify(
     group: &Group,
     expected_domain: &Url,
-    context: &LemmyContext,
-    _request_counter: &mut i32,
+    context: &Data<Self::DataType>,
   ) -> Result<(), LemmyError> {
     group.verify(expected_domain, context).await
   }
 
   /// Converts a `Group` to `Community`, inserts it into the database and updates moderators.
   #[tracing::instrument(skip_all)]
-  async fn from_apub(
+  async fn from_json(
     group: Group,
-    context: &LemmyContext,
-    request_counter: &mut i32,
+    context: &Data<Self::DataType>,
   ) -> Result<ApubCommunity, LemmyError> {
-    let instance_id = fetch_instance_actor_for_object(&group.id, context, request_counter).await?;
+    let instance_id = fetch_instance_actor_for_object(&group.id, context).await?;
 
     let form = Group::into_insert_form(group.clone(), instance_id);
     let languages = LanguageTag::to_language_id_multiple(group.language, context.pool()).await?;
@@ -144,20 +138,19 @@ impl ApubObject for ApubCommunity {
     CommunityLanguage::update(context.pool(), languages, community.id).await?;
 
     let community: ApubCommunity = community.into();
-    let outbox_data = CommunityContext(community.clone(), context.clone());
 
     // Fetching mods and outbox is not necessary for Lemmy to work, so ignore errors. Besides,
     // we need to ignore these errors so that tests can work entirely offline.
     group
       .outbox
-      .dereference(&outbox_data, local_instance(context).await, request_counter)
+      .dereference(&community, context)
       .await
       .map_err(|e| debug!("{}", e))
       .ok();
 
     if let Some(moderators) = group.attributed_to.or(group.moderators) {
       moderators
-        .dereference(&outbox_data, local_instance(context).await, request_counter)
+        .dereference(&community, context)
         .await
         .map_err(|e| debug!("{}", e))
         .ok();
@@ -168,10 +161,18 @@ impl ApubObject for ApubCommunity {
 }
 
 impl Actor for ApubCommunity {
-  fn public_key(&self) -> &str {
+  fn id(&self) -> Url {
+    self.actor_id.inner().clone()
+  }
+
+  fn public_key_pem(&self) -> &str {
     &self.public_key
   }
 
+  fn private_key_pem(&self) -> Option<String> {
+    self.private_key.clone()
+  }
+
   fn inbox(&self) -> Url {
     self.inbox_url.clone().into()
   }
@@ -181,15 +182,6 @@ impl Actor for ApubCommunity {
   }
 }
 
-impl ActorType for ApubCommunity {
-  fn actor_id(&self) -> Url {
-    self.actor_id.clone().into()
-  }
-  fn private_key(&self) -> Option<String> {
-    self.private_key.clone()
-  }
-}
-
 impl ApubCommunity {
   /// For a given community, returns the inboxes of all followers.
   #[tracing::instrument(skip_all)]
@@ -230,27 +222,25 @@ pub(crate) mod tests {
     objects::{instance::tests::parse_lemmy_instance, tests::init_context},
     protocol::tests::file_to_json_object,
   };
+  use activitypub_federation::fetch::collection_id::CollectionId;
   use lemmy_db_schema::{source::site::Site, traits::Crud};
   use serial_test::serial;
 
-  pub(crate) async fn parse_lemmy_community(context: &LemmyContext) -> ApubCommunity {
+  pub(crate) async fn parse_lemmy_community(context: &Data<LemmyContext>) -> ApubCommunity {
+    // use separate counter so this doesnt affect tests
+    let context2 = context.reset_request_count();
     let mut json: Group = file_to_json_object("assets/lemmy/objects/group.json").unwrap();
     // change these links so they dont fetch over the network
     json.moderators = None;
     json.attributed_to = None;
     json.outbox =
-      ObjectId::new(Url::parse("https://enterprise.lemmy.ml/c/tenforward/not_outbox").unwrap());
+      CollectionId::parse("https://enterprise.lemmy.ml/c/tenforward/not_outbox").unwrap();
 
     let url = Url::parse("https://enterprise.lemmy.ml/c/tenforward").unwrap();
-    let mut request_counter = 0;
-    ApubCommunity::verify(&json, &url, context, &mut request_counter)
-      .await
-      .unwrap();
-    let community = ApubCommunity::from_apub(json, context, &mut request_counter)
-      .await
-      .unwrap();
+    ApubCommunity::verify(&json, &url, &context2).await.unwrap();
+    let community = ApubCommunity::from_json(json, &context2).await.unwrap();
     // this makes one requests to the (intentionally broken) outbox collection
-    assert_eq!(request_counter, 1);
+    assert_eq!(context2.request_count(), 1);
     community
   }
 
index 8fa3976ac6b1c0e6e58cb868451a7bd5c34bcdd2..4cb96a0fbda6198923f0fdc7c21851ce01645c39 100644 (file)
@@ -1,22 +1,20 @@
 use crate::{
   check_apub_id_valid_with_strictness,
   fetch_local_site_data,
-  local_instance,
   objects::read_from_string_or_source_opt,
   protocol::{
     objects::{instance::Instance, LanguageTag},
     ImageObject,
     Source,
   },
-  ActorType,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  deser::values::MediaTypeHtml,
-  traits::{Actor, ApubObject},
-  utils::verify_domains_match,
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::actor::ApplicationType,
+  protocol::{values::MediaTypeHtml, verification::verify_domains_match},
+  traits::{Actor, Object},
 };
-use activitystreams_kinds::actor::ApplicationType;
 use chrono::NaiveDateTime;
 use lemmy_api_common::{context::LemmyContext, utils::local_site_opt_to_slur_regex};
 use lemmy_db_schema::{
@@ -57,11 +55,10 @@ impl From<Site> for ApubSite {
   }
 }
 
-#[async_trait::async_trait(?Send)]
-impl ApubObject for ApubSite {
+#[async_trait::async_trait]
+impl Object for ApubSite {
   type DataType = LemmyContext;
-  type ApubType = Instance;
-  type DbType = Site;
+  type Kind = Instance;
   type Error = LemmyError;
 
   fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
@@ -69,9 +66,9 @@ impl ApubObject for ApubSite {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn read_from_apub_id(
+  async fn read_from_id(
     object_id: Url,
-    data: &Self::DataType,
+    data: &Data<Self::DataType>,
   ) -> Result<Option<Self>, LemmyError> {
     Ok(
       Site::read_from_apub_id(data.pool(), object_id)
@@ -80,19 +77,19 @@ impl ApubObject for ApubSite {
     )
   }
 
-  async fn delete(self, _data: &Self::DataType) -> Result<(), LemmyError> {
+  async fn delete(self, _data: &Data<Self::DataType>) -> Result<(), LemmyError> {
     unimplemented!()
   }
 
   #[tracing::instrument(skip_all)]
-  async fn into_apub(self, data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
+  async fn into_json(self, data: &Data<Self::DataType>) -> Result<Self::Kind, LemmyError> {
     let site_id = self.id;
     let langs = SiteLanguage::read(data.pool(), site_id).await?;
     let language = LanguageTag::new_multiple(langs, data.pool()).await?;
 
     let instance = Instance {
       kind: ApplicationType::Application,
-      id: ObjectId::new(self.actor_id()),
+      id: self.id().into(),
       name: self.name.clone(),
       content: self.sidebar.as_ref().map(|d| markdown_to_html(d)),
       source: self.sidebar.clone().map(Source::new),
@@ -102,7 +99,7 @@ impl ApubObject for ApubSite {
       image: self.banner.clone().map(ImageObject::new),
       inbox: self.inbox_url.clone().into(),
       outbox: Url::parse(&format!("{}/site_outbox", self.actor_id))?,
-      public_key: self.get_public_key(),
+      public_key: self.public_key(),
       language,
       published: convert_datetime(self.published),
       updated: self.updated.map(convert_datetime),
@@ -112,10 +109,9 @@ impl ApubObject for ApubSite {
 
   #[tracing::instrument(skip_all)]
   async fn verify(
-    apub: &Self::ApubType,
+    apub: &Self::Kind,
     expected_domain: &Url,
-    data: &Self::DataType,
-    _request_counter: &mut i32,
+    data: &Data<Self::DataType>,
   ) -> Result<(), LemmyError> {
     let local_site_data = fetch_local_site_data(data.pool()).await?;
 
@@ -130,11 +126,7 @@ impl ApubObject for ApubSite {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn from_apub(
-    apub: Self::ApubType,
-    data: &Self::DataType,
-    _request_counter: &mut i32,
-  ) -> Result<Self, LemmyError> {
+  async fn from_json(apub: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, LemmyError> {
     let domain = apub.id.inner().domain().expect("group id has domain");
     let instance = DbInstance::read_or_create(data.pool(), domain.to_string()).await?;
 
@@ -160,20 +152,19 @@ impl ApubObject for ApubSite {
   }
 }
 
-impl ActorType for ApubSite {
-  fn actor_id(&self) -> Url {
-    self.actor_id.clone().into()
-  }
-  fn private_key(&self) -> Option<String> {
-    self.private_key.clone()
+impl Actor for ApubSite {
+  fn id(&self) -> Url {
+    self.actor_id.inner().clone()
   }
-}
 
-impl Actor for ApubSite {
-  fn public_key(&self) -> &str {
+  fn public_key_pem(&self) -> &str {
     &self.public_key
   }
 
+  fn private_key_pem(&self) -> Option<String> {
+    self.private_key.clone()
+  }
+
   fn inbox(&self) -> Url {
     self.inbox_url.clone().into()
   }
@@ -182,13 +173,12 @@ impl Actor for ApubSite {
 /// Try to fetch the instance actor (to make things like instance rules available).
 pub(in crate::objects) async fn fetch_instance_actor_for_object<T: Into<Url> + Clone>(
   object_id: &T,
-  context: &LemmyContext,
-  request_counter: &mut i32,
+  context: &Data<LemmyContext>,
 ) -> Result<InstanceId, LemmyError> {
   let object_id: Url = object_id.clone().into();
   let instance_id = Site::instance_actor_id_from_url(object_id);
-  let site = ObjectId::<ApubSite>::new(instance_id.clone())
-    .dereference(context, local_instance(context).await, request_counter)
+  let site = ObjectId::<ApubSite>::from(instance_id.clone())
+    .dereference(context)
     .await;
   match site {
     Ok(s) => Ok(s.instance_id),
@@ -222,17 +212,12 @@ pub(crate) mod tests {
   use lemmy_db_schema::traits::Crud;
   use serial_test::serial;
 
-  pub(crate) async fn parse_lemmy_instance(context: &LemmyContext) -> ApubSite {
+  pub(crate) async fn parse_lemmy_instance(context: &Data<LemmyContext>) -> ApubSite {
     let json: Instance = file_to_json_object("assets/lemmy/objects/instance.json").unwrap();
     let id = Url::parse("https://enterprise.lemmy.ml/").unwrap();
-    let mut request_counter = 0;
-    ApubSite::verify(&json, &id, context, &mut request_counter)
-      .await
-      .unwrap();
-    let site = ApubSite::from_apub(json, context, &mut request_counter)
-      .await
-      .unwrap();
-    assert_eq!(request_counter, 0);
+    ApubSite::verify(&json, &id, context).await.unwrap();
+    let site = ApubSite::from_json(json, context).await.unwrap();
+    assert_eq!(context.request_count(), 0);
     site
   }
 
index 29df3d64a3ecb342f4cec6167774c0afb62cfc27..6d2ff291cb66ae84c8d86fbc36fb6e489d114958 100644 (file)
@@ -1,5 +1,5 @@
 use crate::protocol::Source;
-use activitypub_federation::deser::values::MediaTypeMarkdownOrHtml;
+use activitypub_federation::protocol::values::MediaTypeMarkdownOrHtml;
 use anyhow::anyhow;
 use html2md::parse_html;
 use lemmy_utils::{error::LemmyError, settings::structs::Settings};
@@ -54,6 +54,7 @@ pub(crate) fn verify_is_remote_object(id: &Url, settings: &Settings) -> Result<(
 
 #[cfg(test)]
 pub(crate) mod tests {
+  use activitypub_federation::config::{Data, FederationConfig};
   use anyhow::anyhow;
   use lemmy_api_common::{
     context::LemmyContext,
@@ -87,7 +88,7 @@ pub(crate) mod tests {
   }
 
   // TODO: would be nice if we didnt have to use a full context for tests.
-  pub(crate) async fn init_context() -> LemmyContext {
+  pub(crate) async fn init_context() -> Data<LemmyContext> {
     async fn x() -> Result<String, LemmyError> {
       Ok(String::new())
     }
@@ -110,13 +111,12 @@ pub(crate) mod tests {
     let rate_limit_cell = RateLimitCell::new(rate_limit_config).await;
 
     let chat_server = Arc::new(ChatServer::startup());
-    LemmyContext::create(
-      pool,
-      chat_server,
-      client,
-      settings,
-      secret,
-      rate_limit_cell.clone(),
-    )
+    let context = LemmyContext::create(pool, chat_server, client, secret, rate_limit_cell.clone());
+    let config = FederationConfig::builder()
+      .domain("example.com")
+      .app_data(context)
+      .build()
+      .unwrap();
+    config.to_request_data()
   }
 }
index 55bfcd29afe1567563d9253c68c94b5afa4d65a1..e5431d141b084007e88e50a9e78c6824897d7343 100644 (file)
@@ -10,12 +10,11 @@ use crate::{
     ImageObject,
     Source,
   },
-  ActorType,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  traits::{Actor, ApubObject},
-  utils::verify_domains_match,
+  config::Data,
+  protocol::verification::verify_domains_match,
+  traits::{Actor, Object},
 };
 use chrono::NaiveDateTime;
 use lemmy_api_common::{
@@ -54,11 +53,10 @@ impl From<DbPerson> for ApubPerson {
   }
 }
 
-#[async_trait::async_trait(?Send)]
-impl ApubObject for ApubPerson {
+#[async_trait::async_trait]
+impl Object for ApubPerson {
   type DataType = LemmyContext;
-  type ApubType = Person;
-  type DbType = DbPerson;
+  type Kind = Person;
   type Error = LemmyError;
 
   fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
@@ -66,9 +64,9 @@ impl ApubObject for ApubPerson {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn read_from_apub_id(
+  async fn read_from_id(
     object_id: Url,
-    context: &LemmyContext,
+    context: &Data<Self::DataType>,
   ) -> Result<Option<Self>, LemmyError> {
     Ok(
       DbPerson::read_from_apub_id(context.pool(), &object_id.into())
@@ -78,14 +76,14 @@ impl ApubObject for ApubPerson {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
+  async fn delete(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
     let form = PersonUpdateForm::builder().deleted(Some(true)).build();
     DbPerson::update(context.pool(), self.id, &form).await?;
     Ok(())
   }
 
   #[tracing::instrument(skip_all)]
-  async fn into_apub(self, _pool: &LemmyContext) -> Result<Person, LemmyError> {
+  async fn into_json(self, _context: &Data<Self::DataType>) -> Result<Person, LemmyError> {
     let kind = if self.bot_account {
       UserTypes::Service
     } else {
@@ -94,7 +92,7 @@ impl ApubObject for ApubPerson {
 
     let person = Person {
       kind,
-      id: ObjectId::new(self.actor_id.clone()),
+      id: self.actor_id.clone().into(),
       preferred_username: self.name.clone(),
       name: self.display_name.clone(),
       summary: self.bio.as_ref().map(|b| markdown_to_html(b)),
@@ -107,7 +105,7 @@ impl ApubObject for ApubPerson {
       endpoints: self.shared_inbox_url.clone().map(|s| Endpoints {
         shared_inbox: s.into(),
       }),
-      public_key: self.get_public_key(),
+      public_key: self.public_key(),
       updated: self.updated.map(convert_datetime),
       inbox: self.inbox_url.clone().into(),
     };
@@ -118,8 +116,7 @@ impl ApubObject for ApubPerson {
   async fn verify(
     person: &Person,
     expected_domain: &Url,
-    context: &LemmyContext,
-    _request_counter: &mut i32,
+    context: &Data<Self::DataType>,
   ) -> Result<(), LemmyError> {
     let local_site_data = fetch_local_site_data(context.pool()).await?;
     let slur_regex = &local_site_opt_to_slur_regex(&local_site_data.local_site);
@@ -141,12 +138,11 @@ impl ApubObject for ApubPerson {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn from_apub(
+  async fn from_json(
     person: Person,
-    context: &LemmyContext,
-    request_counter: &mut i32,
+    context: &Data<Self::DataType>,
   ) -> Result<ApubPerson, LemmyError> {
-    let instance_id = fetch_instance_actor_for_object(&person.id, context, request_counter).await?;
+    let instance_id = fetch_instance_actor_for_object(&person.id, context).await?;
 
     let person_form = PersonInsertForm {
       name: person.preferred_username,
@@ -177,19 +173,17 @@ impl ApubObject for ApubPerson {
   }
 }
 
-impl ActorType for ApubPerson {
-  fn actor_id(&self) -> Url {
-    self.actor_id.clone().into()
+impl Actor for ApubPerson {
+  fn id(&self) -> Url {
+    self.actor_id.inner().clone()
   }
 
-  fn private_key(&self) -> Option<String> {
-    self.private_key.clone()
+  fn public_key_pem(&self) -> &str {
+    &self.public_key
   }
-}
 
-impl Actor for ApubPerson {
-  fn public_key(&self) -> &str {
-    &self.public_key
+  fn private_key_pem(&self) -> Option<String> {
+    self.private_key.clone()
   }
 
   fn inbox(&self) -> Url {
@@ -211,21 +205,17 @@ pub(crate) mod tests {
     },
     protocol::{objects::instance::Instance, tests::file_to_json_object},
   };
+  use activitypub_federation::fetch::object_id::ObjectId;
   use lemmy_db_schema::{source::site::Site, traits::Crud};
   use serial_test::serial;
 
-  pub(crate) async fn parse_lemmy_person(context: &LemmyContext) -> (ApubPerson, ApubSite) {
+  pub(crate) async fn parse_lemmy_person(context: &Data<LemmyContext>) -> (ApubPerson, ApubSite) {
     let site = parse_lemmy_instance(context).await;
     let json = file_to_json_object("assets/lemmy/objects/person.json").unwrap();
     let url = Url::parse("https://enterprise.lemmy.ml/u/picard").unwrap();
-    let mut request_counter = 0;
-    ApubPerson::verify(&json, &url, context, &mut request_counter)
-      .await
-      .unwrap();
-    let person = ApubPerson::from_apub(json, context, &mut request_counter)
-      .await
-      .unwrap();
-    assert_eq!(request_counter, 0);
+    ApubPerson::verify(&json, &url, context).await.unwrap();
+    let person = ApubPerson::from_json(json, context).await.unwrap();
+    assert_eq!(context.request_count(), 0);
     (person, site)
   }
 
@@ -249,27 +239,19 @@ pub(crate) mod tests {
 
     // create and parse a fake pleroma instance actor, to avoid network request during test
     let mut json: Instance = file_to_json_object("assets/lemmy/objects/instance.json").unwrap();
-    let id = Url::parse("https://queer.hacktivis.me/").unwrap();
-    json.id = ObjectId::new(id);
-    let mut request_counter = 0;
-    let site = ApubSite::from_apub(json, &context, &mut request_counter)
-      .await
-      .unwrap();
+    json.id = ObjectId::parse("https://queer.hacktivis.me/").unwrap();
+    let url = Url::parse("https://queer.hacktivis.me/users/lanodan").unwrap();
+    ApubSite::verify(&json, &url, &context).await.unwrap();
+    let site = ApubSite::from_json(json, &context).await.unwrap();
 
     let json = file_to_json_object("assets/pleroma/objects/person.json").unwrap();
-    let url = Url::parse("https://queer.hacktivis.me/users/lanodan").unwrap();
-    let mut request_counter = 0;
-    ApubPerson::verify(&json, &url, &context, &mut request_counter)
-      .await
-      .unwrap();
-    let person = ApubPerson::from_apub(json, &context, &mut request_counter)
-      .await
-      .unwrap();
+    ApubPerson::verify(&json, &url, &context).await.unwrap();
+    let person = ApubPerson::from_json(json, &context).await.unwrap();
 
     assert_eq!(person.actor_id, url.into());
     assert_eq!(person.name, "lanodan");
     assert!(!person.local);
-    assert_eq!(request_counter, 0);
+    assert_eq!(context.request_count(), 0);
     assert_eq!(person.bio.as_ref().unwrap().len(), 873);
 
     cleanup((person, site), &context).await;
index dd7291bd5cc78374e995958d6623732e0b049963..7bc933398dc538a7c217317639b63f9bbf652fa0 100644 (file)
@@ -2,7 +2,6 @@ use crate::{
   activities::{verify_is_public, verify_person_in_community},
   check_apub_id_valid_with_strictness,
   fetch_local_site_data,
-  local_instance,
   objects::{read_from_string_or_source_opt, verify_is_remote_object},
   protocol::{
     objects::{
@@ -15,12 +14,11 @@ use crate::{
   },
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  deser::values::MediaTypeMarkdownOrHtml,
-  traits::ApubObject,
-  utils::verify_domains_match,
+  config::Data,
+  kinds::public,
+  protocol::{values::MediaTypeMarkdownOrHtml, verification::verify_domains_match},
+  traits::Object,
 };
-use activitystreams_kinds::public;
 use anyhow::anyhow;
 use chrono::NaiveDateTime;
 use html2md::parse_html;
@@ -69,11 +67,10 @@ impl From<Post> for ApubPost {
   }
 }
 
-#[async_trait::async_trait(?Send)]
-impl ApubObject for ApubPost {
+#[async_trait::async_trait]
+impl Object for ApubPost {
   type DataType = LemmyContext;
-  type ApubType = Page;
-  type DbType = Post;
+  type Kind = Page;
   type Error = LemmyError;
 
   fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
@@ -81,9 +78,9 @@ impl ApubObject for ApubPost {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn read_from_apub_id(
+  async fn read_from_id(
     object_id: Url,
-    context: &LemmyContext,
+    context: &Data<Self::DataType>,
   ) -> Result<Option<Self>, LemmyError> {
     Ok(
       Post::read_from_apub_id(context.pool(), object_id)
@@ -93,7 +90,7 @@ impl ApubObject for ApubPost {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
+  async fn delete(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
     if !self.deleted {
       let form = PostUpdateForm::builder().deleted(Some(true)).build();
       Post::update(context.pool(), self.id, &form).await?;
@@ -103,7 +100,7 @@ impl ApubObject for ApubPost {
 
   // Turn a Lemmy post into an ActivityPub page that can be sent out over the network.
   #[tracing::instrument(skip_all)]
-  async fn into_apub(self, context: &LemmyContext) -> Result<Page, LemmyError> {
+  async fn into_json(self, context: &Data<Self::DataType>) -> Result<Page, LemmyError> {
     let creator_id = self.creator_id;
     let creator = Person::read(context.pool(), creator_id).await?;
     let community_id = self.community_id;
@@ -112,8 +109,8 @@ impl ApubObject for ApubPost {
 
     let page = Page {
       kind: PageType::Page,
-      id: ObjectId::new(self.ap_id.clone()),
-      attributed_to: AttributedTo::Lemmy(ObjectId::new(creator.actor_id)),
+      id: self.ap_id.clone().into(),
+      attributed_to: AttributedTo::Lemmy(creator.actor_id.into()),
       to: vec![community.actor_id.clone().into(), public()],
       cc: vec![],
       name: Some(self.name.clone()),
@@ -128,7 +125,7 @@ impl ApubObject for ApubPost {
       language,
       published: Some(convert_datetime(self.published)),
       updated: self.updated.map(convert_datetime),
-      audience: Some(ObjectId::new(community.actor_id)),
+      audience: Some(community.actor_id.into()),
       in_reply_to: None,
     };
     Ok(page)
@@ -138,8 +135,7 @@ impl ApubObject for ApubPost {
   async fn verify(
     page: &Page,
     expected_domain: &Url,
-    context: &LemmyContext,
-    request_counter: &mut i32,
+    context: &Data<Self::DataType>,
   ) -> Result<(), LemmyError> {
     // We can't verify the domain in case of mod action, because the mod may be on a different
     // instance from the post author.
@@ -150,14 +146,14 @@ impl ApubObject for ApubPost {
 
     let local_site_data = fetch_local_site_data(context.pool()).await?;
 
-    let community = page.community(context, request_counter).await?;
+    let community = page.community(context).await?;
     check_apub_id_valid_with_strictness(
       page.id.inner(),
       community.local,
       &local_site_data,
       context.settings(),
     )?;
-    verify_person_in_community(&page.creator()?, &community, context, request_counter).await?;
+    verify_person_in_community(&page.creator()?, &community, context).await?;
 
     let slur_regex = &local_site_opt_to_slur_regex(&local_site_data.local_site);
     check_slurs_opt(&page.name, slur_regex)?;
@@ -168,16 +164,9 @@ impl ApubObject for ApubPost {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn from_apub(
-    page: Page,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubPost, LemmyError> {
-    let creator = page
-      .creator()?
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
-    let community = page.community(context, request_counter).await?;
+  async fn from_json(page: Page, context: &Data<Self::DataType>) -> Result<ApubPost, LemmyError> {
+    let creator = page.creator()?.dereference(context).await?;
+    let community = page.community(context).await?;
     if community.posting_restricted_to_mods {
       is_mod_or_admin(context.pool(), creator.id, community.id).await?;
     }
@@ -257,9 +246,7 @@ impl ApubObject for ApubPost {
         .build()
     };
     // read existing, local post if any (for generating mod log)
-    let old_post = ObjectId::<ApubPost>::new(page.id.clone())
-      .dereference_local(context)
-      .await;
+    let old_post = page.id.dereference_local(context).await;
 
     let post = Post::create(context.pool(), &form).await?;
 
@@ -310,13 +297,8 @@ mod tests {
 
     let json = file_to_json_object("assets/lemmy/objects/page.json").unwrap();
     let url = Url::parse("https://enterprise.lemmy.ml/post/55143").unwrap();
-    let mut request_counter = 0;
-    ApubPost::verify(&json, &url, &context, &mut request_counter)
-      .await
-      .unwrap();
-    let post = ApubPost::from_apub(json, &context, &mut request_counter)
-      .await
-      .unwrap();
+    ApubPost::verify(&json, &url, &context).await.unwrap();
+    let post = ApubPost::from_json(json, &context).await.unwrap();
 
     assert_eq!(post.ap_id, url.into());
     assert_eq!(post.name, "Post title");
@@ -324,7 +306,7 @@ mod tests {
     assert_eq!(post.body.as_ref().unwrap().len(), 45);
     assert!(!post.locked);
     assert!(post.featured_community);
-    assert_eq!(request_counter, 0);
+    assert_eq!(context.request_count(), 0);
 
     Post::delete(context.pool(), post.id).await.unwrap();
     Person::delete(context.pool(), person.id).await.unwrap();
index 233e8eaa6757536f44d5ef478514c061b4c77348..01f576ff8ff667f7ed8679850271ad9cc9a8d4f1 100644 (file)
@@ -1,7 +1,6 @@
 use crate::{
   check_apub_id_valid_with_strictness,
   fetch_local_site_data,
-  local_instance,
   objects::read_from_string_or_source,
   protocol::{
     objects::chat_message::{ChatMessage, ChatMessageType},
@@ -9,10 +8,9 @@ use crate::{
   },
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  deser::values::MediaTypeHtml,
-  traits::ApubObject,
-  utils::verify_domains_match,
+  config::Data,
+  protocol::{values::MediaTypeHtml, verification::verify_domains_match},
+  traits::Object,
 };
 use chrono::NaiveDateTime;
 use lemmy_api_common::{context::LemmyContext, utils::check_person_block};
@@ -46,11 +44,10 @@ impl From<PrivateMessage> for ApubPrivateMessage {
   }
 }
 
-#[async_trait::async_trait(?Send)]
-impl ApubObject for ApubPrivateMessage {
+#[async_trait::async_trait]
+impl Object for ApubPrivateMessage {
   type DataType = LemmyContext;
-  type ApubType = ChatMessage;
-  type DbType = PrivateMessage;
+  type Kind = ChatMessage;
   type Error = LemmyError;
 
   fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
@@ -58,9 +55,9 @@ impl ApubObject for ApubPrivateMessage {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn read_from_apub_id(
+  async fn read_from_id(
     object_id: Url,
-    context: &LemmyContext,
+    context: &Data<Self::DataType>,
   ) -> Result<Option<Self>, LemmyError> {
     Ok(
       PrivateMessage::read_from_apub_id(context.pool(), object_id)
@@ -69,13 +66,13 @@ impl ApubObject for ApubPrivateMessage {
     )
   }
 
-  async fn delete(self, _context: &LemmyContext) -> Result<(), LemmyError> {
+  async fn delete(self, _context: &Data<Self::DataType>) -> Result<(), LemmyError> {
     // do nothing, because pm can't be fetched over http
     unimplemented!()
   }
 
   #[tracing::instrument(skip_all)]
-  async fn into_apub(self, context: &LemmyContext) -> Result<ChatMessage, LemmyError> {
+  async fn into_json(self, context: &Data<Self::DataType>) -> Result<ChatMessage, LemmyError> {
     let creator_id = self.creator_id;
     let creator = Person::read(context.pool(), creator_id).await?;
 
@@ -84,9 +81,9 @@ impl ApubObject for ApubPrivateMessage {
 
     let note = ChatMessage {
       r#type: ChatMessageType::ChatMessage,
-      id: ObjectId::new(self.ap_id.clone()),
-      attributed_to: ObjectId::new(creator.actor_id),
-      to: [ObjectId::new(recipient.actor_id)],
+      id: self.ap_id.clone().into(),
+      attributed_to: creator.actor_id.into(),
+      to: [recipient.actor_id.into()],
       content: markdown_to_html(&self.content),
       media_type: Some(MediaTypeHtml::Html),
       source: Some(Source::new(self.content.clone())),
@@ -100,8 +97,7 @@ impl ApubObject for ApubPrivateMessage {
   async fn verify(
     note: &ChatMessage,
     expected_domain: &Url,
-    context: &LemmyContext,
-    request_counter: &mut i32,
+    context: &Data<Self::DataType>,
   ) -> Result<(), LemmyError> {
     verify_domains_match(note.id.inner(), expected_domain)?;
     verify_domains_match(note.attributed_to.inner(), note.id.inner())?;
@@ -114,10 +110,7 @@ impl ApubObject for ApubPrivateMessage {
       &local_site_data,
       context.settings(),
     )?;
-    let person = note
-      .attributed_to
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+    let person = note.attributed_to.dereference(context).await?;
     if person.banned {
       return Err(LemmyError::from_message("Person is banned from site"));
     }
@@ -125,18 +118,12 @@ impl ApubObject for ApubPrivateMessage {
   }
 
   #[tracing::instrument(skip_all)]
-  async fn from_apub(
+  async fn from_json(
     note: ChatMessage,
-    context: &LemmyContext,
-    request_counter: &mut i32,
+    context: &Data<Self::DataType>,
   ) -> Result<ApubPrivateMessage, LemmyError> {
-    let creator = note
-      .attributed_to
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
-    let recipient = note.to[0]
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+    let creator = note.attributed_to.dereference(context).await?;
+    let recipient = note.to[0].dereference(context).await?;
     check_person_block(creator.id, recipient.id, context.pool()).await?;
 
     let form = PrivateMessageInsertForm {
@@ -172,28 +159,29 @@ mod tests {
 
   async fn prepare_comment_test(
     url: &Url,
-    context: &LemmyContext,
+    context: &Data<LemmyContext>,
   ) -> (ApubPerson, ApubPerson, ApubSite) {
+    let context2 = context.reset_request_count();
     let lemmy_person = file_to_json_object("assets/lemmy/objects/person.json").unwrap();
-    let site = parse_lemmy_instance(context).await;
-    ApubPerson::verify(&lemmy_person, url, context, &mut 0)
+    let site = parse_lemmy_instance(&context2).await;
+    ApubPerson::verify(&lemmy_person, url, &context2)
       .await
       .unwrap();
-    let person1 = ApubPerson::from_apub(lemmy_person, context, &mut 0)
+    let person1 = ApubPerson::from_json(lemmy_person, &context2)
       .await
       .unwrap();
     let pleroma_person = file_to_json_object("assets/pleroma/objects/person.json").unwrap();
     let pleroma_url = Url::parse("https://queer.hacktivis.me/users/lanodan").unwrap();
-    ApubPerson::verify(&pleroma_person, &pleroma_url, context, &mut 0)
+    ApubPerson::verify(&pleroma_person, &pleroma_url, &context2)
       .await
       .unwrap();
-    let person2 = ApubPerson::from_apub(pleroma_person, context, &mut 0)
+    let person2 = ApubPerson::from_json(pleroma_person, &context2)
       .await
       .unwrap();
     (person1, person2, site)
   }
 
-  async fn cleanup(data: (ApubPerson, ApubPerson, ApubSite), context: &LemmyContext) {
+  async fn cleanup(data: (ApubPerson, ApubPerson, ApubSite), context: &Data<LemmyContext>) {
     Person::delete(context.pool(), data.0.id).await.unwrap();
     Person::delete(context.pool(), data.1.id).await.unwrap();
     Site::delete(context.pool(), data.2.id).await.unwrap();
@@ -206,20 +194,19 @@ mod tests {
     let url = Url::parse("https://enterprise.lemmy.ml/private_message/1621").unwrap();
     let data = prepare_comment_test(&url, &context).await;
     let json: ChatMessage = file_to_json_object("assets/lemmy/objects/chat_message.json").unwrap();
-    let mut request_counter = 0;
-    ApubPrivateMessage::verify(&json, &url, &context, &mut request_counter)
+    ApubPrivateMessage::verify(&json, &url, &context)
       .await
       .unwrap();
-    let pm = ApubPrivateMessage::from_apub(json.clone(), &context, &mut request_counter)
+    let pm = ApubPrivateMessage::from_json(json.clone(), &context)
       .await
       .unwrap();
 
     assert_eq!(pm.ap_id.clone(), url.into());
     assert_eq!(pm.content.len(), 20);
-    assert_eq!(request_counter, 0);
+    assert_eq!(context.request_count(), 0);
 
     let pm_id = pm.id;
-    let to_apub = pm.into_apub(&context).await.unwrap();
+    let to_apub = pm.into_json(&context).await.unwrap();
     assert_json_include!(actual: json, expected: to_apub);
 
     PrivateMessage::delete(context.pool(), pm_id).await.unwrap();
@@ -234,17 +221,14 @@ mod tests {
     let data = prepare_comment_test(&url, &context).await;
     let pleroma_url = Url::parse("https://queer.hacktivis.me/objects/2").unwrap();
     let json = file_to_json_object("assets/pleroma/objects/chat_message.json").unwrap();
-    let mut request_counter = 0;
-    ApubPrivateMessage::verify(&json, &pleroma_url, &context, &mut request_counter)
-      .await
-      .unwrap();
-    let pm = ApubPrivateMessage::from_apub(json, &context, &mut request_counter)
+    ApubPrivateMessage::verify(&json, &pleroma_url, &context)
       .await
       .unwrap();
+    let pm = ApubPrivateMessage::from_json(json, &context).await.unwrap();
 
     assert_eq!(pm.ap_id, pleroma_url.into());
     assert_eq!(pm.content.len(), 3);
-    assert_eq!(request_counter, 0);
+    assert_eq!(context.request_count(), 0);
 
     PrivateMessage::delete(context.pool(), pm.id).await.unwrap();
     cleanup(data, &context).await;
index 0812489b6635f27aa5f60087488cf23219be013d..2cad2adcd5371f08f72a7d35715b8f63878ddfd8 100644 (file)
@@ -1,11 +1,14 @@
 use crate::{
   activities::{block::SiteOrCommunity, verify_community_matches},
-  local_instance,
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::InCommunity,
 };
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
-use activitystreams_kinds::activity::BlockType;
+use activitypub_federation::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::activity::BlockType,
+  protocol::helpers::deserialize_one_or_many,
+};
 use anyhow::anyhow;
 use chrono::{DateTime, FixedOffset};
 use lemmy_api_common::context::LemmyContext;
@@ -38,17 +41,10 @@ pub struct BlockUser {
   pub(crate) expires: Option<DateTime<FixedOffset>>,
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for BlockUser {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    let target = self
-      .target
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
+    let target = self.target.dereference(context).await?;
     let community = match target {
       SiteOrCommunity::Community(c) => c,
       SiteOrCommunity::Site(_) => return Err(anyhow!("activity is not in community").into()),
index 9466fedc9f6a432ac163f79adafcf2b5c7f31806..758d3fd4b8fdaa526731a00e0ca474ae9ccdf330 100644 (file)
@@ -3,8 +3,12 @@ use crate::{
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::{activities::block::block_user::BlockUser, InCommunity},
 };
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
-use activitystreams_kinds::activity::UndoType;
+use activitypub_federation::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::activity::UndoType,
+  protocol::helpers::deserialize_one_or_many,
+};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_utils::error::LemmyError;
 use serde::{Deserialize, Serialize};
@@ -27,14 +31,10 @@ pub struct UndoBlockUser {
   pub(crate) audience: Option<ObjectId<ApubCommunity>>,
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for UndoBlockUser {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    let community = self.object.community(context, request_counter).await?;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
+    let community = self.object.community(context).await?;
     if let Some(audience) = &self.audience {
       verify_community_matches(audience, community.actor_id.clone())?;
     }
index 7c2e16ec6b648775c56e2d639a2b9c00cb0fa676..e149e5fd1e05edcb2705ce1ebf136421d0d4a6db 100644 (file)
@@ -1,6 +1,9 @@
 use crate::{objects::community::ApubCommunity, protocol::IdOrNestedObject};
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
-use activitystreams_kinds::activity::AnnounceType;
+use activitypub_federation::{
+  fetch::object_id::ObjectId,
+  kinds::activity::AnnounceType,
+  protocol::helpers::deserialize_one_or_many,
+};
 use serde::{Deserialize, Serialize};
 use serde_json::{Map, Value};
 use url::Url;
index a91244189895ba18086c6289783f37cf970bcff8..f3943e31c07737def27a6e95365b31bcc595c071 100644 (file)
@@ -3,8 +3,12 @@ use crate::{
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::InCommunity,
 };
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
-use activitystreams_kinds::activity::AddType;
+use activitypub_federation::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::activity::AddType,
+  protocol::helpers::deserialize_one_or_many,
+};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::source::community::Community;
 use lemmy_utils::error::LemmyError;
@@ -27,13 +31,9 @@ pub struct CollectionAdd {
   pub(crate) audience: Option<ObjectId<ApubCommunity>>,
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for CollectionAdd {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    _request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
     let (community, _) =
       Community::get_by_collection_url(context.pool(), &self.clone().target.into()).await?;
     if let Some(audience) = &self.audience {
index 6ca8a2392439f4992cdab2f119c849506146d3b3..f69fdc6a7b7e7438672a6f61e82c8ecb65ac06fe 100644 (file)
@@ -3,8 +3,12 @@ use crate::{
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::InCommunity,
 };
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
-use activitystreams_kinds::activity::RemoveType;
+use activitypub_federation::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::activity::RemoveType,
+  protocol::helpers::deserialize_one_or_many,
+};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::source::community::Community;
 use lemmy_utils::error::LemmyError;
@@ -17,7 +21,7 @@ pub struct CollectionRemove {
   pub(crate) actor: ObjectId<ApubPerson>,
   #[serde(deserialize_with = "deserialize_one_or_many")]
   pub(crate) to: Vec<Url>,
-  pub(crate) object: ObjectId<ApubPerson>,
+  pub(crate) object: Url,
   #[serde(deserialize_with = "deserialize_one_or_many")]
   pub(crate) cc: Vec<Url>,
   #[serde(rename = "type")]
@@ -27,13 +31,9 @@ pub struct CollectionRemove {
   pub(crate) audience: Option<ObjectId<ApubCommunity>>,
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for CollectionRemove {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    _request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
     let (community, _) =
       Community::get_by_collection_url(context.pool(), &self.clone().target.into()).await?;
     if let Some(audience) = &self.audience {
index f7b5554c640e9070dff403fd3ee0353684abe16f..b19e39749fcf7f258a926b21b42eeedf4a7f8206 100644 (file)
@@ -1,11 +1,14 @@
 use crate::{
   activities::verify_community_matches,
-  local_instance,
   objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
   protocol::InCommunity,
 };
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
-use activitystreams_kinds::activity::UndoType;
+use activitypub_federation::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::activity::UndoType,
+  protocol::helpers::deserialize_one_or_many,
+};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::{source::community::Community, traits::Crud};
 use lemmy_utils::error::LemmyError;
@@ -48,17 +51,10 @@ pub struct UndoLockPage {
   pub(crate) audience: Option<ObjectId<ApubCommunity>>,
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for LockPage {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    let post = self
-      .object
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
+    let post = self.object.dereference(context).await?;
     let community = Community::read(context.pool(), post.community_id).await?;
     if let Some(audience) = &self.audience {
       verify_community_matches(audience, community.actor_id.clone())?;
@@ -67,14 +63,10 @@ impl InCommunity for LockPage {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for UndoLockPage {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    let community = self.object.community(context, request_counter).await?;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
+    let community = self.object.community(context).await?;
     if let Some(audience) = &self.audience {
       verify_community_matches(audience, community.actor_id.clone())?;
     }
index 4d786b3954c901af36cb062d1fa101ae33b9738c..6e8a1bbf33dcf958dcbf2d0354f47ddfe49d279f 100644 (file)
@@ -1,12 +1,15 @@
 use crate::{
   activities::verify_community_matches,
   fetcher::post_or_comment::PostOrComment,
-  local_instance,
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::InCommunity,
 };
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one};
-use activitystreams_kinds::activity::FlagType;
+use activitypub_federation::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::activity::FlagType,
+  protocol::helpers::deserialize_one,
+};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_utils::error::LemmyError;
 use serde::{Deserialize, Serialize};
@@ -26,16 +29,10 @@ pub struct Report {
   pub(crate) audience: Option<ObjectId<ApubCommunity>>,
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for Report {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    let community = self.to[0]
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
+    let community = self.to[0].dereference(context).await?;
     if let Some(audience) = &self.audience {
       verify_community_matches(audience, community.actor_id.clone())?;
     }
index a8934717f5da54c016488e7e33a20f064f69081b..49ec1f5d641c1cfb1151e6e05d16c63e4448d9f5 100644 (file)
@@ -1,11 +1,14 @@
 use crate::{
   activities::verify_community_matches,
-  local_instance,
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::{objects::group::Group, InCommunity},
 };
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
-use activitystreams_kinds::activity::UpdateType;
+use activitypub_federation::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::activity::UpdateType,
+  protocol::helpers::deserialize_one_or_many,
+};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_utils::error::LemmyError;
 use serde::{Deserialize, Serialize};
@@ -29,16 +32,10 @@ pub struct UpdateCommunity {
   pub(crate) audience: Option<ObjectId<ApubCommunity>>,
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for UpdateCommunity {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    let community: ApubCommunity = ObjectId::new(self.object.id.clone())
-      .dereference(context, local_instance(context).await, request_counter)
-      .await?;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
+    let community: ApubCommunity = self.object.id.clone().dereference(context).await?;
     if let Some(audience) = &self.audience {
       verify_community_matches(audience, community.actor_id.clone())?;
     }
index 07a71d255987b576c9dd9d34c74dace553a14d67..30e94a28ddbeb07a26607b0d6bf3c805ebd46ffb 100644 (file)
@@ -2,7 +2,7 @@ use crate::{
   objects::person::ApubPerson,
   protocol::{activities::CreateOrUpdateType, objects::chat_message::ChatMessage},
 };
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one};
+use activitypub_federation::{fetch::object_id::ObjectId, protocol::helpers::deserialize_one};
 use serde::{Deserialize, Serialize};
 use url::Url;
 
index 2cfcd2d8a05170abbd03a1d30ce97ae277eddf65..07bbc7c8d272dfd8215a83ad4d5a952b96b41fdc 100644 (file)
@@ -4,7 +4,11 @@ use crate::{
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::{activities::CreateOrUpdateType, objects::note::Note, InCommunity},
 };
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
+use activitypub_federation::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  protocol::helpers::deserialize_one_or_many,
+};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::{source::community::Community, traits::Crud};
 use lemmy_utils::error::LemmyError;
@@ -28,14 +32,10 @@ pub struct CreateOrUpdateNote {
   pub(crate) audience: Option<ObjectId<ApubCommunity>>,
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for CreateOrUpdateNote {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    let post = self.object.get_parents(context, request_counter).await?.0;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
+    let post = self.object.get_parents(context).await?.0;
     let community = Community::read(context.pool(), post.community_id).await?;
     if let Some(audience) = &self.audience {
       verify_community_matches(audience, community.actor_id.clone())?;
index ad17d7383bd145244fb420ed4c49fe4ba3412485..ec64c31a0e63db4d25d7e8f8648662dd12d44c16 100644 (file)
@@ -3,7 +3,11 @@ use crate::{
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::{activities::CreateOrUpdateType, objects::page::Page, InCommunity},
 };
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
+use activitypub_federation::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  protocol::helpers::deserialize_one_or_many,
+};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_utils::error::LemmyError;
 use serde::{Deserialize, Serialize};
@@ -24,14 +28,10 @@ pub struct CreateOrUpdatePage {
   pub(crate) audience: Option<ObjectId<ApubCommunity>>,
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for CreateOrUpdatePage {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    let community = self.object.community(context, request_counter).await?;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
+    let community = self.object.community(context).await?;
     if let Some(audience) = &self.audience {
       verify_community_matches(audience, community.actor_id.clone())?;
     }
index 162e595f1f28f696accf9b2cc76676f86d7ea990..89ee26d94defdf596e573db04cec6426de1ed848 100644 (file)
@@ -3,8 +3,12 @@ use crate::{
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::{objects::tombstone::Tombstone, IdOrNestedObject, InCommunity},
 };
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
-use activitystreams_kinds::activity::DeleteType;
+use activitypub_federation::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::activity::DeleteType,
+  protocol::helpers::deserialize_one_or_many,
+};
 use anyhow::anyhow;
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::{
@@ -38,13 +42,9 @@ pub struct Delete {
   pub(crate) summary: Option<String>,
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for Delete {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    _request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
     let community_id = match DeletableObjects::read_from_db(self.object.id(), context).await? {
       DeletableObjects::Community(c) => c.id,
       DeletableObjects::Comment(c) => {
index d455be99cc3770db6ceae4e379f12c6b334320a9..f5f9908d5c6909379831a785ff402b1b11c4518b 100644 (file)
@@ -1,6 +1,9 @@
 use crate::objects::person::ApubPerson;
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
-use activitystreams_kinds::activity::DeleteType;
+use activitypub_federation::{
+  fetch::object_id::ObjectId,
+  kinds::activity::DeleteType,
+  protocol::helpers::deserialize_one_or_many,
+};
 use serde::{Deserialize, Serialize};
 use serde_with::skip_serializing_none;
 use url::Url;
index 6c584ccf5299862b7a45d6ab5de782ef80d2b02c..35d9951b17fb0b28950604a292f1c938ef34c061 100644 (file)
@@ -3,8 +3,12 @@ use crate::{
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::{activities::deletion::delete::Delete, InCommunity},
 };
-use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
-use activitystreams_kinds::activity::UndoType;
+use activitypub_federation::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::activity::UndoType,
+  protocol::helpers::deserialize_one_or_many,
+};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_utils::error::LemmyError;
 use serde::{Deserialize, Serialize};
@@ -29,14 +33,10 @@ pub struct UndoDelete {
   pub(crate) cc: Vec<Url>,
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for UndoDelete {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    let community = self.object.community(context, request_counter).await?;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
+    let community = self.object.community(context).await?;
     if let Some(audience) = &self.audience {
       verify_community_matches(audience, community.actor_id.clone())?;
     }
index bc65ea91516463fd6782ff4c0a5bb3c97ec1fb6b..786827ed9bfccb701dd7e5c3a2512457ae71f51c 100644 (file)
@@ -1,6 +1,5 @@
 use crate::{objects::community::ApubCommunity, protocol::activities::following::follow::Follow};
-use activitypub_federation::core::object_id::ObjectId;
-use activitystreams_kinds::activity::AcceptType;
+use activitypub_federation::{fetch::object_id::ObjectId, kinds::activity::AcceptType};
 use serde::{Deserialize, Serialize};
 use url::Url;
 
index d3f4fb591128277c3b67f3145e80e3a26cb994e3..27a3ba4be66d22b99d11e1b7ff881a0c69b1d302 100644 (file)
@@ -1,6 +1,5 @@
 use crate::{fetcher::user_or_community::UserOrCommunity, objects::person::ApubPerson};
-use activitypub_federation::core::object_id::ObjectId;
-use activitystreams_kinds::activity::FollowType;
+use activitypub_federation::{fetch::object_id::ObjectId, kinds::activity::FollowType};
 use serde::{Deserialize, Serialize};
 use url::Url;
 
index 33308c24b6bc5e0eeee38c020595160ef9e54041..4660db40a8d234adf6a7e59488fecba279f99f0a 100644 (file)
@@ -1,6 +1,5 @@
 use crate::{objects::person::ApubPerson, protocol::activities::following::follow::Follow};
-use activitypub_federation::core::object_id::ObjectId;
-use activitystreams_kinds::activity::UndoType;
+use activitypub_federation::{fetch::object_id::ObjectId, kinds::activity::UndoType};
 use serde::{Deserialize, Serialize};
 use url::Url;
 
index a8432c8275752c19f68de822333e67d89f0909f5..746ae68df9eb2c73fe08d01a1a398ba1a542477d 100644 (file)
@@ -3,8 +3,7 @@ use crate::{
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::{activities::voting::vote::Vote, InCommunity},
 };
-use activitypub_federation::core::object_id::ObjectId;
-use activitystreams_kinds::activity::UndoType;
+use activitypub_federation::{config::Data, fetch::object_id::ObjectId, kinds::activity::UndoType};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_utils::error::LemmyError;
 use serde::{Deserialize, Serialize};
@@ -21,14 +20,10 @@ pub struct UndoVote {
   pub(crate) audience: Option<ObjectId<ApubCommunity>>,
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for UndoVote {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    let community = self.object.community(context, request_counter).await?;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
+    let community = self.object.community(context).await?;
     if let Some(audience) = &self.audience {
       verify_community_matches(audience, community.actor_id.clone())?;
     }
index cf79fc9adab41af4a1efde2cbdc20d1e1172ffa1..4450fed8bb2f1e71fff73078738e5ce898dfe8cf 100644 (file)
@@ -1,11 +1,10 @@
 use crate::{
   activities::verify_community_matches,
   fetcher::post_or_comment::PostOrComment,
-  local_instance,
   objects::{community::ApubCommunity, person::ApubPerson},
   protocol::InCommunity,
 };
-use activitypub_federation::core::object_id::ObjectId;
+use activitypub_federation::{config::Data, fetch::object_id::ObjectId};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_utils::error::LemmyError;
 use serde::{Deserialize, Serialize};
@@ -51,19 +50,14 @@ impl From<&VoteType> for i16 {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for Vote {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    let local_instance = local_instance(context).await;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
     let community = self
       .object
-      .dereference(context, local_instance, request_counter)
+      .dereference(context)
       .await?
-      .community(context, request_counter)
+      .community(context)
       .await?;
     if let Some(audience) = &self.audience {
       verify_community_matches(audience, community.actor_id.clone())?;
index b4731f31232a14047e7d74e53fa09dac5599acd3..3801c04e988298c156dc82c57e3ce726de72f12f 100644 (file)
@@ -1,4 +1,4 @@
-use activitystreams_kinds::collection::OrderedCollectionType;
+use activitypub_federation::kinds::collection::OrderedCollectionType;
 use lemmy_utils::error::LemmyError;
 use serde::{Deserialize, Serialize};
 use url::Url;
index cbd7dce4b0b0906d45ae8a2301ba68ebe5ef5374..a36b52911c3173cac62af978d06fcbea6ae30354 100644 (file)
@@ -1,5 +1,5 @@
 use crate::protocol::objects::page::Page;
-use activitystreams_kinds::collection::OrderedCollectionType;
+use activitypub_federation::kinds::collection::OrderedCollectionType;
 use serde::{Deserialize, Serialize};
 use url::Url;
 
index b9cf851827951de3e649435ba30e80a0426401f5..c7df8df2b245f34b5a33553efae29a79653cbc80 100644 (file)
@@ -1,4 +1,4 @@
-use activitystreams_kinds::collection::CollectionType;
+use activitypub_federation::kinds::collection::CollectionType;
 use lemmy_api_common::{context::LemmyContext, utils::generate_followers_url};
 use lemmy_db_schema::source::community::Community;
 use lemmy_db_views_actor::structs::CommunityFollowerView;
index 4d1042821c745064a7a1e161f6f2dc7ba6aabd2a..3e41e1247bf52bc26edc5e548e3aa1efc1b26445 100644 (file)
@@ -1,6 +1,8 @@
 use crate::objects::person::ApubPerson;
-use activitypub_federation::core::object_id::ObjectId;
-use activitystreams_kinds::collection::OrderedCollectionType;
+use activitypub_federation::{
+  fetch::object_id::ObjectId,
+  kinds::collection::OrderedCollectionType,
+};
 use serde::{Deserialize, Serialize};
 use url::Url;
 
index 2806d2695630f7eace510cd7b36b9c4686d3e5a3..77e82348d6d9871536e1195d34f30b6fe7f921bf 100644 (file)
@@ -1,5 +1,5 @@
 use crate::protocol::activities::community::announce::AnnounceActivity;
-use activitystreams_kinds::collection::OrderedCollectionType;
+use activitypub_federation::kinds::collection::OrderedCollectionType;
 use serde::{Deserialize, Serialize};
 use url::Url;
 
index ef0f2a875a8f642b34d85b832e67d9d8766d2b2e..bfc9df772a25d532b7cd9ead706de4a777157f8c 100644 (file)
@@ -1,6 +1,10 @@
-use crate::{local_instance, objects::community::ApubCommunity};
-use activitypub_federation::{deser::values::MediaTypeMarkdown, utils::fetch_object_http};
-use activitystreams_kinds::object::ImageType;
+use crate::objects::community::ApubCommunity;
+use activitypub_federation::{
+  config::Data,
+  fetch::fetch_object_http,
+  kinds::object::ImageType,
+  protocol::values::MediaTypeMarkdown,
+};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::newtypes::DbUrl;
 use lemmy_utils::error::LemmyError;
@@ -60,41 +64,32 @@ pub(crate) enum IdOrNestedObject<Kind: Id> {
   NestedObject(Kind),
 }
 
-impl<Kind: Id + DeserializeOwned> IdOrNestedObject<Kind> {
+impl<Kind: Id + DeserializeOwned + Send> IdOrNestedObject<Kind> {
   pub(crate) fn id(&self) -> &Url {
     match self {
       IdOrNestedObject::Id(i) => i,
       IdOrNestedObject::NestedObject(n) => n.object_id(),
     }
   }
-  pub(crate) async fn object(
-    self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<Kind, LemmyError> {
+  pub(crate) async fn object(self, context: &Data<LemmyContext>) -> Result<Kind, LemmyError> {
     match self {
-      IdOrNestedObject::Id(i) => {
-        Ok(fetch_object_http(&i, local_instance(context).await, request_counter).await?)
-      }
+      // TODO: move IdOrNestedObject struct to library and make fetch_object_http private
+      IdOrNestedObject::Id(i) => Ok(fetch_object_http(&i, context).await?),
       IdOrNestedObject::NestedObject(o) => Ok(o),
     }
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 pub trait InCommunity {
   // TODO: after we use audience field and remove backwards compat, it should be possible to change
   //       this to simply `fn community(&self)  -> Result<ObjectId<ApubCommunity>, LemmyError>`
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError>;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError>;
 }
 
 #[cfg(test)]
 pub(crate) mod tests {
-  use activitypub_federation::deser::context::WithContext;
+  use activitypub_federation::protocol::context::WithContext;
   use assert_json_diff::assert_json_include;
   use lemmy_utils::error::LemmyError;
   use serde::{de::DeserializeOwned, Serialize};
index 152e8508fcd62186be45056bd13e08f29c29e1aa..22bdd916af7281ffdc9311a505993cfd00e8a7a4 100644 (file)
@@ -3,8 +3,8 @@ use crate::{
   protocol::Source,
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  deser::{
+  fetch::object_id::ObjectId,
+  protocol::{
     helpers::{deserialize_one, deserialize_skip_error},
     values::MediaTypeHtml,
   },
index 9c4aa35d0c085f3ee1ce3fcb4e56ee460399b6de..520070cc6c44c2b849e34a830b0b0ba793d3b26c 100644 (file)
@@ -14,11 +14,14 @@ use crate::{
   },
 };
 use activitypub_federation::{
-  core::{object_id::ObjectId, signatures::PublicKey},
-  deser::helpers::deserialize_skip_error,
-  utils::verify_domains_match,
+  fetch::{collection_id::CollectionId, object_id::ObjectId},
+  kinds::actor::GroupType,
+  protocol::{
+    helpers::deserialize_skip_error,
+    public_key::PublicKey,
+    verification::verify_domains_match,
+  },
 };
-use activitystreams_kinds::actor::GroupType;
 use chrono::{DateTime, FixedOffset};
 use lemmy_api_common::{context::LemmyContext, utils::local_site_opt_to_slur_regex};
 use lemmy_db_schema::{
@@ -59,14 +62,14 @@ pub struct Group {
   // lemmy extension
   pub(crate) sensitive: Option<bool>,
   // deprecated, use attributed_to instead
-  pub(crate) moderators: Option<ObjectId<ApubCommunityModerators>>,
+  pub(crate) moderators: Option<CollectionId<ApubCommunityModerators>>,
   #[serde(deserialize_with = "deserialize_skip_error", default)]
-  pub(crate) attributed_to: Option<ObjectId<ApubCommunityModerators>>,
+  pub(crate) attributed_to: Option<CollectionId<ApubCommunityModerators>>,
   // lemmy extension
   pub(crate) posting_restricted_to_mods: Option<bool>,
-  pub(crate) outbox: ObjectId<ApubCommunityOutbox>,
+  pub(crate) outbox: CollectionId<ApubCommunityOutbox>,
   pub(crate) endpoints: Option<Endpoints>,
-  pub(crate) featured: Option<ObjectId<ApubCommunityFeatured>>,
+  pub(crate) featured: Option<CollectionId<ApubCommunityFeatured>>,
   #[serde(default)]
   pub(crate) language: Vec<LanguageTag>,
   pub(crate) published: Option<DateTime<FixedOffset>>,
index 00c9c8be11b896eaf3a0c975afd0bcb0c37aebfc..4a3d6ea2ee261deddd3da09d2f948227ac86b72f 100644 (file)
@@ -3,10 +3,10 @@ use crate::{
   protocol::{objects::LanguageTag, ImageObject, Source},
 };
 use activitypub_federation::{
-  core::{object_id::ObjectId, signatures::PublicKey},
-  deser::{helpers::deserialize_skip_error, values::MediaTypeHtml},
+  fetch::object_id::ObjectId,
+  kinds::actor::ApplicationType,
+  protocol::{helpers::deserialize_skip_error, public_key::PublicKey, values::MediaTypeHtml},
 };
-use activitystreams_kinds::actor::ApplicationType;
 use chrono::{DateTime, FixedOffset};
 use serde::{Deserialize, Serialize};
 use serde_with::skip_serializing_none;
index f93a41ef884a8ed5edb54bd1a90be9375afb1504..de90636e669e9045904d80b40693a5e547fe38bd 100644 (file)
@@ -1,19 +1,19 @@
 use crate::{
   activities::verify_community_matches,
   fetcher::post_or_comment::PostOrComment,
-  local_instance,
   mentions::MentionOrValue,
   objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost},
   protocol::{objects::LanguageTag, InCommunity, Source},
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  deser::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::object::NoteType,
+  protocol::{
     helpers::{deserialize_one_or_many, deserialize_skip_error},
     values::MediaTypeMarkdownOrHtml,
   },
 };
-use activitystreams_kinds::object::NoteType;
 use chrono::{DateTime, FixedOffset};
 use lemmy_api_common::context::LemmyContext;
 use lemmy_db_schema::{
@@ -56,16 +56,10 @@ pub struct Note {
 impl Note {
   pub(crate) async fn get_parents(
     &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
+    context: &Data<LemmyContext>,
   ) -> Result<(ApubPost, Option<ApubComment>), LemmyError> {
     // Fetch parent comment chain in a box, otherwise it can cause a stack overflow.
-    let parent = Box::pin(
-      self
-        .in_reply_to
-        .dereference(context, local_instance(context).await, request_counter)
-        .await?,
-    );
+    let parent = Box::pin(self.in_reply_to.dereference(context).await?);
     match parent.deref() {
       PostOrComment::Post(p) => Ok((p.clone(), None)),
       PostOrComment::Comment(c) => {
@@ -77,14 +71,10 @@ impl Note {
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for Note {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    let (post, _) = self.get_parents(context, request_counter).await?;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
+    let (post, _) = self.get_parents(context).await?;
     let community = Community::read(context.pool(), post.community_id).await?;
     if let Some(audience) = &self.audience {
       verify_community_matches(audience, community.actor_id.clone())?;
index 65a164ecdd473e3b588df4f6ba0057e801f68c7f..9bf8dbe59eafc857d44e5bfbd062ffb66402f10a 100644 (file)
@@ -1,22 +1,21 @@
 use crate::{
   activities::verify_community_matches,
   fetcher::user_or_community::{PersonOrGroupType, UserOrCommunity},
-  local_instance,
   objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
   protocol::{objects::LanguageTag, ImageObject, InCommunity, Source},
 };
 use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
-  deser::{
+  config::Data,
+  fetch::object_id::ObjectId,
+  kinds::{
+    link::LinkType,
+    object::{DocumentType, ImageType},
+  },
+  protocol::{
     helpers::{deserialize_one_or_many, deserialize_skip_error},
     values::MediaTypeMarkdownOrHtml,
   },
-  traits::{ActivityHandler, ApubObject},
-};
-use activitystreams_kinds::{
-  link::LinkType,
-  object::{DocumentType, ImageType},
+  traits::{ActivityHandler, Object},
 };
 use chrono::{DateTime, FixedOffset};
 use itertools::Itertools;
@@ -136,10 +135,11 @@ impl Page {
   /// the current value, it is a mod action and needs to be verified as such.
   ///
   /// Both stickied and locked need to be false on a newly created post (verified in [[CreatePost]].
-  pub(crate) async fn is_mod_action(&self, context: &LemmyContext) -> Result<bool, LemmyError> {
-    let old_post = ObjectId::<ApubPost>::new(self.id.clone())
-      .dereference_local(context)
-      .await;
+  pub(crate) async fn is_mod_action(
+    &self,
+    context: &Data<LemmyContext>,
+  ) -> Result<bool, LemmyError> {
+    let old_post = self.id.clone().dereference_local(context).await;
 
     let featured_changed = Page::is_featured_changed(&old_post, &self.stickied);
     let locked_changed = Page::is_locked_changed(&old_post, &self.comments_enabled);
@@ -178,7 +178,7 @@ impl Page {
       AttributedTo::Peertube(p) => p
         .iter()
         .find(|a| a.kind == PersonOrGroupType::Person)
-        .map(|a| ObjectId::<ApubPerson>::new(a.id.clone().into_inner()))
+        .map(|a| ObjectId::<ApubPerson>::from(a.id.clone().into_inner()))
         .ok_or_else(|| LemmyError::from_message("page does not specify creator person")),
     }
   }
@@ -194,7 +194,7 @@ impl Attachment {
 }
 
 // Used for community outbox, so that it can be compatible with Pleroma/Mastodon.
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl ActivityHandler for Page {
   type DataType = LemmyContext;
   type Error = LemmyError;
@@ -204,38 +204,25 @@ impl ActivityHandler for Page {
   fn actor(&self) -> &Url {
     unimplemented!()
   }
-  async fn verify(
-    &self,
-    data: &Data<Self::DataType>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    ApubPost::verify(self, self.id.inner(), data, request_counter).await
+  async fn verify(&self, data: &Data<Self::DataType>) -> Result<(), LemmyError> {
+    ApubPost::verify(self, self.id.inner(), data).await
   }
-  async fn receive(
-    self,
-    data: &Data<Self::DataType>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    ApubPost::from_apub(self, data, request_counter).await?;
+  async fn receive(self, data: &Data<Self::DataType>) -> Result<(), LemmyError> {
+    ApubPost::from_json(self, data).await?;
     Ok(())
   }
 }
 
-#[async_trait::async_trait(?Send)]
+#[async_trait::async_trait]
 impl InCommunity for Page {
-  async fn community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    let instance = local_instance(context).await;
+  async fn community(&self, context: &Data<LemmyContext>) -> Result<ApubCommunity, LemmyError> {
     let community = match &self.attributed_to {
       AttributedTo::Lemmy(_) => {
         let mut iter = self.to.iter().merge(self.cc.iter());
         loop {
           if let Some(cid) = iter.next() {
-            let cid = ObjectId::new(cid.clone());
-            if let Ok(c) = cid.dereference(context, instance, request_counter).await {
+            let cid = ObjectId::from(cid.clone());
+            if let Ok(c) = cid.dereference(context).await {
               break c;
             }
           } else {
@@ -246,9 +233,9 @@ impl InCommunity for Page {
       AttributedTo::Peertube(p) => {
         p.iter()
           .find(|a| a.kind == PersonOrGroupType::Group)
-          .map(|a| ObjectId::<ApubCommunity>::new(a.id.clone().into_inner()))
+          .map(|a| ObjectId::<ApubCommunity>::from(a.id.clone().into_inner()))
           .ok_or_else(|| LemmyError::from_message("page does not specify group"))?
-          .dereference(context, instance, request_counter)
+          .dereference(context)
           .await?
       }
     };
index eb473250357984e0928c0f637ebee37145f41188..ecedbcd71b9edbd322c88d12b19beef6304d2c41 100644 (file)
@@ -3,8 +3,8 @@ use crate::{
   protocol::{objects::Endpoints, ImageObject, Source},
 };
 use activitypub_federation::{
-  core::{object_id::ObjectId, signatures::PublicKey},
-  deser::helpers::deserialize_skip_error,
+  fetch::object_id::ObjectId,
+  protocol::{helpers::deserialize_skip_error, public_key::PublicKey},
 };
 use chrono::{DateTime, FixedOffset};
 use serde::{Deserialize, Serialize};
index 1b66f2a7eb4d0bfa3c8b94b8176b699d23646a1b..f07a7e9356cda1a2c1a1bd4e7d9f016015e8946d 100644 (file)
@@ -1,5 +1,5 @@
 use crate::protocol::Id;
-use activitystreams_kinds::object::TombstoneType;
+use activitypub_federation::kinds::object::TombstoneType;
 use serde::{Deserialize, Serialize};
 use serde_with::skip_serializing_none;
 use url::Url;
index bdf0f1dc2d32d04781d85ea1df3c48e619e1a52c..a19d20f3a6f73cfa81d208c0a944d3d4936e3707 100644 (file)
@@ -5,14 +5,8 @@ use crate::{
   traits::Crud,
   utils::{get_conn, DbPool},
 };
-use diesel::{
-  dsl::insert_into,
-  result::{DatabaseErrorKind, Error},
-  ExpressionMethods,
-  QueryDsl,
-};
+use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
 use diesel_async::RunQueryDsl;
-use serde_json::Value;
 
 #[async_trait]
 impl Crud for Activity {
@@ -52,33 +46,6 @@ impl Crud for Activity {
 }
 
 impl Activity {
-  /// Returns true if the insert was successful
-  // TODO this should probably just be changed to an upsert on_conflict, rather than an error
-  pub async fn insert(
-    pool: &DbPool,
-    ap_id_: DbUrl,
-    data_: Value,
-    local_: bool,
-    sensitive_: Option<bool>,
-  ) -> Result<bool, Error> {
-    let activity_form = ActivityInsertForm {
-      ap_id: ap_id_,
-      data: data_,
-      local: Some(local_),
-      sensitive: sensitive_,
-      updated: None,
-    };
-    match Activity::create(pool, &activity_form).await {
-      Ok(_) => Ok(true),
-      Err(e) => {
-        if let Error::DatabaseError(DatabaseErrorKind::UniqueViolation, _) = e {
-          return Ok(false);
-        }
-        Err(e)
-      }
-    }
-  }
-
   pub async fn read_from_apub_id(pool: &DbPool, object_id: &DbUrl) -> Result<Activity, Error> {
     let conn = &mut get_conn(pool).await?;
     activity
index da2c9b9e5ccdcdf670d5d24ebf6db70be44a999e..97b0926ab0bf2eb8ac7e6e65d5b84bfcecb671f1 100644 (file)
@@ -1,5 +1,10 @@
 #[cfg(feature = "full")]
-use activitypub_federation::{core::object_id::ObjectId, traits::ApubObject};
+use activitypub_federation::{
+  fetch::collection_id::CollectionId,
+  fetch::object_id::ObjectId,
+  traits::Collection,
+  traits::Object,
+};
 #[cfg(feature = "full")]
 use diesel_ltree::Ltree;
 use serde::{Deserialize, Serialize};
@@ -118,6 +123,12 @@ pub struct CustomEmojiId(i32);
 #[cfg_attr(feature = "full", diesel(sql_type = diesel::sql_types::Text))]
 pub struct DbUrl(pub(crate) Box<Url>);
 
+impl DbUrl {
+  pub fn inner(&self) -> &Url {
+    &self.0
+  }
+}
+
 #[cfg(feature = "full")]
 #[derive(Serialize, Deserialize)]
 #[serde(remote = "Ltree")]
@@ -143,14 +154,40 @@ impl Into<Url> for DbUrl {
     *self.0
   }
 }
+
 #[cfg(feature = "full")]
 impl<T> From<DbUrl> for ObjectId<T>
 where
-  T: ApubObject + Send,
-  for<'de2> <T as ApubObject>::ApubType: Deserialize<'de2>,
+  T: Object + Send + 'static,
+  for<'de2> <T as Object>::Kind: Deserialize<'de2>,
 {
   fn from(value: DbUrl) -> Self {
-    ObjectId::new(value)
+    let url: Url = value.into();
+    ObjectId::from(url)
+  }
+}
+
+#[cfg(feature = "full")]
+impl<T> From<DbUrl> for CollectionId<T>
+where
+  T: Collection + Send + 'static,
+  for<'de2> <T as Collection>::Kind: Deserialize<'de2>,
+{
+  fn from(value: DbUrl) -> Self {
+    let url: Url = value.into();
+    CollectionId::from(url)
+  }
+}
+
+#[cfg(feature = "full")]
+impl<T> From<CollectionId<T>> for DbUrl
+where
+  T: Collection,
+  for<'de2> <T as Collection>::Kind: Deserialize<'de2>,
+{
+  fn from(value: CollectionId<T>) -> Self {
+    let url: Url = value.into();
+    url.into()
   }
 }
 
index d4e0154714aba0920b5cc616ca5537ad0777722d..12b92b3d9ef38d0026c0c4a874fac1226e04a433 100644 (file)
@@ -149,7 +149,6 @@ pub trait JoinView {
 
 #[async_trait]
 pub trait ApubActor {
-  // TODO: this should be in a trait ApubObject (and implemented for Post, Comment, PrivateMessage as well)
   async fn read_from_apub_id(pool: &DbPool, object_id: &DbUrl) -> Result<Option<Self>, Error>
   where
     Self: Sized;
index c05cd565d0dc487c61967f17376d54624959427c..acedab970a9518f91bdd8a484dc8b584a36ce6b6 100644 (file)
@@ -5,7 +5,7 @@ use crate::{
   CommentSortType,
   SortType,
 };
-use activitypub_federation::{core::object_id::ObjectId, traits::ApubObject};
+use activitypub_federation::{fetch::object_id::ObjectId, traits::Object};
 use chrono::NaiveDateTime;
 use deadpool::Runtime;
 use diesel::{
@@ -237,8 +237,8 @@ where
 
 impl<Kind> From<ObjectId<Kind>> for DbUrl
 where
-  Kind: ApubObject + Send + 'static,
-  for<'de2> <Kind as ApubObject>::ApubType: serde::Deserialize<'de2>,
+  Kind: Object + Send + 'static,
+  for<'de2> <Kind as Object>::Kind: serde::Deserialize<'de2>,
 {
   fn from(id: ObjectId<Kind>) -> Self {
     DbUrl(Box::new(id.into()))
index bc2b573e52ab420b0855ea2a8adc7e4d27e04511..c9056abf604d22b28405e11a4d20222615c15717 100644 (file)
@@ -17,6 +17,7 @@ lemmy_db_views = { workspace = true }
 lemmy_db_views_actor = { workspace = true }
 lemmy_db_schema = { workspace = true }
 lemmy_api_common = { workspace = true, features = ["full"] }
+activitypub_federation = { workspace = true }
 diesel = { workspace = true }
 actix-web = { workspace = true }
 anyhow = { workspace = true }
index 4d744de939c2d99934a34cdebf552d90e19752ab..deade1971ad14663f61479dad86c40bb7dc59ffc 100644 (file)
@@ -1,3 +1,4 @@
+use activitypub_federation::fetch::webfinger::{Webfinger, WebfingerLink};
 use actix_web::{web, web::Query, HttpResponse};
 use anyhow::Context;
 use lemmy_api_common::context::LemmyContext;
@@ -5,7 +6,7 @@ use lemmy_db_schema::{
   source::{community::Community, person::Person},
   traits::ApubActor,
 };
-use lemmy_utils::{error::LemmyError, location_info, WebfingerLink, WebfingerResponse};
+use lemmy_utils::{error::LemmyError, location_info};
 use serde::Deserialize;
 use std::collections::HashMap;
 use url::Url;
@@ -61,9 +62,10 @@ async fn get_webfinger_response(
   .flatten()
   .collect();
 
-  let json = WebfingerResponse {
+  let json = Webfinger {
     subject: info.resource.clone(),
     links,
+    ..Default::default()
   };
 
   Ok(HttpResponse::Ok().json(json))
@@ -73,7 +75,9 @@ fn webfinger_link_for_actor(url: Option<Url>, kind: &str) -> Vec<WebfingerLink>
   if let Some(url) = url {
     let mut properties = HashMap::new();
     properties.insert(
-      "https://www.w3.org/ns/activitystreams#type".to_string(),
+      "https://www.w3.org/ns/activitystreams#type"
+        .parse()
+        .expect("parse url"),
       kind.to_string(),
     );
     vec![
@@ -81,7 +85,7 @@ fn webfinger_link_for_actor(url: Option<Url>, kind: &str) -> Vec<WebfingerLink>
         rel: Some("http://webfinger.net/rel/profile-page".to_string()),
         kind: Some("text/html".to_string()),
         href: Some(url.clone()),
-        properties: Default::default(),
+        ..Default::default()
       },
       WebfingerLink {
         rel: Some("self".to_string()),
index cdc8c83aa14927957a6aad9c869b4c461fba1c12..f3213390a393e8fbe8702368914c03274d2a0491 100644 (file)
@@ -14,9 +14,7 @@ pub mod request;
 pub mod utils;
 pub mod version;
 
-use serde::{Deserialize, Serialize};
-use std::{collections::HashMap, fmt, time::Duration};
-use url::Url;
+use std::{fmt, time::Duration};
 
 pub type ConnectionId = usize;
 
@@ -31,22 +29,6 @@ impl fmt::Display for IpAddr {
   }
 }
 
-#[derive(Serialize, Deserialize, Debug)]
-pub struct WebfingerLink {
-  pub rel: Option<String>,
-  #[serde(rename = "type")]
-  pub kind: Option<String>,
-  pub href: Option<Url>,
-  #[serde(default)]
-  pub properties: HashMap<String, String>,
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub struct WebfingerResponse {
-  pub subject: String,
-  pub links: Vec<WebfingerLink>,
-}
-
 #[macro_export]
 macro_rules! location_info {
   () => {
@@ -58,22 +40,3 @@ macro_rules! location_info {
     )
   };
 }
-
-#[cfg(test)]
-mod tests {
-  use super::*;
-  use reqwest::Client;
-
-  #[tokio::test]
-  #[ignore]
-  async fn test_webfinger() {
-    let client = Client::default();
-    let fetch_url =
-      "https://kino.schuerz.at/.well-known/webfinger?resource=acct:h0e@kino.schuerz.at";
-
-    let response = client.get(fetch_url).send().await.unwrap();
-
-    let res = response.json::<WebfingerResponse>().await;
-    assert!(res.is_ok());
-  }
-}
index 068f55c22ab596b1f8effc30da67aae2d4e3115c..4da87a1d8416aee32802c27657910bae0c08eb8d 100644 (file)
@@ -8,12 +8,12 @@ ARG RUST_RELEASE_MODE="debug"
 COPY . .
 
 # Build the project
-RUN echo "pub const VERSION: &str = \"$(git describe --tag)\";" > "crates/utils/src/version.rs"
     
 # Debug mode build
 RUN --mount=type=cache,target=/app/target \
     if [ "$RUST_RELEASE_MODE" = "debug" ] ; then \
-      cargo build --target ${CARGO_BUILD_TARGET} \
+      echo "pub const VERSION: &str = \"$(git describe --tag)\";" > "crates/utils/src/version.rs" \
+      && cargo build --target ${CARGO_BUILD_TARGET} \
       && cp ./target/$CARGO_BUILD_TARGET/$RUST_RELEASE_MODE/lemmy_server /app/lemmy_server; \
     fi
 
index 29127b24f36d7e9612a7b3b1815b5fad01672aa0..64578fc9f026049a359dc09fe651fd67f090f512 100755 (executable)
@@ -1,8 +1,4 @@
 #!/bin/sh
-
-# This script uses a docker file that builds with musl, and runs on linux alpine
-# Its a bit slower for development than the volume mount.
-
 set -e
 
 mkdir -p volumes/pictrs
index 8ab6980e53a02255ba0578a23c1a198e15185233..d59253deecd4ab7f40651e0b1f27d2a3507bf9b0 100644 (file)
@@ -370,6 +370,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
 async fn perform<'a, Data>(
   data: Data,
   context: web::Data<LemmyContext>,
+  apub_data: activitypub_federation::config::Data<LemmyContext>,
 ) -> Result<HttpResponse, Error>
 where
   Data: Perform
@@ -380,13 +381,14 @@ where
     + 'static,
 {
   let res = data.perform(&context, None).await?;
-  SendActivity::send_activity(&data, &res, &context).await?;
+  SendActivity::send_activity(&data, &res, &apub_data).await?;
   Ok(HttpResponse::Ok().json(res))
 }
 
 async fn route_get<'a, Data>(
   data: web::Query<Data>,
   context: web::Data<LemmyContext>,
+  apub_data: activitypub_federation::config::Data<LemmyContext>,
 ) -> Result<HttpResponse, Error>
 where
   Data: Perform
@@ -396,12 +398,12 @@ where
     + Send
     + 'static,
 {
-  perform::<Data>(data.0, context).await
+  perform::<Data>(data.0, context, apub_data).await
 }
 
 async fn route_get_apub<'a, Data>(
   data: web::Query<Data>,
-  context: web::Data<LemmyContext>,
+  context: activitypub_federation::config::Data<LemmyContext>,
 ) -> Result<HttpResponse, Error>
 where
   Data: PerformApub
@@ -419,6 +421,7 @@ where
 async fn route_post<'a, Data>(
   data: web::Json<Data>,
   context: web::Data<LemmyContext>,
+  apub_data: activitypub_federation::config::Data<LemmyContext>,
 ) -> Result<HttpResponse, Error>
 where
   Data: Perform
@@ -428,12 +431,13 @@ where
     + Send
     + 'static,
 {
-  perform::<Data>(data.0, context).await
+  perform::<Data>(data.0, context, apub_data).await
 }
 
 async fn perform_crud<'a, Data>(
   data: Data,
   context: web::Data<LemmyContext>,
+  apub_data: activitypub_federation::config::Data<LemmyContext>,
 ) -> Result<HttpResponse, Error>
 where
   Data: PerformCrud
@@ -444,13 +448,14 @@ where
     + 'static,
 {
   let res = data.perform(&context, None).await?;
-  SendActivity::send_activity(&data, &res, &context).await?;
+  SendActivity::send_activity(&data, &res, &apub_data).await?;
   Ok(HttpResponse::Ok().json(res))
 }
 
 async fn route_get_crud<'a, Data>(
   data: web::Query<Data>,
   context: web::Data<LemmyContext>,
+  apub_data: activitypub_federation::config::Data<LemmyContext>,
 ) -> Result<HttpResponse, Error>
 where
   Data: PerformCrud
@@ -460,12 +465,13 @@ where
     + Send
     + 'static,
 {
-  perform_crud::<Data>(data.0, context).await
+  perform_crud::<Data>(data.0, context, apub_data).await
 }
 
 async fn route_post_crud<'a, Data>(
   data: web::Json<Data>,
   context: web::Data<LemmyContext>,
+  apub_data: activitypub_federation::config::Data<LemmyContext>,
 ) -> Result<HttpResponse, Error>
 where
   Data: PerformCrud
@@ -475,5 +481,5 @@ where
     + Send
     + 'static,
 {
-  perform_crud::<Data>(data.0, context).await
+  perform_crud::<Data>(data.0, context, apub_data).await
 }
index b8d8f2c24bbec25bae0cca70fba1f0c0f422d24b..3ab1efc7007d918fa20df5c6d3b686d321c9269e 100644 (file)
@@ -1,3 +1,4 @@
+use activitypub_federation::config::Data as ContextData;
 use actix_web::{web, Error, HttpRequest, HttpResponse};
 use actix_web_actors::ws;
 use actix_ws::{MessageStream, Session};
@@ -113,6 +114,7 @@ use lemmy_utils::{error::LemmyError, rate_limit::RateLimitCell, ConnectionId, Ip
 use serde::Deserialize;
 use serde_json::Value;
 use std::{
+  ops::Deref,
   result,
   str::FromStr,
   sync::{Arc, Mutex},
@@ -126,6 +128,7 @@ pub async fn websocket(
   body: web::Payload,
   context: web::Data<LemmyContext>,
   rate_limiter: web::Data<RateLimitCell>,
+  apub_data: ContextData<LemmyContext>,
 ) -> Result<HttpResponse, Error> {
   let (response, session, stream) = actix_ws::handle(&req, body)?;
 
@@ -160,7 +163,7 @@ pub async fn websocket(
     connection_id,
     alive,
     rate_limiter,
-    context,
+    apub_data,
   ));
 
   Ok(response)
@@ -173,7 +176,7 @@ async fn handle_messages(
   connection_id: ConnectionId,
   alive: Arc<Mutex<Instant>>,
   rate_limiter: web::Data<RateLimitCell>,
-  context: web::Data<LemmyContext>,
+  context: ContextData<LemmyContext>,
 ) -> Result<(), LemmyError> {
   while let Some(Ok(msg)) = stream.next().await {
     match msg {
@@ -195,7 +198,7 @@ async fn handle_messages(
           client_ip.clone(),
           connection_id,
           rate_limiter.get_ref(),
-          context.get_ref().clone(),
+          context.reset_request_count(),
         )
         .await;
 
@@ -246,7 +249,7 @@ async fn parse_json_message(
   ip: IpAddr,
   connection_id: ConnectionId,
   rate_limiter: &RateLimitCell,
-  context: LemmyContext,
+  context: ContextData<LemmyContext>,
 ) -> Result<String, LemmyError> {
   let json: Value = serde_json::from_str(&msg)?;
   let data = json
@@ -301,7 +304,7 @@ fn check_rate_limit_passed(passed: bool) -> Result<(), LemmyError> {
 }
 
 pub async fn match_websocket_operation_crud(
-  context: LemmyContext,
+  context: ContextData<LemmyContext>,
   id: ConnectionId,
   op: UserOperationCrud,
   data: Value,
@@ -404,25 +407,25 @@ pub async fn match_websocket_operation_crud(
 }
 
 async fn do_websocket_operation_crud<'a, 'b, Data>(
-  context: LemmyContext,
+  context: ContextData<LemmyContext>,
   id: ConnectionId,
   op: UserOperationCrud,
   data: Value,
 ) -> result::Result<String, LemmyError>
 where
-  Data: PerformCrud + SendActivity<Response = <Data as PerformCrud>::Response>,
+  Data: PerformCrud + SendActivity<Response = <Data as PerformCrud>::Response> + Send,
   for<'de> Data: Deserialize<'de>,
 {
   let parsed_data: Data = serde_json::from_value(data)?;
   let res = parsed_data
-    .perform(&web::Data::new(context.clone()), Some(id))
+    .perform(&web::Data::new(context.deref().clone()), Some(id))
     .await?;
   SendActivity::send_activity(&parsed_data, &res, &context).await?;
   serialize_websocket_message(&op, &res)
 }
 
 pub async fn match_websocket_operation_apub(
-  context: LemmyContext,
+  context: ContextData<LemmyContext>,
   id: ConnectionId,
   op: UserOperationApub,
   data: Value,
@@ -448,25 +451,23 @@ pub async fn match_websocket_operation_apub(
 }
 
 async fn do_websocket_operation_apub<'a, 'b, Data>(
-  context: LemmyContext,
+  context: ContextData<LemmyContext>,
   id: ConnectionId,
   op: UserOperationApub,
   data: Value,
 ) -> result::Result<String, LemmyError>
 where
-  Data: PerformApub + SendActivity<Response = <Data as PerformApub>::Response>,
+  Data: PerformApub + SendActivity<Response = <Data as PerformApub>::Response> + Send,
   for<'de> Data: Deserialize<'de>,
 {
   let parsed_data: Data = serde_json::from_value(data)?;
-  let res = parsed_data
-    .perform(&web::Data::new(context.clone()), Some(id))
-    .await?;
+  let res = parsed_data.perform(&context, Some(id)).await?;
   SendActivity::send_activity(&parsed_data, &res, &context).await?;
   serialize_websocket_message(&op, &res)
 }
 
 pub async fn match_websocket_operation(
-  context: LemmyContext,
+  context: ContextData<LemmyContext>,
   id: ConnectionId,
   op: UserOperation,
   data: Value,
@@ -626,18 +627,18 @@ pub async fn match_websocket_operation(
 }
 
 async fn do_websocket_operation<'a, 'b, Data>(
-  context: LemmyContext,
+  context: ContextData<LemmyContext>,
   id: ConnectionId,
   op: UserOperation,
   data: Value,
 ) -> result::Result<String, LemmyError>
 where
-  Data: Perform + SendActivity<Response = <Data as Perform>::Response>,
+  Data: Perform + SendActivity<Response = <Data as Perform>::Response> + Send,
   for<'de> Data: Deserialize<'de>,
 {
   let parsed_data: Data = serde_json::from_value(data)?;
   let res = parsed_data
-    .perform(&web::Data::new(context.clone()), Some(id))
+    .perform(&web::Data::new(context.deref().clone()), Some(id))
     .await?;
   SendActivity::send_activity(&parsed_data, &res, &context).await?;
   serialize_websocket_message(&op, &res)
index 07c29beacdb50f5e2817f290a5d7e1054d1ed8f7..c69ce591c7aa563d8b6cd7449d9d11a6c2cd70b5 100644 (file)
@@ -1,5 +1,5 @@
 // This is for db migrations that require code
-use activitypub_federation::core::signatures::generate_actor_keypair;
+use activitypub_federation::http_signatures::generate_actor_keypair;
 use diesel::{
   sql_types::{Nullable, Text},
   ExpressionMethods,
index d30b214c1cdc622965ede661d02a14a6e8d8a2a5..152e3ded3a96eb8653f65ee50d89bdbbe7820eb6 100644 (file)
@@ -7,6 +7,7 @@ pub mod scheduled_tasks;
 pub mod telemetry;
 
 use crate::{code_migrations::run_advanced_migrations, root_span_builder::QuieterRootSpanBuilder};
+use activitypub_federation::config::{FederationConfig, FederationMiddleware};
 use actix_web::{middleware, web::Data, App, HttpServer, Result};
 use doku::json::{AutoComments, CommentsStyle, Formatting, ObjectsStyle};
 use lemmy_api_common::{
@@ -19,6 +20,7 @@ use lemmy_api_common::{
   },
   websocket::chat_server::ChatServer,
 };
+use lemmy_apub::{VerifyUrlData, FEDERATION_HTTP_FETCH_LIMIT};
 use lemmy_db_schema::{
   source::secret::Secret,
   utils::{build_db_pool, get_database_url, run_migrations},
@@ -140,15 +142,28 @@ pub async fn start_lemmy_server() -> Result<(), LemmyError> {
       pool.clone(),
       chat_server.clone(),
       client.clone(),
-      settings.clone(),
       secret.clone(),
       rate_limit_cell.clone(),
     );
+
+    let federation_config = FederationConfig::builder()
+      .domain(settings.hostname.clone())
+      .app_data(context.clone())
+      .client(client.clone())
+      .http_fetch_limit(FEDERATION_HTTP_FETCH_LIMIT)
+      .worker_count(local_site.federation_worker_count as u64)
+      .debug(cfg!(debug_assertions))
+      .http_signature_compat(true)
+      .url_verifier(Box::new(VerifyUrlData(context.pool().clone())))
+      .build()
+      .expect("configure federation");
+
     App::new()
       .wrap(middleware::Logger::default())
       .wrap(TracingLogger::<QuieterRootSpanBuilder>::new())
       .app_data(Data::new(context))
       .app_data(Data::new(rate_limit_cell.clone()))
+      .wrap(FederationMiddleware::new(federation_config))
       // The routes
       .configure(|cfg| api_routes_http::config(cfg, rate_limit_cell))
       .configure(|cfg| {