events: Fix deserialization without relation

This commit is contained in:
Kévin Commaille 2022-11-25 18:10:50 +01:00
parent 0feb39298a
commit dc18b12506
No known key found for this signature in database
GPG Key ID: DD507DAE96E8245C
16 changed files with 141 additions and 103 deletions

View File

@ -6,6 +6,8 @@ Bug fixes:
during creation of the rich reply
* Don't include sensitive information in `Debug`-format of types from the `events::key`
and `events::secret` modules
* Fix deserialization of `RoomMessageEventContent` and `RoomEncryptedEventContent` when there
is no relation
Breaking changes:

View File

@ -39,7 +39,11 @@ pub struct AudioEventContent {
pub audio: AudioContent,
/// Information about related messages.
#[serde(flatten, skip_serializing_if = "Option::is_none")]
#[serde(
flatten,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::events::room::message::relation_serde::deserialize_relation"
)]
pub relates_to: Option<Relation<AudioEventContentWithoutRelation>>,
}

View File

@ -23,7 +23,11 @@ pub struct EmoteEventContent {
pub message: MessageContent,
/// Information about related messages.
#[serde(flatten, skip_serializing_if = "Option::is_none")]
#[serde(
flatten,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::events::room::message::relation_serde::deserialize_relation"
)]
pub relates_to: Option<Relation<EmoteEventContentWithoutRelation>>,
}

View File

@ -34,7 +34,11 @@ pub struct FileEventContent {
pub file: FileContent,
/// Information about related messages.
#[serde(flatten, skip_serializing_if = "Option::is_none")]
#[serde(
flatten,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::events::room::message::relation_serde::deserialize_relation"
)]
pub relates_to: Option<Relation<FileEventContentWithoutRelation>>,
}

View File

@ -50,7 +50,11 @@ pub struct ImageEventContent {
pub caption: Option<MessageContent>,
/// Information about related messages.
#[serde(flatten, skip_serializing_if = "Option::is_none")]
#[serde(
flatten,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::events::room::message::relation_serde::deserialize_relation"
)]
pub relates_to: Option<Relation<ImageEventContentWithoutRelation>>,
}

View File

@ -39,7 +39,11 @@ pub struct LocationEventContent {
pub ts: Option<MilliSecondsSinceUnixEpoch>,
/// Information about related messages.
#[serde(flatten, skip_serializing_if = "Option::is_none")]
#[serde(
flatten,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::events::room::message::relation_serde::deserialize_relation"
)]
pub relates_to: Option<Relation<LocationEventContentWithoutRelation>>,
}

View File

@ -72,7 +72,11 @@ pub struct MessageEventContent {
pub message: MessageContent,
/// Information about related messages.
#[serde(flatten, skip_serializing_if = "Option::is_none")]
#[serde(
flatten,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::events::room::message::relation_serde::deserialize_relation"
)]
pub relates_to: Option<Relation<MessageEventContentWithoutRelation>>,
}

View File

@ -23,7 +23,11 @@ pub struct NoticeEventContent {
pub message: MessageContent,
/// Information about related messages.
#[serde(flatten, skip_serializing_if = "Option::is_none")]
#[serde(
flatten,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::events::room::message::relation_serde::deserialize_relation"
)]
pub relates_to: Option<Relation<NoticeEventContentWithoutRelation>>,
}

View File

@ -23,7 +23,11 @@ pub struct RoomEncryptedEventContent {
pub scheme: EncryptedEventScheme,
/// Information about related events.
#[serde(flatten, skip_serializing_if = "Option::is_none")]
#[serde(
flatten,
skip_serializing_if = "Option::is_none",
deserialize_with = "relation_serde::deserialize_relation"
)]
pub relates_to: Option<Relation>,
}
@ -400,6 +404,8 @@ mod tests {
assert_eq!(c.ciphertext.len(), 1);
assert_eq!(c.ciphertext["test_curve_key"].body, "encrypted_body");
assert_eq!(c.ciphertext["test_curve_key"].message_type, uint!(1));
assert_matches!(content.relates_to, None);
}
#[test]

