fix(membership): always set reason & allow new events if reason changed

This commit is contained in:
Matthias Ahouansou 2024-05-05 15:28:18 +01:00
parent 08485ea5e4
commit d8badaf64b
No known key found for this signature in database

View file

@ -186,15 +186,7 @@ pub async fn kick_user_route(
) -> Result<kick_user::v3::Response> { ) -> Result<kick_user::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated"); let sender_user = body.sender_user.as_ref().expect("user is authenticated");
if let Ok(true) = services() let event: RoomMemberEventContent = serde_json::from_str(
.rooms
.state_cache
.is_left(sender_user, &body.room_id)
{
return Ok(kick_user::v3::Response {});
}
let mut event: RoomMemberEventContent = serde_json::from_str(
services() services()
.rooms .rooms
.state_accessor .state_accessor
@ -205,15 +197,26 @@ pub async fn kick_user_route(
)? )?
.ok_or(Error::BadRequest( .ok_or(Error::BadRequest(
ErrorKind::BadState, ErrorKind::BadState,
"Cannot kick member that's not in the room.", "Cannot kick a user who is not in the room.",
))? ))?
.content .content
.get(), .get(),
) )
.map_err(|_| Error::bad_database("Invalid member event in database."))?; .map_err(|_| Error::bad_database("Invalid member event in database."))?;
event.membership = MembershipState::Leave; // If they are already kicked and the reason is unchanged, there isn't any point in sending a new event.
event.reason.clone_from(&body.reason); if event.membership == MembershipState::Leave && event.reason == body.reason {
return Ok(kick_user::v3::Response {});
}
let event = RoomMemberEventContent {
is_direct: None,
membership: MembershipState::Leave,
third_party_invite: None,
reason: body.reason.clone(),
join_authorized_via_users_server: None,
..event
};
let mutex_state = Arc::clone( let mutex_state = Arc::clone(
services() services()
@ -254,17 +257,7 @@ pub async fn kick_user_route(
pub async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<ban_user::v3::Response> { pub async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<ban_user::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated"); let sender_user = body.sender_user.as_ref().expect("user is authenticated");
if let Ok(Some(membership_event)) = services() let event = if let Some(event) = services()
.rooms
.state_accessor
.get_member(&body.room_id, sender_user)
{
if membership_event.membership == MembershipState::Ban {
return Ok(ban_user::v3::Response {});
}
}
let event = services()
.rooms .rooms
.state_accessor .state_accessor
.room_state_get( .room_state_get(
@ -272,27 +265,30 @@ pub async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<ban_use
&StateEventType::RoomMember, &StateEventType::RoomMember,
body.user_id.as_ref(), body.user_id.as_ref(),
)? )?
.map_or( // Even when the previous member content is invalid, we should let the ban go through anyways.
Ok(RoomMemberEventContent { .and_then(|event| serde_json::from_str::<RoomMemberEventContent>(event.content.get()).ok())
membership: MembershipState::Ban, {
displayname: services().users.displayname(&body.user_id)?, // If they are already banned and the reason is unchanged, there isn't any point in sending a new event.
avatar_url: services().users.avatar_url(&body.user_id)?, if event.membership == MembershipState::Ban && event.reason == body.reason {
is_direct: None, return Ok(ban_user::v3::Response {});
third_party_invite: None, }
blurhash: services().users.blurhash(&body.user_id)?,
reason: body.reason.clone(), RoomMemberEventContent {
join_authorized_via_users_server: None, membership: MembershipState::Ban,
}), join_authorized_via_users_server: None,
|event| { reason: body.reason.clone(),
serde_json::from_str(event.content.get()) third_party_invite: None,
.map(|event: RoomMemberEventContent| RoomMemberEventContent { is_direct: None,
membership: MembershipState::Ban, avatar_url: event.avatar_url,
join_authorized_via_users_server: None, displayname: event.displayname,
..event blurhash: event.blurhash,
}) }
.map_err(|_| Error::bad_database("Invalid member event in database.")) } else {
}, RoomMemberEventContent {
)?; reason: body.reason.clone(),
..RoomMemberEventContent::new(MembershipState::Ban)
}
};
let mutex_state = Arc::clone( let mutex_state = Arc::clone(
services() services()
@ -335,17 +331,7 @@ pub async fn unban_user_route(
) -> Result<unban_user::v3::Response> { ) -> Result<unban_user::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated"); let sender_user = body.sender_user.as_ref().expect("user is authenticated");
if let Ok(Some(membership_event)) = services() let event: RoomMemberEventContent = serde_json::from_str(
.rooms
.state_accessor
.get_member(&body.room_id, sender_user)
{
if membership_event.membership != MembershipState::Ban {
return Ok(unban_user::v3::Response {});
}
}
let mut event: RoomMemberEventContent = serde_json::from_str(
services() services()
.rooms .rooms
.state_accessor .state_accessor
@ -363,8 +349,19 @@ pub async fn unban_user_route(
) )
.map_err(|_| Error::bad_database("Invalid member event in database."))?; .map_err(|_| Error::bad_database("Invalid member event in database."))?;
event.membership = MembershipState::Leave; // If they are already unbanned and the reason is unchanged, there isn't any point in sending a new event.
event.reason.clone_from(&body.reason); if event.membership == MembershipState::Leave && event.reason == body.reason {
return Ok(unban_user::v3::Response {});
}
let event = RoomMemberEventContent {
is_direct: None,
membership: MembershipState::Leave,
third_party_invite: None,
reason: body.reason.clone(),
join_authorized_via_users_server: None,
..event
};
let mutex_state = Arc::clone( let mutex_state = Arc::clone(
services() services()
@ -1319,60 +1316,59 @@ pub(crate) async fn invite_helper<'a>(
.filter(|server| &**server != services().globals.server_name()); .filter(|server| &**server != services().globals.server_name());
services().sending.send_pdu(servers, &pdu_id)?; services().sending.send_pdu(servers, &pdu_id)?;
} else {
if !services()
.rooms
.state_cache
.is_joined(sender_user, room_id)?
{
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
));
}
return Ok(()); let mutex_state = Arc::clone(
} services()
.globals
.roomid_mutex_state
.write()
.await
.entry(room_id.to_owned())
.or_default(),
);
let state_lock = mutex_state.lock().await;
if !services()
.rooms
.state_cache
.is_joined(sender_user, room_id)?
{
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
));
}
let mutex_state = Arc::clone(
services() services()
.globals .rooms
.roomid_mutex_state .timeline
.write() .build_and_append_pdu(
.await PduBuilder {
.entry(room_id.to_owned()) event_type: TimelineEventType::RoomMember,
.or_default(), content: to_raw_value(&RoomMemberEventContent {
); membership: MembershipState::Invite,
let state_lock = mutex_state.lock().await; displayname: services().users.displayname(user_id)?,
avatar_url: services().users.avatar_url(user_id)?,
is_direct: Some(is_direct),
third_party_invite: None,
blurhash: services().users.blurhash(user_id)?,
reason,
join_authorized_via_users_server: None,
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(user_id.to_string()),
redacts: None,
},
sender_user,
room_id,
&state_lock,
)
.await?;
services() // Critical point ends
.rooms drop(state_lock);
.timeline }
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomMember,
content: to_raw_value(&RoomMemberEventContent {
membership: MembershipState::Invite,
displayname: services().users.displayname(user_id)?,
avatar_url: services().users.avatar_url(user_id)?,
is_direct: Some(is_direct),
third_party_invite: None,
blurhash: services().users.blurhash(user_id)?,
reason,
join_authorized_via_users_server: None,
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(user_id.to_string()),
redacts: None,
},
sender_user,
room_id,
&state_lock,
)
.await?;
drop(state_lock);
Ok(()) Ok(())
} }
@ -1470,12 +1466,15 @@ pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<Strin
Some(e) => e, Some(e) => e,
}; };
let mut event: RoomMemberEventContent = serde_json::from_str(member_event.content.get()) let event = RoomMemberEventContent {
.map_err(|_| Error::bad_database("Invalid member event in database."))?; is_direct: None,
membership: MembershipState::Leave,
event.membership = MembershipState::Leave; third_party_invite: None,
event.reason = reason; reason,
event.join_authorized_via_users_server = None; join_authorized_via_users_server: None,
..serde_json::from_str(member_event.content.get())
.map_err(|_| Error::bad_database("Invalid member event in database."))?
};
services() services()
.rooms .rooms