diff --git a/src/core/matrix/state_res/event_auth.rs b/src/core/matrix/state_res/event_auth.rs index 6c16182f..414c1b87 100644 --- a/src/core/matrix/state_res/event_auth.rs +++ b/src/core/matrix/state_res/event_auth.rs @@ -5,7 +5,7 @@ use futures::{ future::{OptionFuture, join3}, }; use ruma::{ - Int, OwnedUserId, RoomVersionId, UserId, + EventId, Int, OwnedUserId, RoomVersionId, UserId, events::room::{ create::RoomCreateEventContent, join_rules::{JoinRule, RoomJoinRulesEventContent}, @@ -140,14 +140,16 @@ pub fn auth_types_for_event( event_id = incoming_event.event_id().as_str(), ) )] -pub async fn auth_check( +pub async fn auth_check( room_version: &RoomVersion, incoming_event: &Incoming, current_third_party_invite: Option<&Incoming>, - fetch_state: F, + fetch_state: FS, + fetch_event: FE, ) -> Result where - F: Fn(&StateEventType, &str) -> Fut + Send, + FS: Fn(&StateEventType, &str) -> Fut + Send, + FE: Fn(&EventId) -> Fut + Send, Fut: Future> + Send, Fetched: Event + Send, Incoming: Event + Send + Sync, @@ -188,7 +190,8 @@ where } if room_version.create_id_as_room_id { - let expected = format!("!{}:{}", incoming_event.event_id().localpart(), sender.server_name()); + let expected = + format!("!{}:{}", incoming_event.event_id().localpart(), sender.server_name()); if incoming_event.room_id().as_str() != expected { warn!("room create included a room ID that does not match the event ID"); return Ok(false); @@ -200,7 +203,6 @@ where return Ok(false); }; } - // If content.room_version is present and is not a recognized version, reject let content: RoomCreateContentFields = from_json_str(incoming_event.content().get())?; @@ -249,16 +251,39 @@ where } */ - let (room_create_event, power_levels_event, sender_member_event) = join3( + let (mut room_create_event, power_levels_event, sender_member_event) = join3( fetch_state(&StateEventType::RoomCreate, ""), fetch_state(&StateEventType::RoomPowerLevels, ""), fetch_state(&StateEventType::RoomMember, sender.as_str()), ) .await; - let room_create_event = match room_create_event { + if room_version.create_id_as_room_id { + // TODO: fetch the create event from the room ID + let create_event_id = &EventId::parse(incoming_event.room_id().localpart()); + // if let Err(e) = create_event_id { + // error!(?e, "invalid room ID for create event"); + // return Ok(false); + // } + // room_create_event = fetch_event(create_event_id).await; + match create_event_id { + | Ok(id) => { + room_create_event = fetch_event(id).await; + if room_create_event.is_none() { + warn!("could not find m.room.create event for PDU"); + return Ok(false); + } + room_create_event = room_create_event; + }, + | Err(e) => { + error!(?e, "invalid room ID for create event"); + return Ok(false); + }, + } + } + let real_room_create_event = match room_create_event { | None => { - warn!("no m.room.create event in auth chain"); + warn!("could not find an applicable m.room.create event for PDU"); return Ok(false); }, | Some(e) => e, @@ -267,7 +292,8 @@ where // 3. If event does not have m.room.create in auth_events reject if !incoming_event .auth_events() - .any(|id| id == room_create_event.event_id()) + .any(|id| id == real_room_create_event.event_id()) + && !room_version.create_id_as_room_id { warn!("no m.room.create event in auth events"); return Ok(false); @@ -283,9 +309,9 @@ where federate: bool, } let room_create_content: RoomCreateContentFederate = - from_json_str(room_create_event.content().get())?; + from_json_str(real_room_create_event.content().get())?; if !room_create_content.federate - && room_create_event.sender().server_name() != incoming_event.sender().server_name() + && real_room_create_event.sender().server_name() != incoming_event.sender().server_name() { warn!( "room is not federated and event's sender domain does not match create event's \ @@ -370,7 +396,7 @@ where join_rules_event.as_ref(), user_for_join_auth.as_deref(), &user_for_join_auth_membership, - &room_create_event, + &real_room_create_event, )? { return Ok(false); } @@ -419,10 +445,10 @@ where | _ => { // If no power level event found the creator gets 100 everyone else gets 0 let is_creator = if room_version.use_room_create_sender { - room_create_event.sender() == sender + real_room_create_event.sender() == sender } else { #[allow(deprecated)] - from_json_str::(room_create_event.content().get()) + from_json_str::(real_room_create_event.content().get()) .is_ok_and(|create| create.creator.unwrap() == *sender) }; diff --git a/src/core/matrix/state_res/room_version.rs b/src/core/matrix/state_res/room_version.rs index fead8576..33da9368 100644 --- a/src/core/matrix/state_res/room_version.rs +++ b/src/core/matrix/state_res/room_version.rs @@ -83,7 +83,8 @@ pub struct RoomVersion { /// See: [MSC2175](https://github.com/matrix-org/matrix-spec-proposals/pull/2175) for more information. pub use_room_create_sender: bool, /// Whether the room creator is a superuser. - /// A superuser will always have infinite power level and gains special privileges. + /// A superuser will always have infinite power level and gains special + /// privileges. /// /// See: [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289) for more information. pub room_creator_is_superuser: bool, @@ -98,6 +99,12 @@ pub struct RoomVersion { } impl RoomVersion { + pub const HYDRA_V11: Self = Self { + room_creator_is_superuser: true, + estoppel_events: true, + create_id_as_room_id: true, + ..Self::V11 + }; pub const V1: Self = Self { disposition: RoomDisposition::Stable, event_format: EventFormatVersion::V1, @@ -116,6 +123,15 @@ impl RoomVersion { estoppel_events: false, create_id_as_room_id: false, }; + pub const V10: Self = Self { + knock_restricted_join_rule: true, + integer_power_levels: true, + ..Self::V9 + }; + pub const V11: Self = Self { + use_room_create_sender: true, + ..Self::V10 + }; pub const V2: Self = Self { state_res: StateResolutionVersion::V2, ..Self::V1 @@ -139,21 +155,6 @@ impl RoomVersion { pub const V7: Self = Self { allow_knocking: true, ..Self::V6 }; pub const V8: Self = Self { restricted_join_rules: true, ..Self::V7 }; pub const V9: Self = Self::V8; - pub const V10: Self = Self { - knock_restricted_join_rule: true, - integer_power_levels: true, - ..Self::V9 - }; - pub const V11: Self = Self { - use_room_create_sender: true, - ..Self::V10 - }; - pub const HYDRA_V11: Self = Self{ - room_creator_is_superuser: true, - estoppel_events: true, - create_id_as_room_id: true, - ..Self::V11 - }; pub fn new(version: &RoomVersionId) -> Result { Ok(match version { diff --git a/src/service/rooms/event_handler/handle_outlier_pdu.rs b/src/service/rooms/event_handler/handle_outlier_pdu.rs index 5339249d..76aa9054 100644 --- a/src/service/rooms/event_handler/handle_outlier_pdu.rs +++ b/src/service/rooms/event_handler/handle_outlier_pdu.rs @@ -130,12 +130,17 @@ pub(super) async fn handle_outlier_pdu<'a>( let key = (ty.to_owned(), sk.into()); ready(auth_events.get(&key)) }; + let event_fetch = |id: &EventId| { + let id = id.to_owned(); + Box::pin(self.services.timeline.get_pdu(&id)) + }; let auth_check = state_res::event_auth::auth_check( &to_room_version(&room_version_id), &incoming_pdu, None, // TODO: third party invite state_fetch, + event_fetch, ) .await .map_err(|e| err!(Request(Forbidden("Auth check failed: {e:?}"))))?;