]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/mod.rs
Merge pull request #1660 from LemmyNet/merge-apub-crates
[lemmy.git] / crates / apub / src / activities / mod.rs
1 use crate::{
2   check_community_or_site_ban,
3   check_is_apub_id_valid,
4   fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person},
5   generate_moderators_url,
6 };
7 use anyhow::anyhow;
8 use lemmy_api_common::blocking;
9 use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields};
10 use lemmy_db_queries::ApubObject;
11 use lemmy_db_schema::{
12   source::{community::Community, person::Person},
13   DbUrl,
14 };
15 use lemmy_db_views_actor::community_view::CommunityView;
16 use lemmy_utils::LemmyError;
17 use lemmy_websocket::LemmyContext;
18 use url::Url;
19
20 pub mod comment;
21 pub mod community;
22 pub mod deletion;
23 pub mod following;
24 pub mod post;
25 pub mod private_message;
26 pub mod removal;
27 pub mod send;
28 pub mod voting;
29
30 /// Checks that the specified Url actually identifies a Person (by fetching it), and that the person
31 /// doesn't have a site ban.
32 async fn verify_person(
33   person_id: &Url,
34   context: &LemmyContext,
35   request_counter: &mut i32,
36 ) -> Result<(), LemmyError> {
37   let person = get_or_fetch_and_upsert_person(person_id, context, request_counter).await?;
38   if person.banned {
39     return Err(anyhow!("Person {} is banned", person_id).into());
40   }
41   Ok(())
42 }
43
44 /// Fetches the person and community to verify their type, then checks if person is banned from site
45 /// or community.
46 async fn verify_person_in_community(
47   person_id: &Url,
48   cc: &[Url],
49   context: &LemmyContext,
50   request_counter: &mut i32,
51 ) -> Result<Community, LemmyError> {
52   let person = get_or_fetch_and_upsert_person(person_id, context, request_counter).await?;
53   let mut cc_iter = cc.iter();
54   let community: Community = loop {
55     if let Some(cid) = cc_iter.next() {
56       if let Ok(c) = get_or_fetch_and_upsert_community(cid, context, request_counter).await {
57         break c;
58       }
59     } else {
60       return Err(anyhow!("No community found in cc").into());
61     }
62   };
63   check_community_or_site_ban(&person, community.id, context.pool()).await?;
64   Ok(community)
65 }
66
67 /// Simply check that the url actually refers to a valid group.
68 async fn verify_community(
69   community_id: &Url,
70   context: &LemmyContext,
71   request_counter: &mut i32,
72 ) -> Result<(), LemmyError> {
73   get_or_fetch_and_upsert_community(community_id, context, request_counter).await?;
74   Ok(())
75 }
76
77 fn verify_activity(common: &ActivityCommonFields) -> Result<(), LemmyError> {
78   check_is_apub_id_valid(&common.actor, false)?;
79   verify_domains_match(common.id_unchecked(), &common.actor)?;
80   Ok(())
81 }
82
83 async fn verify_mod_action(
84   actor_id: &Url,
85   activity_cc: Url,
86   context: &LemmyContext,
87 ) -> Result<(), LemmyError> {
88   let community = blocking(context.pool(), move |conn| {
89     Community::read_from_apub_id(conn, &activity_cc.into())
90   })
91   .await??;
92
93   if community.local {
94     let actor_id: DbUrl = actor_id.clone().into();
95     let actor = blocking(context.pool(), move |conn| {
96       Person::read_from_apub_id(conn, &actor_id)
97     })
98     .await??;
99
100     // Note: this will also return true for admins in addition to mods, but as we dont know about
101     //       remote admins, it doesnt make any difference.
102     let community_id = community.id;
103     let actor_id = actor.id;
104     let is_mod_or_admin = blocking(context.pool(), move |conn| {
105       CommunityView::is_mod_or_admin(conn, actor_id, community_id)
106     })
107     .await?;
108     if !is_mod_or_admin {
109       return Err(anyhow!("Not a mod").into());
110     }
111   }
112   Ok(())
113 }
114
115 /// For Add/Remove community moderator activities, check that the target field actually contains
116 /// /c/community/moderators. Any different values are unsupported.
117 fn verify_add_remove_moderator_target(target: &Url, community: Url) -> Result<(), LemmyError> {
118   if target != &generate_moderators_url(&community.into())?.into_inner() {
119     return Err(anyhow!("Unkown target url").into());
120   }
121   Ok(())
122 }