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 is_generic && ident.to_string().contains("Redacted") { | ||||
|                 quote! { | ||||
|                     let content = if !C::has_deserialize_fields() { | ||||
|                         C::empty(&event_type).map_err(A::Error::custom)? | ||||
|                     } else { | ||||
|                         let json = content.ok_or_else(|| ::serde::de::Error::missing_field("content"))?; | ||||
|                         C::from_parts(&event_type, json).map_err(A::Error::custom)? | ||||
|                     let content = match C::has_deserialize_fields() { | ||||
|                         ::ruma_events::HasDeserializeFields::False => { | ||||
|                             C::empty(&event_type).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 { | ||||
|  | ||||
| @ -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 } | ||||
|         } else { | ||||
|             quote! { true } | ||||
| @ -170,11 +176,11 @@ pub fn expand_event_content(input: &DeriveInput, emit_redacted: bool) -> syn::Re | ||||
|                 } | ||||
| 
 | ||||
|                 fn has_serialize_fields(&self) -> bool { | ||||
|                     #has_fields | ||||
|                     #has_serialize_fields | ||||
|                 } | ||||
| 
 | ||||
|                 fn has_deserialize_fields() -> bool { | ||||
|                     #has_fields | ||||
|                 fn has_deserialize_fields() -> ::ruma_events::HasDeserializeFields { | ||||
|                     #has_deserialize_fields | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -4,9 +4,9 @@ use serde::Serialize; | ||||
| use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     BasicEventContent, EphemeralRoomEventContent, EventContent, MessageEventContent, | ||||
|     RedactedEventContent, RedactedMessageEventContent, RedactedStateEventContent, RoomEventContent, | ||||
|     StateEventContent, | ||||
|     BasicEventContent, EphemeralRoomEventContent, EventContent, HasDeserializeFields, | ||||
|     MessageEventContent, RedactedEventContent, RedactedMessageEventContent, | ||||
|     RedactedStateEventContent, RoomEventContent, StateEventContent, | ||||
| }; | ||||
| 
 | ||||
| /// A custom event's type and `content` JSON object.
 | ||||
| @ -83,8 +83,8 @@ impl RedactedEventContent for RedactedCustomEventContent { | ||||
|         false | ||||
|     } | ||||
| 
 | ||||
|     fn has_deserialize_fields() -> bool { | ||||
|         false | ||||
|     fn has_deserialize_fields() -> HasDeserializeFields { | ||||
|         HasDeserializeFields::False | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -243,20 +243,27 @@ pub trait StateEventContent: RoomEventContent {} | ||||
| 
 | ||||
| /// 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 { | ||||
|     /// Constructs the redacted event content.
 | ||||
|     ///
 | ||||
|     /// If called for anything but "empty" redacted content this will error.
 | ||||
|     #[doc(hidden)] | ||||
|     fn empty(_event_type: &str) -> Result<Self, serde_json::Error> { | ||||
|         Err(serde::de::Error::custom("this event is not redacted")) | ||||
|     } | ||||
| 
 | ||||
|     /// Determines if the redacted event content needs to serialize fields.
 | ||||
|     #[doc(hidden)] | ||||
|     fn has_serialize_fields(&self) -> bool; | ||||
| 
 | ||||
|     /// 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.
 | ||||
| @ -265,6 +272,21 @@ pub trait RedactedMessageEventContent: RedactedEventContent {} | ||||
| /// Marker trait for the content of a redacted state event.
 | ||||
| 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.
 | ||||
| #[doc(hidden)] | ||||
| #[derive(Debug, Deserialize)] | ||||
|  | ||||
| @ -5,7 +5,9 @@ use ruma_identifiers::RoomAliasId; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| 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.
 | ||||
| pub type AliasesEvent = StateEvent<AliasesEventContent>; | ||||
| @ -53,8 +55,8 @@ impl RedactedEventContent for RedactedAliasesEventContent { | ||||
|         self.aliases.is_some() | ||||
|     } | ||||
| 
 | ||||
|     fn has_deserialize_fields() -> bool { | ||||
|         true | ||||
|     fn has_deserialize_fields() -> HasDeserializeFields { | ||||
|         HasDeserializeFields::Optional | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -19,10 +19,6 @@ use ruma_events::{ | ||||
| use ruma_identifiers::{EventId, RoomId, UserId}; | ||||
| 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 { | ||||
|     let mut unsigned = UnsignedData::default(); | ||||
|     // The presence of `redacted_because` triggers the event enum to return early
 | ||||
| @ -63,7 +59,7 @@ fn redacted_message_event_serialize() { | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn redacted_aliases_event_serialize() { | ||||
| fn redacted_aliases_event_serialize_no_content() { | ||||
|     let redacted = RedactedSyncStateEvent { | ||||
|         content: RedactedAliasesEventContent { aliases: None }, | ||||
|         event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(), | ||||
| @ -85,6 +81,32 @@ fn redacted_aliases_event_serialize() { | ||||
|     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] | ||||
| fn redacted_aliases_deserialize() { | ||||
|     let unsigned = full_unsigned(); | ||||
| @ -101,14 +123,15 @@ fn redacted_aliases_deserialize() { | ||||
|     let actual = to_json_value(&redacted).unwrap(); | ||||
| 
 | ||||
|     assert_matches!( | ||||
|         from_json_value::<EventJson<AnyRoomEventStub>>(actual) | ||||
|         from_json_value::<EventJson<AnySyncRoomEvent>>(actual) | ||||
|             .unwrap() | ||||
|             .deserialize() | ||||
|             .unwrap(), | ||||
|         AnyRoomEventStub::RedactedState(AnyRedactedStateEventStub::RoomAliases(RedactedStateEventStub { | ||||
|             event_id, content, .. | ||||
|         AnySyncRoomEvent::RedactedState(AnyRedactedSyncStateEvent::RoomAliases(RedactedSyncStateEvent { | ||||
|             content: RedactedAliasesEventContent { aliases }, | ||||
|             event_id, .. | ||||
|         })) 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() | ||||
|             .unwrap(), | ||||
|         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() | ||||
|             && room_id == RoomId::try_from("!roomid:room.com").unwrap() | ||||
|             && is_zst(&content) | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| @ -172,9 +195,9 @@ fn redacted_deserialize_any_room_sync() { | ||||
|             .deserialize() | ||||
|             .unwrap(), | ||||
|         AnySyncRoomEvent::RedactedMessage(AnyRedactedSyncMessageEvent::RoomMessage(RedactedSyncMessageEvent { | ||||
|             event_id, content, .. | ||||
|             content: RedactedMessageEventContent, | ||||
|             event_id, .. | ||||
|         })) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap() | ||||
|             && is_zst(&content) | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user