1
0
Fork 0
mirror of https://gitlab.com/famedly/conduit.git synced 2025-08-11 17:50:59 +00:00

refactor: use RoomVersionRules instead of matching against RoomVersionId

This commit is contained in:
Matthias Ahouansou 2025-07-02 19:39:03 +01:00
parent b631621f8c
commit a8fa237fad
No known key found for this signature in database
7 changed files with 135 additions and 219 deletions

View file

@ -23,7 +23,7 @@ use ruma::{
}, },
int, int,
serde::JsonObject, serde::JsonObject,
CanonicalJsonObject, OwnedRoomAliasId, RoomAliasId, RoomId, RoomVersionId, CanonicalJsonObject, OwnedRoomAliasId, RoomAliasId, RoomId,
}; };
use serde_json::{json, value::to_raw_value}; use serde_json::{json, value::to_raw_value};
use std::{cmp::max, collections::BTreeMap, sync::Arc}; use std::{cmp::max, collections::BTreeMap, sync::Arc};
@ -137,6 +137,10 @@ pub async fn create_room_route(
} }
None => services().globals.default_room_version(), None => services().globals.default_room_version(),
}; };
let rules = room_version
.rules()
.expect("Supported room version must have rules.")
.authorization;
let content = match &body.creation_content { let content = match &body.creation_content {
Some(content) => { Some(content) => {
@ -144,17 +148,7 @@ pub async fn create_room_route(
.deserialize_as::<CanonicalJsonObject>() .deserialize_as::<CanonicalJsonObject>()
.expect("Invalid creation content"); .expect("Invalid creation content");
match room_version { if !rules.use_room_create_sender {
RoomVersionId::V1
| RoomVersionId::V2
| RoomVersionId::V3
| RoomVersionId::V4
| RoomVersionId::V5
| RoomVersionId::V6
| RoomVersionId::V7
| RoomVersionId::V8
| RoomVersionId::V9
| RoomVersionId::V10 => {
content.insert( content.insert(
"creator".into(), "creator".into(),
json!(&sender_user).try_into().map_err(|_| { json!(&sender_user).try_into().map_err(|_| {
@ -162,9 +156,6 @@ pub async fn create_room_route(
})?, })?,
); );
} }
RoomVersionId::V11 => {} // V11 removed the "creator" key
_ => unreachable!("Validity of room version already checked"),
}
content.insert( content.insert(
"room_version".into(), "room_version".into(),
@ -175,19 +166,10 @@ pub async fn create_room_route(
content content
} }
None => { None => {
let content = match room_version { let content = if rules.use_room_create_sender {
RoomVersionId::V1 RoomCreateEventContent::new_v11()
| RoomVersionId::V2 } else {
| RoomVersionId::V3 RoomCreateEventContent::new_v1(sender_user.clone())
| RoomVersionId::V4
| RoomVersionId::V5
| RoomVersionId::V6
| RoomVersionId::V7
| RoomVersionId::V8
| RoomVersionId::V9
| RoomVersionId::V10 => RoomCreateEventContent::new_v1(sender_user.clone()),
RoomVersionId::V11 => RoomCreateEventContent::new_v11(),
_ => unreachable!("Validity of room version already checked"),
}; };
let mut content = serde_json::from_str::<CanonicalJsonObject>( let mut content = serde_json::from_str::<CanonicalJsonObject>(
to_raw_value(&content) to_raw_value(&content)
@ -602,6 +584,11 @@ pub async fn upgrade_room_route(
)); ));
} }
let rules = body
.new_version
.rules()
.expect("Supported room version must have rules.");
// Create a replacement room // Create a replacement room
let replacement_room = RoomId::new(services().globals.server_name()); let replacement_room = RoomId::new(services().globals.server_name());
services() services()
@ -676,17 +663,9 @@ pub async fn upgrade_room_route(
)); ));
// Send a m.room.create event containing a predecessor field and the applicable room_version // Send a m.room.create event containing a predecessor field and the applicable room_version
match body.new_version { if rules.authorization.use_room_create_sender {
RoomVersionId::V1 create_event_content.remove("creator");
| RoomVersionId::V2 } else {
| RoomVersionId::V3
| RoomVersionId::V4
| RoomVersionId::V5
| RoomVersionId::V6
| RoomVersionId::V7
| RoomVersionId::V8
| RoomVersionId::V9
| RoomVersionId::V10 => {
create_event_content.insert( create_event_content.insert(
"creator".into(), "creator".into(),
json!(&sender_user).try_into().map_err(|_| { json!(&sender_user).try_into().map_err(|_| {
@ -694,12 +673,7 @@ pub async fn upgrade_room_route(
})?, })?,
); );
} }
RoomVersionId::V11 => {
// "creator" key no longer exists in V11 rooms
create_event_content.remove("creator");
}
_ => unreachable!("Validity of room version already checked"),
}
create_event_content.insert( create_event_content.insert(
"room_version".into(), "room_version".into(),
json!(&body.new_version) json!(&body.new_version)

View file

@ -2021,16 +2021,11 @@ fn user_can_perform_restricted_join(
return Ok(false); return Ok(false);
}; };
if matches!( let rules = room_version_id
room_version_id, .rules()
RoomVersionId::V1 .expect("Supported room version must have rules.")
| RoomVersionId::V2 .authorization;
| RoomVersionId::V3 if !rules.restricted_join_rule {
| RoomVersionId::V4
| RoomVersionId::V5
| RoomVersionId::V6
| RoomVersionId::V7
) {
return Ok(false); return Ok(false);
} }

View file

@ -1693,19 +1693,14 @@ impl Service {
services().users.create(conduit_user, None)?; services().users.create(conduit_user, None)?;
let room_version = services().globals.default_room_version(); let room_version = services().globals.default_room_version();
let mut content = match room_version { let rules = room_version
RoomVersionId::V1 .rules()
| RoomVersionId::V2 .expect("Supported room version must have rules.")
| RoomVersionId::V3 .authorization;
| RoomVersionId::V4 let mut content = if rules.use_room_create_sender {
| RoomVersionId::V5 RoomCreateEventContent::new_v11()
| RoomVersionId::V6 } else {
| RoomVersionId::V7 RoomCreateEventContent::new_v1(conduit_user.to_owned())
| RoomVersionId::V8
| RoomVersionId::V9
| RoomVersionId::V10 => RoomCreateEventContent::new_v1(conduit_user.to_owned()),
RoomVersionId::V11 => RoomCreateEventContent::new_v11(),
_ => unreachable!("Validity of room version already checked"),
}; };
content.federate = true; content.federate = true;
content.predecessor = None; content.predecessor = None;

View file

@ -1,8 +1,8 @@
mod data; mod data;
pub use data::{Data, SigningKeys}; pub use data::{Data, SigningKeys};
use ruma::{ use ruma::{
serde::Base64, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedEventId, OwnedRoomAliasId, room_version_rules::RoomVersionRules, serde::Base64, MilliSecondsSinceUnixEpoch, OwnedDeviceId,
OwnedRoomId, OwnedServerName, OwnedUserId, RoomAliasId, OwnedEventId, OwnedRoomAliasId, OwnedRoomId, OwnedServerName, OwnedUserId, RoomAliasId,
}; };
use crate::api::server_server::DestinationResponse; use crate::api::server_server::DestinationResponse;
@ -427,11 +427,11 @@ impl Service {
&self, &self,
keys: BTreeMap<String, SigningKeys>, keys: BTreeMap<String, SigningKeys>,
timestamp: MilliSecondsSinceUnixEpoch, timestamp: MilliSecondsSinceUnixEpoch,
room_version_id: &RoomVersionId, rules: &RoomVersionRules,
) -> BTreeMap<String, BTreeMap<String, Base64>> { ) -> BTreeMap<String, BTreeMap<String, Base64>> {
keys.into_iter() keys.into_iter()
.filter_map(|(server, keys)| { .filter_map(|(server, keys)| {
self.filter_keys_single_server(keys, timestamp, room_version_id) self.filter_keys_single_server(keys, timestamp, rules)
.map(|keys| (server, keys)) .map(|keys| (server, keys))
}) })
.collect() .collect()
@ -443,15 +443,12 @@ impl Service {
&self, &self,
keys: SigningKeys, keys: SigningKeys,
timestamp: MilliSecondsSinceUnixEpoch, timestamp: MilliSecondsSinceUnixEpoch,
room_version_id: &RoomVersionId, rules: &RoomVersionRules,
) -> Option<BTreeMap<String, Base64>> { ) -> Option<BTreeMap<String, Base64>> {
if keys.valid_until_ts > timestamp if keys.valid_until_ts > timestamp
// valid_until_ts MUST be ignored in room versions 1, 2, 3, and 4. // valid_until_ts MUST be ignored in room versions 1, 2, 3, and 4.
// https://spec.matrix.org/v1.10/server-server-api/#get_matrixkeyv2server // https://spec.matrix.org/v1.10/server-server-api/#get_matrixkeyv2server
|| matches!(room_version_id, RoomVersionId::V1 || !rules.enforce_key_validity
| RoomVersionId::V2
| RoomVersionId::V4
| RoomVersionId::V3)
{ {
// Given that either the room version allows stale keys, or the valid_until_ts is // Given that either the room version allows stale keys, or the valid_until_ts is
// in the future, all verify_keys are valid // in the future, all verify_keys are valid

View file

@ -34,7 +34,7 @@ use ruma::{
room_version_rules::{AuthorizationRules, RoomVersionRules}, room_version_rules::{AuthorizationRules, RoomVersionRules},
state_res::{self, StateMap}, state_res::{self, StateMap},
uint, CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch, uint, CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch,
OwnedServerName, OwnedServerSigningKeyId, RoomId, RoomVersionId, ServerName, OwnedServerName, OwnedServerSigningKeyId, RoomId, ServerName,
}; };
use serde_json::value::RawValue as RawJsonValue; use serde_json::value::RawValue as RawJsonValue;
use tokio::sync::{RwLock, RwLockWriteGuard, Semaphore}; use tokio::sync::{RwLock, RwLockWriteGuard, Semaphore};
@ -373,7 +373,7 @@ impl Service {
let filtered_keys = services().globals.filter_keys_server_map( let filtered_keys = services().globals.filter_keys_server_map(
pkey_map, pkey_map,
origin_server_ts, origin_server_ts,
room_version_id, &room_version_rules,
); );
let mut val = let mut val =
@ -846,29 +846,7 @@ impl Service {
) )
.is_err() .is_err()
|| incoming_pdu.kind == TimelineEventType::RoomRedaction || incoming_pdu.kind == TimelineEventType::RoomRedaction
&& match room_version_id { && if room_version_rules.redaction.content_field_redacts {
RoomVersionId::V1
| RoomVersionId::V2
| RoomVersionId::V3
| RoomVersionId::V4
| RoomVersionId::V5
| RoomVersionId::V6
| RoomVersionId::V7
| RoomVersionId::V8
| RoomVersionId::V9
| RoomVersionId::V10 => {
if let Some(redact_id) = &incoming_pdu.redacts {
!services().rooms.state_accessor.user_can_redact(
redact_id,
&incoming_pdu.sender,
&incoming_pdu.room_id,
true,
)?
} else {
false
}
}
RoomVersionId::V11 => {
let content = serde_json::from_str::<RoomRedactionEventContent>( let content = serde_json::from_str::<RoomRedactionEventContent>(
incoming_pdu.content.get(), incoming_pdu.content.get(),
) )
@ -884,10 +862,15 @@ impl Service {
} else { } else {
false false
} }
} } else if let Some(redact_id) = &incoming_pdu.redacts {
_ => { !services().rooms.state_accessor.user_can_redact(
unreachable!("Validity of room version already checked") redact_id,
} &incoming_pdu.sender,
&incoming_pdu.room_id,
true,
)?
} else {
false
}; };
// 14. Use state resolution to find new room state // 14. Use state resolution to find new room state

View file

@ -722,10 +722,9 @@ async fn validate_and_add_event_id(
let unfiltered_keys = (*pub_key_map.read().await).clone(); let unfiltered_keys = (*pub_key_map.read().await).clone();
let keys = let keys = services()
services()
.globals .globals
.filter_keys_server_map(unfiltered_keys, origin_server_ts, room_version); .filter_keys_server_map(unfiltered_keys, origin_server_ts, rules);
if let Err(e) = ruma::signatures::verify_event(&keys, &value, rules) { if let Err(e) = ruma::signatures::verify_event(&keys, &value, rules) {
warn!("Event {} failed verification {:?} {}", event_id, pdu, e); warn!("Event {} failed verification {:?} {}", event_id, pdu, e);

View file

@ -23,7 +23,7 @@ use ruma::{
push::{Action, Ruleset, Tweak}, push::{Action, Ruleset, Tweak},
state_res::{self, Event}, state_res::{self, Event},
uint, user_id, CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch, uint, user_id, CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch,
OwnedEventId, OwnedRoomId, OwnedServerName, RoomId, RoomVersionId, ServerName, UserId, OwnedEventId, OwnedRoomId, OwnedServerName, RoomId, ServerName, UserId,
}; };
use serde::Deserialize; use serde::Deserialize;
use serde_json::value::{to_raw_value, RawValue as RawJsonValue}; use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
@ -383,29 +383,12 @@ impl Service {
match pdu.kind { match pdu.kind {
TimelineEventType::RoomRedaction => { TimelineEventType::RoomRedaction => {
let room_version_id = services().rooms.state.get_room_version(&pdu.room_id)?; let room_version_id = services().rooms.state.get_room_version(&pdu.room_id)?;
match room_version_id { let rules = room_version_id
RoomVersionId::V1 .rules()
| RoomVersionId::V2 .expect("Supported room version must have rules.")
| RoomVersionId::V3 .redaction;
| RoomVersionId::V4
| RoomVersionId::V5 if rules.content_field_redacts {
| RoomVersionId::V6
| RoomVersionId::V7
| RoomVersionId::V8
| RoomVersionId::V9
| RoomVersionId::V10 => {
if let Some(redact_id) = &pdu.redacts {
if services().rooms.state_accessor.user_can_redact(
redact_id,
&pdu.sender,
&pdu.room_id,
false,
)? {
self.redact_pdu(redact_id, pdu, shortroomid)?;
}
}
}
RoomVersionId::V11 => {
let content = let content =
serde_json::from_str::<RoomRedactionEventContent>(pdu.content.get()) serde_json::from_str::<RoomRedactionEventContent>(pdu.content.get())
.map_err(|_| { .map_err(|_| {
@ -421,8 +404,15 @@ impl Service {
self.redact_pdu(redact_id, pdu, shortroomid)?; self.redact_pdu(redact_id, pdu, shortroomid)?;
} }
} }
} else if let Some(redact_id) = &pdu.redacts {
if services().rooms.state_accessor.user_can_redact(
redact_id,
&pdu.sender,
&pdu.room_id,
false,
)? {
self.redact_pdu(redact_id, pdu, shortroomid)?;
} }
_ => unreachable!("Validity of room version already checked"),
}; };
} }
TimelineEventType::SpaceChild => { TimelineEventType::SpaceChild => {
@ -958,37 +948,15 @@ impl Service {
// If redaction event is not authorized, do not append it to the timeline // If redaction event is not authorized, do not append it to the timeline
if pdu.kind == TimelineEventType::RoomRedaction { if pdu.kind == TimelineEventType::RoomRedaction {
match services().rooms.state.get_room_version(&pdu.room_id)? { let room_version_id = services().rooms.state.get_room_version(&pdu.room_id)?;
RoomVersionId::V1 let rules = room_version_id
| RoomVersionId::V2 .rules()
| RoomVersionId::V3 .expect("Supported room version must have rules.")
| RoomVersionId::V4 .redaction;
| RoomVersionId::V5
| RoomVersionId::V6 if rules.content_field_redacts {
| RoomVersionId::V7 let content = serde_json::from_str::<RoomRedactionEventContent>(pdu.content.get())
| RoomVersionId::V8 .map_err(|_| Error::bad_database("Invalid content in redaction pdu."))?;
| RoomVersionId::V9
| RoomVersionId::V10 => {
if let Some(redact_id) = &pdu.redacts {
if !services().rooms.state_accessor.user_can_redact(
redact_id,
&pdu.sender,
&pdu.room_id,
false,
)? {
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"User cannot redact this event.",
));
}
};
}
RoomVersionId::V11 => {
let content =
serde_json::from_str::<RoomRedactionEventContent>(pdu.content.get())
.map_err(|_| {
Error::bad_database("Invalid content in redaction pdu.")
})?;
if let Some(redact_id) = &content.redacts { if let Some(redact_id) = &content.redacts {
if !services().rooms.state_accessor.user_can_redact( if !services().rooms.state_accessor.user_can_redact(
@ -1003,11 +971,16 @@ impl Service {
)); ));
} }
} }
} } else if let Some(redact_id) = &pdu.redacts {
_ => { if !services().rooms.state_accessor.user_can_redact(
redact_id,
&pdu.sender,
&pdu.room_id,
false,
)? {
return Err(Error::BadRequest( return Err(Error::BadRequest(
ErrorKind::UnsupportedRoomVersion, ErrorKind::forbidden(),
"Unsupported room version", "User cannot redact this event.",
)); ));
} }
} }