From 5299679c2193f17b756776082c5149f68d180cec Mon Sep 17 00:00:00 2001 From: Devin Ragotzy Date: Tue, 22 Dec 2020 14:28:48 -0500 Subject: [PATCH] Use ruma::ServerPdu instead of local type --- Cargo.toml | 6 +- src/event_auth.rs | 224 +++++++++++++++++++++++---------------------- src/lib.rs | 150 ++++++++++++++++++------------ src/state_store.rs | 13 ++- 4 files changed, 218 insertions(+), 175 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dbba7297..138d6150 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,10 +20,10 @@ maplit = "1.0.2" thiserror = "1.0.22" [dependencies.ruma] -git = "https://github.com/ruma/ruma" -# branch = "verified-export" +git = "https://github.com/DevinR528/ruma" +branch = "server-pdu" # path = "../__forks__/ruma/ruma" -rev = "45d01011554f9d07739e9a5edf5498d8ac16f273" +# rev = "45d01011554f9d07739e9a5edf5498d8ac16f273" features = ["client-api", "federation-api", "appservice-api", "unstable-pre-spec", "unstable-synapse-quirks"] #[dependencies.ruma] diff --git a/src/event_auth.rs b/src/event_auth.rs index ee57965f..bb168c93 100644 --- a/src/event_auth.rs +++ b/src/event_auth.rs @@ -3,6 +3,7 @@ use std::{collections::BTreeMap, convert::TryFrom, sync::Arc}; use maplit::btreeset; use ruma::{ events::{ + pdu::ServerPdu, room::{ self, join_rules::JoinRule, @@ -14,49 +15,44 @@ use ruma::{ identifiers::{RoomVersionId, UserId}, }; -use crate::{ - state_event::{Requester, StateEvent}, - Error, Result, StateMap, -}; +use crate::{state_event::Requester, to_requester, Error, Result, StateMap}; /// For the given event `kind` what are the relevant auth events /// that are needed to authenticate this `content`. pub fn auth_types_for_event( - kind: EventType, + kind: &EventType, sender: &UserId, state_key: Option, content: serde_json::Value, -) -> Vec<(EventType, String)> { +) -> Vec<(EventType, Option)> { if kind == EventType::RoomCreate { return vec![]; } let mut auth_types = vec![ - (EventType::RoomPowerLevels, "".to_string()), - (EventType::RoomMember, sender.to_string()), - (EventType::RoomCreate, "".to_string()), + (EventType::RoomPowerLevels, Some("".to_string())), + (EventType::RoomMember, Some(sender.to_string())), + (EventType::RoomCreate, Some("".to_string())), ]; if kind == EventType::RoomMember { if let Ok(content) = serde_json::from_value::(content) { if [MembershipState::Join, MembershipState::Invite].contains(&content.membership) { - let key = (EventType::RoomJoinRules, "".into()); + let key = (EventType::RoomJoinRules, Some("".into())); if !auth_types.contains(&key) { auth_types.push(key) } } // TODO what when we don't find a state_key - if let Some(state_key) = state_key { - let key = (EventType::RoomMember, state_key); - if !auth_types.contains(&key) { - auth_types.push(key) - } + let key = (EventType::RoomMember, state_key); + if !auth_types.contains(&key) { + auth_types.push(key) } if content.membership == MembershipState::Invite { if let Some(t_id) = content.third_party_invite { - let key = (EventType::RoomThirdPartyInvite, t_id.signed.token); + let key = (EventType::RoomThirdPartyInvite, Some(t_id.signed.token)); if !auth_types.contains(&key) { auth_types.push(key) } @@ -74,12 +70,12 @@ pub fn auth_types_for_event( /// * then there are checks for specific event types pub fn auth_check( room_version: &RoomVersionId, - incoming_event: &Arc, - prev_event: Option>, - auth_events: StateMap>, - current_third_party_invite: Option>, + incoming_event: &Arc, + prev_event: Option>, + auth_events: StateMap>, + current_third_party_invite: Option>, ) -> Result { - tracing::info!("auth_check beginning for {}", incoming_event.kind()); + tracing::info!("auth_check beginning for {}", incoming_event.kind); // [synapse] check that all the events are in the same room as `incoming_event` @@ -92,17 +88,17 @@ pub fn auth_check( // Implementation of https://matrix.org/docs/spec/rooms/v1#authorization-rules // // 1. If type is m.room.create: - if incoming_event.kind() == EventType::RoomCreate { + if incoming_event.kind == EventType::RoomCreate { tracing::info!("start m.room.create check"); // If it has any previous events, reject - if !incoming_event.prev_event_ids().is_empty() { + if !incoming_event.prev_events.is_empty() { tracing::warn!("the room creation event had previous events"); return Ok(false); } // If the domain of the room_id does not match the domain of the sender, reject - if incoming_event.room_id().server_name() != incoming_event.sender().server_name() { + if incoming_event.room_id.server_name() != incoming_event.sender.server_name() { tracing::warn!("creation events server does not match sender"); return Ok(false); // creation events room id does not match senders } @@ -110,7 +106,7 @@ pub fn auth_check( // If content.room_version is present and is not a recognized version, reject if serde_json::from_value::( incoming_event - .content() + .content .get("room_version") .cloned() // TODO synapse defaults to version 1 @@ -123,7 +119,7 @@ pub fn auth_check( } // If content has no creator field, reject - if incoming_event.content().get("creator").is_none() { + if incoming_event.content.get("creator").is_none() { tracing::warn!("no creator field found in room create content"); return Ok(false); } @@ -137,9 +133,9 @@ pub fn auth_check( // a. auth_events cannot have duplicate keys since it's a BTree // b. All entries are valid auth events according to spec let expected_auth = auth_types_for_event( - incoming_event.kind(), + incoming_event.kind, incoming_event.sender(), - incoming_event.state_key(), + incoming_event.state_key, incoming_event.content().clone(), ); @@ -156,7 +152,7 @@ pub fn auth_check( // 3. If event does not have m.room.create in auth_events reject if auth_events - .get(&(EventType::RoomCreate, "".into())) + .get(&(EventType::RoomCreate, Some("".into()))) .is_none() { tracing::warn!("no m.room.create event in auth chain"); @@ -167,18 +163,18 @@ pub fn auth_check( // [synapse] checks for federation here // 4. if type is m.room.aliases - if incoming_event.kind() == EventType::RoomAliases { + if incoming_event.kind == EventType::RoomAliases { tracing::info!("starting m.room.aliases check"); // [synapse] adds `&& room_version` "special case aliases auth" // [synapse] - // if event.state_key().unwrap().is_empty() { + // if event.state_key.unwrap().is_empty() { // tracing::warn!("state_key must be non-empty"); // return Ok(false); // and be non-empty state_key (point to a user_id) // } // If sender's domain doesn't matches state_key, reject - if incoming_event.state_key() != incoming_event.sender().server_name().as_str() { + if incoming_event.state_key != Some(incoming_event.sender.server_name().to_string()) { tracing::warn!("state_key does not match sender"); return Ok(false); } @@ -187,19 +183,20 @@ pub fn auth_check( return Ok(true); } - if incoming_event.kind() == EventType::RoomMember { + if incoming_event.kind == EventType::RoomMember { tracing::info!("starting m.room.member check"); - if incoming_event - .deserialize_content::() - .is_err() + if serde_json::from_value::( + incoming_event.content.clone(), + ) + .is_err() { tracing::warn!("no membership filed found for m.room.member event content"); return Ok(false); } if !valid_membership_change( - incoming_event.to_requester(), + to_requester(incoming_event), prev_event, current_third_party_invite, &auth_events, @@ -212,7 +209,7 @@ pub fn auth_check( } // If the sender's current membership state is not join, reject - match check_event_sender_in_room(incoming_event.sender(), &auth_events) { + match check_event_sender_in_room(&incoming_event.sender, &auth_events) { Some(true) => {} // sender in room Some(false) => { tracing::warn!("sender's membership is not join"); @@ -226,8 +223,8 @@ pub fn auth_check( // Allow if and only if sender's current power level is greater than // or equal to the invite level - if incoming_event.kind() == EventType::RoomThirdPartyInvite - && !can_send_invite(&incoming_event.to_requester(), &auth_events)? + if incoming_event.kind == EventType::RoomThirdPartyInvite + && !can_send_invite(&to_requester(incoming_event), &auth_events)? { tracing::warn!("sender's cannot send invites in this room"); return Ok(false); @@ -240,7 +237,7 @@ pub fn auth_check( return Ok(false); } - if incoming_event.kind() == EventType::RoomPowerLevels { + if incoming_event.kind == EventType::RoomPowerLevels { tracing::info!("starting m.room.power_levels check"); if let Some(required_pwr_lvl) = @@ -257,7 +254,7 @@ pub fn auth_check( tracing::info!("power levels event allowed"); } - if incoming_event.kind() == EventType::RoomRedaction + if incoming_event.kind == EventType::RoomRedaction && !check_redaction(room_version, incoming_event, &auth_events)? { return Ok(false); @@ -278,9 +275,9 @@ pub fn auth_check( /// the current State. pub fn valid_membership_change( user: Requester<'_>, - prev_event: Option>, - current_third_party_invite: Option>, - auth_events: &StateMap>, + prev_event: Option>, + current_third_party_invite: Option>, + auth_events: &StateMap>, ) -> Result { let state_key = if let Some(s) = user.state_key.as_ref() { s @@ -296,25 +293,27 @@ pub fn valid_membership_change( let target_user_id = UserId::try_from(state_key.as_str()) .map_err(|e| Error::ConversionError(format!("{}", e)))?; - let key = (EventType::RoomMember, user.sender.to_string()); + let key = (EventType::RoomMember, Some(user.sender.to_string())); let sender = auth_events.get(&key); let sender_membership = sender.map_or(Ok::<_, Error>(member::MembershipState::Leave), |pdu| { - Ok(pdu - .deserialize_content::()? - .membership) + Ok( + serde_json::from_value::(pdu.content.clone())? + .membership, + ) })?; - let key = (EventType::RoomMember, target_user_id.to_string()); + let key = (EventType::RoomMember, Some(target_user_id.to_string())); let current = auth_events.get(&key); let current_membership = current.map_or(Ok::<_, Error>(member::MembershipState::Leave), |pdu| { - Ok(pdu - .deserialize_content::()? - .membership) + Ok( + serde_json::from_value::(pdu.content.clone())? + .membership, + ) })?; - let key = (EventType::RoomPowerLevels, "".into()); + let key = (EventType::RoomPowerLevels, Some("".into())); let power_levels = auth_events.get(&key).map_or_else( || { Ok::<_, Error>(power_levels::PowerLevelsEventContent { @@ -333,8 +332,7 @@ pub fn valid_membership_change( }) }, |power_levels| { - power_levels - .deserialize_content::() + serde_json::from_value::(power_levels.content) .map_err(Into::into) }, )?; @@ -362,17 +360,17 @@ pub fn valid_membership_change( Some, ); - let key = (EventType::RoomJoinRules, "".to_string()); + let key = (EventType::RoomJoinRules, Some("".into())); let join_rules_event = auth_events.get(&key); let mut join_rules = JoinRule::Invite; if let Some(jr) = join_rules_event { - join_rules = jr - .deserialize_content::()? - .join_rule; + join_rules = + serde_json::from_value::(jr.content.clone())? + .join_rule; } if let Some(prev) = prev_event { - if prev.kind() == EventType::RoomCreate && prev.prev_event_ids().is_empty() { + if prev.kind == EventType::RoomCreate && prev.prev_events.is_empty() { return Ok(true); } } @@ -434,11 +432,11 @@ pub fn valid_membership_change( /// Is the event's sender in the room that they sent the event to. pub fn check_event_sender_in_room( sender: &UserId, - auth_events: &StateMap>, + auth_events: &StateMap>, ) -> Option { - let mem = auth_events.get(&(EventType::RoomMember, sender.to_string()))?; + let mem = auth_events.get(&(EventType::RoomMember, Some(sender.to_string())))?; Some( - mem.deserialize_content::() + serde_json::from_value::(mem.content.clone()) .ok()? .membership == MembershipState::Join, @@ -447,15 +445,15 @@ pub fn check_event_sender_in_room( /// Is the user allowed to send a specific event based on the rooms power levels. Does the event /// have the correct userId as it's state_key if it's not the "" state_key. -pub fn can_send_event(event: &Arc, auth_events: &StateMap>) -> bool { - let ple = auth_events.get(&(EventType::RoomPowerLevels, "".into())); +pub fn can_send_event(event: &Arc, auth_events: &StateMap>) -> bool { + let ple = auth_events.get(&(EventType::RoomPowerLevels, Some("".into()))); - let event_type_power_level = get_send_level(event.kind(), Some(event.state_key()), ple); - let user_level = get_user_power_level(event.sender(), auth_events); + let event_type_power_level = get_send_level(event.kind, event.state_key, ple); + let user_level = get_user_power_level(&event.sender, auth_events); tracing::debug!( "{} ev_type {} usr {}", - event.event_id().to_string(), + event.event_id.to_string(), event_type_power_level, user_level ); @@ -464,7 +462,9 @@ pub fn can_send_event(event: &Arc, auth_events: &StateMap, auth_events: &StateMap, - auth_events: &StateMap>, + power_event: &Arc, + auth_events: &StateMap>, ) -> Option { - let key = (power_event.kind(), power_event.state_key()); + let key = (power_event.kind, power_event.state_key); let current_state = if let Some(current_state) = auth_events.get(&key) { current_state } else { @@ -487,17 +487,19 @@ pub fn check_power_levels( // If users key in content is not a dictionary with keys that are valid user IDs // with values that are integers (or a string that is an integer), reject. - let user_content = power_event - .deserialize_content::() - .unwrap(); - let current_content = current_state - .deserialize_content::() - .unwrap(); + let user_content = serde_json::from_value::( + power_event.content.clone(), + ) + .unwrap(); + let current_content = serde_json::from_value::( + current_state.content.clone(), + ) + .unwrap(); // validation of users is done in Ruma, synapse for loops validating user_ids and integers here tracing::info!("validation of power event finished"); - let user_level = get_user_power_level(power_event.sender(), auth_events); + let user_level = get_user_power_level(&power_event.sender, auth_events); let mut user_levels_to_check = btreeset![]; let old_list = ¤t_content.users; @@ -547,7 +549,7 @@ pub fn check_power_levels( } // If the current value is equal to the sender's current power level, reject - if user != power_event.sender() && old_level.map(|int| (*int).into()) == Some(user_level) { + if user != &power_event.sender && old_level.map(|int| (*int).into()) == Some(user_level) { tracing::warn!("m.room.power_level cannot remove ops == to own"); return Some(false); // cannot remove ops level == to own } @@ -620,10 +622,10 @@ fn get_deserialize_levels( /// Does the event redacting come from a user with enough power to redact the given event. pub fn check_redaction( room_version: &RoomVersionId, - redaction_event: &Arc, - auth_events: &StateMap>, + redaction_event: &Arc, + auth_events: &StateMap>, ) -> Result { - let user_level = get_user_power_level(redaction_event.sender(), auth_events); + let user_level = get_user_power_level(&redaction_event.sender, auth_events); let redact_level = get_named_level(auth_events, "redact", 50); if user_level >= redact_level { @@ -641,8 +643,8 @@ pub fn check_redaction( // version 1 check if let RoomVersionId::Version1 = room_version { // If the domain of the event_id of the event being redacted is the same as the domain of the event_id of the m.room.redaction, allow - if redaction_event.event_id().server_name() - == redaction_event.redacts().and_then(|id| id.server_name()) + if redaction_event.event_id.server_name() + == redaction_event.redacts.and_then(|id| id.server_name()) { tracing::info!("redaction event allowed via room version 1 rules"); return Ok(true); @@ -655,10 +657,10 @@ pub fn check_redaction( /// Check that the member event matches `state`. /// /// This function returns false instead of failing when deserialization fails. -pub fn check_membership(member_event: Option>, state: MembershipState) -> bool { +pub fn check_membership(member_event: Option>, state: MembershipState) -> bool { if let Some(event) = member_event { if let Ok(content) = - serde_json::from_value::(event.content().clone()) + serde_json::from_value::(event.content.clone()) { content.membership == state } else { @@ -670,10 +672,10 @@ pub fn check_membership(member_event: Option>, state: Membership } /// Can this room federate based on its m.room.create event. -pub fn can_federate(auth_events: &StateMap>) -> bool { - let creation_event = auth_events.get(&(EventType::RoomCreate, "".into())); +pub fn can_federate(auth_events: &StateMap>) -> bool { + let creation_event = auth_events.get(&(EventType::RoomCreate, Some("".into()))); if let Some(ev) = creation_event { - if let Some(fed) = ev.content().get("m.federate") { + if let Some(fed) = ev.content.get("m.federate") { fed == "true" } else { false @@ -685,11 +687,11 @@ pub fn can_federate(auth_events: &StateMap>) -> bool { /// Helper function to fetch a field, `name`, from a "m.room.power_level" event's content. /// or return `default` if no power level event is found or zero if no field matches `name`. -pub fn get_named_level(auth_events: &StateMap>, name: &str, default: i64) -> i64 { - let power_level_event = auth_events.get(&(EventType::RoomPowerLevels, "".into())); +pub fn get_named_level(auth_events: &StateMap>, name: &str, default: i64) -> i64 { + let power_level_event = auth_events.get(&(EventType::RoomPowerLevels, Some("".into()))); if let Some(pl) = power_level_event { // TODO do this the right way and deserialize - if let Some(level) = pl.content().get(name) { + if let Some(level) = pl.content.get(name) { level.to_string().parse().unwrap_or(default) } else { 0 @@ -701,10 +703,11 @@ pub fn get_named_level(auth_events: &StateMap>, name: &str, defa /// Helper function to fetch a users default power level from a "m.room.power_level" event's `users` /// object. -pub fn get_user_power_level(user_id: &UserId, auth_events: &StateMap>) -> i64 { - if let Some(pl) = auth_events.get(&(EventType::RoomPowerLevels, "".into())) { - if let Ok(content) = pl.deserialize_content::() - { +pub fn get_user_power_level(user_id: &UserId, auth_events: &StateMap>) -> i64 { + if let Some(pl) = auth_events.get(&(EventType::RoomPowerLevels, Some("".into()))) { + if let Ok(content) = serde_json::from_value::( + pl.content.clone(), + ) { if let Some(level) = content.users.get(user_id) { (*level).into() } else { @@ -715,9 +718,11 @@ pub fn get_user_power_level(user_id: &UserId, auth_events: &StateMap() { + if let Ok(c) = + serde_json::from_value::(create.content.clone()) + { if &c.creator == user_id { 100 } else { @@ -737,12 +742,12 @@ pub fn get_user_power_level(user_id: &UserId, auth_events: &StateMap, - power_lvl: Option<&Arc>, + power_lvl: Option<&Arc>, ) -> i64 { tracing::debug!("{:?} {:?}", e_type, state_key); if let Some(ple) = power_lvl { if let Ok(content) = serde_json::from_value::( - ple.content().clone(), + ple.content.clone(), ) { let mut lvl: i64 = content .events @@ -767,17 +772,16 @@ pub fn get_send_level( /// Check user can send invite. pub fn can_send_invite( event: &Requester<'_>, - auth_events: &StateMap>, + auth_events: &StateMap>, ) -> Result { let user_level = get_user_power_level(event.sender, auth_events); - let key = (EventType::RoomPowerLevels, "".into()); + let key = (EventType::RoomPowerLevels, Some("".into())); let invite_level = auth_events .get(&key) .map_or_else( || Ok::<_, Error>(ruma::int!(50)), |power_levels| { - power_levels - .deserialize_content::() + serde_json::from_value::(power_levels.content.clone()) .map(|pl| pl.invite) .map_err(Into::into) }, @@ -790,7 +794,7 @@ pub fn can_send_invite( pub fn verify_third_party_invite( event: &Requester<'_>, tp_id: &member::ThirdPartyInvite, - current_third_party_invite: Option>, + current_third_party_invite: Option>, ) -> bool { // 1. check for user being banned happens before this is called // checking for mxid and token keys is done by ruma when deserializing @@ -802,18 +806,18 @@ pub fn verify_third_party_invite( // If there is no m.room.third_party_invite event in the current room state // with state_key matching token, reject if let Some(current_tpid) = current_third_party_invite { - if current_tpid.state_key() != tp_id.signed.token { + if current_tpid.state_key != Some(tp_id.signed.token) { return false; } - if event.sender != current_tpid.sender() { + if event.sender != ¤t_tpid.sender { return false; } // If any signature in signed matches any public key in the m.room.third_party_invite event, allow if let Ok(tpid_ev) = serde_json::from_value::< ruma::events::room::third_party_invite::ThirdPartyInviteEventContent, - >(current_tpid.content().clone()) + >(current_tpid.content.clone()) { // A list of public keys in the public_keys field for key in tpid_ev.public_keys.unwrap_or_default() { diff --git a/src/lib.rs b/src/lib.rs index 5296aeff..214e3077 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ use std::{ use maplit::btreeset; use ruma::{ - events::EventType, + events::{pdu::ServerPdu, EventType}, identifiers::{EventId, RoomId, RoomVersionId}, }; @@ -19,7 +19,7 @@ mod state_store; pub use error::{Error, Result}; pub use event_auth::{auth_check, auth_types_for_event}; -pub use state_event::{Requester, StateEvent}; +pub use state_event::Requester; pub use state_store::StateStore; // We want to yield to the reactor occasionally during state res when dealing @@ -28,9 +28,9 @@ pub use state_store::StateStore; const _YIELD_AFTER_ITERATIONS: usize = 100; /// A mapping of event type and state_key to some value `T`, usually an `EventId`. -pub type StateMap = BTreeMap<(EventType, String), T>; +pub type StateMap = BTreeMap<(EventType, Option), T>; -/// A mapping of `EventId` to `T`, usually a `StateEvent`. +/// A mapping of `EventId` to `T`, usually a `ServerPdu`. pub type EventMap = BTreeMap; #[derive(Default)] @@ -44,9 +44,9 @@ impl StateResolution { pub fn apply_event( room_id: &RoomId, room_version: &RoomVersionId, - incoming_event: Arc, + incoming_event: Arc, current_state: &StateMap, - event_map: Option>>, + event_map: Option>>, store: &dyn StateStore, ) -> Result { tracing::info!("Applying a single event, state resolution starting"); @@ -57,19 +57,16 @@ impl StateResolution { } else { EventMap::new() }; - let prev_event = if let Some(id) = ev.prev_event_ids().first() { + let prev_event = if let Some(id) = ev.prev_events.first() { store.get_event(room_id, id).ok() } else { None }; let mut auth_events = StateMap::new(); - for key in event_auth::auth_types_for_event( - ev.kind(), - ev.sender(), - Some(ev.state_key()), - ev.content().clone(), - ) { + for key in + event_auth::auth_types_for_event(ev.kind, &ev.sender, ev.state_key, ev.content.clone()) + { if let Some(ev_id) = current_state.get(&key) { if let Some(event) = StateResolution::get_or_load_event(room_id, ev_id, &mut event_map, store) @@ -105,8 +102,8 @@ impl StateResolution { room_id: &RoomId, room_version: &RoomVersionId, state_sets: &[StateMap], - // TODO: make the `Option<&mut EventMap>>` - event_map: Option>>, + // TODO: make the `Option<&mut EventMap>>` + event_map: Option>>, store: &dyn StateStore, ) -> Result> { tracing::info!("State resolution starting"); @@ -157,7 +154,7 @@ impl StateResolution { .unwrap(); // update event_map to include the fetched events - event_map.extend(events.into_iter().map(|ev| (ev.event_id(), ev))); + event_map.extend(events.into_iter().map(|ev| (ev.event_id.clone(), ev))); // at this point our event_map == store there should be no missing events tracing::debug!("event map size: {}", event_map.len()); @@ -233,7 +230,7 @@ impl StateResolution { ); // This "epochs" power level event - let power_event = resolved_control.get(&(EventType::RoomPowerLevels, "".into())); + let power_event = resolved_control.get(&(EventType::RoomPowerLevels, Some("".into()))); tracing::debug!("PL {:?}", power_event); @@ -341,7 +338,7 @@ impl StateResolution { pub fn reverse_topological_power_sort( room_id: &RoomId, events_to_sort: &[EventId], - event_map: &mut EventMap>, + event_map: &mut EventMap>, store: &dyn StateStore, auth_diff: &[EventId], ) -> Vec { @@ -381,12 +378,12 @@ impl StateResolution { let ev = event_map.get(event_id).unwrap(); let pl = event_to_pl.get(event_id).unwrap(); - tracing::debug!("{:?}", (-*pl, *ev.origin_server_ts(), ev.event_id())); + tracing::debug!("{:?}", (-*pl, ev.origin_server_ts, ev.event_id)); // This return value is the key used for sorting events, // events are then sorted by power level, time, // and lexically by event_id. - (-*pl, *ev.origin_server_ts(), ev.event_id()) + (-*pl, ev.origin_server_ts, ev.event_id) }) } @@ -467,7 +464,7 @@ impl StateResolution { fn get_power_level_for_sender( room_id: &RoomId, event_id: &EventId, - event_map: &mut EventMap>, + event_map: &mut EventMap>, store: &dyn StateStore, ) -> i64 { tracing::info!("fetch event ({}) senders power level", event_id.to_string()); @@ -479,11 +476,11 @@ impl StateResolution { // event.auth_event_ids does not include its own event id ? for aid in event .as_ref() - .map(|pdu| pdu.auth_events()) + .map(|pdu| pdu.auth_events) .unwrap_or_default() { if let Some(aev) = StateResolution::get_or_load_event(room_id, &aid, event_map, store) { - if aev.is_type_and_key(EventType::RoomPowerLevels, "") { + if is_type_and_key(&aev, EventType::RoomPowerLevels, "") { pl = Some(aev); break; } @@ -496,15 +493,16 @@ impl StateResolution { if let Some(content) = pl .map(|pl| { - pl.deserialize_content::( + serde_json::from_value::( + pl.content.clone(), ) .ok() }) .flatten() { if let Some(ev) = event { - if let Some(user) = content.users.get(ev.sender()) { - tracing::debug!("found {} at power_level {}", ev.sender().to_string(), user); + if let Some(user) = content.users.get(&ev.sender) { + tracing::debug!("found {} at power_level {}", ev.sender.to_string(), user); return (*user).into(); } } @@ -529,7 +527,7 @@ impl StateResolution { room_version: &RoomVersionId, events_to_check: &[EventId], unconflicted_state: &StateMap, - event_map: &mut EventMap>, + event_map: &mut EventMap>, store: &dyn StateStore, ) -> Result> { tracing::info!("starting iterative auth check"); @@ -549,23 +547,23 @@ impl StateResolution { StateResolution::get_or_load_event(room_id, event_id, event_map, store).unwrap(); let mut auth_events = BTreeMap::new(); - for aid in event.auth_events() { + for aid in &event.auth_events { if let Some(ev) = StateResolution::get_or_load_event(room_id, &aid, event_map, store) { // TODO what to do when no state_key is found ?? // TODO synapse check "rejected_reason", I'm guessing this is redacted_because in ruma ?? - auth_events.insert((ev.kind(), ev.state_key()), ev); + auth_events.insert((ev.kind.clone(), ev.state_key.clone()), ev); } else { tracing::warn!("auth event id for {} is missing {}", aid, event_id); } } for key in event_auth::auth_types_for_event( - event.kind(), - event.sender(), - Some(event.state_key()), - event.content().clone(), + event.kind, + &event.sender, + event.state_key, + event.content.clone(), ) { if let Some(ev_id) = resolved_state.get(&key) { if let Some(event) = @@ -577,10 +575,10 @@ impl StateResolution { } } - tracing::debug!("event to check {:?}", event.event_id().as_str()); + tracing::debug!("event to check {:?}", event.event_id.as_str()); let most_recent_prev_event = event - .prev_event_ids() + .prev_events .iter() .filter_map(|id| StateResolution::get_or_load_event(room_id, id, event_map, store)) .next_back(); @@ -588,7 +586,7 @@ impl StateResolution { // The key for this is (eventType + a state_key of the signed token not sender) so search // for it let current_third_party = auth_events.iter().find_map(|(_, pdu)| { - if pdu.kind() == EventType::RoomThirdPartyInvite { + if pdu.kind == EventType::RoomThirdPartyInvite { Some(pdu.clone()) // TODO no clone, auth_events is borrowed while moved } else { None @@ -603,7 +601,10 @@ impl StateResolution { current_third_party, )? { // add event to resolved state map - resolved_state.insert((event.kind(), event.state_key()), event_id.clone()); + resolved_state.insert( + (event.kind.clone(), event.state_key.clone()), + event_id.clone(), + ); } else { // synapse passes here on AuthError. We do not add this event to resolved_state. tracing::warn!( @@ -632,7 +633,7 @@ impl StateResolution { room_id: &RoomId, to_sort: &[EventId], resolved_power_level: Option<&EventId>, - event_map: &mut EventMap>, + event_map: &mut EventMap>, store: &dyn StateStore, ) -> Vec { tracing::debug!("mainline sort of events"); @@ -649,12 +650,12 @@ impl StateResolution { mainline.push(p.clone()); let event = StateResolution::get_or_load_event(room_id, &p, event_map, store).unwrap(); - let auth_events = event.auth_events(); + let auth_events = &event.auth_events; pl = None; for aid in auth_events { let ev = StateResolution::get_or_load_event(room_id, &aid, event_map, store).unwrap(); - if ev.is_type_and_key(EventType::RoomPowerLevels, "") { + if is_type_and_key(&ev, EventType::RoomPowerLevels, "") { pl = Some(aid.clone()); break; } @@ -690,10 +691,7 @@ impl StateResolution { ev_id, ( depth, - event_map - .get(ev_id) - .map(|ev| ev.origin_server_ts()) - .cloned(), + event_map.get(ev_id).map(|ev| ev.origin_server_ts), ev_id, // TODO should this be a &str to sort lexically?? ), ); @@ -719,26 +717,26 @@ impl StateResolution { /// that has an associated mainline depth. fn get_mainline_depth( room_id: &RoomId, - mut event: Option>, + mut event: Option>, mainline_map: &EventMap, - event_map: &mut EventMap>, + event_map: &mut EventMap>, store: &dyn StateStore, ) -> Result { while let Some(sort_ev) = event { - tracing::debug!("mainline event_id {}", sort_ev.event_id().to_string()); - let id = sort_ev.event_id(); + tracing::debug!("mainline event_id {}", sort_ev.event_id.to_string()); + let id = &sort_ev.event_id; if let Some(depth) = mainline_map.get(&id) { return Ok(*depth); } // dbg!(&sort_ev); - let auth_events = sort_ev.auth_events(); + let auth_events = &sort_ev.auth_events; event = None; for aid in auth_events { // dbg!(&aid); let aev = StateResolution::get_or_load_event(room_id, &aid, event_map, store) .ok_or_else(|| Error::NotFound("Auth event not found".to_owned()))?; - if aev.is_type_and_key(EventType::RoomPowerLevels, "") { + if is_type_and_key(&aev, EventType::RoomPowerLevels, "") { event = Some(aev); break; } @@ -752,7 +750,7 @@ impl StateResolution { room_id: &RoomId, graph: &mut BTreeMap>, event_id: &EventId, - event_map: &mut EventMap>, + event_map: &mut EventMap>, store: &dyn StateStore, auth_diff: &[EventId], ) { @@ -763,9 +761,9 @@ impl StateResolution { graph.entry(eid.clone()).or_insert_with(Vec::new); // prefer the store to event as the store filters dedups the events // otherwise it seems we can loop forever - for aid in StateResolution::get_or_load_event(room_id, &eid, event_map, store) + for aid in &StateResolution::get_or_load_event(room_id, &eid, event_map, store) .unwrap() - .auth_events() + .auth_events { if auth_diff.contains(&aid) { if !graph.contains_key(&aid) { @@ -788,9 +786,9 @@ impl StateResolution { fn get_or_load_event( room_id: &RoomId, ev_id: &EventId, - event_map: &mut EventMap>, + event_map: &mut EventMap>, store: &dyn StateStore, - ) -> Option> { + ) -> Option> { if let Some(e) = event_map.get(ev_id) { return Some(Arc::clone(e)); } @@ -803,9 +801,47 @@ impl StateResolution { } } -pub fn is_power_event(event_id: &EventId, event_map: &EventMap>) -> bool { +pub fn is_power_event(event_id: &EventId, event_map: &EventMap>) -> bool { match event_map.get(event_id) { - Some(state) => state.is_power_event(), + Some(state) => _is_power_event(state), _ => false, } } + +pub fn is_type_and_key(&ev: &Arc, ev_type: EventType, state_key: &str) -> bool { + ev.kind == ev_type && ev.state_key.as_deref() == Some(state_key) +} + +fn _is_power_event(&event: &Arc) -> bool { + use ruma::events::room::member::{MemberEventContent, MembershipState}; + match event.kind { + EventType::RoomPowerLevels | EventType::RoomJoinRules | EventType::RoomCreate => { + event.state_key == Some("".into()) + } + EventType::RoomMember => { + if let Ok(content) = + // TODO fix clone + serde_json::from_value::(event.content.clone()) + { + if [MembershipState::Leave, MembershipState::Ban].contains(&content.membership) { + return event.sender.as_str() + // TODO is None here a failure + != event.state_key.as_deref().unwrap_or("NOT A STATE KEY"); + } + } + + false + } + _ => false, + } +} + +pub fn to_requester(event: &Arc) -> Requester<'_> { + Requester { + prev_event_ids: event.prev_events, + room_id: &event.room_id, + content: &event.content, + state_key: event.state_key.clone(), + sender: &event.sender, + } +} diff --git a/src/state_store.rs b/src/state_store.rs index 2f18692e..796d06fa 100644 --- a/src/state_store.rs +++ b/src/state_store.rs @@ -1,15 +1,18 @@ use std::{collections::BTreeSet, sync::Arc}; -use ruma::identifiers::{EventId, RoomId}; +use ruma::{ + events::pdu::ServerPdu, + identifiers::{EventId, RoomId}, +}; -use crate::{Result, StateEvent}; +use crate::Result; pub trait StateStore { /// Return a single event based on the EventId. - fn get_event(&self, room_id: &RoomId, event_id: &EventId) -> Result>; + fn get_event(&self, room_id: &RoomId, event_id: &EventId) -> Result>; /// Returns the events that correspond to the `event_ids` sorted in the same order. - fn get_events(&self, room_id: &RoomId, event_ids: &[EventId]) -> Result>> { + fn get_events(&self, room_id: &RoomId, event_ids: &[EventId]) -> Result>> { let mut events = vec![]; for id in event_ids { events.push(self.get_event(room_id, id)?); @@ -33,7 +36,7 @@ pub trait StateStore { let event = self.get_event(room_id, &ev_id)?; - stack.extend(event.auth_events()); + stack.extend(event.auth_events.clone()); } Ok(result)