View File

@ -5,8 +5,7 @@ use super::Annotation;
use super::{InReplyTo, Reference, Relation, Replacement, Thread};
use crate::OwnedEventId;
impl<'de> Deserialize<'de> for Relation {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
pub(super) fn deserialize_relation<'de, D>(deserializer: D) -> Result<Option<Relation>, D::Error>
where
D: Deserializer<'de>,
{
@ -21,12 +20,12 @@ impl<'de> Deserialize<'de> for Relation {
.relates_to
.in_reply_to
.ok_or_else(|| serde::de::Error::missing_field("m.in_reply_to"))?;
return Ok(Relation::Thread(Thread { event_id, in_reply_to, is_falling_back }));
return Ok(Some(Relation::Thread(Thread { event_id, in_reply_to, is_falling_back })));
}
let rel = if let Some(in_reply_to) = ev.relates_to.in_reply_to {
Relation::Reply { in_reply_to }
} else if let Some(relation) = ev.relates_to.relation {
match relation {
Some(Relation::Reply { in_reply_to })
} else {
ev.relates_to.relation.map(|relation| match relation {
#[cfg(feature = "unstable-msc2677")]
RelationJsonRepr::Annotation(a) => Relation::Annotation(a),
RelationJsonRepr::Reference(r) => Relation::Reference(r),
@ -39,14 +38,11 @@ impl<'de> Deserialize<'de> for Relation {
// FIXME: Maybe we should log this, though at this point we don't even have
// access to the rel_type of the unknown relation.
RelationJsonRepr::Unknown => Relation::_Custom,
}
} else {
Relation::_Custom
})
};
Ok(rel)
}
}
impl Serialize for Relation {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

View File

@ -21,7 +21,7 @@ mod image;
mod key_verification_request;
mod location;
mod notice;
mod relation_serde;
pub(crate) mod relation_serde;
mod reply;
pub mod sanitize;
mod server_notice;

View File

@ -5,13 +5,13 @@ use serde_json::value::RawValue as RawJsonValue;
#[cfg(feature = "unstable-msc3552")]
use super::ImageMessageEventContent;
use super::{relation_serde::deserialize_relation, MessageType, RoomMessageEventContent};
#[cfg(feature = "unstable-msc3246")]
use super::{AudioInfo, AudioMessageEventContent};
#[cfg(feature = "unstable-msc3551")]
use super::{FileInfo, FileMessageEventContent};
#[cfg(feature = "unstable-msc3488")]
use super::{LocationInfo, LocationMessageEventContent};
use super::{MessageType, Relation, RoomMessageEventContent};
#[cfg(feature = "unstable-msc3553")]
use super::{VideoInfo, VideoMessageEventContent};
#[cfg(feature = "unstable-msc3246")]
@ -47,8 +47,7 @@ impl<'de> Deserialize<'de> for RoomMessageEventContent {
{
let json = Box::<RawJsonValue>::deserialize(deserializer)?;
let mut deserializer = serde_json::Deserializer::from_str(json.get());
let relates_to = Option::<Relation<MessageType>>::deserialize(&mut deserializer)
.map_err(de::Error::custom)?;
let relates_to = deserialize_relation(&mut deserializer).map_err(de::Error::custom)?;
Ok(Self { msgtype: from_raw_json_value(&json)?, relates_to })
}

View File

@ -3,13 +3,12 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
use super::{InReplyTo, Relation, Replacement, Thread};
use crate::OwnedEventId;
impl<'de, C> Deserialize<'de> for Relation<C>
where
C: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
pub(crate) fn deserialize_relation<'de, D, C>(
deserializer: D,
) -> Result<Option<Relation<C>>, D::Error>
where
D: Deserializer<'de>,
C: Deserialize<'de>,
{
let ev = EventWithRelatesToJsonRepr::deserialize(deserializer)?;
@ -22,33 +21,32 @@ where
.relates_to
.in_reply_to
.ok_or_else(|| serde::de::Error::missing_field("m.in_reply_to"))?;
return Ok(Relation::Thread(Thread { event_id, in_reply_to, is_falling_back }));
return Ok(Some(Relation::Thread(Thread { event_id, in_reply_to, is_falling_back })));
}
let rel = if let Some(in_reply_to) = ev.relates_to.in_reply_to {
Relation::Reply { in_reply_to }
Some(Relation::Reply { in_reply_to })
} else if let Some(relation) = ev.relates_to.relation {
match relation {
RelationJsonRepr::Replacement(ReplacementJsonRepr { event_id }) => {
let new_content = ev
.new_content
.ok_or_else(|| serde::de::Error::missing_field("m.new_content"))?;
Relation::Replacement(Replacement { event_id, new_content })
Some(Relation::Replacement(Replacement { event_id, new_content }))
}
// FIXME: Maybe we should log this, though at this point we don't even have
// access to the rel_type of the unknown relation.
RelationJsonRepr::Unknown => Relation::_Custom,
RelationJsonRepr::Unknown => Some(Relation::_Custom),
RelationJsonRepr::ThreadStable(_) | RelationJsonRepr::ThreadUnstable(_) => {
unreachable!()
}
}
} else {
Relation::_Custom
None
};
Ok(rel)
}
}
impl<C> Serialize for Relation<C>
where

