largely stop using RoomCreateEventContent

This became a problem because  #foundation-office:matrix.org has a
malformed create event with its `predecessor` set to a string instead of
a map.

The solution to this is, unfortunately, to do more shotgun parsing to
extract only the desired fields rather than trying to parse the entire
content every time. To prevent this kind of problem from happening
again, `RoomCreateEventContent` must only be used for creating new PDUs,
existing PDUs must be shotgun-parsed.
This commit is contained in:
Charles Hall 2024-11-05 11:34:24 -08:00
parent 9d0cf428a5
commit 51b30d9ba3
No known key found for this signature in database
GPG key ID: 7B8E0645816E07CF
4 changed files with 50 additions and 51 deletions

View file

@ -15,7 +15,6 @@ use ruma::{
room::{
avatar::RoomAvatarEventContent,
canonical_alias::RoomCanonicalAliasEventContent,
create::RoomCreateEventContent,
guest_access::{GuestAccess, RoomGuestAccessEventContent},
history_visibility::{
HistoryVisibility, RoomHistoryVisibilityEventContent,
@ -29,7 +28,9 @@ use ruma::{
};
use tracing::{error, info, warn};
use crate::{services, Ar, Error, Ra, Result};
use crate::{
service::rooms::state::ExtractType, services, Ar, Error, Ra, Result,
};
/// # `POST /_matrix/client/r0/publicRooms`
///
@ -382,19 +383,8 @@ fn room_id_to_chunk(room_id: ruma::OwnedRoomId) -> Result<PublicRoomsChunk> {
Error::bad_database("Missing room join rule event for room.")
})?;
let room_type = services()
.rooms
.state_accessor
.room_state_get(&room_id, &StateEventType::RoomCreate, "")?
.map(|s| {
serde_json::from_str::<RoomCreateEventContent>(s.content.get())
.map_err(|error| {
error!(%error, "Invalid room create event in database");
Error::BadDatabase("Invalid room create event in database.")
})
})
.transpose()?
.and_then(|e| e.room_type);
let room_type =
services().rooms.state.get_create_content::<ExtractType>(&room_id)?;
Ok(PublicRoomsChunk {
canonical_alias,

View file

@ -13,7 +13,6 @@ use ruma::{
room::{
avatar::RoomAvatarEventContent,
canonical_alias::RoomCanonicalAliasEventContent,
create::RoomCreateEventContent,
guest_access::{GuestAccess, RoomGuestAccessEventContent},
history_visibility::{
HistoryVisibility, RoomHistoryVisibilityEventContent,
@ -32,6 +31,7 @@ use ruma::{
use tokio::sync::Mutex;
use tracing::{debug, error, warn};
use super::state::ExtractType;
use crate::{services, Error, PduEvent, Result};
pub(crate) enum CachedJoinRule {
@ -496,27 +496,11 @@ impl Service {
Self::translate_joinrule(&join_rule)?
},
room_type: services()
.rooms
.state_accessor
.room_state_get(room_id, &StateEventType::RoomCreate, "")?
.map(|s| {
serde_json::from_str::<RoomCreateEventContent>(
s.content.get(),
)
.map_err(|error| {
error!(
%error,
event_id = %s.event_id,
"Invalid room create event",
);
Error::BadDatabase(
"Invalid room create event in database.",
)
})
})
.transpose()?
.and_then(|e| e.room_type),
.state
.get_create_content::<ExtractType>(room_id)?,
children_state: children
.into_iter()
.map(|pdu| pdu.to_stripped_spacechild_state_event())

View file

@ -7,9 +7,10 @@ use std::{
use ruma::{
api::client::error::ErrorKind,
events::{
room::member::MembershipState, AnyStrippedStateEvent, StateEventType,
TimelineEventType,
room::{create::PreviousRoom, member::MembershipState},
AnyStrippedStateEvent, StateEventType, TimelineEventType,
},
room::RoomType,
serde::Raw,
state_res::{self, StateMap},
EventId, OwnedEventId, OwnedRoomId, RoomId, RoomVersionId, UserId,
@ -51,6 +52,34 @@ impl ExtractCreateContent for ExtractVersion {
}
}
/// Extract the `type` from an `m.room.create` event
#[derive(Deserialize)]
pub(crate) struct ExtractType {
#[serde(rename = "type")]
kind: Option<RoomType>,
}
impl ExtractCreateContent for ExtractType {
type Extract = Option<RoomType>;
fn extract(self) -> Self::Extract {
self.kind
}
}
#[derive(Deserialize)]
pub(crate) struct ExtractPredecessor {
predecessor: Option<PreviousRoom>,
}
impl ExtractCreateContent for ExtractPredecessor {
type Extract = Option<PreviousRoom>;
fn extract(self) -> Self::Extract {
self.predecessor
}
}
pub(crate) struct Service {
pub(crate) db: &'static dyn Data,
}

View file

@ -5,10 +5,9 @@ use std::{
use ruma::{
events::{
ignored_user_list::IgnoredUserListEvent,
room::{create::RoomCreateEventContent, member::MembershipState},
ignored_user_list::IgnoredUserListEvent, room::member::MembershipState,
AnyStrippedStateEvent, AnySyncStateEvent, GlobalAccountDataEventType,
RoomAccountDataEventType, StateEventType,
RoomAccountDataEventType,
},
serde::Raw,
OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, ServerName, UserId,
@ -25,6 +24,8 @@ mod data;
pub(crate) use data::Data;
use super::state::ExtractPredecessor;
pub(crate) struct Service {
db: &'static dyn Data,
appservice_in_room_cache:
@ -72,18 +73,13 @@ impl Service {
// Check if the room has a predecessor
if let Some(predecessor) = services()
.rooms
.state_accessor
.room_state_get(
room_id,
&StateEventType::RoomCreate,
"",
)?
.and_then(|create| {
serde_json::from_str(create.content.get()).ok()
})
.and_then(|content: RoomCreateEventContent| {
content.predecessor
.state
.get_create_content::<ExtractPredecessor>(room_id)
.inspect_err(|error| {
warn!(%error, "Failed to get room predecessor");
})
.ok()
.flatten()
{
self.copy_upgraded_account_data(
user_id,