Compare commits

...

3 commits

Author SHA1 Message Date
nexy7574
f183f99b07
Utilise the room ID to fetch the create event
Some checks failed
Documentation / Build and Deploy Documentation (push) Failing after 3s
Release Docker Image / define-variables (push) Failing after 1s
Release Docker Image / build-image (linux/amd64, linux-amd64) (push) Has been skipped
Release Docker Image / build-image (linux/arm64, linux-arm64) (push) Has been skipped
Release Docker Image / merge (push) Has been skipped
Rust Checks / Format (push) Failing after 1s
Rust Checks / Clippy (push) Failing after 23s
Rust Checks / Cargo Test (push) Failing after 8s
For #3
Also ran a cargo fmt
2025-06-13 21:06:21 +01:00
nexy7574
78f0031c34
Add new room ID check to m.room.create auth 2025-06-13 18:06:36 +01:00
nexy7574
bb69ee68d0
Add room version H11 2025-06-13 17:55:56 +01:00
5 changed files with 91 additions and 37 deletions

11
Cargo.lock generated
View file

@ -3695,7 +3695,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma" name = "ruma"
version = "0.10.1" version = "0.10.1"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=d6870a7fb7f6cccff63f7fd0ff6c581bad80e983#d6870a7fb7f6cccff63f7fd0ff6c581bad80e983"
dependencies = [ dependencies = [
"assign", "assign",
"js_int", "js_int",
@ -3715,7 +3714,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-appservice-api" name = "ruma-appservice-api"
version = "0.10.0" version = "0.10.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=d6870a7fb7f6cccff63f7fd0ff6c581bad80e983#d6870a7fb7f6cccff63f7fd0ff6c581bad80e983"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-common", "ruma-common",
@ -3727,7 +3725,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-client-api" name = "ruma-client-api"
version = "0.18.0" version = "0.18.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=d6870a7fb7f6cccff63f7fd0ff6c581bad80e983#d6870a7fb7f6cccff63f7fd0ff6c581bad80e983"
dependencies = [ dependencies = [
"as_variant", "as_variant",
"assign", "assign",
@ -3750,7 +3747,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-common" name = "ruma-common"
version = "0.13.0" version = "0.13.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=d6870a7fb7f6cccff63f7fd0ff6c581bad80e983#d6870a7fb7f6cccff63f7fd0ff6c581bad80e983"
dependencies = [ dependencies = [
"as_variant", "as_variant",
"base64 0.22.1", "base64 0.22.1",
@ -3782,7 +3778,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-events" name = "ruma-events"
version = "0.28.1" version = "0.28.1"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=d6870a7fb7f6cccff63f7fd0ff6c581bad80e983#d6870a7fb7f6cccff63f7fd0ff6c581bad80e983"
dependencies = [ dependencies = [
"as_variant", "as_variant",
"indexmap 2.9.0", "indexmap 2.9.0",
@ -3807,7 +3802,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-federation-api" name = "ruma-federation-api"
version = "0.9.0" version = "0.9.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=d6870a7fb7f6cccff63f7fd0ff6c581bad80e983#d6870a7fb7f6cccff63f7fd0ff6c581bad80e983"
dependencies = [ dependencies = [
"bytes", "bytes",
"headers", "headers",
@ -3829,7 +3823,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-identifiers-validation" name = "ruma-identifiers-validation"
version = "0.9.5" version = "0.9.5"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=d6870a7fb7f6cccff63f7fd0ff6c581bad80e983#d6870a7fb7f6cccff63f7fd0ff6c581bad80e983"
dependencies = [ dependencies = [
"js_int", "js_int",
"thiserror 2.0.12", "thiserror 2.0.12",
@ -3838,7 +3831,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-identity-service-api" name = "ruma-identity-service-api"
version = "0.9.0" version = "0.9.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=d6870a7fb7f6cccff63f7fd0ff6c581bad80e983#d6870a7fb7f6cccff63f7fd0ff6c581bad80e983"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-common", "ruma-common",
@ -3848,7 +3840,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-macros" name = "ruma-macros"
version = "0.13.0" version = "0.13.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=d6870a7fb7f6cccff63f7fd0ff6c581bad80e983#d6870a7fb7f6cccff63f7fd0ff6c581bad80e983"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"proc-macro-crate", "proc-macro-crate",
@ -3863,7 +3854,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-push-gateway-api" name = "ruma-push-gateway-api"
version = "0.9.0" version = "0.9.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=d6870a7fb7f6cccff63f7fd0ff6c581bad80e983#d6870a7fb7f6cccff63f7fd0ff6c581bad80e983"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-common", "ruma-common",
@ -3875,7 +3865,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-signatures" name = "ruma-signatures"
version = "0.15.0" version = "0.15.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=d6870a7fb7f6cccff63f7fd0ff6c581bad80e983#d6870a7fb7f6cccff63f7fd0ff6c581bad80e983"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"ed25519-dalek", "ed25519-dalek",

View file

@ -348,9 +348,9 @@ version = "0.1.2"
# Used for matrix spec type definitions and helpers # Used for matrix spec type definitions and helpers
[workspace.dependencies.ruma] [workspace.dependencies.ruma]
git = "https://forgejo.ellis.link/continuwuation/ruwuma" #git = "https://forgejo.ellis.link/continuwuation/ruwuma"
#branch = "conduwuit-changes" #rev = "b1a55ab8fa3d2e3db3240d04339835f71cfc84d4"
rev = "d6870a7fb7f6cccff63f7fd0ff6c581bad80e983" path = "../ruwuma/crates/ruma" # nex: temp
features = [ features = [
"compat", "compat",
"rand", "rand",

View file

@ -5,7 +5,7 @@ use futures::{
future::{OptionFuture, join3}, future::{OptionFuture, join3},
}; };
use ruma::{ use ruma::{
Int, OwnedUserId, RoomVersionId, UserId, EventId, Int, OwnedUserId, RoomVersionId, UserId,
events::room::{ events::room::{
create::RoomCreateEventContent, create::RoomCreateEventContent,
join_rules::{JoinRule, RoomJoinRulesEventContent}, join_rules::{JoinRule, RoomJoinRulesEventContent},
@ -56,6 +56,7 @@ pub fn auth_types_for_event(
sender: &UserId, sender: &UserId,
state_key: Option<&str>, state_key: Option<&str>,
content: &RawJsonValue, content: &RawJsonValue,
room_version: &RoomVersion,
) -> serde_json::Result<Vec<(StateEventType, StateKey)>> { ) -> serde_json::Result<Vec<(StateEventType, StateKey)>> {
if kind == &TimelineEventType::RoomCreate { if kind == &TimelineEventType::RoomCreate {
return Ok(vec![]); return Ok(vec![]);
@ -64,8 +65,11 @@ pub fn auth_types_for_event(
let mut auth_types = vec![ let mut auth_types = vec![
(StateEventType::RoomPowerLevels, StateKey::new()), (StateEventType::RoomPowerLevels, StateKey::new()),
(StateEventType::RoomMember, sender.as_str().into()), (StateEventType::RoomMember, sender.as_str().into()),
(StateEventType::RoomCreate, StateKey::new()),
]; ];
if !room_version.create_id_as_room_id {
auth_types.push((StateEventType::RoomCreate, StateKey::new()))
// m.room.create is only referenced if it isn't the room ID
}
if kind == &TimelineEventType::RoomMember { if kind == &TimelineEventType::RoomMember {
#[derive(Deserialize)] #[derive(Deserialize)]
@ -136,14 +140,16 @@ pub fn auth_types_for_event(
event_id = incoming_event.event_id().as_str(), event_id = incoming_event.event_id().as_str(),
) )
)] )]
pub async fn auth_check<F, Fut, Fetched, Incoming>( pub async fn auth_check<FS, FE, Fut, Fetched, Incoming>(
room_version: &RoomVersion, room_version: &RoomVersion,
incoming_event: &Incoming, incoming_event: &Incoming,
current_third_party_invite: Option<&Incoming>, current_third_party_invite: Option<&Incoming>,
fetch_state: F, fetch_state: FS,
fetch_event: FE,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
F: Fn(&StateEventType, &str) -> Fut + Send, FS: Fn(&StateEventType, &str) -> Fut + Send,
FE: Fn(&EventId) -> Fut + Send,
Fut: Future<Output = Option<Fetched>> + Send, Fut: Future<Output = Option<Fetched>> + Send,
Fetched: Event + Send, Fetched: Event + Send,
Incoming: Event + Send + Sync, Incoming: Event + Send + Sync,
@ -183,15 +189,19 @@ where
return Ok(false); return Ok(false);
} }
// If the domain of the room_id does not match the domain of the sender, reject if room_version.create_id_as_room_id {
let Some(room_id_server_name) = incoming_event.room_id().server_name() else { let expected =
warn!("room ID has no servername"); format!("!{}:{}", incoming_event.event_id().localpart(), sender.server_name());
return Ok(false); 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);
if room_id_server_name != sender.server_name() { }
warn!("servername of room ID does not match servername of sender"); } else {
return Ok(false); // If the domain of the room_id does not match the domain of the sender, reject
let Some(_room_id_server_name) = incoming_event.room_id().server_name() else {
warn!("room ID has no servername");
return Ok(false);
};
} }
// If content.room_version is present and is not a recognized version, reject // If content.room_version is present and is not a recognized version, reject
@ -241,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::RoomCreate, ""),
fetch_state(&StateEventType::RoomPowerLevels, ""), fetch_state(&StateEventType::RoomPowerLevels, ""),
fetch_state(&StateEventType::RoomMember, sender.as_str()), fetch_state(&StateEventType::RoomMember, sender.as_str()),
) )
.await; .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 => { | 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); return Ok(false);
}, },
| Some(e) => e, | Some(e) => e,
@ -259,7 +292,8 @@ where
// 3. If event does not have m.room.create in auth_events reject // 3. If event does not have m.room.create in auth_events reject
if !incoming_event if !incoming_event
.auth_events() .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"); warn!("no m.room.create event in auth events");
return Ok(false); return Ok(false);
@ -275,9 +309,9 @@ where
federate: bool, federate: bool,
} }
let room_create_content: RoomCreateContentFederate = 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 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!( warn!(
"room is not federated and event's sender domain does not match create event's \ "room is not federated and event's sender domain does not match create event's \
@ -362,7 +396,7 @@ where
join_rules_event.as_ref(), join_rules_event.as_ref(),
user_for_join_auth.as_deref(), user_for_join_auth.as_deref(),
&user_for_join_auth_membership, &user_for_join_auth_membership,
&room_create_event, &real_room_create_event,
)? { )? {
return Ok(false); return Ok(false);
} }
@ -411,10 +445,10 @@ where
| _ => { | _ => {
// If no power level event found the creator gets 100 everyone else gets 0 // If no power level event found the creator gets 100 everyone else gets 0
let is_creator = if room_version.use_room_create_sender { let is_creator = if room_version.use_room_create_sender {
room_create_event.sender() == sender real_room_create_event.sender() == sender
} else { } else {
#[allow(deprecated)] #[allow(deprecated)]
from_json_str::<RoomCreateEventContent>(room_create_event.content().get()) from_json_str::<RoomCreateEventContent>(real_room_create_event.content().get())
.is_ok_and(|create| create.creator.unwrap() == *sender) .is_ok_and(|create| create.creator.unwrap() == *sender)
}; };

View file

@ -29,6 +29,8 @@ pub enum StateResolutionVersion {
V1, V1,
/// State resolution for room at version 2 or later. /// State resolution for room at version 2 or later.
V2, V2,
/// State resolution for hydra rooms
V2_1,
} }
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
@ -80,9 +82,29 @@ pub struct RoomVersion {
/// ///
/// See: [MSC2175](https://github.com/matrix-org/matrix-spec-proposals/pull/2175) for more information. /// See: [MSC2175](https://github.com/matrix-org/matrix-spec-proposals/pull/2175) for more information.
pub use_room_create_sender: bool, 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.
///
/// See: [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289) for more information.
pub room_creator_is_superuser: bool,
/// Whether the room version supports estoppel events.
///
/// See: [MSC4290](https://github.com/matrix-org/matrix-spec-proposals/pull/4290)
pub estoppel_events: bool,
/// Whether the room's m.room.create event ID is itself the room ID.
///
/// See: [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291)
pub create_id_as_room_id: bool,
} }
impl 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 { pub const V1: Self = Self {
disposition: RoomDisposition::Stable, disposition: RoomDisposition::Stable,
event_format: EventFormatVersion::V1, event_format: EventFormatVersion::V1,
@ -97,6 +119,9 @@ impl RoomVersion {
knock_restricted_join_rule: false, knock_restricted_join_rule: false,
integer_power_levels: false, integer_power_levels: false,
use_room_create_sender: false, use_room_create_sender: false,
room_creator_is_superuser: false,
estoppel_events: false,
create_id_as_room_id: false,
}; };
pub const V10: Self = Self { pub const V10: Self = Self {
knock_restricted_join_rule: true, knock_restricted_join_rule: true,
@ -144,6 +169,7 @@ impl RoomVersion {
| RoomVersionId::V9 => Self::V9, | RoomVersionId::V9 => Self::V9,
| RoomVersionId::V10 => Self::V10, | RoomVersionId::V10 => Self::V10,
| RoomVersionId::V11 => Self::V11, | RoomVersionId::V11 => Self::V11,
| RoomVersionId::HydraV11 => Self::HYDRA_V11,
| ver => return Err(Error::Unsupported(format!("found version `{ver}`"))), | ver => return Err(Error::Unsupported(format!("found version `{ver}`"))),
}) })
} }

View file

@ -130,12 +130,17 @@ pub(super) async fn handle_outlier_pdu<'a>(
let key = (ty.to_owned(), sk.into()); let key = (ty.to_owned(), sk.into());
ready(auth_events.get(&key)) 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( let auth_check = state_res::event_auth::auth_check(
&to_room_version(&room_version_id), &to_room_version(&room_version_id),
&incoming_pdu, &incoming_pdu,
None, // TODO: third party invite None, // TODO: third party invite
state_fetch, state_fetch,
event_fetch,
) )
.await .await
.map_err(|e| err!(Request(Forbidden("Auth check failed: {e:?}"))))?; .map_err(|e| err!(Request(Forbidden("Auth check failed: {e:?}"))))?;