Add method ApubObject.verify()
authorFelix Ableitner <me@nutomic.com>
Sat, 6 Nov 2021 17:35:14 +0000 (18:35 +0100)
committerFelix Ableitner <me@nutomic.com>
Sat, 6 Nov 2021 17:35:14 +0000 (18:35 +0100)
20 files changed:
crates/apub/src/activities/comment/create_or_update.rs
crates/apub/src/activities/community/update.rs
crates/apub/src/activities/post/create_or_update.rs
crates/apub/src/activities/private_message/create_or_update.rs
crates/apub/src/collections/community_moderators.rs
crates/apub/src/collections/community_outbox.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/objects/comment.rs
crates/apub/src/objects/community.rs
crates/apub/src/objects/person.rs
crates/apub/src/objects/post.rs
crates/apub/src/objects/private_message.rs
crates/apub/src/protocol/objects/chat_message.rs
crates/apub/src/protocol/objects/group.rs
crates/apub/src/protocol/objects/note.rs
crates/apub/src/protocol/objects/page.rs
crates/apub_lib/src/object_id.rs
crates/apub_lib/src/traits.rs

index 0095a511deffbdd028a94030cbc79e19b86db50c..1ba2c8bb5708c624029cce554162644fb5b570fa 100644 (file)
@@ -85,9 +85,7 @@ impl ActivityHandler for CreateOrUpdateComment {
     check_community_deleted_or_removed(&community)?;
     check_post_deleted_or_removed(&post)?;
 
-    // TODO: should add a check that the correct community is in cc (probably needs changes to
-    //       comment deserialization)
-    self.object.verify(context, request_counter).await?;
+    ApubComment::verify(&self.object, self.actor.inner(), context, request_counter).await?;
     Ok(())
   }
 