View File

@ -49,7 +49,11 @@ pub struct VideoEventContent {
pub caption: Option<MessageContent>,
/// Information about related messages.
#[serde(flatten, skip_serializing_if = "Option::is_none")]
#[serde(
flatten,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::events::room::message::relation_serde::deserialize_relation"
)]
pub relates_to: Option<Relation<VideoEventContentWithoutRelation>>,
}

View File

@ -37,7 +37,11 @@ pub struct VoiceEventContent {
pub voice: VoiceContent,
/// Information about related messages.
#[serde(flatten, skip_serializing_if = "Option::is_none")]
#[serde(
flatten,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::events::room::message::relation_serde::deserialize_relation"
)]
pub relates_to: Option<Relation<VoiceEventContentWithoutRelation>>,
}

View File

@ -367,18 +367,19 @@ fn verification_request_deserialization() {
]
});
let content = from_json_value::<RoomMessageEventContent>(json_data).unwrap();
let verification = assert_matches!(
from_json_value::<RoomMessageEventContent>(json_data),
Ok(RoomMessageEventContent {
msgtype: MessageType::VerificationRequest(verification),
..
}) => verification
content.msgtype,
MessageType::VerificationRequest(verification) => verification
);
assert_eq!(verification.body, "@example:localhost is requesting to verify your key, ...");
assert_eq!(verification.to, user_id);
assert_eq!(verification.from_device, device_id);
assert_eq!(verification.methods.len(), 3);
assert!(verification.methods.contains(&VerificationMethod::SasV1));
assert_matches!(content.relates_to, None);
}
#[test]
@ -413,17 +414,17 @@ fn content_deserialization() {
"url": "mxc://example.org/ffed755USFFxlgbQYZGtryd"
});
let content = from_json_value::<RoomMessageEventContent>(json_data).unwrap();
let audio = assert_matches!(
from_json_value::<RoomMessageEventContent>(json_data),
Ok(RoomMessageEventContent {
msgtype: MessageType::Audio(audio),
..
}) => audio
content.msgtype,
MessageType::Audio(audio) => audio
);
assert_eq!(audio.body, "test");
assert_matches!(audio.info, None);
let url = assert_matches!(audio.source, MediaSource::Plain(url) => url);
assert_eq!(url, "mxc://example.org/ffed755USFFxlgbQYZGtryd");
assert_matches!(content.relates_to, None);
}
#[test]