mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-14 11:05:32 -04:00
refactor(crypto): Utilize the decrypted Olm event type more
This patch adds some more stronger guarantees that received room key events and other similarly security critical event types are only handled if they have been received over a secure Olm channel.
This commit is contained in:
@@ -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<Option<SecretName>, 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<Option<InboundGroupSession>, 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
|
||||
|
||||
@@ -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<Option<InboundGroupSession>> {
|
||||
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());
|
||||
|
||||
@@ -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<AnyToDeviceEvent>,
|
||||
pub signing_key: Ed25519PublicKey,
|
||||
pub sender_key: Curve25519PublicKey,
|
||||
pub inbound_group_session: Option<InboundGroupSession>,
|
||||
pub result: DecryptionResult,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct DecryptionResult {
|
||||
pub event: AnyDecryptedOlmEvent,
|
||||
pub raw_event: Raw<AnyToDeviceEvent>,
|
||||
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<AnyToDeviceEvent>, 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<AnyToDeviceEvent>, Ed25519PublicKey)> {
|
||||
let event: DecryptedOlmV1Event = serde_json::from_str(&plaintext)?;
|
||||
) -> OlmResult<DecryptionResult> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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<RoomKeyContent>;
|
||||
|
||||
/// An `m.forwarded_room_key` event that was decrypted using the
|
||||
/// `m.olm.v1.curve25519-aes-sha2` algorithm
|
||||
pub type DecryptedForwardedRoomKeyEvent = DecryptedOlmV1Event<ForwardedRoomKeyContent>;
|
||||
|
||||
/// An `m.secret.send` event that was decrypted using the
|
||||
/// `m.olm.v1.curve25519-aes-sha2` algorithm
|
||||
pub type DecryptedSecretSendEvent = DecryptedOlmV1Event<SecretSendContent>;
|
||||
|
||||
/// 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<C>
|
||||
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<C: EventType + Debug + Sized + Serialize> DecryptedOlmV1Event<C> {
|
||||
#[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<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Helper<'a> {
|
||||
#[serde(rename = "type")]
|
||||
event_type: &'a str,
|
||||
}
|
||||
|
||||
let json = Box::<RawValue>::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)?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user