Port RoomVersion to Rust (#19589)

Principally so that we can share the same room version configuration
between Python and Rust.

For the most part, this is a direct port. Some special handling has had
to go into `KNOWN_ROOM_VERSIONS` so that it can be sensibly shared
between Python and Rust, since we do update it during config parsing.

---------

Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Erik Johnston
2026-03-26 09:17:31 +00:00
committed by GitHub
parent f2b325f86c
commit f545aa4f33
9 changed files with 994 additions and 511 deletions
+1
View File
@@ -0,0 +1 @@
Port `RoomVersion` to Rust.
+2
View File
@@ -15,6 +15,7 @@ pub mod matrix_const;
pub mod msc4388_rendezvous;
pub mod push;
pub mod rendezvous;
pub mod room_versions;
pub mod segmenter;
lazy_static! {
@@ -58,6 +59,7 @@ fn synapse_rust(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
rendezvous::register_module(py, m)?;
msc4388_rendezvous::register_module(py, m)?;
segmenter::register_module(py, m)?;
room_versions::register_module(py, m)?;
Ok(())
}
+825
View File
@@ -0,0 +1,825 @@
/*
* This file is licensed under the Affero General Public License (AGPL) version 3.
*
* Copyright (C) 2026 Element Creations Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* See the GNU Affero General Public License for more details:
* <https://www.gnu.org/licenses/agpl-3.0.html>.
*/
//! Rust implementation of room version definitions.
use std::sync::{Arc, LazyLock, RwLock};
use pyo3::{
exceptions::{PyKeyError, PyRuntimeError},
prelude::*,
types::{PyFrozenSet, PyIterator, PyModule, PyModuleMethods},
Bound, IntoPyObjectExt, PyResult, Python,
};
/// Internal enum for tracking the version of the event format,
/// independently of the room version.
///
/// To reduce confusion, the event format versions are named after the room
/// versions that they were used or introduced in.
/// The concept of an 'event format version' is specific to Synapse (the
/// specification does not mention this term.)
#[pyclass(frozen)]
pub struct EventFormatVersions {}
#[pymethods]
impl EventFormatVersions {
/// $id:server event id format: used for room v1 and v2
#[classattr]
const ROOM_V1_V2: i32 = 1;
/// MSC1659-style $hash event id format: used for room v3
#[classattr]
const ROOM_V3: i32 = 2;
/// MSC1884-style $hash format: introduced for room v4
#[classattr]
const ROOM_V4_PLUS: i32 = 3;
/// MSC4291 room IDs as hashes: introduced for room HydraV11
#[classattr]
const ROOM_V11_HYDRA_PLUS: i32 = 4;
}
/// Enum to identify the state resolution algorithms.
#[pyclass(frozen)]
pub struct StateResolutionVersions {}
#[pymethods]
impl StateResolutionVersions {
/// Room v1 state res
#[classattr]
const V1: i32 = 1;
/// MSC1442 state res: room v2 and later
#[classattr]
const V2: i32 = 2;
/// MSC4297 state res
#[classattr]
const V2_1: i32 = 3;
}
/// Room disposition constants.
#[pyclass(frozen)]
pub struct RoomDisposition {}
#[pymethods]
impl RoomDisposition {
#[classattr]
const STABLE: &'static str = "stable";
#[classattr]
const UNSTABLE: &'static str = "unstable";
}
/// Enum for listing possible MSC3931 room version feature flags, for push rules.
#[pyclass(frozen)]
pub struct PushRuleRoomFlag {}
#[pymethods]
impl PushRuleRoomFlag {
/// MSC3932: Room version supports MSC1767 Extensible Events.
#[classattr]
const EXTENSIBLE_EVENTS: &'static str = "org.matrix.msc3932.extensible_events";
}
/// An object which describes the unique attributes of a room version.
#[pyclass(frozen, eq, hash, get_all)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct RoomVersion {
/// The identifier for this version.
pub identifier: &'static str,
/// One of the RoomDisposition constants.
pub disposition: &'static str,
/// One of the EventFormatVersions constants.
pub event_format: i32,
/// One of the StateResolutionVersions constants.
pub state_res: i32,
pub enforce_key_validity: bool,
/// Before MSC2432, m.room.aliases had special auth rules and redaction rules.
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
pub strict_canonicaljson: bool,
/// MSC2209: Check 'notifications' key while verifying
/// m.room.power_levels auth rules.
pub limit_notifications_power_levels: bool,
/// MSC3820: No longer include the creator in m.room.create events (room version 11).
pub implicit_room_creator: bool,
/// MSC3820: Apply updated redaction rules algorithm from room version 11.
pub updated_redaction_rules: bool,
/// Support the 'restricted' join rule.
pub restricted_join_rule: bool,
/// Support for the proper redaction rules for the restricted join rule.
/// This requires restricted_join_rule to be enabled.
pub restricted_join_rule_fix: bool,
/// Support the 'knock' join rule.
pub knock_join_rule: bool,
/// MSC3389: Protect relation information from redaction.
pub msc3389_relation_redactions: bool,
/// Support the 'knock_restricted' join rule.
pub knock_restricted_join_rule: bool,
/// Enforce integer power levels.
pub enforce_int_power_levels: bool,
/// MSC3931: Adds a push rule condition for "room version feature flags", making
/// some push rules room version dependent. Note that adding a flag to this list
/// is not enough to mark it "supported": the push rule evaluator also needs to
/// support the flag. Unknown flags are ignored by the evaluator, making conditions
/// fail if used. Values from PushRuleRoomFlag.
pub msc3931_push_features: &'static [&'static str],
/// MSC3757: Restricting who can overwrite a state event.
pub msc3757_enabled: bool,
/// MSC4289: Creator power enabled.
pub msc4289_creator_power_enabled: bool,
/// MSC4291: Room IDs as hashes of the create event.
pub msc4291_room_ids_as_hashes: bool,
/// Set of room versions where Synapse strictly enforces event key size limits
/// in bytes, rather than in codepoints.
///
/// In these room versions, we are stricter with event size validation.
pub strict_event_byte_limits_room_versions: bool,
}
const ROOM_VERSION_V1: RoomVersion = RoomVersion {
identifier: "1",
disposition: RoomDisposition::STABLE,
event_format: EventFormatVersions::ROOM_V1_V2,
state_res: StateResolutionVersions::V1,
enforce_key_validity: false,
special_case_aliases_auth: true,
strict_canonicaljson: false,
limit_notifications_power_levels: false,
implicit_room_creator: false,
updated_redaction_rules: false,
restricted_join_rule: false,
restricted_join_rule_fix: false,
knock_join_rule: false,
msc3389_relation_redactions: false,
knock_restricted_join_rule: false,
enforce_int_power_levels: false,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: false,
};
const ROOM_VERSION_V2: RoomVersion = RoomVersion {
identifier: "2",
disposition: RoomDisposition::STABLE,
event_format: EventFormatVersions::ROOM_V1_V2,
state_res: StateResolutionVersions::V2,
enforce_key_validity: false,
special_case_aliases_auth: true,
strict_canonicaljson: false,
limit_notifications_power_levels: false,
implicit_room_creator: false,
updated_redaction_rules: false,
restricted_join_rule: false,
restricted_join_rule_fix: false,
knock_join_rule: false,
msc3389_relation_redactions: false,
knock_restricted_join_rule: false,
enforce_int_power_levels: false,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: false,
};
const ROOM_VERSION_V3: RoomVersion = RoomVersion {
identifier: "3",
disposition: RoomDisposition::STABLE,
event_format: EventFormatVersions::ROOM_V3,
state_res: StateResolutionVersions::V2,
enforce_key_validity: false,
special_case_aliases_auth: true,
strict_canonicaljson: false,
limit_notifications_power_levels: false,
implicit_room_creator: false,
updated_redaction_rules: false,
restricted_join_rule: false,
restricted_join_rule_fix: false,
knock_join_rule: false,
msc3389_relation_redactions: false,
knock_restricted_join_rule: false,
enforce_int_power_levels: false,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: false,
};
const ROOM_VERSION_V4: RoomVersion = RoomVersion {
identifier: "4",
disposition: RoomDisposition::STABLE,
event_format: EventFormatVersions::ROOM_V4_PLUS,
state_res: StateResolutionVersions::V2,
enforce_key_validity: false,
special_case_aliases_auth: true,
strict_canonicaljson: false,
limit_notifications_power_levels: false,
implicit_room_creator: false,
updated_redaction_rules: false,
restricted_join_rule: false,
restricted_join_rule_fix: false,
knock_join_rule: false,
msc3389_relation_redactions: false,
knock_restricted_join_rule: false,
enforce_int_power_levels: false,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: false,
};
const ROOM_VERSION_V5: RoomVersion = RoomVersion {
identifier: "5",
disposition: RoomDisposition::STABLE,
event_format: EventFormatVersions::ROOM_V4_PLUS,
state_res: StateResolutionVersions::V2,
enforce_key_validity: true,
special_case_aliases_auth: true,
strict_canonicaljson: false,
limit_notifications_power_levels: false,
implicit_room_creator: false,
updated_redaction_rules: false,
restricted_join_rule: false,
restricted_join_rule_fix: false,
knock_join_rule: false,
msc3389_relation_redactions: false,
knock_restricted_join_rule: false,
enforce_int_power_levels: false,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: false,
};
const ROOM_VERSION_V6: RoomVersion = RoomVersion {
identifier: "6",
disposition: RoomDisposition::STABLE,
event_format: EventFormatVersions::ROOM_V4_PLUS,
state_res: StateResolutionVersions::V2,
enforce_key_validity: true,
special_case_aliases_auth: false,
strict_canonicaljson: true,
limit_notifications_power_levels: true,
implicit_room_creator: false,
updated_redaction_rules: false,
restricted_join_rule: false,
restricted_join_rule_fix: false,
knock_join_rule: false,
msc3389_relation_redactions: false,
knock_restricted_join_rule: false,
enforce_int_power_levels: false,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: false,
};
const ROOM_VERSION_V7: RoomVersion = RoomVersion {
identifier: "7",
disposition: RoomDisposition::STABLE,
event_format: EventFormatVersions::ROOM_V4_PLUS,
state_res: StateResolutionVersions::V2,
enforce_key_validity: true,
special_case_aliases_auth: false,
strict_canonicaljson: true,
limit_notifications_power_levels: true,
implicit_room_creator: false,
updated_redaction_rules: false,
restricted_join_rule: false,
restricted_join_rule_fix: false,
knock_join_rule: true,
msc3389_relation_redactions: false,
knock_restricted_join_rule: false,
enforce_int_power_levels: false,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: false,
};
const ROOM_VERSION_V8: RoomVersion = RoomVersion {
identifier: "8",
disposition: RoomDisposition::STABLE,
event_format: EventFormatVersions::ROOM_V4_PLUS,
state_res: StateResolutionVersions::V2,
enforce_key_validity: true,
special_case_aliases_auth: false,
strict_canonicaljson: true,
limit_notifications_power_levels: true,
implicit_room_creator: false,
updated_redaction_rules: false,
restricted_join_rule: true,
restricted_join_rule_fix: false,
knock_join_rule: true,
msc3389_relation_redactions: false,
knock_restricted_join_rule: false,
enforce_int_power_levels: false,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: false,
};
const ROOM_VERSION_V9: RoomVersion = RoomVersion {
identifier: "9",
disposition: RoomDisposition::STABLE,
event_format: EventFormatVersions::ROOM_V4_PLUS,
state_res: StateResolutionVersions::V2,
enforce_key_validity: true,
special_case_aliases_auth: false,
strict_canonicaljson: true,
limit_notifications_power_levels: true,
implicit_room_creator: false,
updated_redaction_rules: false,
restricted_join_rule: true,
restricted_join_rule_fix: true,
knock_join_rule: true,
msc3389_relation_redactions: false,
knock_restricted_join_rule: false,
enforce_int_power_levels: false,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: false,
};
const ROOM_VERSION_V10: RoomVersion = RoomVersion {
identifier: "10",
disposition: RoomDisposition::STABLE,
event_format: EventFormatVersions::ROOM_V4_PLUS,
state_res: StateResolutionVersions::V2,
enforce_key_validity: true,
special_case_aliases_auth: false,
strict_canonicaljson: true,
limit_notifications_power_levels: true,
implicit_room_creator: false,
updated_redaction_rules: false,
restricted_join_rule: true,
restricted_join_rule_fix: true,
knock_join_rule: true,
msc3389_relation_redactions: false,
knock_restricted_join_rule: true,
enforce_int_power_levels: true,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: false,
};
/// MSC3389 (Redaction changes for events with a relation) based on room version "10".
const ROOM_VERSION_MSC3389V10: RoomVersion = RoomVersion {
identifier: "org.matrix.msc3389.10",
disposition: RoomDisposition::UNSTABLE,
event_format: EventFormatVersions::ROOM_V4_PLUS,
state_res: StateResolutionVersions::V2,
enforce_key_validity: true,
special_case_aliases_auth: false,
strict_canonicaljson: true,
limit_notifications_power_levels: true,
implicit_room_creator: false,
updated_redaction_rules: false,
restricted_join_rule: true,
restricted_join_rule_fix: true,
knock_join_rule: true,
msc3389_relation_redactions: true, // Changed from v10
knock_restricted_join_rule: true,
enforce_int_power_levels: true,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: true,
};
/// MSC1767 (Extensible Events) based on room version "10".
const ROOM_VERSION_MSC1767V10: RoomVersion = RoomVersion {
identifier: "org.matrix.msc1767.10",
disposition: RoomDisposition::UNSTABLE,
event_format: EventFormatVersions::ROOM_V4_PLUS,
state_res: StateResolutionVersions::V2,
enforce_key_validity: true,
special_case_aliases_auth: false,
strict_canonicaljson: true,
limit_notifications_power_levels: true,
implicit_room_creator: false,
updated_redaction_rules: false,
restricted_join_rule: true,
restricted_join_rule_fix: true,
knock_join_rule: true,
msc3389_relation_redactions: false,
knock_restricted_join_rule: true,
enforce_int_power_levels: true,
msc3931_push_features: &[PushRuleRoomFlag::EXTENSIBLE_EVENTS],
msc3757_enabled: false,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: false,
};
/// MSC3757 (Restricting who can overwrite a state event) based on room version "10".
const ROOM_VERSION_MSC3757V10: RoomVersion = RoomVersion {
identifier: "org.matrix.msc3757.10",
disposition: RoomDisposition::UNSTABLE,
event_format: EventFormatVersions::ROOM_V4_PLUS,
state_res: StateResolutionVersions::V2,
enforce_key_validity: true,
special_case_aliases_auth: false,
strict_canonicaljson: true,
limit_notifications_power_levels: true,
implicit_room_creator: false,
updated_redaction_rules: false,
restricted_join_rule: true,
restricted_join_rule_fix: true,
knock_join_rule: true,
msc3389_relation_redactions: false,
knock_restricted_join_rule: true,
enforce_int_power_levels: true,
msc3931_push_features: &[],
msc3757_enabled: true,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: false,
};
const ROOM_VERSION_V11: RoomVersion = RoomVersion {
identifier: "11",
disposition: RoomDisposition::STABLE,
event_format: EventFormatVersions::ROOM_V4_PLUS,
state_res: StateResolutionVersions::V2,
enforce_key_validity: true,
special_case_aliases_auth: false,
strict_canonicaljson: true,
limit_notifications_power_levels: true,
implicit_room_creator: true, // Used by MSC3820
updated_redaction_rules: true, // Used by MSC3820
restricted_join_rule: true,
restricted_join_rule_fix: true,
knock_join_rule: true,
msc3389_relation_redactions: false,
knock_restricted_join_rule: true,
enforce_int_power_levels: true,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: true, // Changed from v10
};
/// MSC3757 (Restricting who can overwrite a state event) based on room version "11".
const ROOM_VERSION_MSC3757V11: RoomVersion = RoomVersion {
identifier: "org.matrix.msc3757.11",
disposition: RoomDisposition::UNSTABLE,
event_format: EventFormatVersions::ROOM_V4_PLUS,
state_res: StateResolutionVersions::V2,
enforce_key_validity: true,
special_case_aliases_auth: false,
strict_canonicaljson: true,
limit_notifications_power_levels: true,
implicit_room_creator: true, // Used by MSC3820
updated_redaction_rules: true, // Used by MSC3820
restricted_join_rule: true,
restricted_join_rule_fix: true,
knock_join_rule: true,
msc3389_relation_redactions: false,
knock_restricted_join_rule: true,
enforce_int_power_levels: true,
msc3931_push_features: &[],
msc3757_enabled: true,
msc4289_creator_power_enabled: false,
msc4291_room_ids_as_hashes: false,
strict_event_byte_limits_room_versions: true,
};
const ROOM_VERSION_HYDRA_V11: RoomVersion = RoomVersion {
identifier: "org.matrix.hydra.11",
disposition: RoomDisposition::UNSTABLE,
event_format: EventFormatVersions::ROOM_V11_HYDRA_PLUS,
state_res: StateResolutionVersions::V2_1, // Changed from v11
enforce_key_validity: true,
special_case_aliases_auth: false,
strict_canonicaljson: true,
limit_notifications_power_levels: true,
implicit_room_creator: true, // Used by MSC3820
updated_redaction_rules: true, // Used by MSC3820
restricted_join_rule: true,
restricted_join_rule_fix: true,
knock_join_rule: true,
msc3389_relation_redactions: false,
knock_restricted_join_rule: true,
enforce_int_power_levels: true,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: true, // Changed from v11
msc4291_room_ids_as_hashes: true, // Changed from v11
strict_event_byte_limits_room_versions: true,
};
const ROOM_VERSION_V12: RoomVersion = RoomVersion {
identifier: "12",
disposition: RoomDisposition::STABLE,
event_format: EventFormatVersions::ROOM_V11_HYDRA_PLUS,
state_res: StateResolutionVersions::V2_1, // Changed from v11
enforce_key_validity: true,
special_case_aliases_auth: false,
strict_canonicaljson: true,
limit_notifications_power_levels: true,
implicit_room_creator: true, // Used by MSC3820
updated_redaction_rules: true, // Used by MSC3820
restricted_join_rule: true,
restricted_join_rule_fix: true,
knock_join_rule: true,
msc3389_relation_redactions: false,
knock_restricted_join_rule: true,
enforce_int_power_levels: true,
msc3931_push_features: &[],
msc3757_enabled: false,
msc4289_creator_power_enabled: true, // Changed from v11
msc4291_room_ids_as_hashes: true, // Changed from v11
strict_event_byte_limits_room_versions: true,
};
/// Helper class for managing the known room versions, and providing dict-like
/// access to them for Python.
///
/// Note: this is not necessarily all room versions, as we may not want to
/// support all experimental room versions.
///
/// Note: room versions can be added to this mapping at startup (allowing
/// support for experimental room versions to be behind experimental feature
/// flags).
#[pyclass(frozen, mapping)]
#[derive(Clone)]
pub struct KnownRoomVersionsMapping {
// Note we use a Vec here to ensure that the order of keys is
// deterministic. We rely on this when generating parameterized tests in
// Python, as Python will generate the tests names including the room
// version and index (and we need test names to be stable to e.g. support
// running tests in parallel).
pub versions: Arc<RwLock<Vec<RoomVersion>>>,
}
#[pymethods]
impl KnownRoomVersionsMapping {
/// Add a new room version to the mapping, indicating that this instance
/// supports it.
fn add_room_version(&self, version: RoomVersion) -> PyResult<()> {
let mut versions = self
.versions
.write()
.map_err(|_| PyRuntimeError::new_err("KnownRoomVersionsMapping lock poisoned"))?;
if versions.iter().any(|v| v.identifier == version.identifier) {
// We already have this room version, so we don't add it again (as
// otherwise we'd end up with duplicates).
return Ok(());
}
versions.push(version);
Ok(())
}
fn __getitem__(&self, key: &str) -> PyResult<RoomVersion> {
let versions = self.versions.read().unwrap();
versions
.iter()
.find(|v| v.identifier == key)
.copied()
.ok_or_else(|| PyKeyError::new_err(key.to_string()))
}
fn __contains__(&self, key: &str) -> PyResult<bool> {
let versions = self.versions.read().unwrap();
Ok(versions.iter().any(|v| v.identifier == key))
}
fn keys(&self) -> PyResult<Vec<&'static str>> {
// Note that technically we should return a view here (that also acts
// like a Set *and* has a stable ordering). We don't depend on this, so
// for simplicity we just return a list of the keys.
let versions = self.versions.read().unwrap();
Ok(versions.iter().map(|v| v.identifier).collect())
}
fn values(&self) -> PyResult<Vec<RoomVersion>> {
let versions = self.versions.read().unwrap();
Ok(versions.clone())
}
fn items(&self) -> PyResult<Vec<(&'static str, RoomVersion)>> {
// Note that technically we should return a view here (that also acts
// like a Set *and* has a stable ordering). We don't depend on this, so
// for simplicity we just return a list of the items.
let versions = self.versions.read().unwrap();
Ok(versions.iter().map(|v| (v.identifier, *v)).collect())
}
#[pyo3(signature = (key, default=None))]
fn get<'py>(
&self,
py: Python<'py>,
key: Bound<'py, PyAny>,
default: Option<Bound<'py, PyAny>>,
) -> PyResult<Option<Bound<'py, PyAny>>> {
// We need to accept anything as the key, but we know that only strings
// are valid keys, so if it's not a string we just return the default.
let Ok(key) = key.extract::<&str>() else {
return Ok(default);
};
let versions = self.versions.read().unwrap();
if let Some(version) = versions.iter().find(|v| v.identifier == key).copied() {
return Ok(Some(version.into_bound_py_any(py)?));
}
Ok(default)
}
fn __len__(&self) -> PyResult<usize> {
let versions = self
.versions
.read()
.map_err(|_| PyRuntimeError::new_err("KnownRoomVersionsMapping lock poisoned"))?;
Ok(versions.len())
}
fn __iter__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyIterator>> {
let key_list = self.keys()?;
let bound_key_list = key_list.into_bound_py_any(py)?;
PyIterator::from_object(&bound_key_list)
}
}
impl<'py> IntoPyObject<'py> for &KnownRoomVersionsMapping {
type Target = KnownRoomVersionsMapping;
type Output = Bound<'py, Self::Target>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
self.clone().into_pyobject(py)
}
}
/// All room versions this instance knows about, used to build the
/// `KNOWN_ROOM_VERSIONS` dict.
///
/// Note: this is not necessarily all room versions, as we may not want to
/// support all experimental room versions.
static KNOWN_ROOM_VERSIONS: LazyLock<KnownRoomVersionsMapping> = LazyLock::new(|| {
let vec = vec![
ROOM_VERSION_V1,
ROOM_VERSION_V2,
ROOM_VERSION_V3,
ROOM_VERSION_V4,
ROOM_VERSION_V5,
ROOM_VERSION_V6,
ROOM_VERSION_V7,
ROOM_VERSION_V8,
ROOM_VERSION_V9,
ROOM_VERSION_V10,
ROOM_VERSION_V11,
ROOM_VERSION_V12,
ROOM_VERSION_MSC3757V10,
ROOM_VERSION_MSC3757V11,
ROOM_VERSION_HYDRA_V11,
];
KnownRoomVersionsMapping {
versions: Arc::new(RwLock::new(vec)),
}
});
/// Container class for room version constants.
///
/// This should contain all room versions that we know about.
#[pyclass(frozen)]
pub struct RoomVersions {}
#[pymethods]
#[allow(non_snake_case)]
impl RoomVersions {
#[classattr]
fn V1(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_V1.into_py_any(py)
}
#[classattr]
fn V2(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_V2.into_py_any(py)
}
#[classattr]
fn V3(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_V3.into_py_any(py)
}
#[classattr]
fn V4(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_V4.into_py_any(py)
}
#[classattr]
fn V5(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_V5.into_py_any(py)
}
#[classattr]
fn V6(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_V6.into_py_any(py)
}
#[classattr]
fn V7(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_V7.into_py_any(py)
}
#[classattr]
fn V8(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_V8.into_py_any(py)
}
#[classattr]
fn V9(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_V9.into_py_any(py)
}
#[classattr]
fn V10(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_V10.into_py_any(py)
}
#[classattr]
fn MSC1767v10(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_MSC1767V10.into_py_any(py)
}
#[classattr]
fn MSC3389v10(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_MSC3389V10.into_py_any(py)
}
#[classattr]
fn MSC3757v10(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_MSC3757V10.into_py_any(py)
}
#[classattr]
fn V11(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_V11.into_py_any(py)
}
#[classattr]
fn MSC3757v11(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_MSC3757V11.into_py_any(py)
}
#[classattr]
fn HydraV11(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_HYDRA_V11.into_py_any(py)
}
#[classattr]
fn V12(py: Python<'_>) -> PyResult<Py<PyAny>> {
ROOM_VERSION_V12.into_py_any(py)
}
}
/// Called when registering modules with python.
pub fn register_module(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
let child_module = PyModule::new(py, "room_versions")?;
child_module.add_class::<EventFormatVersions>()?;
child_module.add_class::<StateResolutionVersions>()?;
child_module.add_class::<PushRuleRoomFlag>()?;
child_module.add_class::<RoomVersion>()?;
child_module.add_class::<RoomVersions>()?;
child_module.add_class::<KnownRoomVersionsMapping>()?;
child_module.add_class::<RoomDisposition>()?;
// Build KNOWN_EVENT_FORMAT_VERSIONS as a frozenset
let known_ef: [i32; 4] = [
EventFormatVersions::ROOM_V1_V2,
EventFormatVersions::ROOM_V3,
EventFormatVersions::ROOM_V4_PLUS,
EventFormatVersions::ROOM_V11_HYDRA_PLUS,
];
let known_event_format_versions = PyFrozenSet::new(py, known_ef)?;
child_module.add("KNOWN_EVENT_FORMAT_VERSIONS", known_event_format_versions)?;
child_module.add("KNOWN_ROOM_VERSIONS", &*KNOWN_ROOM_VERSIONS)?;
m.add_submodule(&child_module)?;
// Register in sys.modules
py.import("sys")?
.getattr("modules")?
.set_item("synapse.synapse_rust.room_versions", child_module)?;
Ok(())
}
+18 -476
View File
@@ -18,480 +18,22 @@
#
#
from synapse.synapse_rust.room_versions import (
KNOWN_EVENT_FORMAT_VERSIONS,
KNOWN_ROOM_VERSIONS,
EventFormatVersions,
PushRuleRoomFlag,
RoomVersion,
RoomVersions,
StateResolutionVersions,
)
import attr
class EventFormatVersions:
"""This is an internal enum for tracking the version of the event format,
independently of the room version.
To reduce confusion, the event format versions are named after the room
versions that they were used or introduced in.
The concept of an 'event format version' is specific to Synapse (the
specification does not mention this term.)
"""
ROOM_V1_V2 = 1 # $id:server event id format: used for room v1 and v2
ROOM_V3 = 2 # MSC1659-style $hash event id format: used for room v3
ROOM_V4_PLUS = 3 # MSC1884-style $hash format: introduced for room v4
ROOM_V11_HYDRA_PLUS = 4 # MSC4291 room IDs as hashes: introduced for room HydraV11
KNOWN_EVENT_FORMAT_VERSIONS = {
EventFormatVersions.ROOM_V1_V2,
EventFormatVersions.ROOM_V3,
EventFormatVersions.ROOM_V4_PLUS,
EventFormatVersions.ROOM_V11_HYDRA_PLUS,
}
class StateResolutionVersions:
"""Enum to identify the state resolution algorithms"""
V1 = 1 # room v1 state res
V2 = 2 # MSC1442 state res: room v2 and later
V2_1 = 3 # MSC4297 state res
class RoomDisposition:
STABLE = "stable"
UNSTABLE = "unstable"
class PushRuleRoomFlag:
"""Enum for listing possible MSC3931 room version feature flags, for push rules"""
# MSC3932: Room version supports MSC1767 Extensible Events.
EXTENSIBLE_EVENTS = "org.matrix.msc3932.extensible_events"
@attr.s(slots=True, frozen=True, auto_attribs=True)
class RoomVersion:
"""An object which describes the unique attributes of a room version."""
identifier: str # the identifier for this version
disposition: str # one of the RoomDispositions
event_format: int # one of the EventFormatVersions
state_res: int # one of the StateResolutionVersions
enforce_key_validity: bool
# Before MSC2432, m.room.aliases had special auth rules and redaction rules
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
strict_canonicaljson: bool
# MSC2209: Check 'notifications' key while verifying
# m.room.power_levels auth rules.
limit_notifications_power_levels: bool
# MSC3820: No longer include the creator in m.room.create events (room version 11)
implicit_room_creator: bool
# MSC3820: Apply updated redaction rules algorithm from room version 11
updated_redaction_rules: bool
# Support the 'restricted' join rule.
restricted_join_rule: bool
# Support for the proper redaction rules for the restricted join rule. This requires
# restricted_join_rule to be enabled.
restricted_join_rule_fix: bool
# Support the 'knock' join rule.
knock_join_rule: bool
# MSC3389: Protect relation information from redaction.
msc3389_relation_redactions: bool
# Support the 'knock_restricted' join rule.
knock_restricted_join_rule: bool
# Enforce integer power levels
enforce_int_power_levels: bool
# MSC3931: Adds a push rule condition for "room version feature flags", making
# some push rules room version dependent. Note that adding a flag to this list
# is not enough to mark it "supported": the push rule evaluator also needs to
# support the flag. Unknown flags are ignored by the evaluator, making conditions
# fail if used.
msc3931_push_features: tuple[str, ...] # values from PushRuleRoomFlag
# MSC3757: Restricting who can overwrite a state event
msc3757_enabled: bool
# MSC4289: Creator power enabled
msc4289_creator_power_enabled: bool
# MSC4291: Room IDs as hashes of the create event
msc4291_room_ids_as_hashes: bool
class RoomVersions:
V1 = RoomVersion(
"1",
RoomDisposition.STABLE,
EventFormatVersions.ROOM_V1_V2,
StateResolutionVersions.V1,
enforce_key_validity=False,
special_case_aliases_auth=True,
strict_canonicaljson=False,
limit_notifications_power_levels=False,
implicit_room_creator=False,
updated_redaction_rules=False,
restricted_join_rule=False,
restricted_join_rule_fix=False,
knock_join_rule=False,
msc3389_relation_redactions=False,
knock_restricted_join_rule=False,
enforce_int_power_levels=False,
msc3931_push_features=(),
msc3757_enabled=False,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
V2 = RoomVersion(
"2",
RoomDisposition.STABLE,
EventFormatVersions.ROOM_V1_V2,
StateResolutionVersions.V2,
enforce_key_validity=False,
special_case_aliases_auth=True,
strict_canonicaljson=False,
limit_notifications_power_levels=False,
implicit_room_creator=False,
updated_redaction_rules=False,
restricted_join_rule=False,
restricted_join_rule_fix=False,
knock_join_rule=False,
msc3389_relation_redactions=False,
knock_restricted_join_rule=False,
enforce_int_power_levels=False,
msc3931_push_features=(),
msc3757_enabled=False,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
V3 = RoomVersion(
"3",
RoomDisposition.STABLE,
EventFormatVersions.ROOM_V3,
StateResolutionVersions.V2,
enforce_key_validity=False,
special_case_aliases_auth=True,
strict_canonicaljson=False,
limit_notifications_power_levels=False,
implicit_room_creator=False,
updated_redaction_rules=False,
restricted_join_rule=False,
restricted_join_rule_fix=False,
knock_join_rule=False,
msc3389_relation_redactions=False,
knock_restricted_join_rule=False,
enforce_int_power_levels=False,
msc3931_push_features=(),
msc3757_enabled=False,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
V4 = RoomVersion(
"4",
RoomDisposition.STABLE,
EventFormatVersions.ROOM_V4_PLUS,
StateResolutionVersions.V2,
enforce_key_validity=False,
special_case_aliases_auth=True,
strict_canonicaljson=False,
limit_notifications_power_levels=False,
implicit_room_creator=False,
updated_redaction_rules=False,
restricted_join_rule=False,
restricted_join_rule_fix=False,
knock_join_rule=False,
msc3389_relation_redactions=False,
knock_restricted_join_rule=False,
enforce_int_power_levels=False,
msc3931_push_features=(),
msc3757_enabled=False,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
V5 = RoomVersion(
"5",
RoomDisposition.STABLE,
EventFormatVersions.ROOM_V4_PLUS,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=True,
strict_canonicaljson=False,
limit_notifications_power_levels=False,
implicit_room_creator=False,
updated_redaction_rules=False,
restricted_join_rule=False,
restricted_join_rule_fix=False,
knock_join_rule=False,
msc3389_relation_redactions=False,
knock_restricted_join_rule=False,
enforce_int_power_levels=False,
msc3931_push_features=(),
msc3757_enabled=False,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
V6 = RoomVersion(
"6",
RoomDisposition.STABLE,
EventFormatVersions.ROOM_V4_PLUS,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
implicit_room_creator=False,
updated_redaction_rules=False,
restricted_join_rule=False,
restricted_join_rule_fix=False,
knock_join_rule=False,
msc3389_relation_redactions=False,
knock_restricted_join_rule=False,
enforce_int_power_levels=False,
msc3931_push_features=(),
msc3757_enabled=False,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
V7 = RoomVersion(
"7",
RoomDisposition.STABLE,
EventFormatVersions.ROOM_V4_PLUS,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
implicit_room_creator=False,
updated_redaction_rules=False,
restricted_join_rule=False,
restricted_join_rule_fix=False,
knock_join_rule=True,
msc3389_relation_redactions=False,
knock_restricted_join_rule=False,
enforce_int_power_levels=False,
msc3931_push_features=(),
msc3757_enabled=False,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
V8 = RoomVersion(
"8",
RoomDisposition.STABLE,
EventFormatVersions.ROOM_V4_PLUS,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
implicit_room_creator=False,
updated_redaction_rules=False,
restricted_join_rule=True,
restricted_join_rule_fix=False,
knock_join_rule=True,
msc3389_relation_redactions=False,
knock_restricted_join_rule=False,
enforce_int_power_levels=False,
msc3931_push_features=(),
msc3757_enabled=False,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
V9 = RoomVersion(
"9",
RoomDisposition.STABLE,
EventFormatVersions.ROOM_V4_PLUS,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
implicit_room_creator=False,
updated_redaction_rules=False,
restricted_join_rule=True,
restricted_join_rule_fix=True,
knock_join_rule=True,
msc3389_relation_redactions=False,
knock_restricted_join_rule=False,
enforce_int_power_levels=False,
msc3931_push_features=(),
msc3757_enabled=False,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
V10 = RoomVersion(
"10",
RoomDisposition.STABLE,
EventFormatVersions.ROOM_V4_PLUS,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
implicit_room_creator=False,
updated_redaction_rules=False,
restricted_join_rule=True,
restricted_join_rule_fix=True,
knock_join_rule=True,
msc3389_relation_redactions=False,
knock_restricted_join_rule=True,
enforce_int_power_levels=True,
msc3931_push_features=(),
msc3757_enabled=False,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
MSC1767v10 = RoomVersion(
# MSC1767 (Extensible Events) based on room version "10"
"org.matrix.msc1767.10",
RoomDisposition.UNSTABLE,
EventFormatVersions.ROOM_V4_PLUS,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
implicit_room_creator=False,
updated_redaction_rules=False,
restricted_join_rule=True,
restricted_join_rule_fix=True,
knock_join_rule=True,
msc3389_relation_redactions=False,
knock_restricted_join_rule=True,
enforce_int_power_levels=True,
msc3931_push_features=(PushRuleRoomFlag.EXTENSIBLE_EVENTS,),
msc3757_enabled=False,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
MSC3757v10 = RoomVersion(
# MSC3757 (Restricting who can overwrite a state event) based on room version "10"
"org.matrix.msc3757.10",
RoomDisposition.UNSTABLE,
EventFormatVersions.ROOM_V4_PLUS,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
implicit_room_creator=False,
updated_redaction_rules=False,
restricted_join_rule=True,
restricted_join_rule_fix=True,
knock_join_rule=True,
msc3389_relation_redactions=False,
knock_restricted_join_rule=True,
enforce_int_power_levels=True,
msc3931_push_features=(),
msc3757_enabled=True,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
V11 = RoomVersion(
"11",
RoomDisposition.STABLE,
EventFormatVersions.ROOM_V4_PLUS,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
implicit_room_creator=True, # Used by MSC3820
updated_redaction_rules=True, # Used by MSC3820
restricted_join_rule=True,
restricted_join_rule_fix=True,
knock_join_rule=True,
msc3389_relation_redactions=False,
knock_restricted_join_rule=True,
enforce_int_power_levels=True,
msc3931_push_features=(),
msc3757_enabled=False,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
MSC3757v11 = RoomVersion(
# MSC3757 (Restricting who can overwrite a state event) based on room version "11"
"org.matrix.msc3757.11",
RoomDisposition.UNSTABLE,
EventFormatVersions.ROOM_V4_PLUS,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
implicit_room_creator=True, # Used by MSC3820
updated_redaction_rules=True, # Used by MSC3820
restricted_join_rule=True,
restricted_join_rule_fix=True,
knock_join_rule=True,
msc3389_relation_redactions=False,
knock_restricted_join_rule=True,
enforce_int_power_levels=True,
msc3931_push_features=(),
msc3757_enabled=True,
msc4289_creator_power_enabled=False,
msc4291_room_ids_as_hashes=False,
)
HydraV11 = RoomVersion(
"org.matrix.hydra.11",
RoomDisposition.UNSTABLE,
EventFormatVersions.ROOM_V11_HYDRA_PLUS,
StateResolutionVersions.V2_1, # Changed from v11
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
implicit_room_creator=True, # Used by MSC3820
updated_redaction_rules=True, # Used by MSC3820
restricted_join_rule=True,
restricted_join_rule_fix=True,
knock_join_rule=True,
msc3389_relation_redactions=False,
knock_restricted_join_rule=True,
enforce_int_power_levels=True,
msc3931_push_features=(),
msc3757_enabled=False,
msc4289_creator_power_enabled=True, # Changed from v11
msc4291_room_ids_as_hashes=True, # Changed from v11
)
V12 = RoomVersion(
"12",
RoomDisposition.STABLE,
EventFormatVersions.ROOM_V11_HYDRA_PLUS,
StateResolutionVersions.V2_1, # Changed from v11
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
implicit_room_creator=True, # Used by MSC3820
updated_redaction_rules=True, # Used by MSC3820
restricted_join_rule=True,
restricted_join_rule_fix=True,
knock_join_rule=True,
msc3389_relation_redactions=False,
knock_restricted_join_rule=True,
enforce_int_power_levels=True,
msc3931_push_features=(),
msc3757_enabled=False,
msc4289_creator_power_enabled=True, # Changed from v11
msc4291_room_ids_as_hashes=True, # Changed from v11
)
KNOWN_ROOM_VERSIONS: dict[str, RoomVersion] = {
v.identifier: v
for v in (
RoomVersions.V1,
RoomVersions.V2,
RoomVersions.V3,
RoomVersions.V4,
RoomVersions.V5,
RoomVersions.V6,
RoomVersions.V7,
RoomVersions.V8,
RoomVersions.V9,
RoomVersions.V10,
RoomVersions.V11,
RoomVersions.V12,
RoomVersions.MSC3757v10,
RoomVersions.MSC3757v11,
RoomVersions.HydraV11,
)
}
__all__ = [
"EventFormatVersions",
"KNOWN_EVENT_FORMAT_VERSIONS",
"KNOWN_ROOM_VERSIONS",
"PushRuleRoomFlag",
"RoomVersion",
"RoomVersions",
"StateResolutionVersions",
]
+1 -2
View File
@@ -477,8 +477,7 @@ class ExperimentalConfig(Config):
self.msc1767_enabled: bool = experimental.get("msc1767_enabled", False)
if self.msc1767_enabled:
# Enable room version (and thus applicable push rules from MSC3931/3932)
version_id = RoomVersions.MSC1767v10.identifier
KNOWN_ROOM_VERSIONS[version_id] = RoomVersions.MSC1767v10
KNOWN_ROOM_VERSIONS.add_room_version(RoomVersions.MSC1767v10)
# MSC3391: Removing account data.
self.msc3391_enabled = experimental.get("msc3391_enabled", False)
+1 -23
View File
@@ -60,7 +60,6 @@ from synapse.api.room_versions import (
KNOWN_ROOM_VERSIONS,
EventFormatVersions,
RoomVersion,
RoomVersions,
)
from synapse.events import is_creator
from synapse.state import CREATE_KEY
@@ -383,25 +382,6 @@ def check_state_dependent_auth_rules(
logger.debug("Allowing! %s", event)
# Set of room versions where Synapse did not apply event key size limits
# in bytes, but rather in codepoints.
# In these room versions, we are more lenient with event size validation.
LENIENT_EVENT_BYTE_LIMITS_ROOM_VERSIONS = {
RoomVersions.V1,
RoomVersions.V2,
RoomVersions.V3,
RoomVersions.V4,
RoomVersions.V5,
RoomVersions.V6,
RoomVersions.V7,
RoomVersions.V8,
RoomVersions.V9,
RoomVersions.V10,
RoomVersions.MSC1767v10,
RoomVersions.MSC3757v10,
}
def _check_size_limits(event: "EventBase") -> None:
"""
Checks the size limits in a PDU.
@@ -440,9 +420,7 @@ def _check_size_limits(event: "EventBase") -> None:
if len(event.event_id) > 255:
raise EventSizeError("'event_id' too large", unpersistable=True)
strict_byte_limits = (
event.room_version not in LENIENT_EVENT_BYTE_LIMITS_ROOM_VERSIONS
)
strict_byte_limits = event.room_version.strict_event_byte_limits_room_versions
# Byte size check: if these fail, then be lenient to avoid breaking rooms.
if len(event.user_id.encode("utf-8")) > 255:
+1 -1
View File
@@ -65,7 +65,7 @@ class PushRuleEvaluator:
notification_power_levels: Mapping[str, int],
related_events_flattened: Mapping[str, Mapping[str, JsonValue]],
related_event_match_enabled: bool,
room_version_feature_flags: tuple[str, ...],
room_version_feature_flags: list[str],
msc3931_enabled: bool,
msc4210_enabled: bool,
msc4306_enabled: bool,
+142
View File
@@ -0,0 +1,142 @@
# This file is licensed under the Affero General Public License (AGPL) version 3.
#
# Copyright (C) 2026 Element Creations Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# See the GNU Affero General Public License for more details:
# <https://www.gnu.org/licenses/agpl-3.0.html>.
from collections.abc import Mapping
from typing import Iterator
class EventFormatVersions:
"""Internal enum for tracking the version of the event format,
independently of the room version.
To reduce confusion, the event format versions are named after the room
versions that they were used or introduced in.
The concept of an 'event format version' is specific to Synapse (the
specification does not mention this term.)
"""
ROOM_V1_V2: int
""":server event id format: used for room v1 and v2"""
ROOM_V3: int
"""MSC1659-style event id format: used for room v3"""
ROOM_V4_PLUS: int
"""MSC1884-style format: introduced for room v4"""
ROOM_V11_HYDRA_PLUS: int
"""MSC4291 room IDs as hashes: introduced for room HydraV11"""
KNOWN_EVENT_FORMAT_VERSIONS: frozenset[int]
class StateResolutionVersions:
"""Enum to identify the state resolution algorithms."""
V1: int
"""Room v1 state res"""
V2: int
"""MSC1442 state res: room v2 and later"""
V2_1: int
"""MSC4297 state res"""
class RoomDisposition:
"""Room disposition constants."""
STABLE: str
UNSTABLE: str
class PushRuleRoomFlag:
"""Enum for listing possible MSC3931 room version feature flags, for push rules."""
EXTENSIBLE_EVENTS: str
"""MSC3932: Room version supports MSC1767 Extensible Events."""
class RoomVersion:
"""An object which describes the unique attributes of a room version."""
identifier: str
"""The identifier for this version."""
disposition: str
"""One of the RoomDisposition constants."""
event_format: int
"""One of the EventFormatVersions constants."""
state_res: int
"""One of the StateResolutionVersions constants."""
enforce_key_validity: bool
special_case_aliases_auth: bool
"""Before MSC2432, m.room.aliases had special auth rules and redaction rules."""
strict_canonicaljson: bool
"""Strictly enforce canonicaljson, do not allow:
* Integers outside the range of [-2^53 + 1, 2^53 - 1]
* Floats
* NaN, Infinity, -Infinity
"""
limit_notifications_power_levels: bool
"""MSC2209: Check 'notifications' key while verifying
m.room.power_levels auth rules."""
implicit_room_creator: bool
"""MSC3820: No longer include the creator in m.room.create events (room version 11)."""
updated_redaction_rules: bool
"""MSC3820: Apply updated redaction rules algorithm from room version 11."""
restricted_join_rule: bool
"""Support the 'restricted' join rule."""
restricted_join_rule_fix: bool
"""Support for the proper redaction rules for the restricted join rule.
This requires restricted_join_rule to be enabled."""
knock_join_rule: bool
"""Support the 'knock' join rule."""
msc3389_relation_redactions: bool
"""MSC3389: Protect relation information from redaction."""
knock_restricted_join_rule: bool
"""Support the 'knock_restricted' join rule."""
enforce_int_power_levels: bool
"""Enforce integer power levels."""
msc3931_push_features: list[str]
"""MSC3931: Adds a push rule condition for "room version feature flags", making
some push rules room version dependent. Note that adding a flag to this list
is not enough to mark it "supported": the push rule evaluator also needs to
support the flag. Unknown flags are ignored by the evaluator, making conditions
fail if used. Values from PushRuleRoomFlag."""
msc3757_enabled: bool
"""MSC3757: Restricting who can overwrite a state event."""
msc4289_creator_power_enabled: bool
"""MSC4289: Creator power enabled."""
msc4291_room_ids_as_hashes: bool
"""MSC4291: Room IDs as hashes of the create event."""
strict_event_byte_limits_room_versions: bool
"""Whether this room version strictly enforces event key size limits in bytes,
rather than in codepoints.
If true, this room version uses stricter event size validation."""
class RoomVersions:
V1: RoomVersion
V2: RoomVersion
V3: RoomVersion
V4: RoomVersion
V5: RoomVersion
V6: RoomVersion
V7: RoomVersion
V8: RoomVersion
V9: RoomVersion
V10: RoomVersion
MSC1767v10: RoomVersion
MSC3389v10: RoomVersion
MSC3757v10: RoomVersion
V11: RoomVersion
MSC3757v11: RoomVersion
HydraV11: RoomVersion
V12: RoomVersion
class KnownRoomVersionsMapping(Mapping[str, RoomVersion]):
def add_room_version(self, room_version: RoomVersion) -> None: ...
def __getitem__(self, key: str) -> RoomVersion: ...
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[str]: ...
KNOWN_ROOM_VERSIONS: KnownRoomVersionsMapping
+3 -9
View File
@@ -22,7 +22,6 @@
import unittest as stdlib_unittest
from typing import Any, Mapping
import attr
from parameterized import parameterized
from synapse.api.constants import EventContentFields
@@ -553,11 +552,6 @@ class PruneEventTestCase(stdlib_unittest.TestCase):
room_version=RoomVersions.V10,
)
# Create a new room version.
msc3389_room_ver = attr.evolve(
RoomVersions.V10, msc3389_relation_redactions=True
)
self.run_test(
{
"type": "m.room.message",
@@ -581,7 +575,7 @@ class PruneEventTestCase(stdlib_unittest.TestCase):
"signatures": {},
"unsigned": {},
},
room_version=msc3389_room_ver,
room_version=RoomVersions.MSC3389v10,
)
# If the field is not an object, redact it.
@@ -599,7 +593,7 @@ class PruneEventTestCase(stdlib_unittest.TestCase):
"signatures": {},
"unsigned": {},
},
room_version=msc3389_room_ver,
room_version=RoomVersions.MSC3389v10,
)
# If the m.relates_to property would be empty, redact it.
@@ -614,7 +608,7 @@ class PruneEventTestCase(stdlib_unittest.TestCase):
"signatures": {},
"unsigned": {},
},
room_version=msc3389_room_ver,
room_version=RoomVersions.MSC3389v10,
)