Skip to content

Commit

Permalink
sdk-ui: Fix a bug where local echoes were showing unencrypted shields.
Browse files Browse the repository at this point in the history
  • Loading branch information
pixlwave authored and stefanceriu committed Aug 1, 2024
1 parent 7c5c5a8 commit aee8728
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 4 deletions.
2 changes: 1 addition & 1 deletion crates/matrix-sdk-ui/src/timeline/event_item/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ impl EventTimelineItem {
/// Gets the [`ShieldState`] which can be used to decorate messages in the
/// recommended way.
pub fn get_shield(&self, strict: bool) -> Option<ShieldState> {
if self.is_room_encrypted != Some(true) {
if self.is_room_encrypted != Some(true) || self.is_local_echo() {
return None;
}

Expand Down
80 changes: 77 additions & 3 deletions crates/matrix-sdk-ui/src/timeline/tests/shields.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use assert_matches::assert_matches;
use eyeball_im::VectorDiff;
use matrix_sdk_base::deserialized_responses::ShieldState;
use matrix_sdk_test::{async_test, ALICE};
use ruma::events::room::message::RoomMessageEventContent;
use matrix_sdk_test::{async_test, sync_timeline_event, ALICE};
use ruma::{
event_id,
events::{room::message::RoomMessageEventContent, AnyMessageLikeEventContent},
};
use stream_assert::assert_next_matches;

use crate::timeline::tests::TestTimeline;
use crate::timeline::{tests::TestTimeline, EventSendState};

#[async_test]
async fn test_no_shield_in_unencrypted_room() {
Expand Down Expand Up @@ -39,3 +43,73 @@ async fn test_sent_in_clear_shield() {
let shield = item.as_event().unwrap().get_shield(false);
assert_eq!(shield, Some(ShieldState::Grey { message: "Sent in clear." }));
}

#[async_test]
/// Note: This is a regression test for a bug where the SentInClear shield was
/// incorrectly shown on a local echo whilst sending and was then removed once
/// the local echo came back. There doesn't appear to be an obvious way to mock
/// trust in the timeline, so this test uses a message sent in the clear, making
/// sure the shield only appears once the remote echo is received.
async fn test_local_sent_in_clear_shield() {
// Given an encrypted timeline.
let timeline = TestTimeline::with_is_room_encrypted(true);
let mut stream = timeline.subscribe().await;

// When sending an unencrypted event.
let event_id = event_id!("$W6mZSLWMmfuQQ9jhZWeTxFIM");
let txn_id = timeline
.handle_local_event(AnyMessageLikeEventContent::RoomMessage(
RoomMessageEventContent::text_plain("Local message"),
))
.await;
let item = assert_next_matches!(stream, VectorDiff::PushBack { value } => value);
let event_item = item.as_event().unwrap();

// Then it's local echo should not have a shield (as encryption info isn't
// available).
assert!(event_item.is_local_echo());
let shield = event_item.get_shield(false);
assert_eq!(shield, None);

{
// The day divider comes in late.
let day_divider = assert_next_matches!(stream, VectorDiff::PushFront { value } => value);
assert!(day_divider.is_day_divider());
}

// When the event is sent (but without a remote echo).
timeline
.inner
.update_event_send_state(&txn_id, EventSendState::Sent { event_id: event_id.to_owned() })
.await;
let item = assert_next_matches!(stream, VectorDiff::Set { value, index: 1 } => value);
let event_item = item.as_event().unwrap();
let timestamp = event_item.timestamp();
assert_matches!(event_item.send_state(), Some(EventSendState::Sent { .. }));

// Then the local echo still should not have a shield.
assert!(event_item.is_local_echo());
let shield = event_item.get_shield(false);
assert_eq!(shield, None);

// When the remote echo comes in.
timeline
.handle_live_event(sync_timeline_event!({
"content": {
"body": "Local message",
"msgtype": "m.text",
},
"sender": &*ALICE,
"event_id": event_id,
"origin_server_ts": timestamp,
"type": "m.room.message",
}))
.await;
let item = assert_next_matches!(stream, VectorDiff::Set { index: 1, value } => value);
let event_item = item.as_event().unwrap();

// Then the remote echo should now be showing the shield.
assert!(!event_item.is_local_echo());
let shield = event_item.get_shield(false);
assert_eq!(shield, Some(ShieldState::Grey { message: "Sent in clear." }));
}

0 comments on commit aee8728

Please sign in to comment.