@@ -96,8 +94,7 @@ impl ActivityHandler for CreateOrUpdateComment {
     context: &Data<LemmyContext>,
     request_counter: &mut i32,
   ) -> Result<(), LemmyError> {
-    let comment =
-      ApubComment::from_apub(self.object, context, self.actor.inner(), request_counter).await?;
+    let comment = ApubComment::from_apub(self.object, context, request_counter).await?;
     let recipients = get_notif_recipients(&self.actor, &comment, context, request_counter).await?;
     let notif_type = match self.kind {
       CreateOrUpdateType::Create => UserOperationCrud::CreateComment,
index f5d7e56518ed4b9eb0777ff38601affdf9ca004e..eebfe336c49b844e532dad958274f34da92d9a7b 100644 (file)
@@ -63,6 +63,13 @@ impl ActivityHandler for UpdateCommunity {
     let community = self.get_community(context, request_counter).await?;
     verify_person_in_community(&self.actor, &community, context, request_counter).await?;
     verify_mod_action(&self.actor, &community, context, request_counter).await?;
+    ApubCommunity::verify(
+      &self.object,
+      &community.actor_id.clone().into(),
+      context,
+      request_counter,
+    )
+    .await?;
     Ok(())
   }
 
@@ -73,10 +80,7 @@ impl ActivityHandler for UpdateCommunity {
   ) -> Result<(), LemmyError> {
     let community = self.get_community(context, request_counter).await?;
 
-    let updated_community = self
-      .object
-      .into_form(&community.actor_id.clone().into(), &context.settings())
-      .await?;
+    let updated_community = self.object.into_form()?;
     let cf = CommunityForm {
       name: updated_community.name,
       title: updated_community.title,
index 1c71c8ec1a7f50c37f05a7dd1532261218f45cab..db5d725fc2c9a5f4caeef0b3cf47ae36d86124e8 100644 (file)
@@ -104,7 +104,7 @@ impl ActivityHandler for CreateOrUpdatePost {
         }
       }
     }
-    self.object.verify(context, request_counter).await?;
+    ApubPost::verify(&self.object, self.actor.inner(), context, request_counter).await?;
     Ok(())
   }
 
@@ -113,9 +113,7 @@ impl ActivityHandler for CreateOrUpdatePost {
     context: &Data<LemmyContext>,
     request_counter: &mut i32,
   ) -> Result<(), LemmyError> {
-    let actor = self.actor.dereference(context, request_counter).await?;
-    let post =
-      ApubPost::from_apub(self.object, context, &actor.actor_id(), request_counter).await?;
+    let post = ApubPost::from_apub(self.object, context, request_counter).await?;
 
     let notif_type = match self.kind {
       CreateOrUpdateType::Create => UserOperationCrud::CreatePost,
index 7f40b5fbc76be1af85ec853780ae76bf91d2d804..e3d72f54a5a408f190d78a4d25a3b54110f79a21 100644 (file)
@@ -57,7 +57,7 @@ impl ActivityHandler for CreateOrUpdatePrivateMessage {
     verify_activity(&self.id, self.actor.inner(), &context.settings())?;
     verify_person(&self.actor, context, request_counter).await?;
     verify_domains_match(self.actor.inner(), self.object.id.inner())?;
-    self.object.verify(context, request_counter).await?;
+    ApubPrivateMessage::verify(&self.object, self.actor.inner(), context, request_counter).await?;
     Ok(())
   }
 
@@ -67,8 +67,7 @@ impl ActivityHandler for CreateOrUpdatePrivateMessage {
     request_counter: &mut i32,
   ) -> Result<(), LemmyError> {
     let private_message =
-      ApubPrivateMessage::from_apub(self.object, context, self.actor.inner(), request_counter)
-        .await?;
+      ApubPrivateMessage::from_apub(self.object, context, request_counter).await?;
 
     let notif_type = match self.kind {
       CreateOrUpdateType::Create => UserOperationCrud::CreatePrivateMessage,
index cbbe66708d2380e5cbc23ebf2d105baf79059fac..695f7aca1ff53c6a0a19045fcc626f6690726d00 100644 (file)
@@ -66,13 +66,21 @@ impl ApubObject for ApubCommunityModerators {
     unimplemented!()
   }
 
+  async fn verify(
+    group_moderators: &GroupModerators,
+    expected_domain: &Url,
+    _context: &CommunityContext,
+    _request_counter: &mut i32,
+  ) -> Result<(), LemmyError> {
+    verify_domains_match(&group_moderators.id, expected_domain)?;
+    Ok(())
+  }
+
   async fn from_apub(
     apub: Self::ApubType,
     data: &Self::DataType,
-    expected_domain: &Url,
     request_counter: &mut i32,
   ) -> Result<Self, LemmyError> {
-    verify_domains_match(expected_domain, &apub.id)?;
     let community_id = data.0.id;
     let current_moderators = blocking(data.1.pool(), move |conn| {
       CommunityModeratorView::for_community(conn, community_id)
@@ -165,7 +173,10 @@ mod tests {
       0: community,
       1: context,
     };
-    ApubCommunityModerators::from_apub(json, &community_context, &url, &mut request_counter)
+    ApubCommunityModerators::verify(&json, &url, &community_context, &mut request_counter)
+      .await
+      .unwrap();
+    ApubCommunityModerators::from_apub(json, &community_context, &mut request_counter)
       .await
       .unwrap();
     assert_eq!(request_counter, 0);
index cbad5c484fb17863a5d7e59a1eb5fa40015bda20..3632f61a7febb1123261b70c1b6b687b0ac450fe 100644 (file)
@@ -85,13 +85,21 @@ impl ApubObject for ApubCommunityOutbox {
     unimplemented!()
   }
 
+  async fn verify(
+    group_outbox: &GroupOutbox,
+    expected_domain: &Url,
+    _context: &CommunityContext,
+    _request_counter: &mut i32,
+  ) -> Result<(), LemmyError> {
+    verify_domains_match(expected_domain, &group_outbox.id)?;
+    Ok(())
+  }
+
   async fn from_apub(
     apub: Self::ApubType,
     data: &Self::DataType,
-    expected_domain: &Url,
     request_counter: &mut i32,
   ) -> Result<Self, LemmyError> {
-    verify_domains_match(expected_domain, &apub.id)?;
     let mut outbox_activities = apub.ordered_items;
     if outbox_activities.len() > 20 {
       outbox_activities = outbox_activities[0..20].to_vec();
index dc1546f9cc346df778db297c3744335c3f2acd7d..2ca84bee14e9549b9eea13a8bc759e9bfafebefd 100644 (file)
@@ -61,19 +61,30 @@ impl ApubObject for PostOrComment {
     unimplemented!()
   }
 
+  async fn verify(
+    apub: &Self::ApubType,
+    expected_domain: &Url,
+    data: &Self::DataType,
+    request_counter: &mut i32,
+  ) -> 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,
+    }
+  }
+
   async fn from_apub(
     apub: PageOrNote,
     context: &LemmyContext,
-    expected_domain: &Url,
     request_counter: &mut i32,
   ) -> Result<Self, LemmyError> {
     Ok(match apub {
-      PageOrNote::Page(p) => PostOrComment::Post(
-        ApubPost::from_apub(p, context, expected_domain, request_counter).await?,
-      ),
-      PageOrNote::Note(n) => PostOrComment::Comment(
-        ApubComment::from_apub(n, context, expected_domain, request_counter).await?,
-      ),
+      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?)
+      }
     })
   }
 }
index 557fc1b542c11ae55426dfaad3ebe5cdf5b8eb99..1c03a10bd7b3e4c293badd9a15e1f66964590c16 100644 (file)
@@ -163,19 +163,40 @@ impl ApubObject for SearchableObjects {
     unimplemented!()
   }
 
+  async fn verify(
+    apub: &Self::ApubType,
+    expected_domain: &Url,
+    data: &Self::DataType,
+    request_counter: &mut i32,
+  ) -> 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
+      }
+    }
+  }
+
   async fn from_apub(
     apub: Self::ApubType,
     context: &LemmyContext,
-    ed: &Url,
     rc: &mut i32,
   ) -> Result<Self, LemmyError> {
     use SearchableApubTypes as SAT;
     use SearchableObjects as SO;
     Ok(match apub {
-      SAT::Group(g) => SO::Community(ApubCommunity::from_apub(g, context, ed, rc).await?),
-      SAT::Person(p) => SO::Person(ApubPerson::from_apub(p, context, ed, rc).await?),
-      SAT::Page(p) => SO::Post(ApubPost::from_apub(p, context, ed, rc).await?),
-      SAT::Note(n) => SO::Comment(ApubComment::from_apub(n, context, ed, rc).await?),
+      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?),
     })
   }
 }
