Use the RoomVersion struct in event_auth

This commit is contained in:
Devin Ragotzy 2021-04-29 12:06:50 -04:00 committed by Devin Ragotzy
parent c20893e536
commit 138ecd4f35
4 changed files with 48 additions and 31 deletions

View File

@ -1,5 +1,3 @@
use std::num::ParseIntError;
use serde_json::Error as JsonError; use serde_json::Error as JsonError;
use thiserror::Error; use thiserror::Error;
@ -13,19 +11,19 @@ pub enum Error {
#[error(transparent)] #[error(transparent)]
SerdeJson(#[from] JsonError), SerdeJson(#[from] JsonError),
/// An error that occurs when converting from JSON numbers to rust. /// The given option or version is unsupported.
#[error(transparent)] #[error("Unsupported room version: {0}")]
IntParseError(#[from] ParseIntError), Unsupported(String),
/// The given event was not found.
#[error("Not found error: {0}")] #[error("Not found error: {0}")]
NotFound(String), NotFound(String),
/// Invalid fields in the given PDU.
#[error("Invalid PDU: {0}")] #[error("Invalid PDU: {0}")]
InvalidPdu(String), InvalidPdu(String),
#[error("Conversion failed: {0}")] /// A custom error.
ConversionError(String),
#[error("{0}")] #[error("{0}")]
Custom(Box<dyn std::error::Error>), Custom(Box<dyn std::error::Error>),
} }

View File

@ -15,7 +15,7 @@ use ruma::{
RoomVersionId, UserId, 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 /// For the given event `kind` what are the relevant auth events
/// that are needed to authenticate this `content`. /// that are needed to authenticate this `content`.
@ -82,7 +82,7 @@ pub fn auth_types_for_event(
/// ## Returns /// ## Returns
/// This returns an `Error` only when serialization fails or some other fatal outcome. /// This returns an `Error` only when serialization fails or some other fatal outcome.
pub fn auth_check<E: Event>( pub fn auth_check<E: Event>(
room_version: &RoomVersionId, room_version: &RoomVersion,
incoming_event: &Arc<E>, incoming_event: &Arc<E>,
prev_event: Option<Arc<E>>, prev_event: Option<Arc<E>>,
auth_events: &StateMap<Arc<E>>, auth_events: &StateMap<Arc<E>>,
@ -180,7 +180,7 @@ pub fn auth_check<E: Event>(
// [synapse] checks for federation here // [synapse] checks for federation here
// 4. if type is m.room.aliases // 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"); log::info!("starting m.room.aliases check");
// If sender's domain doesn't matches state_key, reject // If sender's domain doesn't matches state_key, reject
@ -280,7 +280,7 @@ pub fn auth_check<E: Event>(
// Servers should only apply redaction's to events where the sender's domains match, // 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. // 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 && incoming_event.kind() == EventType::RoomRedaction
&& !check_redaction(room_version, incoming_event, &auth_events)? && !check_redaction(room_version, incoming_event, &auth_events)?
{ {
@ -320,7 +320,7 @@ pub fn valid_membership_change<E: Event>(
.map(|t| serde_json::from_value::<room::member::ThirdPartyInvite>(t.clone())); .map(|t| serde_json::from_value::<room::member::ThirdPartyInvite>(t.clone()));
let target_user_id = 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 key = (EventType::RoomMember, user_sender.to_string());
let sender = auth_events.get(&key); let sender = auth_events.get(&key);
@ -538,7 +538,7 @@ pub fn can_send_event<E: Event>(event: &Arc<E>, auth_events: &StateMap<Arc<E>>)
/// Confirm that the event sender has the required power levels. /// Confirm that the event sender has the required power levels.
pub fn check_power_levels<E: Event>( pub fn check_power_levels<E: Event>(
room_version: &RoomVersionId, room_version: &RoomVersion,
power_event: &Arc<E>, power_event: &Arc<E>,
auth_events: &StateMap<Arc<E>>, auth_events: &StateMap<Arc<E>>,
) -> Option<bool> { ) -> Option<bool> {
@ -639,7 +639,7 @@ pub fn check_power_levels<E: Event>(
} }
// Notifications, currently there is only @room // 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 old_level = old_state.notifications.room;
let new_level = new_state.notifications.room; let new_level = new_state.notifications.room;
if old_level != new_level { 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. /// Does the event redacting come from a user with enough power to redact the given event.
pub fn check_redaction<E: Event>( pub fn check_redaction<E: Event>(
_room_version: &RoomVersionId, _room_version: &RoomVersion,
redaction_event: &Arc<E>, redaction_event: &Arc<E>,
auth_events: &StateMap<Arc<E>>, auth_events: &StateMap<Arc<E>>,
) -> Result<bool> { ) -> Result<bool> {
@ -705,7 +705,8 @@ pub fn check_redaction<E: Event>(
return Ok(true); 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() if redaction_event.event_id().server_name()
== redaction_event == redaction_event
.redacts() .redacts()

View File

@ -6,6 +6,7 @@ use std::{
}; };
use maplit::btreeset; use maplit::btreeset;
use room_version::RoomVersion;
use ruma::{ use ruma::{
events::{ events::{
room::{ room::{
@ -21,12 +22,10 @@ mod error;
pub mod event_auth; pub mod event_auth;
pub mod room_version; pub mod room_version;
mod state_event; mod state_event;
mod state_store;
pub use error::{Error, Result}; pub use error::{Error, Result};
pub use event_auth::{auth_check, auth_types_for_event}; pub use event_auth::{auth_check, auth_types_for_event};
pub use state_event::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`. /// A mapping of event type and state_key to some value `T`, usually an `EventId`.
pub type StateMap<T> = BTreeMap<(EventType, String), T>; pub type StateMap<T> = BTreeMap<(EventType, String), T>;
@ -111,10 +110,11 @@ impl StateResolution {
log::debug!("SRTD {:?}", sorted_control_levels); log::debug!("SRTD {:?}", sorted_control_levels);
let room_version = RoomVersion::new(room_version)?;
// sequentially auth check each control event. // sequentially auth check each control event.
let resolved_control = StateResolution::iterative_auth_check( let resolved_control = StateResolution::iterative_auth_check(
room_id, room_id,
room_version, &room_version,
&sorted_control_levels, &sorted_control_levels,
&clean, &clean,
event_map, event_map,
@ -166,7 +166,7 @@ impl StateResolution {
let mut resolved_state = StateResolution::iterative_auth_check( let mut resolved_state = StateResolution::iterative_auth_check(
room_id, room_id,
room_version, &room_version,
&sorted_left_events, &sorted_left_events,
&resolved_control, // The control events are added to the final resolved state &resolved_control, // The control events are added to the final resolved state
event_map, event_map,
@ -436,7 +436,7 @@ impl StateResolution {
/// function. /// function.
pub fn iterative_auth_check<E: Event>( pub fn iterative_auth_check<E: Event>(
room_id: &RoomId, room_id: &RoomId,
room_version: &RoomVersionId, room_version: &RoomVersion,
events_to_check: &[EventId], events_to_check: &[EventId],
unconflicted_state: &StateMap<EventId>, unconflicted_state: &StateMap<EventId>,
event_map: &mut EventMap<Arc<E>>, event_map: &mut EventMap<Arc<E>>,

View File

@ -1,5 +1,7 @@
use ruma::RoomVersionId; use ruma::RoomVersionId;
use crate::{Error, Result};
pub enum RoomDisposition { pub enum RoomDisposition {
/// A room version that has a stable specification. /// A room version that has a stable specification.
Stable, Stable,
@ -36,29 +38,39 @@ pub struct RoomVersion {
/// not sure /// not sure
pub enforce_key_validity: bool, 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, pub special_case_aliases_auth: bool,
// Strictly enforce canonicaljson, do not allow: /// Strictly enforce canonicaljson, do not allow:
// * Integers outside the range of [-2 ^ 53 + 1, 2 ^ 53 - 1] /// * Integers outside the range of [-2 ^ 53 + 1, 2 ^ 53 - 1]
// * Floats /// * Floats
// * NaN, Infinity, -Infinity /// * NaN, Infinity, -Infinity
pub strict_canonicaljson: bool, pub strict_canonicaljson: bool,
// bool: MSC2209: Check 'notifications' key while verifying // bool: MSC2209: Check 'notifications' key while verifying
// m.room.power_levels auth rules. // m.room.power_levels auth rules.
/// Verify notifications key while checking m.room.power_levels.
pub limit_notifications_power_levels: bool, pub limit_notifications_power_levels: bool,
/// Extra rules when verifying redaction events.
pub extra_redaction_checks: bool,
} }
impl RoomVersion { impl RoomVersion {
pub fn new(version: &RoomVersionId) -> Self { pub fn new(version: &RoomVersionId) -> Result<Self> {
match version { Ok(match version {
RoomVersionId::Version1 => Self::version_1(), RoomVersionId::Version1 => Self::version_1(),
RoomVersionId::Version2 => Self::version_2(), RoomVersionId::Version2 => Self::version_2(),
RoomVersionId::Version3 => Self::version_3(), RoomVersionId::Version3 => Self::version_3(),
RoomVersionId::Version4 => Self::version_4(), RoomVersionId::Version4 => Self::version_4(),
RoomVersionId::Version5 => Self::version_5(), RoomVersionId::Version5 => Self::version_5(),
RoomVersionId::Version6 => Self::version_6(), 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 { fn version_1() -> Self {
@ -71,6 +83,7 @@ impl RoomVersion {
special_case_aliases_auth: true, special_case_aliases_auth: true,
strict_canonicaljson: false, strict_canonicaljson: false,
limit_notifications_power_levels: false, limit_notifications_power_levels: false,
extra_redaction_checks: false,
} }
} }
@ -84,6 +97,7 @@ impl RoomVersion {
special_case_aliases_auth: true, special_case_aliases_auth: true,
strict_canonicaljson: false, strict_canonicaljson: false,
limit_notifications_power_levels: false, limit_notifications_power_levels: false,
extra_redaction_checks: false,
} }
} }
@ -97,6 +111,7 @@ impl RoomVersion {
special_case_aliases_auth: true, special_case_aliases_auth: true,
strict_canonicaljson: false, strict_canonicaljson: false,
limit_notifications_power_levels: false, limit_notifications_power_levels: false,
extra_redaction_checks: true,
} }
} }
@ -110,6 +125,7 @@ impl RoomVersion {
special_case_aliases_auth: true, special_case_aliases_auth: true,
strict_canonicaljson: false, strict_canonicaljson: false,
limit_notifications_power_levels: false, limit_notifications_power_levels: false,
extra_redaction_checks: true,
} }
} }
@ -123,6 +139,7 @@ impl RoomVersion {
special_case_aliases_auth: true, special_case_aliases_auth: true,
strict_canonicaljson: false, strict_canonicaljson: false,
limit_notifications_power_levels: false, limit_notifications_power_levels: false,
extra_redaction_checks: true,
} }
} }
@ -136,6 +153,7 @@ impl RoomVersion {
special_case_aliases_auth: false, special_case_aliases_auth: false,
strict_canonicaljson: true, strict_canonicaljson: true,
limit_notifications_power_levels: true, limit_notifications_power_levels: true,
extra_redaction_checks: true,
} }
} }
} }