diff --git a/crates/matrix-sdk-crypto/src/gossiping/machine.rs b/crates/matrix-sdk-crypto/src/gossiping/machine.rs index 554feb1f0..5cb6dd30f 100644 --- a/crates/matrix-sdk-crypto/src/gossiping/machine.rs +++ b/crates/matrix-sdk-crypto/src/gossiping/machine.rs @@ -45,10 +45,9 @@ use crate::{ session_manager::GroupSessionCache, store::{Changes, CryptoStoreError, SecretImportError, Store}, types::events::{ - forwarded_room_key::{ - ForwardedMegolmV1AesSha2Content, ForwardedRoomKeyContent, ForwardedRoomKeyEvent, - }, - secret_send::{SecretSendContent, SecretSendEvent}, + forwarded_room_key::{ForwardedMegolmV1AesSha2Content, ForwardedRoomKeyContent}, + olm_v1::{DecryptedForwardedRoomKeyEvent, DecryptedSecretSendEvent}, + secret_send::SecretSendContent, EventType, }, Device, @@ -779,7 +778,7 @@ impl GossipMachine { async fn accept_secret( &self, - event: &mut SecretSendEvent, + event: &DecryptedSecretSendEvent, request: &GossipRequest, secret_name: &SecretName, ) -> Result<(), CryptoStoreError> { @@ -817,14 +816,10 @@ impl GossipMachine { async fn receive_secret( &self, sender_key: Curve25519PublicKey, - event: &mut SecretSendEvent, + event: &DecryptedSecretSendEvent, request: &GossipRequest, secret_name: &SecretName, ) -> Result<(), CryptoStoreError> { - // Set the secret name so other consumers of the event know - // what this event is about. - event.content.secret_name = Some(secret_name.to_owned()); - debug!( sender = event.sender.as_str(), request_id = event.content.request_id.as_str(), @@ -863,8 +858,8 @@ impl GossipMachine { pub async fn receive_secret_event( &self, sender_key: Curve25519PublicKey, - event: &mut SecretSendEvent, - ) -> Result<(), CryptoStoreError> { + event: &DecryptedSecretSendEvent, + ) -> Result, CryptoStoreError> { debug!( sender = event.sender.as_str(), request_id = event.content.request_id.as_str(), @@ -873,7 +868,7 @@ impl GossipMachine { let request_id = <&TransactionId>::from(event.content.request_id.as_str()); - if let Some(request) = self.store.get_outgoing_secret_requests(request_id).await? { + Ok(if let Some(request) = self.store.get_outgoing_secret_requests(request_id).await? { match &request.info { SecretInfo::KeyRequest(_) => { warn!( @@ -881,14 +876,18 @@ impl GossipMachine { request_id = event.content.request_id.as_str(), "Received a m.secret.send event but the request was for a room key" ); + + None } SecretInfo::SecretRequest(secret_name) => { self.receive_secret(sender_key, event, &request, secret_name).await?; + + Some(secret_name.to_owned()) } } - } - - Ok(()) + } else { + None + }) } async fn accept_forwarded_room_key( @@ -965,7 +964,7 @@ impl GossipMachine { pub async fn receive_forwarded_room_key( &self, sender_key: Curve25519PublicKey, - event: &ForwardedRoomKeyEvent, + event: &DecryptedForwardedRoomKeyEvent, ) -> Result, CryptoStoreError> { match &event.content { ForwardedRoomKeyContent::MegolmV1AesSha2(content) => { @@ -978,7 +977,7 @@ impl GossipMachine { room_id = content.room_id.as_str(), session_id = content.session_id.as_str(), claimed_sender_key = content.claimed_sender_key.to_base64(), - algorithm = %event.algorithm(), + algorithm = %event.content.algorithm(), "Received a forwarded room key that we didn't request", ); @@ -989,7 +988,7 @@ impl GossipMachine { warn!( sender = event.sender.as_str(), sender_key = sender_key.to_base64(), - algorithm = %event.algorithm(), + algorithm = %event.content.algorithm(), "Received a forwarded room key with an unsupported algorithm", ); @@ -1025,7 +1024,8 @@ mod tests { session_manager::GroupSessionCache, store::{Changes, CryptoStore, MemoryStore, Store}, types::events::{ - forwarded_room_key::ForwardedRoomKeyContent, ToDeviceEvent, ToDeviceEvents, + forwarded_room_key::ForwardedRoomKeyContent, + olm_v1::{AnyDecryptedOlmEvent, DecryptedOlmV1Event}, }, utilities::json_convert, verification::VerificationMachine, @@ -1319,8 +1319,12 @@ mod tests { let content: ForwardedRoomKeyContent = export.try_into().unwrap(); - let event = - ToDeviceEvent { sender: alice_id().to_owned(), content, other: Default::default() }; + let event = DecryptedOlmV1Event::new( + alice_id(), + alice_id(), + alice_device.ed25519_key().unwrap(), + content, + ); assert!(machine .store @@ -1368,8 +1372,12 @@ mod tests { let content: ForwardedRoomKeyContent = export.try_into().unwrap(); - let event = - ToDeviceEvent { sender: alice_id().to_owned(), content, other: Default::default() }; + let event = DecryptedOlmV1Event::new( + alice_id(), + alice_id(), + alice_device.ed25519_key().unwrap(), + content, + ); let second_session = machine .receive_forwarded_room_key(alice_device.curve25519_key().unwrap(), &event) @@ -1382,8 +1390,12 @@ mod tests { let content: ForwardedRoomKeyContent = export.try_into().unwrap(); - let event = - ToDeviceEvent { sender: alice_id().to_owned(), content, other: Default::default() }; + let event = DecryptedOlmV1Event::new( + alice_id(), + alice_id(), + alice_device.ed25519_key().unwrap(), + content, + ); let second_session = machine .receive_forwarded_room_key(alice_device.curve25519_key().unwrap(), &event) @@ -1552,9 +1564,11 @@ mod tests { let decrypted = alice_account.decrypt_to_device_event(&event).await.unwrap(); - if let ToDeviceEvents::ForwardedRoomKey(e) = decrypted.event.deserialize_as().unwrap() { - let session = - alice_machine.receive_forwarded_room_key(decrypted.sender_key, &e).await.unwrap(); + if let AnyDecryptedOlmEvent::ForwardedRoomKey(e) = decrypted.result.event { + let session = alice_machine + .receive_forwarded_room_key(decrypted.result.sender_key, &e) + .await + .unwrap(); alice_machine.store.save_inbound_group_sessions(&[session.unwrap()]).await.unwrap(); } else { panic!("Invalid decrypted event type"); @@ -1565,7 +1579,7 @@ mod tests { .store .get_inbound_group_session( room_id(), - &decrypted.sender_key.to_base64(), + &decrypted.result.sender_key.to_base64(), group_session.session_id(), ) .await @@ -1710,9 +1724,11 @@ mod tests { let decrypted = alice_account.decrypt_to_device_event(&event).await.unwrap(); - if let ToDeviceEvents::ForwardedRoomKey(e) = decrypted.event.deserialize_as().unwrap() { - let session = - alice_machine.receive_forwarded_room_key(decrypted.sender_key, &e).await.unwrap(); + if let AnyDecryptedOlmEvent::ForwardedRoomKey(e) = decrypted.result.event { + let session = alice_machine + .receive_forwarded_room_key(decrypted.result.sender_key, &e) + .await + .unwrap(); alice_machine.store.save_inbound_group_sessions(&[session.unwrap()]).await.unwrap(); } else { panic!("Invalid decrypted event type"); @@ -1723,7 +1739,7 @@ mod tests { .store .get_inbound_group_session( room_id(), - &decrypted.sender_key.to_base64(), + &decrypted.result.sender_key.to_base64(), group_session.session_id(), ) .await diff --git a/crates/matrix-sdk-crypto/src/machine.rs b/crates/matrix-sdk-crypto/src/machine.rs index 5e7a242c1..a54c34d8c 100644 --- a/crates/matrix-sdk-crypto/src/machine.rs +++ b/crates/matrix-sdk-crypto/src/machine.rs @@ -43,7 +43,7 @@ use ruma::{ }; use serde_json::{value::to_raw_value, Value}; use tracing::{debug, error, info, trace, warn}; -use vodozemac::{megolm::SessionOrdering, Curve25519PublicKey, Ed25519PublicKey, Ed25519Signature}; +use vodozemac::{megolm::SessionOrdering, Curve25519PublicKey, Ed25519Signature}; #[cfg(feature = "backups_v1")] use crate::backups::BackupMachine; @@ -64,11 +64,12 @@ use crate::{ }, types::{ events::{ + olm_v1::{AnyDecryptedOlmEvent, DecryptedRoomKeyEvent}, room::encrypted::{ EncryptedEvent, EncryptedToDeviceEvent, RoomEncryptedEventContent, RoomEventEncryptionScheme, SupportedEventEncryptionSchemes, }, - room_key::{RoomKeyContent, RoomKeyEvent}, + room_key::RoomKeyContent, ToDeviceEvents, }, Signatures, @@ -551,14 +552,13 @@ impl OlmMachine { async fn add_room_key( &self, sender_key: Curve25519PublicKey, - signing_key: Ed25519PublicKey, - event: &RoomKeyEvent, + event: &DecryptedRoomKeyEvent, ) -> OlmResult> { let unsupported_warning = || { warn!( sender = %event.sender, sender_key = sender_key.to_base64(), - algorithm = %event.algorithm(), + algorithm = %event.content.algorithm(), "Received room key with unsupported key algorithm", ); }; @@ -567,10 +567,10 @@ impl OlmMachine { RoomKeyContent::MegolmV1AesSha2(content) => { let session = InboundGroupSession::new( sender_key, - signing_key, + event.keys.ed25519, &content.room_id, &content.session_key, - event.algorithm(), + event.content.algorithm(), None, ); @@ -715,47 +715,43 @@ impl OlmMachine { &self, decrypted: &mut OlmDecryptionInfo, ) -> OlmResult<()> { - let event: ToDeviceEvents = match decrypted.event.deserialize_as() { - Ok(e) => e, - Err(e) => { - warn!( - sender = decrypted.sender.as_str(), - sender_key = decrypted.sender_key.to_base64(), - error = ?e, - "Decrypted to-device event failed to be deserialized correctly" - ); - - return Ok(()); - } - }; - trace!( - sender = decrypted.sender.as_str(), - sender_key = decrypted.sender_key.to_base64(), - event_type = %event.event_type(), + sender = %decrypted.sender, + sender_key = %decrypted.result.sender_key, + event_type = decrypted.result.event.event_type(), "Received a decrypted to-device event" ); - match event { - ToDeviceEvents::RoomKey(e) => { - let session = - self.add_room_key(decrypted.sender_key, decrypted.signing_key, &e).await?; + match &decrypted.result.event { + AnyDecryptedOlmEvent::RoomKey(e) => { + let session = self.add_room_key(decrypted.result.sender_key, e).await?; decrypted.inbound_group_session = session; } - ToDeviceEvents::ForwardedRoomKey(e) => { + AnyDecryptedOlmEvent::ForwardedRoomKey(e) => { let session = self .key_request_machine - .receive_forwarded_room_key(decrypted.sender_key, &e) + .receive_forwarded_room_key(decrypted.result.sender_key, e) .await?; decrypted.inbound_group_session = session; } - ToDeviceEvents::SecretSend(mut e) => { - self.key_request_machine.receive_secret_event(decrypted.sender_key, &mut e).await?; - decrypted.event = Raw::from_json(to_raw_value(&e)?) + AnyDecryptedOlmEvent::SecretSend(e) => { + let name = self + .key_request_machine + .receive_secret_event(decrypted.result.sender_key, e) + .await?; + + // Set the secret name so other consumers of the event know + // what this event is about. + if let Ok(ToDeviceEvents::SecretSend(mut e)) = + decrypted.result.raw_event.deserialize_as() + { + e.content.secret_name = name; + decrypted.result.raw_event = Raw::from_json(to_raw_value(&e)?) + } } - _ => { + AnyDecryptedOlmEvent::Custom(e) => { warn!( - event_type = ?event.event_type(), + event_type = ?e.event_type, "Received an unexpected encrypted to-device event" ); } @@ -930,7 +926,7 @@ impl OlmMachine { changes.inbound_group_sessions.push(group_session); } - match decrypted.event.deserialize_as() { + match decrypted.result.raw_event.deserialize_as() { Ok(event) => { self.handle_to_device_event(&event).await; @@ -944,7 +940,7 @@ impl OlmMachine { error = ?e, "Received an invalid encrypted to-device event" ); - raw_event = decrypted.event; + raw_event = decrypted.result.raw_event; } } } @@ -1942,7 +1938,14 @@ pub(crate) mod tests { other: Default::default(), }; - let event = bob.decrypt_to_device_event(&event).await.unwrap().event.deserialize().unwrap(); + let event = bob + .decrypt_to_device_event(&event) + .await + .unwrap() + .result + .raw_event + .deserialize() + .unwrap(); if let AnyToDeviceEvent::Dummy(e) = event { assert_eq!(&e.sender, alice.user_id()); diff --git a/crates/matrix-sdk-crypto/src/olm/account.rs b/crates/matrix-sdk-crypto/src/olm/account.rs index 65db30f7b..5cd6957cb 100644 --- a/crates/matrix-sdk-crypto/src/olm/account.rs +++ b/crates/matrix-sdk-crypto/src/olm/account.rs @@ -42,7 +42,7 @@ use vodozemac::{ Account as InnerAccount, AccountPickle, IdentityKeys, OlmMessage, PreKeyMessage, SessionConfig, }, - Curve25519PublicKey, Ed25519PublicKey, Ed25519Signature, KeyId, PickleError, + Curve25519PublicKey, Ed25519Signature, KeyId, PickleError, }; use super::{ @@ -56,11 +56,11 @@ use crate::{ store::{Changes, Store}, types::{ events::{ + olm_v1::AnyDecryptedOlmEvent, room::encrypted::{ EncryptedToDeviceEvent, OlmV1Curve25519AesSha2Content, ToDeviceEncryptedEventContent, }, - DecryptedOlmV1Event, }, CrossSigningKey, DeviceKeys, OneTimeKey, SignedKey, }, @@ -101,15 +101,20 @@ impl SessionType { /// /// Contains the decrypted event plaintext along with some associated metadata, /// such as the identity (Curve25519) key of the to-device event sender. -#[derive(Debug, Clone)] +#[derive(Debug)] pub(crate) struct OlmDecryptionInfo { pub sender: OwnedUserId, pub session: SessionType, pub message_hash: OlmMessageHash, - pub event: Raw, - pub signing_key: Ed25519PublicKey, - pub sender_key: Curve25519PublicKey, pub inbound_group_session: Option, + pub result: DecryptionResult, +} + +#[derive(Debug)] +pub(crate) struct DecryptionResult { + pub event: AnyDecryptedOlmEvent, + pub raw_event: Raw, + pub sender_key: Curve25519PublicKey, } /// A hash of a successfully decrypted Olm message. @@ -160,13 +165,11 @@ impl Account { let message_hash = OlmMessageHash::new(sender_key, ciphertext); match self.decrypt_olm_message(sender, sender_key, ciphertext).await { - Ok((session, event, signing_key)) => Ok(OlmDecryptionInfo { + Ok((session, result)) => Ok(OlmDecryptionInfo { sender: sender.to_owned(), session, message_hash, - event, - signing_key, - sender_key, + result, inbound_group_session: None, }), Err(OlmError::SessionWedged(user_id, sender_key)) => { @@ -290,7 +293,7 @@ impl Account { sender: &UserId, sender_key: Curve25519PublicKey, message: &OlmMessage, - ) -> OlmResult<(SessionType, Raw, Ed25519PublicKey)> { + ) -> OlmResult<(SessionType, DecryptionResult)> { // First try to decrypt using an existing session. let (session, plaintext) = if let Some(d) = self.decrypt_with_existing_sessions(sender_key, message).await? @@ -355,8 +358,8 @@ impl Account { "Successfully decrypted an Olm message" ); - match self.parse_decrypted_to_device_event(sender, plaintext) { - Ok((event, signing_key)) => Ok((session, event, signing_key)), + match self.parse_decrypted_to_device_event(sender, sender_key, plaintext) { + Ok(result) => Ok((session, result)), Err(e) => { // We might created a new session but decryption might still // have failed, store it for the error case here, this is fine @@ -393,23 +396,32 @@ impl Account { fn parse_decrypted_to_device_event( &self, sender: &UserId, + sender_key: Curve25519PublicKey, plaintext: String, - ) -> OlmResult<(Raw, Ed25519PublicKey)> { - let event: DecryptedOlmV1Event = serde_json::from_str(&plaintext)?; + ) -> OlmResult { + let event: AnyDecryptedOlmEvent = serde_json::from_str(&plaintext)?; let identity_keys = self.inner.identity_keys(); - if event.recipient != self.user_id() { - Err(EventError::MismatchedSender(event.recipient, self.user_id().to_owned()).into()) - } else if event.sender != sender { - Err(EventError::MismatchedSender(event.sender, sender.to_owned()).into()) - } else if identity_keys.ed25519 != event.recipient_keys.ed25519 { + if event.recipient() != self.user_id() { + Err(EventError::MismatchedSender( + event.recipient().to_owned(), + self.user_id().to_owned(), + ) + .into()) + } else if event.sender() != sender { + Err(EventError::MismatchedSender(event.sender().to_owned(), sender.to_owned()).into()) + } else if identity_keys.ed25519 != event.recipient_keys().ed25519 { Err(EventError::MismatchedKeys( identity_keys.ed25519.into(), - event.recipient_keys.ed25519.into(), + event.recipient_keys().ed25519.into(), ) .into()) } else { - Ok((Raw::from_json(RawJsonValue::from_string(plaintext)?), event.keys.ed25519)) + Ok(DecryptionResult { + event, + raw_event: Raw::from_json(RawJsonValue::from_string(plaintext)?), + sender_key, + }) } } } diff --git a/crates/matrix-sdk-crypto/src/types/events/mod.rs b/crates/matrix-sdk-crypto/src/types/events/mod.rs index 5e0309e55..01ea0f2d1 100644 --- a/crates/matrix-sdk-crypto/src/types/events/mod.rs +++ b/crates/matrix-sdk-crypto/src/types/events/mod.rs @@ -19,13 +19,12 @@ //! the type is dropped. pub mod forwarded_room_key; -mod olm_v1; +pub mod olm_v1; pub mod room; pub mod room_key; pub mod secret_send; mod to_device; -pub use olm_v1::DecryptedOlmV1Event; use ruma::serde::Raw; pub use to_device::{ToDeviceCustomEvent, ToDeviceEvent, ToDeviceEvents}; diff --git a/crates/matrix-sdk-crypto/src/types/events/olm_v1.rs b/crates/matrix-sdk-crypto/src/types/events/olm_v1.rs index e71c33041..01679ebdb 100644 --- a/crates/matrix-sdk-crypto/src/types/events/olm_v1.rs +++ b/crates/matrix-sdk-crypto/src/types/events/olm_v1.rs @@ -12,15 +12,134 @@ // See the License for the specific language governing permissions and // limitations under the License. -use ruma::OwnedUserId; +//! Module containing specialized event types that were decrypted using the Olm +//! protocol + +use std::fmt::Debug; + +use ruma::{OwnedUserId, UserId}; use serde::{Deserialize, Serialize}; +use serde_json::value::RawValue; use vodozemac::Ed25519PublicKey; -use crate::types::{deserialize_ed25519_key, serialize_ed25519_key}; +use super::{ + forwarded_room_key::ForwardedRoomKeyContent, room_key::RoomKeyContent, + secret_send::SecretSendContent, EventType, +}; +use crate::types::{deserialize_ed25519_key, events::from_str, serialize_ed25519_key}; + +/// An `m.room_key` event that was decrypted using the +/// `m.olm.v1.curve25519-aes-sha2` algorithm +pub type DecryptedRoomKeyEvent = DecryptedOlmV1Event; + +/// An `m.forwarded_room_key` event that was decrypted using the +/// `m.olm.v1.curve25519-aes-sha2` algorithm +pub type DecryptedForwardedRoomKeyEvent = DecryptedOlmV1Event; + +/// An `m.secret.send` event that was decrypted using the +/// `m.olm.v1.curve25519-aes-sha2` algorithm +pub type DecryptedSecretSendEvent = DecryptedOlmV1Event; + +/// An enum over the various events that were decrypted using the +/// `m.olm.v1.curve25519-aes-sha2` algorithm. +#[derive(Debug)] +pub enum AnyDecryptedOlmEvent { + /// The `m.room_key` decrypted to-device event. + RoomKey(DecryptedRoomKeyEvent), + /// The `m.forwarded_room_key` decrypted to-device event. + ForwardedRoomKey(DecryptedForwardedRoomKeyEvent), + /// The `m.secret.send` decrypted to-device event. + SecretSend(DecryptedSecretSendEvent), + /// A decrypted to-device event of an unknown or custom type. + Custom(ToDeviceCustomEvent), +} + +impl AnyDecryptedOlmEvent { + /// The sender of the event, as set by the sender of the event. + pub fn sender(&self) -> &UserId { + match self { + AnyDecryptedOlmEvent::RoomKey(e) => &e.sender, + AnyDecryptedOlmEvent::ForwardedRoomKey(e) => &e.sender, + AnyDecryptedOlmEvent::SecretSend(e) => &e.sender, + AnyDecryptedOlmEvent::Custom(e) => &e.sender, + } + } + + /// The intended recipient of the event, as set by the sender of the event. + pub fn recipient(&self) -> &UserId { + match self { + AnyDecryptedOlmEvent::RoomKey(e) => &e.recipient, + AnyDecryptedOlmEvent::ForwardedRoomKey(e) => &e.recipient, + AnyDecryptedOlmEvent::SecretSend(e) => &e.recipient, + AnyDecryptedOlmEvent::Custom(e) => &e.recipient, + } + } + + /// The sender's signing keys of the encrypted event. + pub fn keys(&self) -> &OlmV1Keys { + match self { + AnyDecryptedOlmEvent::RoomKey(e) => &e.keys, + AnyDecryptedOlmEvent::ForwardedRoomKey(e) => &e.keys, + AnyDecryptedOlmEvent::SecretSend(e) => &e.keys, + AnyDecryptedOlmEvent::Custom(e) => &e.keys, + } + } + + /// The recipient's signing keys of the encrypted event. + pub fn recipient_keys(&self) -> &OlmV1Keys { + match self { + AnyDecryptedOlmEvent::RoomKey(e) => &e.recipient_keys, + AnyDecryptedOlmEvent::ForwardedRoomKey(e) => &e.recipient_keys, + AnyDecryptedOlmEvent::SecretSend(e) => &e.recipient_keys, + AnyDecryptedOlmEvent::Custom(e) => &e.recipient_keys, + } + } + + /// The event type of the encrypted event. + pub fn event_type(&self) -> &str { + match self { + AnyDecryptedOlmEvent::Custom(e) => &e.event_type, + AnyDecryptedOlmEvent::RoomKey(e) => e.content.event_type(), + AnyDecryptedOlmEvent::ForwardedRoomKey(e) => e.content.event_type(), + AnyDecryptedOlmEvent::SecretSend(e) => e.content.event_type(), + } + } +} /// An `m.olm.v1.curve25519-aes-sha2` decrypted to-device event. #[derive(Clone, Debug, Deserialize, Serialize)] -pub struct DecryptedOlmV1Event { +pub struct DecryptedOlmV1Event +where + C: EventType + Debug + Sized + Serialize, +{ + /// The sender of the event, as set by the sender of the event. + pub sender: OwnedUserId, + /// The intended recipient of the event, as set by the sender of the event. + pub recipient: OwnedUserId, + /// The sender's signing keys of the encrypted event. + pub keys: OlmV1Keys, + /// The recipient's signing keys of the encrypted event. + pub recipient_keys: OlmV1Keys, + /// The type of the event. + pub content: C, +} + +impl DecryptedOlmV1Event { + #[cfg(test)] + pub fn new(sender: &UserId, recipient: &UserId, key: Ed25519PublicKey, content: C) -> Self { + Self { + sender: sender.to_owned(), + recipient: recipient.to_owned(), + keys: OlmV1Keys { ed25519: key }, + recipient_keys: OlmV1Keys { ed25519: key }, + content, + } + } +} + +/// A decrypted to-device event with an unknown type and content. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct ToDeviceCustomEvent { /// The sender of the encrypted to-device event. pub sender: OwnedUserId, /// The recipient of the encrypted to-device event. @@ -44,3 +163,30 @@ pub struct OlmV1Keys { )] pub ed25519: Ed25519PublicKey, } + +impl<'de> Deserialize<'de> for AnyDecryptedOlmEvent { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(Debug, Deserialize)] + struct Helper<'a> { + #[serde(rename = "type")] + event_type: &'a str, + } + + let json = Box::::deserialize(deserializer)?; + let helper: Helper<'_> = + serde_json::from_str(json.get()).map_err(serde::de::Error::custom)?; + + let json = json.get(); + + Ok(match helper.event_type { + "m.room_key" => AnyDecryptedOlmEvent::RoomKey(from_str(json)?), + "m.forwarded_room_key" => AnyDecryptedOlmEvent::ForwardedRoomKey(from_str(json)?), + "m.secret.send" => AnyDecryptedOlmEvent::SecretSend(from_str(json)?), + + _ => AnyDecryptedOlmEvent::Custom(from_str(json)?), + }) + } +}