diff --git a/src/error.rs b/src/error.rs index 51ca8fcc..1f27df89 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,3 @@ -use std::num::ParseIntError; - use serde_json::Error as JsonError; use thiserror::Error; @@ -13,19 +11,19 @@ pub enum Error { #[error(transparent)] SerdeJson(#[from] JsonError), - /// An error that occurs when converting from JSON numbers to rust. - #[error(transparent)] - IntParseError(#[from] ParseIntError), + /// The given option or version is unsupported. + #[error("Unsupported room version: {0}")] + Unsupported(String), + /// The given event was not found. #[error("Not found error: {0}")] NotFound(String), + /// Invalid fields in the given PDU. #[error("Invalid PDU: {0}")] InvalidPdu(String), - #[error("Conversion failed: {0}")] - ConversionError(String), - + /// A custom error. #[error("{0}")] Custom(Box), } diff --git a/src/event_auth.rs b/src/event_auth.rs index 25aab27a..286e5d17 100644 --- a/src/event_auth.rs +++ b/src/event_auth.rs @@ -15,7 +15,7 @@ use ruma::{ RoomVersionId, UserId, }; -use crate::{Error, Event, Result, StateMap}; +use crate::{room_version::RoomVersion, Error, Event, Result, StateMap}; /// For the given event `kind` what are the relevant auth events /// that are needed to authenticate this `content`. @@ -82,7 +82,7 @@ pub fn auth_types_for_event( /// ## Returns /// This returns an `Error` only when serialization fails or some other fatal outcome. pub fn auth_check( - room_version: &RoomVersionId, + room_version: &RoomVersion, incoming_event: &Arc, prev_event: Option>, auth_events: &StateMap>, @@ -180,7 +180,7 @@ pub fn auth_check( // [synapse] checks for federation here // 4. if type is m.room.aliases - if incoming_event.kind() == EventType::RoomAliases && room_version < &RoomVersionId::Version6 { + if incoming_event.kind() == EventType::RoomAliases && room_version.special_case_aliases_auth { log::info!("starting m.room.aliases check"); // If sender's domain doesn't matches state_key, reject @@ -280,7 +280,7 @@ pub fn auth_check( // Servers should only apply redaction's to events where the sender's domains match, // or the sender of the redaction has the appropriate permissions per the power levels. - if room_version >= &RoomVersionId::Version3 + if room_version.extra_redaction_checks && incoming_event.kind() == EventType::RoomRedaction && !check_redaction(room_version, incoming_event, &auth_events)? { @@ -320,7 +320,7 @@ pub fn valid_membership_change( .map(|t| serde_json::from_value::(t.clone())); let target_user_id = - UserId::try_from(state_key).map_err(|e| Error::ConversionError(format!("{}", e)))?; + UserId::try_from(state_key).map_err(|e| Error::InvalidPdu(format!("{}", e)))?; let key = (EventType::RoomMember, user_sender.to_string()); let sender = auth_events.get(&key); @@ -538,7 +538,7 @@ pub fn can_send_event(event: &Arc, auth_events: &StateMap>) /// Confirm that the event sender has the required power levels. pub fn check_power_levels( - room_version: &RoomVersionId, + room_version: &RoomVersion, power_event: &Arc, auth_events: &StateMap>, ) -> Option { @@ -639,7 +639,7 @@ pub fn check_power_levels( } // Notifications, currently there is only @room - if room_version >= &RoomVersionId::Version6 { + if room_version.limit_notifications_power_levels { let old_level = old_state.notifications.room; let new_level = new_state.notifications.room; if old_level != new_level { @@ -693,7 +693,7 @@ 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, + _room_version: &RoomVersion, redaction_event: &Arc, auth_events: &StateMap>, ) -> Result { @@ -705,7 +705,8 @@ pub fn check_redaction( return Ok(true); } - // 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 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() diff --git a/src/lib.rs b/src/lib.rs index 569b4575..69883e53 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ use std::{ }; use maplit::btreeset; +use room_version::RoomVersion; use ruma::{ events::{ room::{ @@ -21,12 +22,10 @@ mod error; pub mod event_auth; pub mod room_version; mod state_event; -mod state_store; pub use error::{Error, Result}; pub use event_auth::{auth_check, auth_types_for_event}; pub use state_event::Event; -pub use state_store::StateStore; /// A mapping of event type and state_key to some value `T`, usually an `EventId`. pub type StateMap = BTreeMap<(EventType, String), T>; @@ -111,10 +110,11 @@ impl StateResolution { log::debug!("SRTD {:?}", sorted_control_levels); + let room_version = RoomVersion::new(room_version)?; // sequentially auth check each control event. let resolved_control = StateResolution::iterative_auth_check( room_id, - room_version, + &room_version, &sorted_control_levels, &clean, event_map, @@ -166,7 +166,7 @@ impl StateResolution { let mut resolved_state = StateResolution::iterative_auth_check( room_id, - room_version, + &room_version, &sorted_left_events, &resolved_control, // The control events are added to the final resolved state event_map, @@ -436,7 +436,7 @@ impl StateResolution { /// function. pub fn iterative_auth_check( room_id: &RoomId, - room_version: &RoomVersionId, + room_version: &RoomVersion, events_to_check: &[EventId], unconflicted_state: &StateMap, event_map: &mut EventMap>, diff --git a/src/room_version.rs b/src/room_version.rs index a8db26ea..10e64639 100644 --- a/src/room_version.rs +++ b/src/room_version.rs @@ -1,5 +1,7 @@ use ruma::RoomVersionId; +use crate::{Error, Result}; + pub enum RoomDisposition { /// A room version that has a stable specification. Stable, @@ -36,29 +38,39 @@ pub struct RoomVersion { /// not sure pub enforce_key_validity: bool, - // bool: before MSC2261/MSC2432, m.room.aliases had special auth rules and redaction rules + // bool: before MSC2261/MSC2432, + /// `m.room.aliases` had special auth rules and redaction rules + /// before room version 6. pub special_case_aliases_auth: bool, - // Strictly enforce canonicaljson, do not allow: - // * Integers outside the range of [-2 ^ 53 + 1, 2 ^ 53 - 1] - // * Floats - // * NaN, Infinity, -Infinity + /// Strictly enforce canonicaljson, do not allow: + /// * Integers outside the range of [-2 ^ 53 + 1, 2 ^ 53 - 1] + /// * Floats + /// * NaN, Infinity, -Infinity pub strict_canonicaljson: bool, // bool: MSC2209: Check 'notifications' key while verifying // m.room.power_levels auth rules. + /// Verify notifications key while checking m.room.power_levels. pub limit_notifications_power_levels: bool, + /// Extra rules when verifying redaction events. + pub extra_redaction_checks: bool, } impl RoomVersion { - pub fn new(version: &RoomVersionId) -> Self { - match version { + pub fn new(version: &RoomVersionId) -> Result { + Ok(match version { RoomVersionId::Version1 => Self::version_1(), RoomVersionId::Version2 => Self::version_2(), RoomVersionId::Version3 => Self::version_3(), RoomVersionId::Version4 => Self::version_4(), RoomVersionId::Version5 => Self::version_5(), RoomVersionId::Version6 => Self::version_6(), - _ => panic!("unspec'ed room version"), - } + ver => { + return Err(Error::Unsupported(format!( + "found version `{}`", + ver.as_str() + ))) + } + }) } fn version_1() -> Self { @@ -71,6 +83,7 @@ impl RoomVersion { special_case_aliases_auth: true, strict_canonicaljson: false, limit_notifications_power_levels: false, + extra_redaction_checks: false, } } @@ -84,6 +97,7 @@ impl RoomVersion { special_case_aliases_auth: true, strict_canonicaljson: false, limit_notifications_power_levels: false, + extra_redaction_checks: false, } } @@ -97,6 +111,7 @@ impl RoomVersion { special_case_aliases_auth: true, strict_canonicaljson: false, limit_notifications_power_levels: false, + extra_redaction_checks: true, } } @@ -110,6 +125,7 @@ impl RoomVersion { special_case_aliases_auth: true, strict_canonicaljson: false, limit_notifications_power_levels: false, + extra_redaction_checks: true, } } @@ -123,6 +139,7 @@ impl RoomVersion { special_case_aliases_auth: true, strict_canonicaljson: false, limit_notifications_power_levels: false, + extra_redaction_checks: true, } } @@ -136,6 +153,7 @@ impl RoomVersion { special_case_aliases_auth: false, strict_canonicaljson: true, limit_notifications_power_levels: true, + extra_redaction_checks: true, } } }