Fix redacted aliases event deserialization
This commit is contained in:
		
							parent
							
								
									3f951e931b
								
							
						
					
					
						commit
						6f69a6fe76
					
				| @ -151,11 +151,18 @@ fn expand_deserialize_event( | |||||||
|         if name == "content" { |         if name == "content" { | ||||||
|             if is_generic && ident.to_string().contains("Redacted") { |             if is_generic && ident.to_string().contains("Redacted") { | ||||||
|                 quote! { |                 quote! { | ||||||
|                     let content = if !C::has_deserialize_fields() { |                     let content = match C::has_deserialize_fields() { | ||||||
|                         C::empty(&event_type).map_err(A::Error::custom)? |                         ::ruma_events::HasDeserializeFields::False => { | ||||||
|                     } else { |                             C::empty(&event_type).map_err(A::Error::custom)? | ||||||
|                         let json = content.ok_or_else(|| ::serde::de::Error::missing_field("content"))?; |                         }, | ||||||
|                         C::from_parts(&event_type, json).map_err(A::Error::custom)? |                         ::ruma_events::HasDeserializeFields::True => { | ||||||
|  |                             let json = content.ok_or_else(|| ::serde::de::Error::missing_field("content"))?; | ||||||
|  |                             C::from_parts(&event_type, json).map_err(A::Error::custom)? | ||||||
|  |                         }, | ||||||
|  |                         ::ruma_events::HasDeserializeFields::Optional => { | ||||||
|  |                             let json = content.unwrap_or(::serde_json::value::RawValue::from_string("{}".to_string()).unwrap()); | ||||||
|  |                             C::from_parts(&event_type, json).map_err(A::Error::custom)? | ||||||
|  |                         }, | ||||||
|                     }; |                     }; | ||||||
|                 } |                 } | ||||||
|             } else if is_generic { |             } else if is_generic { | ||||||
|  | |||||||
| @ -135,7 +135,13 @@ pub fn expand_event_content(input: &DeriveInput, emit_redacted: bool) -> syn::Re | |||||||
|             ) |             ) | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         let has_fields = if kept_redacted_fields.is_empty() { |         let has_deserialize_fields = if kept_redacted_fields.is_empty() { | ||||||
|  |             quote! { ::ruma_events::HasDeserializeFields::False } | ||||||
|  |         } else { | ||||||
|  |             quote! { ::ruma_events::HasDeserializeFields::True } | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         let has_serialize_fields = if kept_redacted_fields.is_empty() { | ||||||
|             quote! { false } |             quote! { false } | ||||||
|         } else { |         } else { | ||||||
|             quote! { true } |             quote! { true } | ||||||
| @ -170,11 +176,11 @@ pub fn expand_event_content(input: &DeriveInput, emit_redacted: bool) -> syn::Re | |||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 fn has_serialize_fields(&self) -> bool { |                 fn has_serialize_fields(&self) -> bool { | ||||||
|                     #has_fields |                     #has_serialize_fields | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 fn has_deserialize_fields() -> bool { |                 fn has_deserialize_fields() -> ::ruma_events::HasDeserializeFields { | ||||||
|                     #has_fields |                     #has_deserialize_fields | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -4,9 +4,9 @@ use serde::Serialize; | |||||||
| use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue}; | use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue}; | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     BasicEventContent, EphemeralRoomEventContent, EventContent, MessageEventContent, |     BasicEventContent, EphemeralRoomEventContent, EventContent, HasDeserializeFields, | ||||||
|     RedactedEventContent, RedactedMessageEventContent, RedactedStateEventContent, RoomEventContent, |     MessageEventContent, RedactedEventContent, RedactedMessageEventContent, | ||||||
|     StateEventContent, |     RedactedStateEventContent, RoomEventContent, StateEventContent, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// A custom event's type and `content` JSON object.
 | /// A custom event's type and `content` JSON object.
 | ||||||
| @ -83,8 +83,8 @@ impl RedactedEventContent for RedactedCustomEventContent { | |||||||
|         false |         false | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn has_deserialize_fields() -> bool { |     fn has_deserialize_fields() -> HasDeserializeFields { | ||||||
|         false |         HasDeserializeFields::False | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -243,20 +243,27 @@ pub trait StateEventContent: RoomEventContent {} | |||||||
| 
 | 
 | ||||||
| /// The base trait that all redacted event content types implement.
 | /// The base trait that all redacted event content types implement.
 | ||||||
| ///
 | ///
 | ||||||
| /// Implementing this trait allows content types to be serialized as well as deserialized.
 | /// This trait's associated functions and methods should not be used to build
 | ||||||
|  | /// redacted events, prefer the `redact` method on `AnyStateEvent` and
 | ||||||
|  | /// `AnyMessageEvent` and their "sync" and "stripped" counterparts. The
 | ||||||
|  | /// `RedactedEventContent` trait is an implementation detail, ruma makes no
 | ||||||
|  | /// API guarantees.
 | ||||||
| pub trait RedactedEventContent: EventContent { | pub trait RedactedEventContent: EventContent { | ||||||
|     /// Constructs the redacted event content.
 |     /// Constructs the redacted event content.
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// If called for anything but "empty" redacted content this will error.
 |     /// If called for anything but "empty" redacted content this will error.
 | ||||||
|  |     #[doc(hidden)] | ||||||
|     fn empty(_event_type: &str) -> Result<Self, serde_json::Error> { |     fn empty(_event_type: &str) -> Result<Self, serde_json::Error> { | ||||||
|         Err(serde::de::Error::custom("this event is not redacted")) |         Err(serde::de::Error::custom("this event is not redacted")) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Determines if the redacted event content needs to serialize fields.
 |     /// Determines if the redacted event content needs to serialize fields.
 | ||||||
|  |     #[doc(hidden)] | ||||||
|     fn has_serialize_fields(&self) -> bool; |     fn has_serialize_fields(&self) -> bool; | ||||||
| 
 | 
 | ||||||
|     /// Determines if the redacted event content needs to deserialize fields.
 |     /// Determines if the redacted event content needs to deserialize fields.
 | ||||||
|     fn has_deserialize_fields() -> bool; |     #[doc(hidden)] | ||||||
|  |     fn has_deserialize_fields() -> HasDeserializeFields; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Marker trait for the content of a redacted message event.
 | /// Marker trait for the content of a redacted message event.
 | ||||||
| @ -265,6 +272,21 @@ pub trait RedactedMessageEventContent: RedactedEventContent {} | |||||||
| /// Marker trait for the content of a redacted state event.
 | /// Marker trait for the content of a redacted state event.
 | ||||||
| pub trait RedactedStateEventContent: RedactedEventContent {} | pub trait RedactedStateEventContent: RedactedEventContent {} | ||||||
| 
 | 
 | ||||||
|  | /// `HasDeserializeFields` is used in the code generated by the `Event` derive
 | ||||||
|  | /// to aid in deserializing redacted events.
 | ||||||
|  | #[doc(hidden)] | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub enum HasDeserializeFields { | ||||||
|  |     /// Deserialize the event's content, failing if invalid.
 | ||||||
|  |     True, | ||||||
|  |     /// Return the redacted version of this event's content.
 | ||||||
|  |     False, | ||||||
|  |     /// `Optional` is used for `RedactedAliasesEventContent` since it has
 | ||||||
|  |     /// an empty version and one with content left after redaction that
 | ||||||
|  |     /// must be supported together.
 | ||||||
|  |     Optional, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// Helper struct to determine if the event has been redacted.
 | /// Helper struct to determine if the event has been redacted.
 | ||||||
| #[doc(hidden)] | #[doc(hidden)] | ||||||
| #[derive(Debug, Deserialize)] | #[derive(Debug, Deserialize)] | ||||||
|  | |||||||
| @ -5,7 +5,9 @@ use ruma_identifiers::RoomAliasId; | |||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
| use serde_json::value::RawValue as RawJsonValue; | use serde_json::value::RawValue as RawJsonValue; | ||||||
| 
 | 
 | ||||||
| use crate::{EventContent, RedactedEventContent, RedactedStateEventContent, StateEvent}; | use crate::{ | ||||||
|  |     EventContent, HasDeserializeFields, RedactedEventContent, RedactedStateEventContent, StateEvent, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| /// Informs the room about what room aliases it has been given.
 | /// Informs the room about what room aliases it has been given.
 | ||||||
| pub type AliasesEvent = StateEvent<AliasesEventContent>; | pub type AliasesEvent = StateEvent<AliasesEventContent>; | ||||||
| @ -53,8 +55,8 @@ impl RedactedEventContent for RedactedAliasesEventContent { | |||||||
|         self.aliases.is_some() |         self.aliases.is_some() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn has_deserialize_fields() -> bool { |     fn has_deserialize_fields() -> HasDeserializeFields { | ||||||
|         true |         HasDeserializeFields::Optional | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -19,10 +19,6 @@ use ruma_events::{ | |||||||
| use ruma_identifiers::{EventId, RoomId, UserId}; | use ruma_identifiers::{EventId, RoomId, UserId}; | ||||||
| use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; | use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; | ||||||
| 
 | 
 | ||||||
| fn is_zst<T>(_: &T) -> bool { |  | ||||||
|     std::mem::size_of::<T>() == 0 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn full_unsigned() -> UnsignedData { | fn full_unsigned() -> UnsignedData { | ||||||
|     let mut unsigned = UnsignedData::default(); |     let mut unsigned = UnsignedData::default(); | ||||||
|     // The presence of `redacted_because` triggers the event enum to return early
 |     // The presence of `redacted_because` triggers the event enum to return early
 | ||||||
| @ -63,7 +59,7 @@ fn redacted_message_event_serialize() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn redacted_aliases_event_serialize() { | fn redacted_aliases_event_serialize_no_content() { | ||||||
|     let redacted = RedactedSyncStateEvent { |     let redacted = RedactedSyncStateEvent { | ||||||
|         content: RedactedAliasesEventContent { aliases: None }, |         content: RedactedAliasesEventContent { aliases: None }, | ||||||
|         event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(), |         event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(), | ||||||
| @ -85,6 +81,32 @@ fn redacted_aliases_event_serialize() { | |||||||
|     assert_eq!(actual, expected); |     assert_eq!(actual, expected); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[test] | ||||||
|  | fn redacted_aliases_event_serialize_with_content() { | ||||||
|  |     let redacted = RedactedSyncStateEvent { | ||||||
|  |         content: RedactedAliasesEventContent { aliases: Some(vec![]) }, | ||||||
|  |         event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(), | ||||||
|  |         state_key: "".to_string(), | ||||||
|  |         origin_server_ts: UNIX_EPOCH + Duration::from_millis(1), | ||||||
|  |         sender: UserId::try_from("@carl:example.com").unwrap(), | ||||||
|  |         unsigned: UnsignedData::default(), | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let expected = json!({ | ||||||
|  |       "content": { | ||||||
|  |           "aliases": [] | ||||||
|  |       }, | ||||||
|  |       "event_id": "$h29iv0s8:example.com", | ||||||
|  |       "state_key": "", | ||||||
|  |       "origin_server_ts": 1, | ||||||
|  |       "sender": "@carl:example.com", | ||||||
|  |       "type": "m.room.aliases" | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     let actual = to_json_value(&redacted).unwrap(); | ||||||
|  |     assert_eq!(actual, expected); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[test] | #[test] | ||||||
| fn redacted_aliases_deserialize() { | fn redacted_aliases_deserialize() { | ||||||
|     let unsigned = full_unsigned(); |     let unsigned = full_unsigned(); | ||||||
| @ -101,14 +123,15 @@ fn redacted_aliases_deserialize() { | |||||||
|     let actual = to_json_value(&redacted).unwrap(); |     let actual = to_json_value(&redacted).unwrap(); | ||||||
| 
 | 
 | ||||||
|     assert_matches!( |     assert_matches!( | ||||||
|         from_json_value::<EventJson<AnyRoomEventStub>>(actual) |         from_json_value::<EventJson<AnySyncRoomEvent>>(actual) | ||||||
|             .unwrap() |             .unwrap() | ||||||
|             .deserialize() |             .deserialize() | ||||||
|             .unwrap(), |             .unwrap(), | ||||||
|         AnyRoomEventStub::RedactedState(AnyRedactedStateEventStub::RoomAliases(RedactedStateEventStub { |         AnySyncRoomEvent::RedactedState(AnyRedactedSyncStateEvent::RoomAliases(RedactedSyncStateEvent { | ||||||
|             event_id, content, .. |             content: RedactedAliasesEventContent { aliases }, | ||||||
|  |             event_id, .. | ||||||
|         })) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap() |         })) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap() | ||||||
|             && is_zst(&content) |             && aliases.is_none() | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -133,10 +156,10 @@ fn redacted_deserialize_any_room() { | |||||||
|             .deserialize() |             .deserialize() | ||||||
|             .unwrap(), |             .unwrap(), | ||||||
|         AnyRoomEvent::RedactedMessage(AnyRedactedMessageEvent::RoomMessage(RedactedMessageEvent { |         AnyRoomEvent::RedactedMessage(AnyRedactedMessageEvent::RoomMessage(RedactedMessageEvent { | ||||||
|             event_id, room_id, content, .. |             content: RedactedMessageEventContent, | ||||||
|  |             event_id, room_id, .. | ||||||
|         })) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap() |         })) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap() | ||||||
|             && room_id == RoomId::try_from("!roomid:room.com").unwrap() |             && room_id == RoomId::try_from("!roomid:room.com").unwrap() | ||||||
|             && is_zst(&content) |  | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -172,9 +195,9 @@ fn redacted_deserialize_any_room_sync() { | |||||||
|             .deserialize() |             .deserialize() | ||||||
|             .unwrap(), |             .unwrap(), | ||||||
|         AnySyncRoomEvent::RedactedMessage(AnyRedactedSyncMessageEvent::RoomMessage(RedactedSyncMessageEvent { |         AnySyncRoomEvent::RedactedMessage(AnyRedactedSyncMessageEvent::RoomMessage(RedactedSyncMessageEvent { | ||||||
|             event_id, content, .. |             content: RedactedMessageEventContent, | ||||||
|  |             event_id, .. | ||||||
|         })) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap() |         })) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap() | ||||||
|             && is_zst(&content) |  | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user