From 9721042198fb5f2c4b7eb66ec6ad3ee6d3921e17 Mon Sep 17 00:00:00 2001 From: Devin Ragotzy Date: Wed, 30 Dec 2020 15:13:07 -0500 Subject: [PATCH] Turn pdu into trait to avoid having our own PDU type --- src/event_auth.rs | 176 ++++++++++++++++++++++----------------------- src/lib.rs | 154 ++++++++++++++++++--------------------- src/state_event.rs | 45 +++++++++++- src/state_store.rs | 10 +-- 4 files changed, 203 insertions(+), 182 deletions(-) diff --git a/src/event_auth.rs b/src/event_auth.rs index 05159aea..271a1fce 100644 --- a/src/event_auth.rs +++ b/src/event_auth.rs @@ -15,7 +15,7 @@ use ruma::{ identifiers::{RoomVersionId, UserId}, }; -use crate::{state_event::Requester, to_requester, Error, Result, StateMap}; +use crate::{Error, Event, Result, StateMap}; /// For the given event `kind` what are the relevant auth events /// that are needed to authenticate this `content`. @@ -68,14 +68,14 @@ pub fn auth_types_for_event( /// * check that the event is being authenticated for the correct room /// * check that the events signatures are valid /// * then there are checks for specific event types -pub fn auth_check( +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` @@ -88,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_events.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 } @@ -106,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 @@ -119,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); } @@ -163,7 +163,7 @@ 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" @@ -174,7 +174,7 @@ pub fn auth_check( // } // If sender's domain doesn't matches state_key, reject - if incoming_event.state_key != Some(incoming_event.sender.server_name().to_string()) { + if incoming_event.state_key() != Some(incoming_event.sender().server_name().to_string()) { tracing::warn!("state_key does not match sender"); return Ok(false); } @@ -183,20 +183,18 @@ 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 serde_json::from_value::( - incoming_event.content.clone(), - ) - .is_err() + if serde_json::from_value::(incoming_event.content()) + .is_err() { tracing::warn!("no membership filed found for m.room.member event content"); return Ok(false); } if !valid_membership_change( - to_requester(incoming_event), + incoming_event, prev_event, current_third_party_invite, &auth_events, @@ -209,7 +207,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"); @@ -223,8 +221,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(&to_requester(incoming_event), &auth_events)? + if incoming_event.kind() == EventType::RoomThirdPartyInvite + && !can_send_invite(incoming_event, &auth_events)? { tracing::warn!("sender's cannot send invites in this room"); return Ok(false); @@ -237,7 +235,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) = @@ -254,7 +252,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); @@ -273,32 +271,31 @@ pub fn auth_check( /// * `auth_events` - The set of auth events that relate to a membership event. /// this is generated by calling `auth_types_for_event` with the membership event and /// the current State. -pub fn valid_membership_change( - user: Requester<'_>, - prev_event: Option>, - current_third_party_invite: Option>, - auth_events: &StateMap>, +pub fn valid_membership_change( + user: &Arc, + prev_event: Option>, + current_third_party_invite: Option>, + auth_events: &StateMap>, ) -> Result { - let state_key = if let Some(s) = user.state_key.as_ref() { + let state_key = if let Some(s) = user.state_key() { s } else { return Err(Error::InvalidPdu("State event requires state_key".into())); }; - let content = - serde_json::from_str::(&user.content.to_string())?; + let content = serde_json::from_value::(user.content())?; let target_membership = content.membership; let target_user_id = UserId::try_from(state_key.as_str()) .map_err(|e| Error::ConversionError(format!("{}", e)))?; - let key = (EventType::RoomMember, Some(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( - serde_json::from_value::(pdu.content.clone())? + serde_json::from_value::(pdu.content())? .membership, ) })?; @@ -308,7 +305,7 @@ pub fn valid_membership_change( let current_membership = current.map_or(Ok::<_, Error>(member::MembershipState::Leave), |pdu| { Ok( - serde_json::from_value::(pdu.content.clone())? + serde_json::from_value::(pdu.content())? .membership, ) })?; @@ -332,12 +329,12 @@ pub fn valid_membership_change( }) }, |power_levels| { - serde_json::from_value::(power_levels.content.clone()) + serde_json::from_value::(power_levels.content()) .map_err(Into::into) }, )?; - let sender_power = power_levels.users.get(&user.sender).map_or_else( + let sender_power = power_levels.users.get(&user.sender()).map_or_else( || { if sender_membership != member::MembershipState::Join { None @@ -365,18 +362,18 @@ pub fn valid_membership_change( let mut join_rules = JoinRule::Invite; if let Some(jr) = join_rules_event { join_rules = - serde_json::from_value::(jr.content.clone())? + serde_json::from_value::(jr.content())? .join_rule; } if let Some(prev) = prev_event { - if prev.kind == EventType::RoomCreate && prev.prev_events.is_empty() { + if prev.kind() == EventType::RoomCreate && prev.prev_events().is_empty() { return Ok(true); } } Ok(if target_membership == MembershipState::Join { - if user.sender != &target_user_id { + if user.sender() != target_user_id { false } else if let MembershipState::Ban = current_membership { false @@ -392,7 +389,7 @@ pub fn valid_membership_change( if current_membership == MembershipState::Ban { false } else { - verify_third_party_invite(&user, &tp_id, current_third_party_invite) + verify_third_party_invite(user, &tp_id, current_third_party_invite) } } else if sender_membership != MembershipState::Join || current_membership == MembershipState::Join @@ -405,7 +402,7 @@ pub fn valid_membership_change( .is_some() } } else if target_membership == MembershipState::Leave { - if user.sender == &target_user_id { + if user.sender() == target_user_id { current_membership == MembershipState::Join || current_membership == MembershipState::Invite } else if sender_membership != MembershipState::Join @@ -430,13 +427,13 @@ 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( +pub fn check_event_sender_in_room( sender: &UserId, - auth_events: &StateMap>, + auth_events: &StateMap>, ) -> Option { let mem = auth_events.get(&(EventType::RoomMember, Some(sender.to_string())))?; Some( - serde_json::from_value::(mem.content.clone()) + serde_json::from_value::(mem.content()) .ok()? .membership == MembershipState::Join, @@ -445,15 +442,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 { +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, event.state_key.clone(), 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 ); @@ -463,10 +460,10 @@ pub fn can_send_event(event: &Arc, auth_events: &StateMap, auth_events: &StateMap( _: &RoomVersionId, - power_event: &Arc, - auth_events: &StateMap>, + power_event: &Arc, + auth_events: &StateMap>, ) -> Option { - let key = (power_event.kind.clone(), power_event.state_key.clone()); + let key = (power_event.kind(), power_event.state_key()); let current_state = if let Some(current_state) = auth_events.get(&key) { current_state } else { @@ -491,18 +488,18 @@ 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 = serde_json::from_value::( - power_event.content.clone(), + power_event.content(), ) .unwrap(); let current_content = serde_json::from_value::( - current_state.content.clone(), + current_state.content(), ) .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; @@ -552,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 } @@ -623,12 +620,12 @@ fn get_deserialize_levels( } /// Does the event redacting come from a user with enough power to redact the given event. -pub fn check_redaction( +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 { @@ -646,9 +643,9 @@ 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() + if redaction_event.event_id().server_name() == redaction_event - .redacts + .redacts() .as_ref() .and_then(|id| id.server_name()) { @@ -693,11 +690,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 { +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 @@ -709,11 +706,11 @@ pub fn get_named_level(auth_events: &StateMap>, name: &str, defau /// 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 { +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 Ok(content) = + serde_json::from_value::(pl.content()) + { if let Some(level) = content.users.get(user_id) { (*level).into() } else { @@ -727,7 +724,7 @@ pub fn get_user_power_level(user_id: &UserId, auth_events: &StateMap(create.content.clone()) + serde_json::from_value::(create.content()) { if &c.creator == user_id { 100 @@ -745,16 +742,16 @@ pub fn get_user_power_level(user_id: &UserId, auth_events: &StateMap( e_type: &EventType, state_key: Option, - 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(), - ) { + if let Ok(content) = + serde_json::from_value::(ple.content()) + { let mut lvl: i64 = content .events .get(&e_type) @@ -776,18 +773,15 @@ pub fn get_send_level( } /// Check user can send invite. -pub fn can_send_invite( - event: &Requester<'_>, - auth_events: &StateMap>, -) -> Result { - let user_level = get_user_power_level(event.sender, auth_events); +pub fn can_send_invite(event: &Arc, auth_events: &StateMap>) -> Result { + let user_level = get_user_power_level(&event.sender(), auth_events); let key = (EventType::RoomPowerLevels, Some("".into())); let invite_level = auth_events .get(&key) .map_or_else( || Ok::<_, Error>(ruma::int!(50)), |power_levels| { - serde_json::from_value::(power_levels.content.clone()) + serde_json::from_value::(power_levels.content()) .map(|pl| pl.invite) .map_err(Into::into) }, @@ -797,33 +791,33 @@ pub fn can_send_invite( Ok(user_level >= invite_level) } -pub fn verify_third_party_invite( - event: &Requester<'_>, +pub fn verify_third_party_invite( + event: &Arc, 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 - if event.state_key != Some(tp_id.signed.mxid.to_string()) { + if event.state_key() != Some(tp_id.signed.mxid.to_string()) { return false; } // 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.as_ref() != Some(&tp_id.signed.token) { + if current_tpid.state_key().as_ref() != Some(&tp_id.signed.token) { return false; } - if event.sender != ¤t_tpid.sender { + if event.sender() != current_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()) { // 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 01a7113a..3c923d66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; +pub use state_event::{Event, Requester}; pub use state_store::StateStore; // We want to yield to the reactor occasionally during state res when dealing @@ -41,13 +41,13 @@ impl StateResolution { /// /// This will authenticate the event against the current state of the room. It /// is important that the `current_state` argument is accurate and complete. - pub fn apply_event( + pub fn apply_event( room_id: &RoomId, room_version: &RoomVersionId, - incoming_event: Arc, + incoming_event: Arc, current_state: &StateMap, - event_map: Option>>, - store: &dyn StateStore, + event_map: Option>>, + store: &dyn StateStore, ) -> Result { tracing::info!("Applying a single event, state resolution starting"); let ev = incoming_event; @@ -57,19 +57,16 @@ impl StateResolution { } else { EventMap::new() }; - let prev_event = if let Some(id) = ev.prev_events.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, - ev.state_key.clone(), - ev.content.clone(), - ) { + for key in + event_auth::auth_types_for_event(&ev.kind(), &ev.sender(), ev.state_key(), ev.content()) + { 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) @@ -101,13 +98,13 @@ impl StateResolution { /// /// It is up the the caller to check that the events returned from `StateStore::get_event` are /// events for the correct room (synapse checks that all events are in the right room). - pub fn resolve( + pub fn resolve( room_id: &RoomId, room_version: &RoomVersionId, state_sets: &[StateMap], // TODO: make the `Option<&mut EventMap>>` - event_map: Option>>, - store: &dyn StateStore, + 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.clone(), ev))); + event_map.extend(events.into_iter().map(|ev| (ev.event_id(), ev))); // at this point our event_map == store there should be no missing events tracing::debug!("event map size: {}", event_map.len()); @@ -312,10 +309,10 @@ impl StateResolution { } /// Returns a Vec of deduped EventIds that appear in some chains but not others. - pub fn get_auth_chain_diff( + pub fn get_auth_chain_diff( room_id: &RoomId, state_sets: &[StateMap], - store: &dyn StateStore, + store: &dyn StateStore, ) -> Result> { use itertools::Itertools; @@ -338,11 +335,11 @@ impl StateResolution { /// /// The power level is negative because a higher power level is equated to an /// earlier (further back in time) origin server timestamp. - pub fn reverse_topological_power_sort( + pub fn reverse_topological_power_sort( room_id: &RoomId, events_to_sort: &[EventId], - event_map: &mut EventMap>, - store: &dyn StateStore, + event_map: &mut EventMap>, + store: &dyn StateStore, auth_diff: &[EventId], ) -> Vec { tracing::debug!("reverse topological sort of power events"); @@ -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.clone()) + (-*pl, ev.origin_server_ts(), ev.event_id()) }) } @@ -464,11 +461,11 @@ impl StateResolution { } /// Find the power level for the sender of `event_id` or return a default value of zero. - fn get_power_level_for_sender( + fn get_power_level_for_sender( room_id: &RoomId, event_id: &EventId, - event_map: &mut EventMap>, - store: &dyn StateStore, + event_map: &mut EventMap>, + store: &dyn StateStore, ) -> i64 { tracing::info!("fetch event ({}) senders power level", event_id.to_string()); @@ -479,7 +476,7 @@ impl StateResolution { // event.auth_event_ids does not include its own event id ? for aid in event .as_ref() - .map(|pdu| pdu.auth_events.to_vec()) + .map(|pdu| pdu.auth_events()) .unwrap_or_default() { if let Some(aev) = StateResolution::get_or_load_event(room_id, &aid, event_map, store) { @@ -497,15 +494,15 @@ impl StateResolution { if let Some(content) = pl .map(|pl| { serde_json::from_value::( - pl.content.clone(), + pl.content(), ) .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(); } } @@ -525,13 +522,13 @@ impl StateResolution { /// For each `events_to_check` event we gather the events needed to auth it from the /// `event_map` or `store` and verify each event using the `event_auth::auth_check` /// function. - pub fn iterative_auth_check( + pub fn iterative_auth_check( room_id: &RoomId, room_version: &RoomVersionId, events_to_check: &[EventId], unconflicted_state: &StateMap, - event_map: &mut EventMap>, - store: &dyn StateStore, + event_map: &mut EventMap>, + store: &dyn StateStore, ) -> Result> { tracing::info!("starting iterative auth check"); @@ -550,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.clone(), ev.state_key.clone()), ev); + auth_events.insert((ev.kind(), ev.state_key()), 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, - event.state_key.clone(), - event.content.clone(), + &event.kind(), + &event.sender(), + event.state_key(), + event.content(), ) { if let Some(ev_id) = resolved_state.get(&key) { if let Some(event) = @@ -578,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_events + .prev_events() .iter() .filter_map(|id| StateResolution::get_or_load_event(room_id, id, event_map, store)) .next_back(); @@ -589,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 @@ -604,10 +601,7 @@ impl StateResolution { current_third_party, )? { // add event to resolved state map - resolved_state.insert( - (event.kind.clone(), event.state_key.clone()), - event_id.clone(), - ); + resolved_state.insert((event.kind(), event.state_key()), event_id.clone()); } else { // synapse passes here on AuthError. We do not add this event to resolved_state. tracing::warn!( @@ -632,12 +626,12 @@ impl StateResolution { /// power_level event. If there have been two power events the after the most recent are /// depth 0, the events before (with the first power level as a parent) will be marked /// as depth 1. depth 1 is "older" than depth 0. - pub fn mainline_sort( + pub fn mainline_sort( room_id: &RoomId, to_sort: &[EventId], resolved_power_level: Option<&EventId>, - event_map: &mut EventMap>, - store: &dyn StateStore, + event_map: &mut EventMap>, + store: &dyn StateStore, ) -> Vec { tracing::debug!("mainline sort of events"); @@ -653,7 +647,7 @@ 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 = @@ -694,7 +688,7 @@ impl StateResolution { ev_id, ( depth, - event_map.get(ev_id).map(|ev| ev.origin_server_ts), + event_map.get(ev_id).map(|ev| ev.origin_server_ts()), ev_id, // TODO should this be a &str to sort lexically?? ), ); @@ -718,22 +712,22 @@ impl StateResolution { /// Get the mainline depth from the `mainline_map` or finds a power_level event /// that has an associated mainline depth. - fn get_mainline_depth( + fn get_mainline_depth( room_id: &RoomId, - mut event: Option>, + mut event: Option>, mainline_map: &EventMap, - event_map: &mut EventMap>, - store: &dyn StateStore, + 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); @@ -749,12 +743,12 @@ impl StateResolution { Ok(0) } - fn add_event_and_auth_chain_to_graph( + fn add_event_and_auth_chain_to_graph( room_id: &RoomId, graph: &mut BTreeMap>, event_id: &EventId, - event_map: &mut EventMap>, - store: &dyn StateStore, + event_map: &mut EventMap>, + store: &dyn StateStore, auth_diff: &[EventId], ) { let mut state = vec![event_id.clone()]; @@ -766,7 +760,7 @@ impl StateResolution { // otherwise it seems we can loop forever 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) { @@ -786,12 +780,12 @@ impl StateResolution { /// if the event_map does not have the PDU. /// /// If the PDU is missing from the `event_map` it is added. - fn get_or_load_event( + fn get_or_load_event( room_id: &RoomId, ev_id: &EventId, - event_map: &mut EventMap>, - store: &dyn StateStore, - ) -> Option> { + event_map: &mut EventMap>, + store: &dyn StateStore, + ) -> Option> { if let Some(e) = event_map.get(ev_id) { return Some(Arc::clone(e)); } @@ -804,32 +798,32 @@ impl StateResolution { } } -pub fn is_power_event_id(event_id: &EventId, event_map: &EventMap>) -> bool { +pub fn is_power_event_id(event_id: &EventId, event_map: &EventMap>) -> bool { match event_map.get(event_id) { 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) +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) } -pub fn is_power_event(event: &Arc) -> bool { +pub fn is_power_event(event: &Arc) -> bool { use ruma::events::room::member::{MemberEventContent, MembershipState}; - match event.kind { + match event.kind() { EventType::RoomPowerLevels | EventType::RoomJoinRules | EventType::RoomCreate => { - event.state_key == Some("".into()) + event.state_key() == Some("".into()) } EventType::RoomMember => { if let Ok(content) = // TODO fix clone - serde_json::from_value::(event.content.clone()) + serde_json::from_value::(event.content()) { if [MembershipState::Leave, MembershipState::Ban].contains(&content.membership) { - return event.sender.as_str() + return event.sender().as_str() // TODO is None here a failure - != event.state_key.as_deref().unwrap_or("NOT A STATE KEY"); + != event.state_key().as_deref().unwrap_or("NOT A STATE KEY"); } } @@ -838,13 +832,3 @@ pub fn is_power_event(event: &Arc) -> bool { _ => false, } } - -pub fn to_requester(event: &Arc) -> Requester<'_> { - Requester { - prev_event_ids: event.prev_events.to_vec(), - room_id: &event.room_id, - content: &event.content, - state_key: event.state_key.clone(), - sender: &event.sender, - } -} diff --git a/src/state_event.rs b/src/state_event.rs index 141b896a..ab87b56f 100644 --- a/src/state_event.rs +++ b/src/state_event.rs @@ -8,12 +8,55 @@ use ruma::{ EventDeHelper, EventType, }, serde::CanonicalJsonValue, - signatures::reference_hash, + signatures::{reference_hash, CanonicalJsonObject}, EventId, RoomId, RoomVersionId, ServerName, UInt, UserId, }; use serde::{de, ser, Deserialize, Serialize}; use serde_json::value::RawValue as RawJsonValue; +/// Abstraction of a PDU so users can have their own PDU types. +pub trait Event { + /// The `EventId` of this event. + fn event_id(&self) -> EventId; + + /// The `RoomId` of this event. + fn room_id(&self) -> RoomId; + + /// The `UserId` of this event. + fn sender(&self) -> UserId; + + /// The time of creation on the originating server. + fn origin_server_ts(&self) -> SystemTime; + + /// The kind of event. + fn kind(&self) -> EventType; + + /// The `UserId` of this PDU. + fn content(&self) -> serde_json::Value; + + /// The state key for this event. + fn state_key(&self) -> Option; + + /// The events before this event. + fn prev_events(&self) -> Vec; + + /// The maximum number of `prev_events` plus 1. + fn depth(&self) -> UInt; + + /// All the authenticating events for this event. + fn auth_events(&self) -> Vec; + + /// If this event is a redaction event this is the event it redacts. + fn redacts(&self) -> Option; + + /// The `unsigned` content of this event. + fn unsigned(&self) -> CanonicalJsonObject; + + fn hashes(&self) -> &EventHash; + + fn signatures(&self) -> BTreeMap, BTreeMap>; +} + #[derive(Clone, Debug, Deserialize, Serialize)] struct EventIdHelper { event_id: EventId, diff --git a/src/state_store.rs b/src/state_store.rs index 796d06fa..9f863fca 100644 --- a/src/state_store.rs +++ b/src/state_store.rs @@ -5,14 +5,14 @@ use ruma::{ identifiers::{EventId, RoomId}, }; -use crate::Result; +use crate::{Event, Result}; -pub trait StateStore { +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)?); @@ -36,7 +36,7 @@ pub trait StateStore { let event = self.get_event(room_id, &ev_id)?; - stack.extend(event.auth_events.clone()); + stack.extend(event.auth_events().clone()); } Ok(result)