mirror of
https://gitlab.computer.surgery/matrix/grapevine.git
synced 2025-12-18 08:11:24 +01:00
fix room version comparisons
Fixes a set of bugs introduced by00b77144c1, where we replaced explicit `RoomVersionId` matches with `version < V11` comparisons. The `Ord` impl on `RoomVersionId` does not work like that, and is in fact a lexicographic string comparison[1]. The most visible effect of these bugs is that incoming redaction events would sometimes be ignored. Instead of reverting to the explicit matches, which were quite verbose, I implemented a `RoomVersion` struct that has flags for each property that we care about. This is similar to the approach used by ruma[2] and synapse[3]. [1]:7cfa3be0c6/crates/ruma-common/src/identifiers/room_version_id.rs (L136)[2]:7cfa3be0c6/crates/ruma-state-res/src/room_version.rs[3]:c856ae4724/synapse/api/room_versions.py
This commit is contained in:
parent
ad37eae869
commit
9add9a1e96
8 changed files with 237 additions and 199 deletions
|
|
@ -34,7 +34,7 @@ use super::pdu::PduBuilder;
|
|||
use crate::{
|
||||
api::client_server::{leave_all_rooms, AUTO_GEN_PASSWORD_LENGTH},
|
||||
services,
|
||||
utils::{self, dbg_truncate_str},
|
||||
utils::{self, dbg_truncate_str, room_version::RoomVersion},
|
||||
Error, PduEvent, Result,
|
||||
};
|
||||
|
||||
|
|
@ -1301,23 +1301,18 @@ impl Service {
|
|||
|
||||
services().users.create(&services().globals.admin_bot_user_id, None)?;
|
||||
|
||||
let room_version = services().globals.default_room_version();
|
||||
let mut content = match &room_version {
|
||||
room_version if *room_version < RoomVersionId::V11 => {
|
||||
RoomCreateEventContent::new_v1(
|
||||
services().globals.admin_bot_user_id.clone(),
|
||||
)
|
||||
}
|
||||
RoomVersionId::V11 => RoomCreateEventContent::new_v11(),
|
||||
_ => {
|
||||
return Err(Error::BadServerResponse(
|
||||
"Unsupported room version.",
|
||||
))
|
||||
}
|
||||
let room_version_id = services().globals.default_room_version();
|
||||
let room_version = RoomVersion::try_from(&room_version_id)?;
|
||||
let mut content = if room_version.create_event_creator_prop {
|
||||
RoomCreateEventContent::new_v1(
|
||||
services().globals.admin_bot_user_id.clone(),
|
||||
)
|
||||
} else {
|
||||
RoomCreateEventContent::new_v11()
|
||||
};
|
||||
content.federate = true;
|
||||
content.predecessor = None;
|
||||
content.room_version = room_version;
|
||||
content.room_version = room_version_id;
|
||||
|
||||
// 1. The room create event
|
||||
services()
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use ruma::{
|
|||
StateEventType, TimelineEventType,
|
||||
},
|
||||
int,
|
||||
state_res::{self, RoomVersion, StateMap},
|
||||
state_res::{self, StateMap},
|
||||
uint, CanonicalJsonObject, CanonicalJsonValue, EventId,
|
||||
MilliSecondsSinceUnixEpoch, OwnedServerName, OwnedServerSigningKeyId,
|
||||
RoomId, RoomVersionId, ServerName,
|
||||
|
|
@ -44,7 +44,7 @@ use super::{
|
|||
use crate::{
|
||||
service::{globals::SigningKeys, pdu},
|
||||
services,
|
||||
utils::debug_slice_truncated,
|
||||
utils::{debug_slice_truncated, room_version::RoomVersion},
|
||||
Error, PduEvent, Result,
|
||||
};
|
||||
|
||||
|
|
@ -339,8 +339,10 @@ impl Service {
|
|||
)?;
|
||||
|
||||
let room_version_id = &create_event_content.room_version;
|
||||
let room_version = RoomVersion::new(room_version_id)
|
||||
.expect("room version is supported");
|
||||
let ruma_room_version =
|
||||
state_res::RoomVersion::new(room_version_id).map_err(|_| {
|
||||
Error::UnsupportedRoomVersion(room_version_id.clone())
|
||||
})?;
|
||||
|
||||
// TODO: For RoomVersion6 we must check that Raw<..> is canonical,
|
||||
// do we anywhere?
|
||||
|
|
@ -527,7 +529,7 @@ impl Service {
|
|||
}
|
||||
|
||||
if !state_res::event_auth::auth_check(
|
||||
&room_version,
|
||||
&ruma_room_version,
|
||||
&incoming_pdu,
|
||||
// TODO: third party invite
|
||||
None::<PduEvent>,
|
||||
|
|
@ -601,8 +603,11 @@ impl Service {
|
|||
)?;
|
||||
|
||||
let room_version_id = &create_event_content.room_version;
|
||||
let room_version = RoomVersion::new(room_version_id)
|
||||
.expect("room version is supported");
|
||||
let room_version = RoomVersion::try_from(room_version_id)?;
|
||||
let ruma_room_version = state_res::RoomVersion::new(room_version_id)
|
||||
.map_err(|_| {
|
||||
Error::UnsupportedRoomVersion(room_version_id.clone())
|
||||
})?;
|
||||
|
||||
// 10. Fetch missing state and auth chain events by calling /state_ids
|
||||
// at backwards extremities doing all the checks in this list
|
||||
|
|
@ -885,7 +890,7 @@ impl Service {
|
|||
// 11. Check the auth of the event passes based on the state of the
|
||||
// event
|
||||
let check_result = state_res::event_auth::auth_check(
|
||||
&room_version,
|
||||
&ruma_room_version,
|
||||
&incoming_pdu,
|
||||
// TODO: third party invite
|
||||
None::<PduEvent>,
|
||||
|
|
@ -930,7 +935,7 @@ impl Service {
|
|||
)?;
|
||||
|
||||
let soft_fail = !state_res::event_auth::auth_check(
|
||||
&room_version,
|
||||
&ruma_room_version,
|
||||
&incoming_pdu,
|
||||
None::<PduEvent>,
|
||||
|k, s| auth_events.get(&(k.clone(), s.to_owned())),
|
||||
|
|
@ -939,45 +944,34 @@ impl Service {
|
|||
Error::BadRequest(ErrorKind::InvalidParam, "Auth check failed.")
|
||||
})? || incoming_pdu.kind
|
||||
== TimelineEventType::RoomRedaction
|
||||
&& match room_version_id {
|
||||
room_version if *room_version < RoomVersionId::V11 => {
|
||||
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,
|
||||
>(
|
||||
incoming_pdu.content.get()
|
||||
&& if room_version.redaction_event_redacts_in_content {
|
||||
let content =
|
||||
serde_json::from_str::<RoomRedactionEventContent>(
|
||||
incoming_pdu.content.get(),
|
||||
)
|
||||
.map_err(|_| {
|
||||
Error::bad_database("Invalid content in redaction pdu.")
|
||||
})?;
|
||||
|
||||
if let Some(redact_id) = &content.redacts {
|
||||
!services().rooms.state_accessor.user_can_redact(
|
||||
redact_id,
|
||||
&incoming_pdu.sender,
|
||||
&incoming_pdu.room_id,
|
||||
true,
|
||||
)?
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::BadServerResponse(
|
||||
"Unsupported room version.",
|
||||
))
|
||||
if let Some(redact_id) = &content.redacts {
|
||||
!services().rooms.state_accessor.user_can_redact(
|
||||
redact_id,
|
||||
&incoming_pdu.sender,
|
||||
&incoming_pdu.room_id,
|
||||
true,
|
||||
)?
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else 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
|
||||
};
|
||||
|
||||
// 13. Use state resolution to find new room state
|
||||
|
|
|
|||
|
|
@ -21,10 +21,9 @@ use ruma::{
|
|||
GlobalAccountDataEventType, StateEventType, TimelineEventType,
|
||||
},
|
||||
push::{Action, Ruleset, Tweak},
|
||||
state_res::{self, Event, RoomVersion},
|
||||
state_res::{self, Event},
|
||||
uint, user_id, CanonicalJsonObject, CanonicalJsonValue, EventId,
|
||||
OwnedEventId, OwnedRoomId, OwnedServerName, RoomId, RoomVersionId,
|
||||
ServerName, UserId,
|
||||
OwnedEventId, OwnedRoomId, OwnedServerName, RoomId, ServerName, UserId,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
|
||||
|
|
@ -40,7 +39,7 @@ use crate::{
|
|||
pdu::{EventHash, PduBuilder},
|
||||
},
|
||||
services,
|
||||
utils::{self, on_demand_hashmap::KeyToken},
|
||||
utils::{self, on_demand_hashmap::KeyToken, room_version::RoomVersion},
|
||||
Error, PduEvent, Result,
|
||||
};
|
||||
|
||||
|
|
@ -410,44 +409,32 @@ impl Service {
|
|||
TimelineEventType::RoomRedaction => {
|
||||
let room_version_id =
|
||||
services().rooms.state.get_room_version(&pdu.room_id)?;
|
||||
match &room_version_id {
|
||||
room_version if *room_version < RoomVersionId::V11 => {
|
||||
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)?;
|
||||
}
|
||||
let room_version = RoomVersion::try_from(&room_version_id)?;
|
||||
if room_version.redaction_event_redacts_in_content {
|
||||
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 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 =
|
||||
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 services().rooms.state_accessor.user_can_redact(
|
||||
redact_id,
|
||||
&pdu.sender,
|
||||
&pdu.room_id,
|
||||
false,
|
||||
)? {
|
||||
self.redact_pdu(redact_id, pdu, shortroomid)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::BadServerResponse(
|
||||
"Unsupported room version.",
|
||||
));
|
||||
} 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)?;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -737,8 +724,10 @@ impl Service {
|
|||
}
|
||||
})?;
|
||||
|
||||
let room_version = RoomVersion::new(&room_version_id)
|
||||
.expect("room version is supported");
|
||||
let ruma_room_version = state_res::RoomVersion::new(&room_version_id)
|
||||
.map_err(|_| {
|
||||
Error::UnsupportedRoomVersion(room_version_id.clone())
|
||||
})?;
|
||||
|
||||
let auth_events = services().rooms.state.get_auth_events(
|
||||
room_id,
|
||||
|
|
@ -810,7 +799,7 @@ impl Service {
|
|||
};
|
||||
|
||||
let auth_check = state_res::auth_check(
|
||||
&room_version,
|
||||
&ruma_room_version,
|
||||
&pdu,
|
||||
// TODO: third_party_invite
|
||||
None::<PduEvent>,
|
||||
|
|
@ -1008,57 +997,41 @@ impl Service {
|
|||
// If redaction event is not authorized, do not append it to the
|
||||
// timeline
|
||||
if pdu.kind == TimelineEventType::RoomRedaction {
|
||||
match services().rooms.state.get_room_version(&pdu.room_id)? {
|
||||
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) = &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())
|
||||
let room_version_id =
|
||||
services().rooms.state.get_room_version(&pdu.room_id)?;
|
||||
let room_version = RoomVersion::try_from(&room_version_id)?;
|
||||
if room_version.redaction_event_redacts_in_content {
|
||||
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 !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.",
|
||||
));
|
||||
}
|
||||
if let Some(redact_id) = &content.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.",
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
} 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(
|
||||
ErrorKind::UnsupportedRoomVersion,
|
||||
"Unsupported room version",
|
||||
ErrorKind::forbidden(),
|
||||
"User cannot redact this event.",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue