]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/block/undo_block_user.rs
Sanitize html (#3708)
[lemmy.git] / crates / apub / src / activities / block / undo_block_user.rs
1 use crate::{
2   activities::{
3     block::{generate_cc, SiteOrCommunity},
4     community::send_activity_in_community,
5     generate_activity_id,
6     send_lemmy_activity,
7     verify_is_public,
8   },
9   activity_lists::AnnouncableActivities,
10   insert_received_activity,
11   objects::{instance::remote_instance_inboxes, person::ApubPerson},
12   protocol::activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
13 };
14 use activitypub_federation::{
15   config::Data,
16   kinds::{activity::UndoType, public},
17   protocol::verification::verify_domains_match,
18   traits::{ActivityHandler, Actor},
19 };
20 use lemmy_api_common::{context::LemmyContext, utils::sanitize_html_opt};
21 use lemmy_db_schema::{
22   source::{
23     community::{CommunityPersonBan, CommunityPersonBanForm},
24     moderator::{ModBan, ModBanForm, ModBanFromCommunity, ModBanFromCommunityForm},
25     person::{Person, PersonUpdateForm},
26   },
27   traits::{Bannable, Crud},
28 };
29 use lemmy_utils::error::LemmyError;
30 use url::Url;
31
32 impl UndoBlockUser {
33   #[tracing::instrument(skip_all)]
34   pub async fn send(
35     target: &SiteOrCommunity,
36     user: &ApubPerson,
37     mod_: &ApubPerson,
38     reason: Option<String>,
39     context: &Data<LemmyContext>,
40   ) -> Result<(), LemmyError> {
41     let block = BlockUser::new(target, user, mod_, None, reason, None, context).await?;
42     let audience = if let SiteOrCommunity::Community(c) = target {
43       Some(c.id().into())
44     } else {
45       None
46     };
47
48     let id = generate_activity_id(
49       UndoType::Undo,
50       &context.settings().get_protocol_and_hostname(),
51     )?;
52     let undo = UndoBlockUser {
53       actor: mod_.id().into(),
54       to: vec![public()],
55       object: block,
56       cc: generate_cc(target, &mut context.pool()).await?,
57       kind: UndoType::Undo,
58       id: id.clone(),
59       audience,
60     };
61
62     let mut inboxes = vec![user.shared_inbox_or_inbox()];
63     match target {
64       SiteOrCommunity::Site(_) => {
65         inboxes.append(&mut remote_instance_inboxes(&mut context.pool()).await?);
66         send_lemmy_activity(context, undo, mod_, inboxes, false).await
67       }
68       SiteOrCommunity::Community(c) => {
69         let activity = AnnouncableActivities::UndoBlockUser(undo);
70         send_activity_in_community(activity, mod_, c, inboxes, true, context).await
71       }
72     }
73   }
74 }
75
76 #[async_trait::async_trait]
77 impl ActivityHandler for UndoBlockUser {
78   type DataType = LemmyContext;
79   type Error = LemmyError;
80
81   fn id(&self) -> &Url {
82     &self.id
83   }
84
85   fn actor(&self) -> &Url {
86     self.actor.inner()
87   }
88
89   #[tracing::instrument(skip_all)]
90   async fn verify(&self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
91     insert_received_activity(&self.id, context).await?;
92     verify_is_public(&self.to, &self.cc)?;
93     verify_domains_match(self.actor.inner(), self.object.actor.inner())?;
94     self.object.verify(context).await?;
95     Ok(())
96   }
97
98   #[tracing::instrument(skip_all)]
99   async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
100     let expires = self.object.expires.map(|u| u.naive_local());
101     let mod_person = self.actor.dereference(context).await?;
102     let blocked_person = self.object.object.dereference(context).await?;
103     match self.object.target.dereference(context).await? {
104       SiteOrCommunity::Site(_site) => {
105         let blocked_person = Person::update(
106           &mut context.pool(),
107           blocked_person.id,
108           &PersonUpdateForm::builder()
109             .banned(Some(false))
110             .ban_expires(Some(expires))
111             .build(),
112         )
113         .await?;
114
115         // write mod log
116         let form = ModBanForm {
117           mod_person_id: mod_person.id,
118           other_person_id: blocked_person.id,
119           reason: sanitize_html_opt(&self.object.summary),
120           banned: Some(false),
121           expires,
122         };
123         ModBan::create(&mut context.pool(), &form).await?;
124       }
125       SiteOrCommunity::Community(community) => {
126         let community_user_ban_form = CommunityPersonBanForm {
127           community_id: community.id,
128           person_id: blocked_person.id,
129           expires: None,
130         };
131         CommunityPersonBan::unban(&mut context.pool(), &community_user_ban_form).await?;
132
133         // write to mod log
134         let form = ModBanFromCommunityForm {
135           mod_person_id: mod_person.id,
136           other_person_id: blocked_person.id,
137           community_id: community.id,
138           reason: sanitize_html_opt(&self.object.summary),
139           banned: Some(false),
140           expires,
141         };
142         ModBanFromCommunity::create(&mut context.pool(), &form).await?;
143       }
144     }
145
146     Ok(())
147   }
148 }