index 5f7c388ed0c7f768c774619782b0e30549106524..e5bc49ba84b80e3255124bfb77317c66c1e627c7 100644 (file)
@@ -62,19 +62,34 @@ impl ApubObject for UserOrCommunity {
     unimplemented!()
   }
 
+  async fn verify(
+    apub: &Self::ApubType,
+    expected_domain: &Url,
+    data: &Self::DataType,
+    request_counter: &mut i32,
+  ) -> 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
+      }
+    }
+  }
+
   async fn from_apub(
     apub: Self::ApubType,
     data: &Self::DataType,
-    expected_domain: &Url,
     request_counter: &mut i32,
   ) -> Result<Self, LemmyError> {
     Ok(match apub {
-      PersonOrGroup::Person(p) => UserOrCommunity::User(
-        ApubPerson::from_apub(p, data, expected_domain, request_counter).await?,
-      ),
-      PersonOrGroup::Group(p) => UserOrCommunity::Community(
-        ApubCommunity::from_apub(p, data, expected_domain, request_counter).await?,
-      ),
+      PersonOrGroup::Person(p) => {
+        UserOrCommunity::User(ApubPerson::from_apub(p, data, request_counter).await?)
+      }
+      PersonOrGroup::Group(p) => {
+        UserOrCommunity::Community(ApubCommunity::from_apub(p, data, request_counter).await?)
+      }
     })
   }
 }
