feat(matrix-sdk): Expose method to decrypt room events

Merge pull request #614 from jsparber/fix_decrypt_timeline
This commit is contained in:
Benjamin Kampmann
2022-05-11 17:34:19 +02:00
committed by GitHub
3 changed files with 72 additions and 52 deletions

View File

@@ -26,19 +26,15 @@ use std::{
};
use futures_util::stream::{self, StreamExt};
pub use matrix_sdk_base::crypto::{LocalTrust, MediaEncryptionInfo, RoomKeyImportResult};
use matrix_sdk_base::{
crypto::{
store::CryptoStoreError, CrossSigningStatus, OutgoingRequest, RoomMessageRequest,
ToDeviceRequest,
},
deserialized_responses::RoomEvent,
use matrix_sdk_base::crypto::{
store::CryptoStoreError, CrossSigningStatus, OutgoingRequest, RoomMessageRequest,
ToDeviceRequest,
};
pub use matrix_sdk_base::crypto::{LocalTrust, MediaEncryptionInfo, RoomKeyImportResult};
use matrix_sdk_common::instant::Duration;
#[cfg(feature = "e2e-encryption")]
use ruma::{
api::client::config::set_global_account_data,
events::{GlobalAccountDataEventContent, MessageLikeEvent},
api::client::config::set_global_account_data, events::GlobalAccountDataEventContent,
OwnedDeviceId,
};
use ruma::{
@@ -54,8 +50,7 @@ use ruma::{
uiaa::AuthData,
},
assign,
events::{AnyMessageLikeEvent, AnyRoomEvent, GlobalAccountDataEventType},
serde::Raw,
events::GlobalAccountDataEventType,
DeviceId, OwnedUserId, TransactionId, UserId,
};
use tracing::{debug, instrument, trace, warn};
@@ -71,33 +66,6 @@ use crate::{
};
impl Client {
/// Tries to decrypt a `AnyRoomEvent`. Returns undecrypted room event when
/// decryption fails.
#[cfg(feature = "e2e-encryption")]
pub(crate) async fn decrypt_room_event(&self, event: Raw<AnyRoomEvent>) -> RoomEvent {
if let Some(machine) = self.olm_machine().await {
if let Ok(AnyRoomEvent::MessageLike(event)) = event.deserialize() {
if let AnyMessageLikeEvent::RoomEncrypted(_) = event {
let room_id = event.room_id();
if let AnyMessageLikeEvent::RoomEncrypted(MessageLikeEvent::Original(ev)) =
&event
{
// Turn the OriginalMessageLikeEvent into a OriginalSyncMessageLikeEvent
let ev = ev.clone().into();
if let Ok(decrypted) = machine.decrypt_room_event(&ev, room_id).await {
return decrypted;
}
}
}
}
}
// Fallback to still-encrypted room event
RoomEvent { event, encryption_info: None }
}
/// Query the server for users device keys.
///
/// # Panics

View File

@@ -122,6 +122,11 @@ pub enum Error {
#[error("The olm machine has already been initialized")]
BadCryptoStoreState,
/// Attempting to access the olm-machine but it is not yet available.
#[cfg(feature = "e2e-encryption")]
#[error("The olm machine isn't yet available")]
NoOlmMachine,
/// An error de/serializing type for the `StateStore`
#[error(transparent)]
SerdeJson(#[from] JsonError),

View File

@@ -4,13 +4,15 @@ use std::{collections::BTreeMap, ops::Deref, sync::Arc};
use futures_core::stream::Stream;
use matrix_sdk_base::deserialized_responses::{MembersResponse, RoomEvent};
#[cfg(feature = "experimental-timeline")]
use matrix_sdk_base::{
deserialized_responses::{SyncRoomEvent, TimelineSlice},
TimelineStreamError,
};
use matrix_sdk_base::{deserialized_responses::TimelineSlice, TimelineStreamError};
use matrix_sdk_common::locks::Mutex;
#[cfg(feature = "experimental-timeline")]
use ruma::api::client::filter::LazyLoadOptions;
#[cfg(feature = "e2e-encryption")]
use ruma::events::{
room::encrypted::OriginalSyncRoomEncryptedEvent, AnySyncMessageLikeEvent, AnySyncRoomEvent,
SyncMessageLikeEvent,
};
use ruma::{
api::client::{
config::set_global_account_data,
@@ -178,24 +180,47 @@ impl Common {
/// # });
/// ```
pub async fn messages(&self, options: MessagesOptions<'_>) -> Result<Messages> {
let request = options.into_request(self.inner.room_id());
let room_id = self.inner.room_id();
let request = options.into_request(room_id);
let http_response = self.client.send(request, None).await?;
#[allow(unused_mut)]
let mut response = Messages {
start: http_response.start,
end: http_response.end,
#[cfg(not(feature = "e2e-encryption"))]
chunk: http_response
.chunk
.into_iter()
.map(|event| RoomEvent { event, encryption_info: None })
.collect(),
#[cfg(feature = "e2e-encryption")]
chunk: Vec::with_capacity(http_response.chunk.len()),
state: http_response.state,
};
for event in http_response.chunk {
#[cfg(feature = "e2e-encryption")]
let event = self.client.decrypt_room_event(event).await;
#[cfg(feature = "e2e-encryption")]
if let Some(machine) = self.client.olm_machine().await {
for event in http_response.chunk {
let decrypted_event =
if let AnySyncRoomEvent::MessageLike(AnySyncMessageLikeEvent::RoomEncrypted(
SyncMessageLikeEvent::Original(encrypted_event),
)) = event.deserialize_as::<AnySyncRoomEvent>()?
{
machine.decrypt_room_event(&encrypted_event, room_id).await?
} else {
RoomEvent { event, encryption_info: None }
};
#[cfg(not(feature = "e2e-encryption"))]
let event = RoomEvent { event, encryption_info: None };
response.chunk.push(event);
response.chunk.push(decrypted_event);
}
} else {
response.chunk.extend(
http_response
.chunk
.into_iter()
.map(|event| RoomEvent { event, encryption_info: None }),
);
}
Ok(response)
@@ -450,10 +475,17 @@ impl Common {
let event = self.client.send(request, None).await?.event;
#[cfg(feature = "e2e-encryption")]
return Ok(self.client.decrypt_room_event(event).await);
if let AnySyncRoomEvent::MessageLike(AnySyncMessageLikeEvent::RoomEncrypted(
SyncMessageLikeEvent::Original(encrypted_event),
)) = event.deserialize_as::<AnySyncRoomEvent>()?
{
Ok(self.decrypt_event(&encrypted_event).await?)
} else {
Ok(RoomEvent { event, encryption_info: None })
}
#[cfg(not(feature = "e2e-encryption"))]
return Ok(RoomEvent { event, encryption_info: None });
Ok(RoomEvent { event, encryption_info: None })
}
pub(crate) async fn request_members(&self) -> Result<Option<MembersResponse>> {
@@ -876,6 +908,21 @@ impl Common {
self.client.send(request, None).await?;
Ok(())
}
/// Tries to decrypt a room event.
///
/// # Arguments
/// * `event` - The room event to be decrypted.
///
/// Returns the decrypted event.
#[cfg(feature = "e2e-encryption")]
pub async fn decrypt_event(&self, event: &OriginalSyncRoomEncryptedEvent) -> Result<RoomEvent> {
if let Some(machine) = self.client.olm_machine().await {
Ok(machine.decrypt_room_event(event, self.inner.room_id()).await?)
} else {
Err(Error::NoOlmMachine)
}
}
}
/// Options for [`messages`][Common::messages].