Skip to content

refactor!(crypto): Don't process in-room verification implicitly #1342

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bindings/matrix-sdk-crypto-ffi/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,6 @@ pub enum DecryptionError {
Identifier(#[from] IdParseError),
#[error(transparent)]
Megolm(#[from] MegolmError),
#[error(transparent)]
Store(#[from] InnerStoreError),
}
42 changes: 38 additions & 4 deletions bindings/matrix-sdk-crypto-ffi/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ use ruma::{
},
IncomingResponse,
},
events::{key::verification::VerificationMethod, AnySyncMessageLikeEvent},
events::{
key::verification::VerificationMethod, room::message::MessageType, AnyMessageLikeEvent,
AnySyncMessageLikeEvent, AnyTimelineEvent, MessageLikeEvent,
},
serde::Raw,
DeviceKeyAlgorithm, EventId, OwnedTransactionId, OwnedUserId, RoomId, UserId,
};
Expand Down Expand Up @@ -635,6 +638,7 @@ impl OlmMachine {
&self,
event: &str,
room_id: &str,
handle_verification_events: bool,
) -> Result<DecryptedEvent, DecryptionError> {
// Element Android wants only the content and the type and will create a
// decrypted event with those two itself, this struct makes sure we
Expand All @@ -652,6 +656,25 @@ impl OlmMachine {

let decrypted = self.runtime.block_on(self.inner.decrypt_room_event(&event, &room_id))?;

if handle_verification_events {
if let Ok(AnyTimelineEvent::MessageLike(e)) = decrypted.event.deserialize() {
match &e {
AnyMessageLikeEvent::RoomMessage(MessageLikeEvent::Original(
original_event,
)) => {
if let MessageType::VerificationRequest(_) = &original_event.content.msgtype
{
self.runtime.block_on(self.inner.receive_verification_event(&e))?;
}
}
_ if e.event_type().to_string().starts_with("m.key.verification") => {
self.runtime.block_on(self.inner.receive_verification_event(&e))?;
}
_ => (),
}
}
}

let encryption_info =
decrypted.encryption_info.expect("Decrypted event didn't contain any encryption info");

Expand Down Expand Up @@ -810,19 +833,30 @@ impl OlmMachine {
/// This method can be used to pass verification events that are happening
/// in unencrypted rooms to the `OlmMachine`.
///
/// **Note**: This does not need to be called for encrypted events since
/// those will get passed to the `OlmMachine` during decryption.
/// **Note**: This has been deprecated.
pub fn receive_unencrypted_verification_event(
&self,
event: &str,
room_id: &str,
) -> Result<(), CryptoStoreError> {
self.receive_verification_event(event, room_id)
}

/// Receive a verification event.
///
/// This method can be used to pass verification events that are happening
/// in rooms to the `OlmMachine`. The event should be in the decrypted form.
pub fn receive_verification_event(
&self,
event: &str,
room_id: &str,
) -> Result<(), CryptoStoreError> {
let room_id = RoomId::parse(room_id)?;
let event: AnySyncMessageLikeEvent = serde_json::from_str(event)?;

let event = event.into_full_event(room_id);

self.runtime.block_on(self.inner.receive_unencrypted_verification_event(&event))?;
self.runtime.block_on(self.inner.receive_verification_event(&event))?;

Ok(())
}
Expand Down
5 changes: 4 additions & 1 deletion bindings/matrix-sdk-crypto-ffi/src/olm.udl
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ enum DecryptionError {
"Identifier",
"Serialization",
"Megolm",
"Store",
};

dictionary DeviceLists {
Expand Down Expand Up @@ -365,7 +366,7 @@ interface OlmMachine {
);

[Throws=DecryptionError]
DecryptedEvent decrypt_room_event([ByRef] string event, [ByRef] string room_id);
DecryptedEvent decrypt_room_event([ByRef] string event, [ByRef] string room_id, boolean handle_verificaton_events);
[Throws=CryptoStoreError]
string encrypt([ByRef] string room_id, [ByRef] string event_type, [ByRef] string content);

Expand Down Expand Up @@ -396,6 +397,8 @@ interface OlmMachine {

[Throws=CryptoStoreError]
void receive_unencrypted_verification_event([ByRef] string event, [ByRef] string room_id);
[Throws=CryptoStoreError]
void receive_verification_event([ByRef] string event, [ByRef] string room_id);
sequence<VerificationRequest> get_verification_requests([ByRef] string user_id);
VerificationRequest? get_verification_request([ByRef] string user_id, [ByRef] string flow_id);
Verification? get_verification([ByRef] string user_id, [ByRef] string flow_id);
Expand Down
19 changes: 6 additions & 13 deletions bindings/matrix-sdk-crypto-js/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -633,24 +633,17 @@ impl OlmMachine {
.collect()
}

/// Receive an unencrypted verification event.
/// Receive a verification event.
///
/// This method can be used to pass verification events that are
/// happening in unencrypted rooms to the `OlmMachine`.
///
/// Note: This does not need to be called for encrypted events
/// since those will get passed to the `OlmMachine` during
/// decryption.
#[wasm_bindgen(js_name = "receiveUnencryptedVerificationEvent")]
pub fn receive_unencrypted_verification_event(&self, event: &str) -> Result<Promise, JsError> {
/// This method can be used to pass verification events that are happening
/// in rooms to the `OlmMachine`. The event should be in the decrypted form.
#[wasm_bindgen(js_name = "receiveVerificationEvent")]
pub fn receive_verification_event(&self, event: &str) -> Result<Promise, JsError> {
let event: ruma::events::AnyMessageLikeEvent = serde_json::from_str(event)?;
let me = self.inner.clone();

Ok(future_to_promise(async move {
Ok(me
.receive_unencrypted_verification_event(&event)
.await
.map(|_| JsValue::UNDEFINED)?)
Ok(me.receive_verification_event(&event).await.map(|_| JsValue::UNDEFINED)?)
}))
}

Expand Down
58 changes: 43 additions & 15 deletions crates/matrix-sdk-base/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ use matrix_sdk_crypto::{
use once_cell::sync::OnceCell;
#[cfg(feature = "e2e-encryption")]
use ruma::events::{
room::{history_visibility::HistoryVisibility, redaction::SyncRoomRedactionEvent},
room::{
history_visibility::HistoryVisibility, message::MessageType,
redaction::SyncRoomRedactionEvent,
},
AnySyncMessageLikeEvent, SyncMessageLikeEvent,
};
use ruma::{
Expand Down Expand Up @@ -240,21 +243,49 @@ impl BaseClient {
}

#[cfg(feature = "e2e-encryption")]
async fn handle_unencrypted_verification_event(
async fn handle_verification_event(
&self,
event: &AnySyncMessageLikeEvent,
room_id: &RoomId,
) -> Result<()> {
if let Some(olm) = self.olm_machine() {
olm.receive_unencrypted_verification_event(
&event.clone().into_full_event(room_id.to_owned()),
)
.await?;
olm.receive_verification_event(&event.clone().into_full_event(room_id.to_owned()))
.await?;
}

Ok(())
}

#[cfg(feature = "e2e-encryption")]
async fn decrypt_sync_room_event(
&self,
event: &Raw<AnySyncTimelineEvent>,
room_id: &RoomId,
) -> Result<Option<SyncTimelineEvent>> {
let Some(olm) = self.olm_machine() else { return Ok(None) };

let event = olm.decrypt_room_event(event.cast_ref(), room_id).await.unwrap();
let event: SyncTimelineEvent = event.into();

if let Ok(AnySyncTimelineEvent::MessageLike(e)) = event.event.deserialize() {
match &e {
AnySyncMessageLikeEvent::RoomMessage(SyncMessageLikeEvent::Original(
original_event,
)) => {
if let MessageType::VerificationRequest(_) = &original_event.content.msgtype {
self.handle_verification_event(&e, room_id).await?;
}
}
_ if e.event_type().to_string().starts_with("m.key.verification") => {
self.handle_verification_event(&e, room_id).await?;
}
_ => (),
}
}

Ok(Some(event))
}

#[allow(clippy::too_many_arguments)]
pub(crate) async fn handle_timeline(
&self,
Expand Down Expand Up @@ -338,13 +369,10 @@ impl BaseClient {
AnySyncMessageLikeEvent::RoomEncrypted(
SyncMessageLikeEvent::Original(_),
) => {
if let Some(olm) = self.olm_machine() {
if let Ok(decrypted) = olm
.decrypt_room_event(event.event.cast_ref(), room_id)
.await
{
event = decrypted.into();
}
if let Ok(Some(e)) =
self.decrypt_sync_room_event(&event.event, room_id).await
{
event = e;
}
}
AnySyncMessageLikeEvent::RoomMessage(
Expand All @@ -353,12 +381,12 @@ impl BaseClient {
ruma::events::room::message::MessageType::VerificationRequest(
_,
) => {
self.handle_unencrypted_verification_event(e, room_id).await?;
self.handle_verification_event(e, room_id).await?;
}
_ => (),
},
_ if e.event_type().to_string().starts_with("m.key.verification") => {
self.handle_unencrypted_verification_event(e, room_id).await?;
self.handle_verification_event(e, room_id).await?;
}
_ => (),
},
Expand Down
30 changes: 11 additions & 19 deletions crates/matrix-sdk-crypto/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,14 @@ use ruma::{
},
assign,
events::{
secret::request::SecretName, AnyMessageLikeEvent, AnyTimelineEvent, AnyToDeviceEvent,
MessageLikeEventContent,
secret::request::SecretName, AnyMessageLikeEvent, AnyToDeviceEvent, MessageLikeEventContent,
},
serde::Raw,
DeviceId, DeviceKeyAlgorithm, OwnedDeviceId, OwnedDeviceKeyId, OwnedTransactionId, OwnedUserId,
RoomId, TransactionId, UInt, UserId,
};
use serde_json::{value::to_raw_value, Value};
use tracing::{debug, error, field::debug, info, instrument, trace, warn};
use tracing::{debug, error, field::debug, info, instrument, warn};
use vodozemac::{
megolm::{DecryptionError, SessionOrdering},
Curve25519PublicKey, Ed25519Signature,
Expand Down Expand Up @@ -731,13 +730,22 @@ impl OlmMachine {
///
/// **Note**: This does not need to be called for encrypted events since
/// those will get passed to the `OlmMachine` during decryption.
#[deprecated(note = "Use OlmMachine::receive_verification_event instead", since = "0.7.0")]
pub async fn receive_unencrypted_verification_event(
&self,
event: &AnyMessageLikeEvent,
) -> StoreResult<()> {
self.verification_machine.receive_any_event(event).await
}

/// Receive a verification event.
///
/// in rooms to the `OlmMachine`. The event should be in the decrypted form.
/// in rooms to the `OlmMachine`.
pub async fn receive_verification_event(&self, event: &AnyMessageLikeEvent) -> StoreResult<()> {
self.verification_machine.receive_any_event(event).await
}

/// Receive and properly handle a decrypted to-device event.
///
/// # Arguments
Expand Down Expand Up @@ -1127,22 +1135,6 @@ impl OlmMachine {

// TODO: check the message index.
let (decrypted_event, _) = session.decrypt(event).await?;

match decrypted_event.deserialize() {
Ok(e) => {
// TODO: log the event type once `AnyTimelineEvent` has the
// method as well
trace!("Successfully decrypted a room event");

if let AnyTimelineEvent::MessageLike(e) = e {
self.verification_machine.receive_any_event(&e).await?;
}
}
Err(e) => {
warn!("Event was successfully decrypted but has an invalid format: {e}");
}
}

let encryption_info = self.get_encryption_info(&session, &event.sender).await?;

Ok(TimelineEvent { encryption_info: Some(encryption_info), event: decrypted_event })
Expand Down