index da96f8fab603e78129aa5600e27d99ca26667c84..d0f74acfad54c427babbeb1824d5388836f0f179 100644 (file)
@@ -1,5 +1,5 @@
 use crate::{
-  activities::verify_person_in_community,
+  activities::{verify_is_public, verify_person_in_community},
   check_is_apub_id_valid,
   protocol::{
     objects::{
@@ -129,21 +129,16 @@ impl ApubObject for ApubComment {
     ))
   }
 
-  /// Converts a `Note` to `Comment`.
-  ///
-  /// If the parent community, post and comment(s) are not known locally, these are also fetched.
-  async fn from_apub(
-    note: Note,
-    context: &LemmyContext,
+  async fn verify(
+    note: &Note,
     expected_domain: &Url,
+    context: &LemmyContext,
     request_counter: &mut i32,
-  ) -> Result<ApubComment, LemmyError> {
+  ) -> Result<(), LemmyError> {
     verify_domains_match(note.id.inner(), expected_domain)?;
-    let creator = note
-      .attributed_to
-      .dereference(context, request_counter)
-      .await?;
-    let (post, parent_comment_id) = note.get_parents(context, request_counter).await?;
+    verify_domains_match(note.attributed_to.inner(), note.id.inner())?;
+    verify_is_public(&note.to)?;
+    let (post, _) = note.get_parents(context, request_counter).await?;
     let community_id = post.community_id;
     let community = blocking(context.pool(), move |conn| {
       Community::read(conn, community_id)
@@ -160,6 +155,22 @@ impl ApubObject for ApubComment {
     if post.locked {
       return Err(anyhow!("Post is locked").into());
     }
+    Ok(())
+  }
+
+  /// Converts a `Note` to `Comment`.
+  ///
+  /// If the parent community, post and comment(s) are not known locally, these are also fetched.
+  async fn from_apub(
+    note: Note,
+    context: &LemmyContext,
+    request_counter: &mut i32,
+  ) -> Result<ApubComment, LemmyError> {
+    let creator = note
+      .attributed_to
+      .dereference(context, request_counter)
+      .await?;
+    let (post, parent_comment_id) = note.get_parents(context, request_counter).await?;
 
     let content = if let SourceCompat::Lemmy(source) = &note.source {
       source.content.clone()
@@ -205,7 +216,10 @@ pub(crate) mod tests {
     let person = parse_lemmy_person(context).await;
     let community = parse_lemmy_community(context).await;
     let post_json = file_to_json_object("assets/lemmy/objects/page.json");
-    let post = ApubPost::from_apub(post_json, context, url, &mut 0)
+    ApubPost::verify(&post_json, url, context, &mut 0)
+      .await
+      .unwrap();
+    let post = ApubPost::from_apub(post_json, context, &mut 0)
       .await
       .unwrap();
     (person, community, post)
@@ -226,7 +240,10 @@ pub(crate) mod tests {
 
     let json: Note = file_to_json_object("assets/lemmy/objects/note.json");
     let mut request_counter = 0;
-    let comment = ApubComment::from_apub(json.clone(), &context, &url, &mut request_counter)
+    ApubComment::verify(&json, &url, &context, &mut request_counter)
+      .await
+      .unwrap();
+    let comment = ApubComment::from_apub(json.clone(), &context, &mut request_counter)
       .await
       .unwrap();
 
@@ -254,12 +271,18 @@ 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");
-    ApubPerson::from_apub(person_json, &context, &pleroma_url, &mut 0)
+    ApubPerson::verify(&person_json, &pleroma_url, &context, &mut 0)
+      .await
+      .unwrap();
+    ApubPerson::from_apub(person_json, &context, &mut 0)
       .await
       .unwrap();
     let json = file_to_json_object("assets/pleroma/objects/note.json");
     let mut request_counter = 0;
-    let comment = ApubComment::from_apub(json, &context, &pleroma_url, &mut request_counter)
+    ApubComment::verify(&json, &pleroma_url, &context, &mut request_counter)
+      .await
+      .unwrap();
+    let comment = ApubComment::from_apub(json, &context, &mut request_counter)
       .await
       .unwrap();
 
index f6737a3a8233cd1f0774b861f068b668e42404c5..21ca9d4f5747f751109a5cddc2e3fda18350556d 100644 (file)
@@ -124,14 +124,22 @@ impl ApubObject for ApubCommunity {
     ))
   }
 
+  async fn verify(
+    group: &Group,
+    expected_domain: &Url,
+    context: &LemmyContext,
+    _request_counter: &mut i32,
+  ) -> Result<(), LemmyError> {
+    group.verify(expected_domain, context).await
+  }
+
   /// Converts a `Group` to `Community`, inserts it into the database and updates moderators.
   async fn from_apub(
     group: Group,
     context: &LemmyContext,
-    expected_domain: &Url,
     request_counter: &mut i32,
   ) -> Result<ApubCommunity, LemmyError> {
-    let form = Group::into_form(group.clone(), expected_domain, &context.settings()).await?;
+    let form = Group::into_form(group.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.
@@ -232,7 +240,10 @@ pub(crate) mod tests {
 
     let url = Url::parse("https://enterprise.lemmy.ml/c/tenforward").unwrap();
     let mut request_counter = 0;
-    let community = ApubCommunity::from_apub(json, context, &url, &mut request_counter)
+    ApubCommunity::verify(&json, &url, context, &mut request_counter)
+      .await
+      .unwrap();
+    let community = ApubCommunity::from_apub(json, context, &mut request_counter)
       .await
       .unwrap();
     // this makes two requests to the (intentionally) broken outbox/moderators collections
index ea08832144fe0b1df446fa8cfe21fdaf1a4df29c..e3fcdd2eeb010f308220ae6002ab0d90d1d6637b 100644 (file)
@@ -125,32 +125,31 @@ impl ApubObject for ApubPerson {
     unimplemented!()
   }
 
-  async fn from_apub(
-    person: Person,
-    context: &LemmyContext,
+  async fn verify(
+    person: &Person,
     expected_domain: &Url,
+    context: &LemmyContext,
     _request_counter: &mut i32,
-  ) -> Result<ApubPerson, LemmyError> {
+  ) -> Result<(), LemmyError> {
     verify_domains_match(person.id.inner(), expected_domain)?;
-    let name = person.preferred_username;
-    let display_name: Option<String> = person.name;
-    let bio = get_summary_from_string_or_source(&person.summary, &person.source);
-    let shared_inbox = person.endpoints.shared_inbox.map(|s| s.into());
-    let bot_account = match person.kind {
-      UserTypes::Person => false,
-      UserTypes::Service => true,
-    };
+    check_is_apub_id_valid(person.id.inner(), false, &context.settings())?;
 
     let slur_regex = &context.settings().slur_regex();
-    check_slurs(&name, slur_regex)?;
-    check_slurs_opt(&display_name, slur_regex)?;
+    check_slurs(&person.preferred_username, slur_regex)?;
+    check_slurs_opt(&person.name, slur_regex)?;
+    let bio = get_summary_from_string_or_source(&person.summary, &person.source);
     check_slurs_opt(&bio, slur_regex)?;
+    Ok(())
+  }
 
-    check_is_apub_id_valid(person.id.inner(), false, &context.settings())?;
-
+  async fn from_apub(
+    person: Person,
+    context: &LemmyContext,
+    _request_counter: &mut i32,
+  ) -> Result<ApubPerson, LemmyError> {
     let person_form = PersonForm {
-      name,
-      display_name: Some(display_name),
+      name: person.preferred_username,
+      display_name: Some(person.name),
       banned: None,
       deleted: None,
       avatar: Some(person.icon.map(|i| i.url.into())),
@@ -158,15 +157,18 @@ impl ApubObject for ApubPerson {
       published: person.published.map(|u| u.naive_local()),
       updated: person.updated.map(|u| u.naive_local()),
       actor_id: Some(person.id.into()),
-      bio: Some(bio),
+      bio: Some(get_summary_from_string_or_source(
+        &person.summary,
+        &person.source,
+      )),
       local: Some(false),
       admin: Some(false),
-      bot_account: Some(bot_account),
+      bot_account: Some(person.kind == UserTypes::Service),
       private_key: None,
       public_key: Some(Some(person.public_key.public_key_pem)),
       last_refreshed_at: Some(naive_now()),
       inbox_url: Some(person.inbox.into()),
-      shared_inbox_url: Some(shared_inbox),
+      shared_inbox_url: Some(person.endpoints.shared_inbox.map(|s| s.into())),
       matrix_user_id: Some(person.matrix_user_id),
     };
     let person = blocking(context.pool(), move |conn| {
@@ -210,7 +212,10 @@ pub(crate) mod tests {
     let json = file_to_json_object("assets/lemmy/objects/person.json");
     let url = Url::parse("https://enterprise.lemmy.ml/u/picard").unwrap();
     let mut request_counter = 0;
-    let person = ApubPerson::from_apub(json, context, &url, &mut request_counter)
+    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);
@@ -238,7 +243,10 @@ pub(crate) mod tests {
     let json = file_to_json_object("assets/pleroma/objects/person.json");
     let url = Url::parse("https://queer.hacktivis.me/users/lanodan").unwrap();
     let mut request_counter = 0;
-    let person = ApubPerson::from_apub(json, &context, &url, &mut request_counter)
+    ApubPerson::verify(&json, &url, &context, &mut request_counter)
+      .await
+      .unwrap();
+    let person = ApubPerson::from_apub(json, &context, &mut request_counter)
       .await
       .unwrap();
 
index bbb5537e2b77a28af86e6ec566073f8bb4889ecc..9e68cbb1de1e0fbb0c36b24a10ae1395a9b34bc6 100644 (file)
@@ -1,5 +1,5 @@
 use crate::{
-  activities::verify_person_in_community,
+  activities::{verify_is_public, verify_person_in_community},
   check_is_apub_id_valid,
   protocol::{
     objects::{page::Page, tombstone::Tombstone},
@@ -30,7 +30,7 @@ use lemmy_db_schema::{
 };
 use lemmy_utils::{
   request::fetch_site_data,
-  utils::{convert_datetime, markdown_to_html, remove_slurs},
+  utils::{check_slurs, convert_datetime, markdown_to_html, remove_slurs},
   LemmyError,
 };
 use lemmy_websocket::LemmyContext;
@@ -133,24 +133,37 @@ impl ApubObject for ApubPost {
     ))
   }
 
-  async fn from_apub(
-    page: Page,
-    context: &LemmyContext,
+  async fn verify(
+    page: &Page,
     expected_domain: &Url,
+    context: &LemmyContext,
     request_counter: &mut i32,
-  ) -> Result<ApubPost, LemmyError> {
+  ) -> 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.
     if !page.is_mod_action(context).await? {
       verify_domains_match(page.id.inner(), expected_domain)?;
     };
+
+    let community = page.extract_community(context, request_counter).await?;
+    check_is_apub_id_valid(page.id.inner(), community.local, &context.settings())?;
+    verify_person_in_community(&page.attributed_to, &community, context, request_counter).await?;
+    check_slurs(&page.name, &context.settings().slur_regex())?;
+    verify_domains_match(page.attributed_to.inner(), page.id.inner())?;
+    verify_is_public(&page.to.clone())?;
+    Ok(())
+  }
+
+  async fn from_apub(
+    page: Page,
+    context: &LemmyContext,
+    request_counter: &mut i32,
+  ) -> Result<ApubPost, LemmyError> {
     let creator = page
       .attributed_to
       .dereference(context, request_counter)
       .await?;
     let community = page.extract_community(context, request_counter).await?;
-    check_is_apub_id_valid(page.id.inner(), community.local, &context.settings())?;
-    verify_person_in_community(&page.attributed_to, &community, context, request_counter).await?;
 
     let thumbnail_url: Option<Url> = page.image.map(|i| i.url);
     let (metadata_res, pictrs_thumbnail) = if let Some(url) = &page.url {
@@ -212,7 +225,10 @@ mod tests {
     let json = file_to_json_object("assets/lemmy/objects/page.json");
     let url = Url::parse("https://enterprise.lemmy.ml/post/55143").unwrap();
     let mut request_counter = 0;
-    let post = ApubPost::from_apub(json, &context, &url, &mut request_counter)
+    ApubPost::verify(&json, &url, &context, &mut request_counter)
+      .await
+      .unwrap();
+    let post = ApubPost::from_apub(json, &context, &mut request_counter)
       .await
       .unwrap();
 
index 334f37c5fa96a80ec789dc16deb8205d44466f37..30c8e4dc5e86ec76fb55873dfb07d1187a9c2f7a 100644 (file)
@@ -2,6 +2,7 @@ use crate::protocol::{
   objects::chat_message::{ChatMessage, ChatMessageType},
   Source,
 };
+use anyhow::anyhow;
 use chrono::NaiveDateTime;
 use html2md::parse_html;
 use lemmy_api_common::blocking;
@@ -100,14 +101,29 @@ impl ApubObject for ApubPrivateMessage {
     unimplemented!()
   }
 
+  async fn verify(
+    note: &ChatMessage,
+    expected_domain: &Url,
+    context: &LemmyContext,
+    request_counter: &mut i32,
+  ) -> Result<(), LemmyError> {
+    verify_domains_match(note.id.inner(), expected_domain)?;
+    verify_domains_match(note.attributed_to.inner(), note.id.inner())?;
+    let person = note
+      .attributed_to
+      .dereference(context, request_counter)
+      .await?;
+    if person.banned {
+      return Err(anyhow!("Person is banned from site").into());
+    }
+    Ok(())
+  }
+
   async fn from_apub(
     note: ChatMessage,
     context: &LemmyContext,
-    expected_domain: &Url,
     request_counter: &mut i32,
   ) -> Result<ApubPrivateMessage, LemmyError> {
-    verify_domains_match(note.id.inner(), expected_domain)?;
-    let ap_id = Some(note.id.into());
     let creator = note
       .attributed_to
       .dereference(context, request_counter)
@@ -127,7 +143,7 @@ impl ApubObject for ApubPrivateMessage {
       updated: note.updated.map(|u| u.naive_local()),
       deleted: None,
       read: None,
-      ap_id,
+      ap_id: Some(note.id.into()),
       local: Some(false),
     };
     let pm = blocking(context.pool(), move |conn| {
@@ -150,12 +166,18 @@ mod tests {
 
   async fn prepare_comment_test(url: &Url, context: &LemmyContext) -> (ApubPerson, ApubPerson) {
     let lemmy_person = file_to_json_object("assets/lemmy/objects/person.json");
-    let person1 = ApubPerson::from_apub(lemmy_person, context, url, &mut 0)
+    ApubPerson::verify(&lemmy_person, url, context, &mut 0)
+      .await
+      .unwrap();
+    let person1 = ApubPerson::from_apub(lemmy_person, context, &mut 0)
       .await
       .unwrap();
     let pleroma_person = file_to_json_object("assets/pleroma/objects/person.json");
     let pleroma_url = Url::parse("https://queer.hacktivis.me/users/lanodan").unwrap();
-    let person2 = ApubPerson::from_apub(pleroma_person, context, &pleroma_url, &mut 0)
+    ApubPerson::verify(&pleroma_person, &pleroma_url, context, &mut 0)
+      .await
+      .unwrap();
+    let person2 = ApubPerson::from_apub(pleroma_person, context, &mut 0)
       .await
       .unwrap();
     (person1, person2)
@@ -174,7 +196,10 @@ mod tests {
     let data = prepare_comment_test(&url, &context).await;
     let json: ChatMessage = file_to_json_object("assets/lemmy/objects/chat_message.json");
     let mut request_counter = 0;
-    let pm = ApubPrivateMessage::from_apub(json.clone(), &context, &url, &mut request_counter)
+    ApubPrivateMessage::verify(&json, &url, &context, &mut request_counter)
+      .await
+      .unwrap();
+    let pm = ApubPrivateMessage::from_apub(json.clone(), &context, &mut request_counter)
       .await
       .unwrap();
 
@@ -199,7 +224,10 @@ mod tests {
     let pleroma_url = Url::parse("https://queer.hacktivis.me/objects/2").unwrap();
     let json = file_to_json_object("assets/pleroma/objects/chat_message.json");
     let mut request_counter = 0;
-    let pm = ApubPrivateMessage::from_apub(json, &context, &pleroma_url, &mut request_counter)
+    ApubPrivateMessage::verify(&json, &pleroma_url, &context, &mut request_counter)
+      .await
+      .unwrap();
+    let pm = ApubPrivateMessage::from_apub(json, &context, &mut request_counter)
       .await
       .unwrap();
 
index 3a019967e944249a221ae4d0686bdd701dde9103..b86929139f497bc5a3b3f0af5bad26ab8b8c81fc 100644 (file)
@@ -6,10 +6,7 @@ use activitystreams::{
   chrono::{DateTime, FixedOffset},
   unparsed::Unparsed,
 };
-use anyhow::anyhow;
-use lemmy_apub_lib::{object_id::ObjectId, values::MediaTypeHtml, verify::verify_domains_match};
-use lemmy_utils::LemmyError;
-use lemmy_websocket::LemmyContext;
+use lemmy_apub_lib::{object_id::ObjectId, values::MediaTypeHtml};
 use serde::{Deserialize, Serialize};
 use serde_with::skip_serializing_none;
 
@@ -35,21 +32,3 @@ pub struct ChatMessage {
 pub enum ChatMessageType {
   ChatMessage,
 }
-
-impl ChatMessage {
-  pub(crate) async fn verify(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    verify_domains_match(self.attributed_to.inner(), self.id.inner())?;
-    let person = self
-      .attributed_to
-      .dereference(context, request_counter)
-      .await?;
-    if person.banned {
-      return Err(anyhow!("Person is banned from site").into());
-    }
-    Ok(())
-  }
-}
index a761a4425ee0e260ac8db320f80d6ce79f75a223..8a6e672037eca15b26b589aa86ed521568bb50dd 100644 (file)
@@ -12,10 +12,10 @@ use chrono::{DateTime, FixedOffset};
 use lemmy_apub_lib::{object_id::ObjectId, signatures::PublicKey, verify::verify_domains_match};
 use lemmy_db_schema::{naive_now, source::community::CommunityForm};
 use lemmy_utils::{
-  settings::structs::Settings,
   utils::{check_slurs, check_slurs_opt},
   LemmyError,
 };
+use lemmy_websocket::LemmyContext;
 use serde::{Deserialize, Serialize};
 use serde_with::skip_serializing_none;
 use url::Url;
@@ -52,27 +52,27 @@ pub struct Group {
 }
 
 impl Group {
-  pub(crate) async fn into_form(
-    self,
+  pub(crate) async fn verify(
+    &self,
     expected_domain: &Url,
-    settings: &Settings,
-  ) -> Result<CommunityForm, LemmyError> {
-    check_is_apub_id_valid(self.id.inner(), true, settings)?;
+    context: &LemmyContext,
+  ) -> Result<(), LemmyError> {
+    check_is_apub_id_valid(self.id.inner(), true, &context.settings())?;
     verify_domains_match(expected_domain, self.id.inner())?;
-    let name = self.preferred_username;
-    let title = self.name;
-    let description = get_summary_from_string_or_source(&self.summary, &self.source);
-    let shared_inbox = self.endpoints.shared_inbox.map(|s| s.into());
 
-    let slur_regex = &settings.slur_regex();
-    check_slurs(&name, slur_regex)?;
-    check_slurs(&title, slur_regex)?;
+    let slur_regex = &context.settings().slur_regex();
+    check_slurs(&self.preferred_username, slur_regex)?;
+    check_slurs(&self.name, slur_regex)?;
+    let description = get_summary_from_string_or_source(&self.summary, &self.source);
     check_slurs_opt(&description, slur_regex)?;
+    Ok(())
+  }
 
+  pub(crate) fn into_form(self) -> Result<CommunityForm, LemmyError> {
     Ok(CommunityForm {
-      name,
-      title,
-      description,
+      name: self.preferred_username,
+      title: self.name,
+      description: get_summary_from_string_or_source(&self.summary, &self.source),
       removed: None,
       published: self.published.map(|u| u.naive_local()),
       updated: self.updated.map(|u| u.naive_local()),
@@ -87,7 +87,7 @@ impl Group {
       banner: Some(self.image.map(|i| i.url.into())),
       followers_url: Some(self.followers.into()),
       inbox_url: Some(self.inbox.into()),
-      shared_inbox_url: Some(shared_inbox),
+      shared_inbox_url: Some(self.endpoints.shared_inbox.map(|s| s.into())),
     })
   }
 }
index 34cb6bed0c52bc5e8256edb92c4bd8f2e5812a36..acb4b6fb18b0949b3f46b98678ab07132ad9fd61 100644 (file)
@@ -1,19 +1,13 @@
 use crate::{
-  activities::{verify_is_public, verify_person_in_community},
   fetcher::post_or_comment::PostOrComment,
-  objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost},
+  objects::{comment::ApubComment, person::ApubPerson, post::ApubPost},
   protocol::Source,
 };
 use activitystreams::{object::kind::NoteType, unparsed::Unparsed};
-use anyhow::anyhow;
 use chrono::{DateTime, FixedOffset};
 use lemmy_api_common::blocking;
-use lemmy_apub_lib::{object_id::ObjectId, values::MediaTypeHtml, verify::verify_domains_match};
-use lemmy_db_schema::{
-  newtypes::CommentId,
-  source::{community::Community, post::Post},
-  traits::Crud,
-};
+use lemmy_apub_lib::{object_id::ObjectId, values::MediaTypeHtml};
+use lemmy_db_schema::{newtypes::CommentId, source::post::Post, traits::Crud};
 use lemmy_utils::LemmyError;
 use lemmy_websocket::LemmyContext;
 use serde::{Deserialize, Serialize};
@@ -76,26 +70,4 @@ impl Note {
       }
     }
   }
-
-  pub(crate) async fn verify(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let (post, _parent_comment_id) = self.get_parents(context, request_counter).await?;
-    let community_id = post.community_id;
-    let community: ApubCommunity = blocking(context.pool(), move |conn| {
-      Community::read(conn, community_id)
-    })
-    .await??
-    .into();
-
-    if post.locked {
-      return Err(anyhow!("Post is locked").into());
-    }
-    verify_domains_match(self.attributed_to.inner(), self.id.inner())?;
-    verify_person_in_community(&self.attributed_to, &community, context, request_counter).await?;
-    verify_is_public(&self.to)?;
-    Ok(())
-  }
 }
index 285a0e04eb043a29daa450b847c414bb0e93d8b1..ef7ab6e69d96a3abbe99c9b903d5f88368f3d478 100644 (file)
@@ -1,13 +1,12 @@
 use crate::{
-  activities::{verify_is_public, verify_person_in_community},
   objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
   protocol::{ImageObject, Source},
 };
 use activitystreams::{object::kind::PageType, unparsed::Unparsed};
 use anyhow::anyhow;
 use chrono::{DateTime, FixedOffset};
-use lemmy_apub_lib::{object_id::ObjectId, values::MediaTypeHtml, verify::verify_domains_match};
-use lemmy_utils::{utils::check_slurs, LemmyError};
+use lemmy_apub_lib::{object_id::ObjectId, values::MediaTypeHtml};
+use lemmy_utils::LemmyError;
 use lemmy_websocket::LemmyContext;
 use serde::{Deserialize, Serialize};
 use serde_with::skip_serializing_none;
@@ -54,20 +53,6 @@ impl Page {
     Ok(is_mod_action)
   }
 
-  pub(crate) async fn verify(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    let community = self.extract_community(context, request_counter).await?;
-
-    check_slurs(&self.name, &context.settings().slur_regex())?;
-    verify_domains_match(self.attributed_to.inner(), self.id.inner())?;
-    verify_person_in_community(&self.attributed_to, &community, context, request_counter).await?;
-    verify_is_public(&self.to.clone())?;
-    Ok(())
-  }
-
   pub(crate) async fn extract_community(
     &self,
     context: &LemmyContext,
index 8e4b70a237b73815af83861a763e1e078644d939..5464306851eaf6144da23914057a6cf18f4f3f45 100644 (file)
@@ -140,7 +140,8 @@ where
 
     let res2: Kind::ApubType = res.json().await?;
 
-    Ok(Kind::from_apub(res2, data, self.inner(), request_counter).await?)
+    Kind::verify(&res2, self.inner(), data, request_counter).await?;
+    Ok(Kind::from_apub(res2, data, request_counter).await?)
   }
 }
 
index e5dcbc1edc1b6851a141daf4389fd3c055cd23ef..c0cdb1afb51b16cfae5174d0370c29f6dd9332ef 100644 (file)
@@ -44,6 +44,13 @@ pub trait ApubObject {
   async fn into_apub(self, data: &Self::DataType) -> Result<Self::ApubType, LemmyError>;
   fn to_tombstone(&self) -> Result<Self::TombstoneType, LemmyError>;
 
+  async fn verify(
+    apub: &Self::ApubType,
+    expected_domain: &Url,
+    data: &Self::DataType,
+    request_counter: &mut i32,
+  ) -> Result<(), LemmyError>;
+
   /// Converts an object from ActivityPub type to Lemmy internal type.
   ///
   /// * `apub` The object to read from
@@ -53,7 +60,6 @@ pub trait ApubObject {
   async fn from_apub(
     apub: Self::ApubType,
     data: &Self::DataType,
-    expected_domain: &Url,
     request_counter: &mut i32,
   ) -> Result<Self, LemmyError>
   where