Add redact method to all event_enum! generated enums

… and to AliasesEventContent
This commit is contained in:
Ragotzy.devin 2020-07-16 19:07:07 -04:00 committed by GitHub
parent b260a13d4b
commit 1db0082281
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 178 additions and 11 deletions

View File

@ -153,7 +153,7 @@ pub fn expand_event_content(input: &DeriveInput, emit_redacted: bool) -> syn::Re
// this is the non redacted event content's impl // this is the non redacted event content's impl
impl #ident { impl #ident {
/// Transforms the full event content into a redacted content according to spec. /// Transforms the full event content into a redacted content according to spec.
pub fn redact(self) -> #redacted_ident { pub fn redact(self, version: ::ruma_identifiers::RoomVersionId) -> #redacted_ident {
#redacted_ident { #( #redaction_struct_fields: self.#redaction_struct_fields, )* } #redacted_ident { #( #redaction_struct_fields: self.#redaction_struct_fields, )* }
} }
} }

View File

@ -131,15 +131,122 @@ fn expand_any_with_deser(
let field_accessor_impl = accessor_methods(kind, var, &variants); let field_accessor_impl = accessor_methods(kind, var, &variants);
let redact_impl = generate_redact(&ident, kind, var, &variants);
Some(quote! { Some(quote! {
#any_enum #any_enum
#field_accessor_impl #field_accessor_impl
#redact_impl
#event_deserialize_impl #event_deserialize_impl
}) })
} }
fn generate_redact(
ident: &Ident,
kind: &EventKind,
var: &EventKindVariation,
variants: &[Ident],
) -> Option<TokenStream> {
if let EventKindVariation::Full | EventKindVariation::Sync | EventKindVariation::Stripped = var
{
let (param, redaction_type, redaction_enum) = match var {
EventKindVariation::Full => {
let struct_id = kind.to_event_ident(&EventKindVariation::Redacted)?;
(
quote! { ::ruma_events::room::redaction::RedactionEvent },
quote! { ::ruma_events::#struct_id },
kind.to_event_enum_ident(&EventKindVariation::Redacted)?,
)
}
EventKindVariation::Sync => {
let struct_id = kind.to_event_ident(&EventKindVariation::RedactedSync)?;
(
quote! { ::ruma_events::room::redaction::SyncRedactionEvent },
quote! { ::ruma_events::#struct_id },
kind.to_event_enum_ident(&EventKindVariation::RedactedSync)?,
)
}
EventKindVariation::Stripped => {
let struct_id = kind.to_event_ident(&EventKindVariation::RedactedStripped)?;
(
quote! { ::ruma_events::room::redaction::SyncRedactionEvent },
quote! { ::ruma_events::#struct_id },
kind.to_event_enum_ident(&EventKindVariation::RedactedStripped)?,
)
}
_ => return None,
};
let fields = EVENT_FIELDS
.iter()
.map(|(name, has_field)| generate_redacted_fields(name, kind, var, *has_field));
let fields = quote! { #( #fields )* };
Some(quote! {
impl #ident {
/// Redacts `Self` given a valid `Redaction[Sync]Event`.
pub fn redact(self, redaction: #param, version: ::ruma_identifiers::RoomVersionId) -> #redaction_enum {
match self {
#(
Self::#variants(event) => {
let content = event.content.redact(version);
#redaction_enum::#variants(#redaction_type {
content,
#fields
})
}
)*
Self::Custom(event) => {
let content = event.content.redact(version);
#redaction_enum::Custom(#redaction_type {
content,
#fields
})
}
}
}
}
})
} else {
None
}
}
fn generate_redacted_fields(
name: &str,
kind: &EventKind,
var: &EventKindVariation,
is_event_kind: EventKindFn,
) -> TokenStream {
if is_event_kind(kind, var) {
let name = Ident::new(name, Span::call_site());
if name == "unsigned" {
let redaction_type = if let EventKindVariation::Sync = var {
quote! { RedactedSyncUnsigned }
} else {
quote! { RedactedUnsigned }
};
quote! {
unsigned: ::ruma_events::#redaction_type {
redacted_because: Some(::ruma_events::EventJson::from(redaction)),
},
}
} else {
quote! {
#name: event.#name,
}
}
} else {
TokenStream::new()
}
}
/// Generates the 3 redacted state enums, 2 redacted message enums, /// Generates the 3 redacted state enums, 2 redacted message enums,
/// and `Deserialize` implementations. /// and `Deserialize` implementations.
/// ///

View File

