From 5eeea83c19245c2b34880d8ef1c34dbf1555a742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Wed, 22 Mar 2023 16:26:00 +0100 Subject: [PATCH] sdk: Get push actions of retried decrypted events in the timeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- crates/matrix-sdk/src/room/common.rs | 2 +- crates/matrix-sdk/src/room/timeline/inner.rs | 35 +++++++- .../src/room/timeline/tests/encryption.rs | 85 +++++++++++++++++++ .../matrix-sdk/src/room/timeline/tests/mod.rs | 23 ++++- 4 files changed, 140 insertions(+), 5 deletions(-) diff --git a/crates/matrix-sdk/src/room/common.rs b/crates/matrix-sdk/src/room/common.rs index 18495832a..731b548db 100644 --- a/crates/matrix-sdk/src/room/common.rs +++ b/crates/matrix-sdk/src/room/common.rs @@ -1027,7 +1027,7 @@ impl Common { /// /// Returns `None` if some data couldn't be found. This should only happen /// in brand new rooms, while we process its state. - async fn push_context(&self) -> Result> { + pub(crate) async fn push_context(&self) -> Result> { let room_id = self.room_id(); let user_id = self.own_user_id(); let room_info = self.clone_info(); diff --git a/crates/matrix-sdk/src/room/timeline/inner.rs b/crates/matrix-sdk/src/room/timeline/inner.rs index 226582148..add5def68 100644 --- a/crates/matrix-sdk/src/room/timeline/inner.rs +++ b/crates/matrix-sdk/src/room/timeline/inner.rs @@ -36,7 +36,7 @@ use ruma::{ relation::Annotation, AnyMessageLikeEventContent, AnySyncTimelineEvent, }, - push::Action, + push::{Action, PushConditionRoomCtx, Ruleset}, serde::Raw, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, OwnedUserId, TransactionId, UserId, @@ -359,6 +359,9 @@ impl TimelineInner

{ use super::EncryptedMessage; trace!("Retrying decryption"); + + let push_rules_context = self.room_data_provider.push_rules_and_context().await; + let should_retry = |session_id: &str| { if let Some(session_ids) = &session_ids { session_ids.contains(session_id) @@ -422,10 +425,17 @@ impl TimelineInner

{ continue; }; + let push_actions = push_rules_context + .as_ref() + .map(|(push_rules, push_context)| { + push_rules.get_actions(&event.event, push_context).to_owned() + }) + .unwrap_or_default(); + let result = handle_remote_event( event.event.cast(), event.encryption_info, - event.push_actions, + push_actions, TimelineItemPosition::Update(idx), &mut state, &self.room_data_provider, @@ -710,6 +720,7 @@ pub(super) trait RoomDataProvider { fn own_user_id(&self) -> &UserId; async fn profile(&self, user_id: &UserId) -> Option; async fn read_receipts_for_event(&self, event_id: &EventId) -> IndexMap; + async fn push_rules_and_context(&self) -> Option<(Ruleset, PushConditionRoomCtx)>; } #[async_trait] @@ -747,6 +758,26 @@ impl RoomDataProvider for room::Common { } } } + + async fn push_rules_and_context(&self) -> Option<(Ruleset, PushConditionRoomCtx)> { + match self.push_context().await { + Ok(Some(push_context)) => match self.client().account().push_rules().await { + Ok(push_rules) => Some((push_rules, push_context)), + Err(e) => { + error!("Could not get push rules: {e}"); + None + } + }, + Ok(None) => { + debug!("Could not aggregate push context"); + None + } + Err(e) => { + error!("Could not get push context: {e}"); + None + } + } + } } /// Handle a remote event. diff --git a/crates/matrix-sdk/src/room/timeline/tests/encryption.rs b/crates/matrix-sdk/src/room/timeline/tests/encryption.rs index 3deba7770..de221f8b2 100644 --- a/crates/matrix-sdk/src/room/timeline/tests/encryption.rs +++ b/crates/matrix-sdk/src/room/timeline/tests/encryption.rs @@ -101,6 +101,7 @@ async fn retry_message_decryption() { assert_matches!(event.encryption_info(), Some(_)); let text = assert_matches!(event.content(), TimelineItemContent::Message(msg) => msg.body()); assert_eq!(text, "It's a secret to everybody"); + assert!(!event.is_highlighted()); } #[async_test] @@ -310,3 +311,87 @@ async fn retry_edit_and_more() { "Another message" ); } + +#[async_test] +async fn retry_message_decryption_highlighted() { + const SESSION_ID: &str = "C25PoE+4MlNidQD0YU5ibZqHawV0zZ/up7R8vYJBYTY"; + const SESSION_KEY: &[u8] = b"\ + -----BEGIN MEGOLM SESSION DATA-----\n\ + AUBvCG7VHqpYOpNJoIVxsTS1Qyu83w6xFDw67qDe1edSAAAACrnzwQzFMw//BB9iNKTviUfGPEKD9XlL9f8N\ + svGCe971WnKLqWJjtrc42UfyDXH0fz4HXeCN1b104GlzWVFp0r+9RuQpPsP3IZ1DxWPm/xsotr3N4BY3pdgK\ + wpbCq3oD9bQ0jcYqajrWfmEagSInobo9jd6CPyj6kz7mU/SXwva+aoYB8fVJptdYbIXQbvD8t9vS5SC6ZGlP\ + CpcJBscXIq79HpWgDjnfvUNZiITlazFcgPB8zI78MwISm4FX/4KAwxjWf0eGNwKPiTP8fjXpxKurgnMQEET/\ + nVb/r4yIO1Z8rM6vmzoTcQvUc5pXmAGhcLGWN6Q06D3hBuWw0etCKRW5bqcMRit5wmawvBV6j+QNKSPKy7xQ\ + zQhzx9TFfgGZ7rRsl9EPxn0FB/EJNHOkbqYqOmKix9jbh820jRG9i4vD+x+U6iXGpRPyb2S8w+1f9n3uH3yI\ + 0XWypoX/eEh7cJv9YChq4Wst4UkP2l6ztP8H/dWXfDYHddkMMKnveeb3sjWRjJep7Ih3W5PyMmxfge85DryB\ + Sgvx6TKvtiC4zOKp1VStbXNgrpipWixhXP2F8BkDmJJvDYO1idWU2NbDJZY6AkKockUscnovpmV1yhovm83Y\ + sAZRyV3W2MlFpA5qAgdXWlBA4WZ/jus/Mey0dqFZtvDS6fC1S4cx5p6hXBwADLRjIiqq2dpn49+aUwqPMn/b\ + FM8H2PpVkKgrA+tx8LNQD+FWDfp6MyhmEJEvk9r5vU9LtTXtZl4toYvNY0UHUBbZj2xF9U9Z9A\n\ + -----END MEGOLM SESSION DATA-----"; + + let timeline = TestTimeline::new(); + let mut stream = timeline.subscribe().await; + + timeline + .handle_live_message_event( + &BOB, + RoomEncryptedEventContent::new( + EncryptedEventScheme::MegolmV1AesSha2( + MegolmV1AesSha2ContentInit { + ciphertext: "\ + AwgAEpABNOd7Rxpc/98gaaOanApQ/h40uNyYE/aiFd8PKeQPH65bwuxBy/glodmteryH\ + 4t5d0cKSPjb+996yK90+A8YUevQKBuC+/+4iRF2CSqMNvArdOCnFHJdZBuCyRP6W82DZ\ + sR1w5X/tKGs/A9egJdxomLCzMRZarayTXUlgMT8Kj7E9zKOgyLEZGki6Y9IPybfrU3+S\ + b4VbF7RKY395/lIZFiLvJ5hUT+Ao1k13opeTE9GHtdOK0GzQPVFLnN61pRa3K/vV9Otk\ + D0QbVS/4mE3C29+yIC1lEkwA" + .to_owned(), + sender_key: "peI8cfSKqZvTOAfY0Od2e7doDpJ1cxdBsOhSceTLU3E".to_owned(), + device_id: "KDCTEHOVSS".into(), + session_id: SESSION_ID.into(), + } + .into(), + ), + None, + ), + ) + .await; + + assert_eq!(timeline.inner.items().await.len(), 2); + + let _day_divider = + assert_matches!(stream.next().await, Some(VectorDiff::PushBack { value }) => value); + let item = assert_matches!(stream.next().await, Some(VectorDiff::PushBack { value }) => value); + let event = item.as_event().unwrap(); + let session_id = assert_matches!( + event.content(), + TimelineItemContent::UnableToDecrypt( + EncryptedMessage::MegolmV1AesSha2 { session_id, .. }, + ) => session_id + ); + assert_eq!(session_id, SESSION_ID); + + let own_user_id = user_id!("@example:matrix.org"); + let exported_keys = decrypt_room_key_export(Cursor::new(SESSION_KEY), "1234").unwrap(); + + let olm_machine = OlmMachine::new(own_user_id, "SomeDeviceId".into()).await; + olm_machine.import_room_keys(exported_keys, false, |_, _| {}).await.unwrap(); + + timeline + .inner + .retry_event_decryption( + room_id!("!rYtFvMGENJleNQVJzb:matrix.org"), + &olm_machine, + Some(iter::once(SESSION_ID).collect()), + ) + .await; + + assert_eq!(timeline.inner.items().await.len(), 2); + + let item = + assert_matches!(stream.next().await, Some(VectorDiff::Set { index: 1, value }) => value); + let event = item.as_event().unwrap().as_remote().unwrap(); + assert_matches!(event.encryption_info(), Some(_)); + let text = assert_matches!(event.content(), TimelineItemContent::Message(msg) => msg.body()); + assert_eq!(text, "A secret to everybody but Alice"); + assert!(event.is_highlighted()); +} diff --git a/crates/matrix-sdk/src/room/timeline/tests/mod.rs b/crates/matrix-sdk/src/room/timeline/tests/mod.rs index 9105846af..3603a3e66 100644 --- a/crates/matrix-sdk/src/room/timeline/tests/mod.rs +++ b/crates/matrix-sdk/src/room/timeline/tests/mod.rs @@ -35,9 +35,13 @@ use ruma::{ RedactedMessageLikeEventContent, RedactedStateEventContent, StateEventContent, StaticStateEventContent, }, + int, + power_levels::NotificationPowerLevels, + push::{PushConditionRoomCtx, Ruleset}, + room_id, serde::Raw, - server_name, user_id, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, - OwnedUserId, TransactionId, UserId, + server_name, uint, user_id, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, + OwnedTransactionId, OwnedUserId, TransactionId, UserId, }; use serde_json::{json, Value as JsonValue}; @@ -305,4 +309,19 @@ impl RoomDataProvider for TestRoomDataProvider { async fn read_receipts_for_event(&self, _event_id: &EventId) -> IndexMap { IndexMap::new() } + + async fn push_rules_and_context(&self) -> Option<(Ruleset, PushConditionRoomCtx)> { + let push_rules = Ruleset::server_default(&ALICE); + let push_context = PushConditionRoomCtx { + room_id: room_id!("!my_room:server.name").to_owned(), + member_count: uint!(2), + user_id: ALICE.to_owned(), + user_display_name: "Alice".to_owned(), + users_power_levels: BTreeMap::new(), + default_power_level: int!(0), + notification_power_levels: NotificationPowerLevels::new(), + }; + + Some((push_rules, push_context)) + } }