Skip to main content

tuwunel_api/client/membership/
invite.rs

1use axum::extract::State;
2use futures::{FutureExt, join};
3use ruma::{
4	api::client::membership::invite_user::{
5		self,
6		v3::{InvitationRecipient, InviteUserId},
7	},
8	events::room::member::MembershipState,
9};
10use tuwunel_core::{Err, Result};
11
12use super::banned_room_check;
13use crate::{ClientIp, Ruma, client::utils::invite_check};
14
15/// # `POST /_matrix/client/r0/rooms/{roomId}/invite`
16///
17/// Tries to send an invite event into the room.
18#[tracing::instrument(skip_all, fields(%client), name = "invite")]
19pub(crate) async fn invite_user_route(
20	State(services): State<crate::State>,
21	ClientIp(client): ClientIp,
22	body: Ruma<invite_user::v3::Request>,
23) -> Result<invite_user::v3::Response> {
24	let sender_user = body.sender_user();
25
26	let room_id = &body.room_id;
27
28	invite_check(&services, sender_user, room_id).await?;
29
30	banned_room_check(&services, sender_user, room_id, None, client).await?;
31
32	let InvitationRecipient::UserId(InviteUserId { user_id, reason }) = &body.recipient else {
33		return Err!(Request(ThreepidDenied("Third party identifiers are not implemented")));
34	};
35
36	let sender_ignored_recipient = services
37		.users
38		.user_is_ignored(sender_user, user_id);
39
40	let recipient_ignored_by_sender = services
41		.users
42		.user_is_ignored(user_id, sender_user);
43
44	let (sender_ignored_recipient, recipient_ignored_by_sender) =
45		join!(sender_ignored_recipient, recipient_ignored_by_sender);
46
47	if sender_ignored_recipient {
48		return Ok(invite_user::v3::Response {});
49	}
50
51	// TODO: this should be in the service, but moving it from here would
52	// trigger the recipient_ignored_by_sender check before the banned check,
53	// revealing the ignore state to the sending user if the recipient is banned
54	if let Ok(target_user_membership) = services
55		.state_accessor
56		.get_member(room_id, user_id)
57		.await && target_user_membership.membership == MembershipState::Ban
58	{
59		return Err!(Request(Forbidden("User is banned from this room.")));
60	}
61
62	if recipient_ignored_by_sender {
63		// silently drop the invite to the recipient if they've been ignored by the
64		// sender, pretend it worked
65		return Ok(invite_user::v3::Response {});
66	}
67
68	services
69		.membership
70		.invite(sender_user, user_id, room_id, reason.as_ref(), false)
71		.boxed()
72		.await?;
73
74	Ok(invite_user::v3::Response {})
75}