Merge branch 'authorized-user-search' into 'next'

fix(membership): perform stricter checks when choosing an authorized user

See merge request famedly/conduit!620
This commit is contained in:
Timo Kösters 2024-04-24 21:00:52 +00:00
commit a140bf8a6f

View file

@ -15,7 +15,6 @@ use ruma::{
room::{ room::{
join_rules::{AllowRule, JoinRule, RoomJoinRulesEventContent}, join_rules::{AllowRule, JoinRule, RoomJoinRulesEventContent},
member::{MembershipState, RoomMemberEventContent}, member::{MembershipState, RoomMemberEventContent},
power_levels::RoomPowerLevelsEventContent,
}, },
StateEventType, TimelineEventType, StateEventType, TimelineEventType,
}, },
@ -858,11 +857,6 @@ async fn join_room_by_id_helper(
&StateEventType::RoomJoinRules, &StateEventType::RoomJoinRules,
"", "",
)?; )?;
let power_levels_event = services().rooms.state_accessor.room_state_get(
room_id,
&StateEventType::RoomPowerLevels,
"",
)?;
let join_rules_event_content: Option<RoomJoinRulesEventContent> = join_rules_event let join_rules_event_content: Option<RoomJoinRulesEventContent> = join_rules_event
.as_ref() .as_ref()
@ -873,15 +867,6 @@ async fn join_room_by_id_helper(
}) })
}) })
.transpose()?; .transpose()?;
let power_levels_event_content: Option<RoomPowerLevelsEventContent> = power_levels_event
.as_ref()
.map(|power_levels_event| {
serde_json::from_str(power_levels_event.content.get()).map_err(|e| {
warn!("Invalid power levels event: {}", e);
Error::bad_database("Invalid power levels event in db.")
})
})
.transpose()?;
let restriction_rooms = match join_rules_event_content { let restriction_rooms = match join_rules_event_content {
Some(RoomJoinRulesEventContent { Some(RoomJoinRulesEventContent {
@ -900,47 +885,37 @@ async fn join_room_by_id_helper(
_ => Vec::new(), _ => Vec::new(),
}; };
let authorized_user = restriction_rooms let authorized_user = if restriction_rooms.iter().any(|restriction_room_id| {
.iter() services()
.find_map(|restriction_room_id| { .rooms
if !services() .state_cache
.rooms .is_joined(sender_user, restriction_room_id)
.state_cache .unwrap_or(false)
.is_joined(sender_user, restriction_room_id) }) {
.ok()? let mut auth_user = None;
for user in services()
.rooms
.state_cache
.room_members(room_id)
.filter_map(Result::ok)
.collect::<Vec<_>>()
{
if user.server_name() == services().globals.server_name()
&& services()
.rooms
.state_accessor
.user_can_invite(room_id, &user, sender_user, &state_lock)
.await
.unwrap_or(false)
{ {
return None; auth_user = Some(user);
break;
} }
let authorized_user = power_levels_event_content }
.as_ref() auth_user
.and_then(|c| { } else {
c.users None
.iter() };
.filter(|(uid, i)| {
uid.server_name() == services().globals.server_name()
&& **i > ruma::int!(0)
&& services()
.rooms
.state_cache
.is_joined(uid, restriction_room_id)
.unwrap_or(false)
})
.max_by_key(|(_, i)| *i)
.map(|(u, _)| u.to_owned())
})
.or_else(|| {
// TODO: Check here if user is actually allowed to invite. Currently the auth
// check will just fail in this case.
services()
.rooms
.state_cache
.room_members(restriction_room_id)
.filter_map(|r| r.ok())
.find(|uid| uid.server_name() == services().globals.server_name())
});
Some(authorized_user)
})
.flatten();
let event = RoomMemberEventContent { let event = RoomMemberEventContent {
membership: MembershipState::Join, membership: MembershipState::Join,
@ -978,9 +953,7 @@ async fn join_room_by_id_helper(
if !restriction_rooms.is_empty() if !restriction_rooms.is_empty()
&& servers && servers
.iter() .iter()
.filter(|s| *s != services().globals.server_name()) .any(|s| *s != services().globals.server_name())
.count()
> 0
{ {
info!( info!(
"We couldn't do the join locally, maybe federation can help to satisfy the restricted join requirements" "We couldn't do the join locally, maybe federation can help to satisfy the restricted join requirements"