feat: Allow local server admins to bypass summary visibility checks

feat: Allow local server admins to bypass summary visibility checks

Also improve error messages so they aren't so damn long.
This commit is contained in:
timedout
2025-12-31 20:01:29 +00:00
committed by Jade Ellis
parent 8a561fcd3a
commit a7e6e6e83f
+52 -46
View File
@@ -1,12 +1,13 @@
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::InsecureClientIp;
use conduwuit::{ use conduwuit::{
Err, Result, debug_warn, trace, Err, Result, debug, debug_warn, info, trace,
utils::{IterStream, future::TryExtExt}, utils::{IterStream, future::TryExtExt},
warn,
}; };
use futures::{ use futures::{
FutureExt, StreamExt, FutureExt, StreamExt, TryFutureExt,
future::{OptionFuture, join3}, future::{OptionFuture, join, join3},
stream::FuturesUnordered, stream::FuturesUnordered,
}; };
use ruma::{ use ruma::{
@@ -111,26 +112,26 @@ async fn local_room_summary_response(
sender_user: Option<&UserId>, sender_user: Option<&UserId>,
) -> Result<get_summary::msc3266::Response> { ) -> Result<get_summary::msc3266::Response> {
trace!(?sender_user, "Sending local room summary response for {room_id:?}"); trace!(?sender_user, "Sending local room summary response for {room_id:?}");
let join_rule = services.rooms.state_accessor.get_join_rules(room_id); let join_rule = services.rooms.state_accessor.get_join_rules(room_id).await;
// Synapse allows server admins to bypass visibility checks.
// That seems neat so we'll copy that behaviour.
if sender_user.is_none() || !services.users.is_admin(sender_user.unwrap()).await {
let world_readable = services.rooms.state_accessor.is_world_readable(room_id);
let guest_can_join = services.rooms.state_accessor.guest_can_join(room_id);
let (world_readable, guest_can_join) = join(world_readable, guest_can_join).await;
let world_readable = services.rooms.state_accessor.is_world_readable(room_id); trace!("{join_rule:?}, {world_readable:?}, {guest_can_join:?}");
user_can_see_summary(
let guest_can_join = services.rooms.state_accessor.guest_can_join(room_id); services,
room_id,
let (join_rule, world_readable, guest_can_join) = &join_rule.clone().into(),
join3(join_rule, world_readable, guest_can_join).await; guest_can_join,
world_readable,
trace!("{join_rule:?}, {world_readable:?}, {guest_can_join:?}"); join_rule.allowed_rooms(),
user_can_see_summary( sender_user,
services, )
room_id, .await?;
&join_rule.clone().into(), }
guest_can_join,
world_readable,
join_rule.allowed_rooms(),
sender_user,
)
.await?;
let canonical_alias = services let canonical_alias = services
.rooms .rooms
@@ -231,15 +232,27 @@ async fn remote_room_summary_hierarchy_response(
"Federaton of room {room_id} is currently disabled on this server." "Federaton of room {room_id} is currently disabled on this server."
))); )));
} }
if servers.is_empty() {
return Err!(Request(MissingParam(
"No servers were provided to fetch the room over federation"
)));
}
let request = get_hierarchy::v1::Request::new(room_id.to_owned()); let request = get_hierarchy::v1::Request::new(room_id.to_owned());
let mut requests: FuturesUnordered<_> = servers let mut requests: FuturesUnordered<_> = servers
.iter() .iter()
.map(|server| { .map(|server| {
info!("Fetching room summary for {room_id} from server {server}");
services services
.sending .sending
.send_federation_request(server, request.clone()) .send_federation_request(server, request.clone())
.inspect_ok(|v| {
debug!("Fetched room summary for {room_id} from server {server}: {v:?}");
})
.inspect_err(|e| {
info!("Failed to fetch room summary for {room_id} from server {server}: {e}");
})
}) })
.collect(); .collect();
@@ -255,23 +268,23 @@ async fn remote_room_summary_hierarchy_response(
continue; continue;
} }
return user_can_see_summary( if sender_user.is_none() || !services.users.is_admin(sender_user.unwrap()).await {
services, return user_can_see_summary(
room_id, services,
&room.join_rule, room_id,
room.guest_can_join, &room.join_rule,
room.world_readable, room.guest_can_join,
room.allowed_room_ids.iter().map(AsRef::as_ref), room.world_readable,
sender_user, room.allowed_room_ids.iter().map(AsRef::as_ref),
) sender_user,
.await )
.map(|()| room); .await
.map(|()| room);
}
return Ok(room);
} }
Err!(Request(NotFound( Err!(Request(NotFound("Room not found or is not accessible")))
"Room is unknown to this server and was unable to fetch over federation with the \
provided servers available"
)))
} }
async fn user_can_see_summary<'a, I>( async fn user_can_see_summary<'a, I>(
@@ -311,21 +324,14 @@ where
return Ok(()); return Ok(());
} }
Err!(Request(Forbidden( Err!(Request(Forbidden("Room is not accessible")))
"Room is not world readable, not publicly accessible/joinable, restricted room \
conditions not met, and guest access is forbidden. Not allowed to see details \
of this room."
)))
}, },
| None => { | None => {
if is_public_room || world_readable { if is_public_room || world_readable {
return Ok(()); return Ok(());
} }
Err!(Request(Forbidden( Err!(Request(Forbidden("Room is not accessible")))
"Room is not world readable or publicly accessible/joinable, authentication is \
required"
)))
}, },
} }
} }