events: Fix deserialization without relation
This commit is contained in:
parent
0feb39298a
commit
dc18b12506
@ -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:
|
||||
|
||||
|
@ -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>>,
|
||||
}
|
||||
|
||||
|
@ -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>>,
|
||||
}
|
||||
|
||||
|
@ -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>>,
|
||||
}
|
||||
|
||||
|
@ -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>>,
|
||||
}
|
||||
|
||||
|
@ -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>>,
|
||||
}
|
||||
|
||||
|
@ -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>>,
|
||||
}
|
||||
|
||||
|
@ -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>>,
|
||||
}
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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 })
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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>>,
|
||||
}
|
||||
|
||||
|
@ -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>>,
|
||||
}
|
||||
|
||||
|
@ -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]
|
||||
|
Loading…
x
Reference in New Issue
Block a user