Compare commits

...

1 Commits

Author SHA1 Message Date
timedout a8c3a0116a fix: Allow server admins and v12 room creators to publish rooms 2026-04-09 19:25:30 +01:00
+56 -25
View File
@@ -1,7 +1,9 @@
use std::iter::once;
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::InsecureClientIp;
use conduwuit::{ use conduwuit::{
Err, Event, Result, err, info, Err, Event, Result, RoomVersion, err, info,
utils::{ utils::{
TryFutureExtExt, TryFutureExtExt,
math::Expected, math::Expected,
@@ -30,12 +32,14 @@ use ruma::{
events::{ events::{
StateEventType, StateEventType,
room::{ room::{
create::RoomCreateEventContent,
join_rules::{JoinRule, RoomJoinRulesEventContent}, join_rules::{JoinRule, RoomJoinRulesEventContent},
power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent}, power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent},
}, },
}, },
uint, uint,
}; };
use tokio::join;
use crate::Ruma; use crate::Ruma;
@@ -339,36 +343,63 @@ pub(crate) async fn get_public_rooms_filtered_helper(
}) })
} }
/// Check whether the user can publish to the room directory via power levels of /// Checks whether the given user ID is allowed to publish the target room to
/// room history visibility event or room creator /// the server's public room directory. Users are allowed to publish rooms if
/// they are server admins, room creators (in v12), or have the power level to
/// send `m.room.canonical_alias`.
async fn user_can_publish_room( async fn user_can_publish_room(
services: &Services, services: &Services,
user_id: &UserId, user_id: &UserId,
room_id: &RoomId, room_id: &RoomId,
) -> Result<bool> { ) -> Result<bool> {
match services if services.users.is_admin(user_id).await {
.rooms // Server admins can always publish to their own room directory.
.state_accessor return Ok(true);
.room_state_get(room_id, &StateEventType::RoomPowerLevels, "") }
.await let (create_event, room_version, power_levels_content) = join!(
services
.rooms
.state_accessor
.room_state_get(room_id, &StateEventType::RoomCreate, ""),
services.rooms.state.get_room_version(room_id),
services
.rooms
.state_accessor
.room_state_get_content::<RoomPowerLevelsEventContent>(
room_id,
&StateEventType::RoomPowerLevels,
""
)
);
let room_version = room_version
.as_ref()
.map_err(|_| err!(Request(NotFound("Unknown room"))))?;
let create_event = create_event.map_err(|_| err!(Request(NotFound("Unknown room"))))?;
if RoomVersion::new(room_version)
.expect("room version must be supported")
.explicitly_privilege_room_creators
{ {
| Ok(event) => serde_json::from_str(event.content().get()) let create_content: RoomCreateEventContent =
.map_err(|_| err!(Database("Invalid event content for m.room.power_levels"))) serde_json::from_str(create_event.content().get())
.map(|content: RoomPowerLevelsEventContent| { .map_err(|_| err!(Database("Invalid event content for m.room.create")))?;
RoomPowerLevels::from(content) let is_creator = create_content
.user_can_send_state(user_id, StateEventType::RoomHistoryVisibility) .additional_creators
}), .unwrap_or_default()
| _ => { .into_iter()
match services .chain(once(create_event.sender().to_owned()))
.rooms .any(|sender| sender == user_id);
.state_accessor if is_creator {
.room_state_get(room_id, &StateEventType::RoomCreate, "") return Ok(true);
.await }
{ }
| Ok(event) => Ok(event.sender() == user_id), match power_levels_content.map(RoomPowerLevels::from) {
| _ => Err!(Request(Forbidden("User is not allowed to publish this room"))), | Ok(pl) => Ok(pl.user_can_send_state(user_id, StateEventType::RoomCanonicalAlias)),
} | Err(e) =>
}, if e.is_not_found() {
Ok(create_event.sender() == user_id)
} else {
Err!(Database("Invalid event content for m.room.power_levels: {e}"))
},
} }
} }