From 4b66911886805a85bb2d863568dd19ef62a8ca77 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Thu, 28 Aug 2025 01:41:13 +0000 Subject: [PATCH] Eliminate redundant duplicate auth and matching room check. Signed-off-by: Jason Volk --- .../rooms/event_handler/fetch_state.rs | 9 +- .../rooms/event_handler/handle_outlier_pdu.rs | 89 ++++++++----------- 2 files changed, 43 insertions(+), 55 deletions(-) diff --git a/src/service/rooms/event_handler/fetch_state.rs b/src/service/rooms/event_handler/fetch_state.rs index d2cbe757..e5c13567 100644 --- a/src/service/rooms/event_handler/fetch_state.rs +++ b/src/service/rooms/event_handler/fetch_state.rs @@ -60,9 +60,12 @@ pub(super) async fn fetch_state( v.insert(pdu.event_id().to_owned()); }, | hash_map::Entry::Occupied(_) => { - return Err!(Database( - "State event's type and state_key combination exists multiple times.", - )); + return Err!(Request(InvalidParam( + "State event's type and state_key ({:?},{:?}) exists multiple times.", + pdu.event_type(), + pdu.state_key() + .expect("all state events have state_key"), + ))); }, } } diff --git a/src/service/rooms/event_handler/handle_outlier_pdu.rs b/src/service/rooms/event_handler/handle_outlier_pdu.rs index e4832298..c287dbbe 100644 --- a/src/service/rooms/event_handler/handle_outlier_pdu.rs +++ b/src/service/rooms/event_handler/handle_outlier_pdu.rs @@ -1,13 +1,14 @@ -use std::collections::{HashMap, hash_map}; - +use futures::{StreamExt, TryFutureExt}; use ruma::{ CanonicalJsonObject, CanonicalJsonValue, EventId, RoomId, RoomVersionId, ServerName, - events::{StateEventType, TimelineEventType}, + events::TimelineEventType, }; use tuwunel_core::{ Err, Result, debug, debug_info, err, implement, matrix::{Event, PduEvent, event::TypeExt, room_version}, - state_res, trace, warn, + ref_at, state_res, trace, + utils::{future::TryExtExt, stream::IterStream}, + warn, }; use super::check_room_id; @@ -89,67 +90,51 @@ pub(super) async fn handle_outlier_pdu( debug!("Checking based on auth events"); let room_rules = room_version::rules(room_version)?; - let is_create = *event.kind() == TimelineEventType::RoomCreate; - let is_hydra = room_rules - .authorization - .room_create_event_id_as_room_id; + let is_hydra = !room_rules + .event_format + .allow_room_create_in_auth_events; - let hydra_create_id = (is_hydra && !is_create).then_some(event.room_id().as_event_id()?); - let auth_event_ids = event + let not_create = *event.kind() != TimelineEventType::RoomCreate; + let hydra_create_id = (not_create && is_hydra) + .then(|| event.room_id().as_event_id().ok()) + .flatten(); + + let auth_events: Vec<_> = event .auth_events() - .map(ToOwned::to_owned) - .chain(hydra_create_id.into_iter()); + .chain(hydra_create_id.as_deref().into_iter()) + .stream() + .filter_map(|auth_event_id| { + self.event_fetch(auth_event_id) + .inspect_err(move |e| warn!("Missing auth_event {auth_event_id}: {e}")) + .ok() + }) + .map(|auth_event| { + let event_type = auth_event.event_type(); + let state_key = auth_event + .state_key() + .expect("all auth events have state_key"); - // Build map of auth events - let mut auth_events = HashMap::with_capacity(event.auth_events().count().saturating_add(1)); - for id in auth_event_ids { - let Ok(auth_event) = self.services.timeline.get_pdu(&id).await else { - warn!("Could not find auth event {id}"); - continue; - }; - - check_room_id(room_id, &auth_event)?; - match auth_events.entry(( - auth_event.kind.to_string().into(), - auth_event - .state_key - .clone() - .expect("all auth events have state keys"), - )) { - | hash_map::Entry::Vacant(v) => { - v.insert(auth_event); - }, - | hash_map::Entry::Occupied(_) => { - return Err!(Request(InvalidParam( - "Auth event's type and state_key combination exists multiple times.", - ))); - }, - } - } - - // The original create event must be in the auth events - if !matches!( - auth_events.get(&(StateEventType::RoomCreate, String::new().into())), - Some(_) | None - ) { - return Err!(Request(InvalidParam("Incoming event refers to wrong create event."))); - } + (event_type.with_state_key(state_key), auth_event) + }) + .collect() + .await; state_res::auth_check( &room_rules, &event, &async |event_id| self.event_fetch(&event_id).await, &async |event_type, state_key| { + let target = event_type.with_state_key(state_key); auth_events - .get(&event_type.with_state_key(state_key.as_str())) - .map(ToOwned::to_owned) + .iter() + .find(|(type_state_key, _)| *type_state_key == target) + .map(ref_at!(1)) + .cloned() .ok_or_else(|| err!(Request(NotFound("state not found")))) }, ) - .await - .map_err(|e| err!(Request(Forbidden("Auth check failed: {e:?}"))))?; - - trace!("Validation successful."); + .inspect_ok(|()| trace!("Validation successful.")) + .await?; // 7. Persist the event as an outlier. self.services