@ -1,5 +1,6 @@
//! Types for custom events outside of the Matrix specification. //! Types for custom events outside of the Matrix specification.
use ruma_identifiers::RoomVersionId;
use serde::Serialize; use serde::Serialize;
use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue}; use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue};
@ -23,7 +24,7 @@ pub struct CustomEventContent {
impl CustomEventContent { impl CustomEventContent {
/// Transforms the full event content into a redacted content according to spec. /// Transforms the full event content into a redacted content according to spec.
pub fn redact(self) -> RedactedCustomEventContent { pub fn redact(self, _: RoomVersionId) -> RedactedCustomEventContent {
RedactedCustomEventContent { event_type: self.event_type } RedactedCustomEventContent { event_type: self.event_type }
} }
} }

View File

@ -1,7 +1,7 @@
//! Types for the *m.room.aliases* event. //! Types for the *m.room.aliases* event.
use ruma_events_macros::StateEventContent; use ruma_events_macros::StateEventContent;
use ruma_identifiers::RoomAliasId; use ruma_identifiers::{RoomAliasId, RoomVersionId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::value::RawValue as RawJsonValue; use serde_json::value::RawValue as RawJsonValue;
@ -27,6 +27,22 @@ impl AliasesEventContent {
pub fn new(aliases: Vec<RoomAliasId>) -> Self { pub fn new(aliases: Vec<RoomAliasId>) -> Self {
Self { aliases } Self { aliases }
} }
/// Redact an `AliasesEventContent` according to current Matrix spec.
pub fn redact(self, version: RoomVersionId) -> RedactedAliasesEventContent {
// We compare the long way to avoid pre version 6 behavior if/when
// a new room version is introduced.
if version.is_version_1()
|| version.is_version_2()
|| version.is_version_3()
|| version.is_version_4()
|| version.is_version_5()
{
RedactedAliasesEventContent { aliases: Some(self.aliases) }
} else {
RedactedAliasesEventContent { aliases: None }
}
}
} }
/// An aliases event that has been redacted. /// An aliases event that has been redacted.

View File

@ -13,11 +13,12 @@ use ruma_events::{
message::RedactedMessageEventContent, message::RedactedMessageEventContent,
redaction::{RedactionEvent, RedactionEventContent, SyncRedactionEvent}, redaction::{RedactionEvent, RedactionEventContent, SyncRedactionEvent},
}, },
AnyRedactedMessageEvent, AnyRedactedSyncMessageEvent, AnyRedactedSyncStateEvent, AnyRoomEvent, AnyMessageEvent, AnyRedactedMessageEvent, AnyRedactedSyncMessageEvent,
AnySyncRoomEvent, RedactedMessageEvent, RedactedSyncMessageEvent, RedactedSyncStateEvent, AnyRedactedSyncStateEvent, AnyRoomEvent, AnySyncRoomEvent, RedactedMessageEvent,
RedactedSyncUnsigned, RedactedUnsigned, Unsigned, RedactedSyncMessageEvent, RedactedSyncStateEvent, RedactedSyncUnsigned, RedactedUnsigned,
Unsigned,
}; };
use ruma_identifiers::{EventId, RoomId, UserId}; use ruma_identifiers::{EventId, RoomId, RoomVersionId, 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 full_unsigned() -> RedactedSyncUnsigned { fn full_unsigned() -> RedactedSyncUnsigned {
@ -263,10 +264,8 @@ fn redacted_custom_event_serialize() {
&& event_type == "m.made.up" && event_type == "m.made.up"
); );
let x = from_json_value::<Raw<crate::AnyRedactedSyncStateEvent>>(redacted) let x =
.unwrap() from_json_value::<Raw<AnyRedactedSyncStateEvent>>(redacted).unwrap().deserialize().unwrap();
.deserialize()
.unwrap();
assert_eq!(x.event_id(), &EventId::try_from("$h29iv0s8:example.com").unwrap()) assert_eq!(x.event_id(), &EventId::try_from("$h29iv0s8:example.com").unwrap())
} }
@ -295,3 +294,47 @@ fn redacted_custom_event_deserialize() {
let actual = to_json_value(&redacted).unwrap(); let actual = to_json_value(&redacted).unwrap();
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
#[test]
fn redact_method_properly_redacts() {
let ev = json!({
"type": "m.room.message",
"event_id": "$143273582443PhrSn:example.com",
"origin_server_ts": 1,
"room_id": "!roomid:room.com",
"sender": "@user:example.com",
"content": {
"body": "test",
"msgtype": "m.audio",
"url": "http://example.com/audio.mp3",
}
});
let redaction = RedactionEvent {
content: RedactionEventContent { reason: Some("redacted because".into()) },
redacts: EventId::try_from("$143273582443PhrSn:example.com").unwrap(),
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
room_id: RoomId::try_from("!roomid:room.com").unwrap(),
sender: UserId::try_from("@carl:example.com").unwrap(),
unsigned: Unsigned::default(),
};
let event = from_json_value::<Raw<AnyMessageEvent>>(ev).unwrap().deserialize().unwrap();
assert_matches!(
event.redact(redaction, RoomVersionId::version_6()),
AnyRedactedMessageEvent::RoomMessage(RedactedMessageEvent {
content: RedactedMessageEventContent,
event_id,
room_id,
sender,
origin_server_ts,
unsigned,
}) if event_id == EventId::try_from("$143273582443PhrSn:example.com").unwrap()
&& unsigned.redacted_because.is_some()
&& room_id == RoomId::try_from("!roomid:room.com").unwrap()
&& sender == UserId::try_from("@user:example.com").unwrap()
&& origin_server_ts == UNIX_EPOCH + Duration::from_millis(1)
);
}