Use the RoomVersion struct in event_auth
This commit is contained in:
parent
c20893e536
commit
138ecd4f35
14
src/error.rs
14
src/error.rs
@ -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>),
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
10
src/lib.rs
10
src/lib.rs
@ -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>>,
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user