Skip to content

Commit b3e0a96

Browse files
committed
crypto: Provide EncryptionState to hold reasons why events were UTD
1 parent 866b6e5 commit b3e0a96

File tree

17 files changed

+159
-68
lines changed

17 files changed

+159
-68
lines changed

bindings/matrix-sdk-crypto-ffi/src/machine.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::{
88
};
99

1010
use js_int::UInt;
11-
use matrix_sdk_common::deserialized_responses::AlgorithmInfo;
11+
use matrix_sdk_common::deserialized_responses::{AlgorithmInfo, EncryptionState};
1212
use matrix_sdk_crypto::{
1313
backups::{
1414
MegolmV1BackupKey as RustBackupKey, SignatureState,
@@ -909,8 +909,15 @@ impl OlmMachine {
909909
}
910910
}
911911

912-
let encryption_info =
913-
decrypted.encryption_info.expect("Decrypted event didn't contain any encryption info");
912+
let encryption_info = match decrypted.encryption_state {
913+
EncryptionState::Unencrypted => {
914+
panic!("Decrypted event didn't contain any encryption info")
915+
}
916+
EncryptionState::Decrypted(encryption_info) => encryption_info,
917+
EncryptionState::Utd(_) => {
918+
panic!("Apparently-decrypted event was unable to decrypt")
919+
}
920+
};
914921

915922
let event_json: Event<'_> = serde_json::from_str(decrypted.event.json().get())?;
916923

crates/matrix-sdk-base/src/latest_event.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ mod tests {
562562
json!({
563563
"latest_event": {
564564
"event": {
565-
"encryption_info": null,
565+
"encryption_state": "Unencrypted",
566566
"event": {
567567
"event_id": "$1"
568568
}

crates/matrix-sdk-base/src/rooms/normal.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1805,7 +1805,7 @@ mod tests {
18051805
"encryption_state_synced": true,
18061806
"latest_event": {
18071807
"event": {
1808-
"encryption_info": null,
1808+
"encryption_state": "Unencrypted",
18091809
"event": {
18101810
"sender": "@u:i.uk",
18111811
},

crates/matrix-sdk-common/src/deserialized_responses.rs

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -296,15 +296,31 @@ pub struct EncryptionInfo {
296296
pub verification_state: VerificationState,
297297
}
298298

299+
#[derive(Clone, Debug, Deserialize, Serialize)]
300+
pub enum EncryptionState {
301+
Unencrypted,
302+
Decrypted(EncryptionInfo),
303+
Utd(UtdReason),
304+
}
305+
306+
#[derive(Clone, Debug, Deserialize, Serialize)]
307+
pub enum UtdReason {
308+
FromInsecureDevice,
309+
IdentityViolation,
310+
/// The key was deliberately withheld. Contains the witheld code e.g.
311+
/// "m.unverified" or "m.unavailable".
312+
KeyWithheld(String),
313+
Other,
314+
}
315+
299316
/// A customized version of a room event coming from a sync that holds optional
300317
/// encryption info.
301318
#[derive(Clone, Deserialize, Serialize)]
302319
pub struct SyncTimelineEvent {
303320
/// The actual event.
304321
pub event: Raw<AnySyncTimelineEvent>,
305-
/// The encryption info about the event. Will be `None` if the event was not
306-
/// encrypted.
307-
pub encryption_info: Option<EncryptionInfo>,
322+
/// Whether the event was encrypted, and why it failed to decrypt if it did.
323+
pub encryption_state: EncryptionState,
308324
/// The push actions associated with this event.
309325
#[serde(default, skip_serializing_if = "Vec::is_empty")]
310326
pub push_actions: Vec<Action>,
@@ -321,7 +337,12 @@ impl SyncTimelineEvent {
321337
/// This is a convenience constructor for when you don't need to set
322338
/// `encryption_info` or `push_action`, for example inside a test.
323339
pub fn new(event: Raw<AnySyncTimelineEvent>) -> Self {
324-
Self { event, encryption_info: None, push_actions: vec![], unsigned_encryption_info: None }
340+
Self {
341+
event,
342+
encryption_state: EncryptionState::Unencrypted,
343+
push_actions: vec![],
344+
unsigned_encryption_info: None,
345+
}
325346
}
326347

327348
/// Create a new `SyncTimelineEvent` from the given raw event and push
@@ -333,7 +354,12 @@ impl SyncTimelineEvent {
333354
event: Raw<AnySyncTimelineEvent>,
334355
push_actions: Vec<Action>,
335356
) -> Self {
336-
Self { event, encryption_info: None, push_actions, unsigned_encryption_info: None }
357+
Self {
358+
event,
359+
encryption_state: EncryptionState::Unencrypted,
360+
push_actions,
361+
unsigned_encryption_info: None,
362+
}
337363
}
338364

339365
/// Get the event id of this `SyncTimelineEvent` if the event has any valid
@@ -346,11 +372,11 @@ impl SyncTimelineEvent {
346372
#[cfg(not(tarpaulin_include))]
347373
impl fmt::Debug for SyncTimelineEvent {
348374
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
349-
let SyncTimelineEvent { event, encryption_info, push_actions, unsigned_encryption_info } =
375+
let SyncTimelineEvent { event, encryption_state, push_actions, unsigned_encryption_info } =
350376
self;
351377
let mut s = f.debug_struct("SyncTimelineEvent");
352378
s.field("event", &DebugRawEvent(event));
353-
s.maybe_field("encryption_info", encryption_info);
379+
s.field("encryption_state", encryption_state);
354380
if !push_actions.is_empty() {
355381
s.field("push_actions", push_actions);
356382
}
@@ -373,7 +399,7 @@ impl From<TimelineEvent> for SyncTimelineEvent {
373399
// ignored by a subsequent deserialization.
374400
Self {
375401
event: o.event.cast(),
376-
encryption_info: o.encryption_info,
402+
encryption_state: o.encryption_state,
377403
push_actions: o.push_actions.unwrap_or_default(),
378404
unsigned_encryption_info: o.unsigned_encryption_info,
379405
}
@@ -384,9 +410,8 @@ impl From<TimelineEvent> for SyncTimelineEvent {
384410
pub struct TimelineEvent {
385411
/// The actual event.
386412
pub event: Raw<AnyTimelineEvent>,
387-
/// The encryption info about the event. Will be `None` if the event was not
388-
/// encrypted.
389-
pub encryption_info: Option<EncryptionInfo>,
413+
/// Whether the event was encrypted, and why it failed to decrypt if it did.
414+
pub encryption_state: EncryptionState,
390415
/// The push actions associated with this event, if we had sufficient
391416
/// context to compute them.
392417
pub push_actions: Option<Vec<Action>>,
@@ -402,17 +427,23 @@ impl TimelineEvent {
402427
/// This is a convenience constructor for when you don't need to set
403428
/// `encryption_info` or `push_action`, for example inside a test.
404429
pub fn new(event: Raw<AnyTimelineEvent>) -> Self {
405-
Self { event, encryption_info: None, push_actions: None, unsigned_encryption_info: None }
430+
Self {
431+
event,
432+
encryption_state: EncryptionState::Unencrypted,
433+
push_actions: None,
434+
unsigned_encryption_info: None,
435+
}
406436
}
407437
}
408438

409439
#[cfg(not(tarpaulin_include))]
410440
impl fmt::Debug for TimelineEvent {
411441
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
412-
let TimelineEvent { event, encryption_info, push_actions, unsigned_encryption_info } = self;
442+
let TimelineEvent { event, encryption_state, push_actions, unsigned_encryption_info } =
443+
self;
413444
let mut s = f.debug_struct("TimelineEvent");
414445
s.field("event", &DebugRawEvent(event));
415-
s.maybe_field("encryption_info", encryption_info);
446+
s.field("encryption_state", encryption_state);
416447
if let Some(push_actions) = &push_actions {
417448
if !push_actions.is_empty() {
418449
s.field("push_actions", push_actions);

crates/matrix-sdk-crypto/src/machine/mod.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ use std::{
2121
use itertools::Itertools;
2222
use matrix_sdk_common::{
2323
deserialized_responses::{
24-
AlgorithmInfo, DeviceLinkProblem, EncryptionInfo, TimelineEvent, UnableToDecryptInfo,
25-
UnsignedDecryptionResult, UnsignedEventLocation, VerificationLevel, VerificationState,
24+
AlgorithmInfo, DeviceLinkProblem, EncryptionInfo, EncryptionState, TimelineEvent,
25+
UnableToDecryptInfo, UnsignedDecryptionResult, UnsignedEventLocation, VerificationLevel,
26+
VerificationState,
2627
},
2728
BoxFuture,
2829
};
@@ -1818,7 +1819,7 @@ impl OlmMachine {
18181819

18191820
Ok(TimelineEvent {
18201821
event,
1821-
encryption_info: Some(encryption_info),
1822+
encryption_state: EncryptionState::Decrypted(encryption_info),
18221823
push_actions: None,
18231824
unsigned_encryption_info,
18241825
})
@@ -1902,7 +1903,12 @@ impl OlmMachine {
19021903
Ok(decrypted_event) => {
19031904
// Replace the encrypted event.
19041905
*event = serde_json::to_value(decrypted_event.event).ok()?;
1905-
Some(UnsignedDecryptionResult::Decrypted(decrypted_event.encryption_info?))
1906+
let encryption_info = match decrypted_event.encryption_state {
1907+
EncryptionState::Unencrypted => None,
1908+
EncryptionState::Decrypted(encryption_info) => Some(encryption_info),
1909+
EncryptionState::Utd(_) => None,
1910+
}?;
1911+
Some(UnsignedDecryptionResult::Decrypted(encryption_info))
19061912
}
19071913
Err(_) => {
19081914
let session_id =

crates/matrix-sdk-crypto/src/machine/tests/decryption_verification_state.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use std::{iter, sync::Arc};
1616

1717
use assert_matches2::{assert_let, assert_matches};
1818
use matrix_sdk_common::deserialized_responses::{
19-
DeviceLinkProblem, ShieldState, VerificationLevel, VerificationState,
19+
DeviceLinkProblem, EncryptionState, ShieldState, VerificationLevel, VerificationState,
2020
};
2121
use matrix_sdk_test::{async_test, ruma_response_from_json, test_json};
2222
use ruma::{
@@ -113,12 +113,16 @@ async fn test_decryption_verification_state() {
113113

114114
let decryption_settings =
115115
DecryptionSettings { sender_device_trust_requirement: TrustRequirement::Untrusted };
116-
let encryption_info = bob
116+
let encryption_info = match bob
117117
.decrypt_room_event(&event, room_id, &decryption_settings)
118118
.await
119119
.unwrap()
120-
.encryption_info
121-
.unwrap();
120+
.encryption_state
121+
{
122+
EncryptionState::Unencrypted => panic!("Event was unexpectedly unencrypted"),
123+
EncryptionState::Decrypted(encryption_info) => encryption_info,
124+
EncryptionState::Utd(_) => panic!("Unexpectedely failed to decrypt"),
125+
};
122126

123127
assert_eq!(
124128
VerificationState::Unverified(VerificationLevel::UnsignedDevice),

crates/matrix-sdk-crypto/src/machine/tests/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use assert_matches2::assert_matches;
1818
use futures_util::{pin_mut, FutureExt, StreamExt};
1919
use itertools::Itertools;
2020
use matrix_sdk_common::deserialized_responses::{
21-
UnableToDecryptInfo, UnsignedDecryptionResult, UnsignedEventLocation,
21+
EncryptionState, UnableToDecryptInfo, UnsignedDecryptionResult, UnsignedEventLocation,
2222
};
2323
use matrix_sdk_test::{async_test, message_like_event_content, ruma_response_from_json, test_json};
2424
use ruma::{
@@ -1300,7 +1300,7 @@ async fn test_unsigned_decryption() {
13001300
assert_eq!(first_message.content.body(), first_message_text);
13011301
assert!(first_message.unsigned.relations.is_empty());
13021302

1303-
assert!(raw_decrypted_event.encryption_info.is_some());
1303+
assert_matches!(raw_decrypted_event.encryption_state, EncryptionState::Decrypted(_));
13041304
assert!(raw_decrypted_event.unsigned_encryption_info.is_none());
13051305

13061306
// Get a new room key, but don't give it to Bob yet.
@@ -1355,7 +1355,7 @@ async fn test_unsigned_decryption() {
13551355
assert!(first_message.unsigned.relations.replace.is_none());
13561356
assert!(first_message.unsigned.relations.has_replacement());
13571357

1358-
assert!(raw_decrypted_event.encryption_info.is_some());
1358+
assert_matches!(raw_decrypted_event.encryption_state, EncryptionState::Decrypted(_));
13591359
let unsigned_encryption_info = raw_decrypted_event.unsigned_encryption_info.unwrap();
13601360
assert_eq!(unsigned_encryption_info.len(), 1);
13611361
let replace_encryption_result =
@@ -1399,7 +1399,7 @@ async fn test_unsigned_decryption() {
13991399
assert_matches!(&replace.content.relates_to, Some(Relation::Replacement(replace_content)));
14001400
assert_eq!(replace_content.new_content.msgtype.body(), second_message_text);
14011401

1402-
assert!(raw_decrypted_event.encryption_info.is_some());
1402+
assert_matches!(raw_decrypted_event.encryption_state, EncryptionState::Decrypted(_));
14031403
let unsigned_encryption_info = raw_decrypted_event.unsigned_encryption_info.unwrap();
14041404
assert_eq!(unsigned_encryption_info.len(), 1);
14051405
let replace_encryption_result =
@@ -1465,7 +1465,7 @@ async fn test_unsigned_decryption() {
14651465
let thread = first_message.unsigned.relations.thread.as_ref().unwrap();
14661466
assert_matches!(thread.latest_event.deserialize(), Ok(AnyMessageLikeEvent::RoomEncrypted(_)));
14671467

1468-
assert!(raw_decrypted_event.encryption_info.is_some());
1468+
assert_matches!(raw_decrypted_event.encryption_state, EncryptionState::Decrypted(_));
14691469
let unsigned_encryption_info = raw_decrypted_event.unsigned_encryption_info.unwrap();
14701470
assert_eq!(unsigned_encryption_info.len(), 2);
14711471
let replace_encryption_result =
@@ -1517,7 +1517,7 @@ async fn test_unsigned_decryption() {
15171517
let third_message = third_message.as_original().unwrap();
15181518
assert_eq!(third_message.content.body(), third_message_text);
15191519

1520-
assert!(raw_decrypted_event.encryption_info.is_some());
1520+
assert_matches!(raw_decrypted_event.encryption_state, EncryptionState::Decrypted(_));
15211521
let unsigned_encryption_info = raw_decrypted_event.unsigned_encryption_info.unwrap();
15221522
assert_eq!(unsigned_encryption_info.len(), 2);
15231523
let replace_encryption_result =

crates/matrix-sdk-ui/src/timeline/controller/state.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ use std::{
2222
use eyeball_im::{ObservableVector, ObservableVectorTransaction, ObservableVectorTransactionEntry};
2323
use itertools::Itertools as _;
2424
use matrix_sdk::{
25-
deserialized_responses::SyncTimelineEvent, ring_buffer::RingBuffer, send_queue::SendHandle,
25+
deserialized_responses::{EncryptionState, SyncTimelineEvent},
26+
ring_buffer::RingBuffer,
27+
send_queue::SendHandle,
2628
};
2729
use matrix_sdk_base::deserialized_responses::TimelineEvent;
2830
#[cfg(test)]
@@ -584,7 +586,11 @@ impl TimelineStateTransaction<'_> {
584586
flow: Flow::Remote {
585587
event_id: event_id.clone(),
586588
raw_event: raw.clone(),
587-
encryption_info: event.encryption_info,
589+
encryption_info: match event.encryption_state {
590+
EncryptionState::Unencrypted => None,
591+
EncryptionState::Decrypted(encryption_info) => Some(encryption_info),
592+
EncryptionState::Utd(_) => None,
593+
},
588594
txn_id,
589595
position,
590596
},

crates/matrix-sdk-ui/src/timeline/day_dividers.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ enum DayDividerInsertError {
609609
mod tests {
610610
use assert_matches2::assert_let;
611611
use eyeball_im::ObservableVector;
612+
use matrix_sdk::deserialized_responses::EncryptionState;
612613
use ruma::{owned_event_id, owned_user_id, uint, MilliSecondsSinceUnixEpoch};
613614

614615
use super::DayDividerAdjuster;
@@ -626,7 +627,7 @@ mod tests {
626627
read_receipts: Default::default(),
627628
is_own: false,
628629
is_highlighted: false,
629-
encryption_info: None,
630+
encryption_state: EncryptionState::Unencrypted,
630631
original_json: None,
631632
latest_edit_json: None,
632633
origin: crate::timeline::event_item::RemoteEventOrigin::Sync,

crates/matrix-sdk-ui/src/timeline/event_handler.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ use as_variant::as_variant;
1818
use eyeball_im::{ObservableVectorTransaction, ObservableVectorTransactionEntry};
1919
use indexmap::IndexMap;
2020
use matrix_sdk::{
21-
crypto::types::events::UtdCause, deserialized_responses::EncryptionInfo, send_queue::SendHandle,
21+
crypto::types::events::UtdCause,
22+
deserialized_responses::{EncryptionInfo, EncryptionState},
23+
send_queue::SendHandle,
2224
};
2325
use ruma::{
2426
events::{
@@ -598,7 +600,13 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> {
598600
if let EventTimelineItemKind::Remote(remote_event) = &item.kind {
599601
if let Flow::Remote { encryption_info, .. } = &self.ctx.flow {
600602
new_item = new_item.with_kind(EventTimelineItemKind::Remote(
601-
remote_event.with_encryption_info(encryption_info.clone()),
603+
remote_event.with_encryption_state(
604+
if let Some(encryption_info) = encryption_info {
605+
EncryptionState::Decrypted(encryption_info.clone())
606+
} else {
607+
EncryptionState::Unencrypted
608+
},
609+
),
602610
));
603611
}
604612
}
@@ -948,7 +956,11 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> {
948956
read_receipts: self.ctx.read_receipts.clone(),
949957
is_own: self.ctx.is_own_event,
950958
is_highlighted: self.ctx.is_highlighted,
951-
encryption_info: encryption_info.clone(),
959+
encryption_state: if let Some(encryption_info) = encryption_info {
960+
EncryptionState::Decrypted(encryption_info.clone())
961+
} else {
962+
EncryptionState::Unencrypted
963+
},
952964
original_json: Some(raw_event.clone()),
953965
latest_edit_json: None,
954966
origin,

0 commit comments

Comments
 (0)