From 15fdf1e86e589be7a34bb6f97f580c239f7afb2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 1 Jul 2025 15:32:06 +0200 Subject: [PATCH] feat(base): Remember when a user explicitly accepted an invite --- crates/matrix-sdk-base/CHANGELOG.md | 7 +++++ crates/matrix-sdk-base/src/client.rs | 18 +++++++++++ crates/matrix-sdk-base/src/room/room_info.rs | 31 +++++++++++++++++-- .../src/store/migration_helpers.rs | 1 + 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/crates/matrix-sdk-base/CHANGELOG.md b/crates/matrix-sdk-base/CHANGELOG.md index 16108fadc..c1bff808b 100644 --- a/crates/matrix-sdk-base/CHANGELOG.md +++ b/crates/matrix-sdk-base/CHANGELOG.md @@ -6,6 +6,13 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - ReleaseDate +### Features +- The `RoomInfo` now remembers when an invite was explicitly accepted when the + `BaseClient::room_joined()` method was called. A new getter for this + timestamp exists, the `RoomInfo::invite_accepted_at()` method returns this + timestamp. + ([#5333](https://github.com/matrix-org/matrix-rust-sdk/pull/5333)) + ### Refactor - The cached `ServerCapabilities` has been renamed to `ServerInfo` and diff --git a/crates/matrix-sdk-base/src/client.rs b/crates/matrix-sdk-base/src/client.rs index 7bb1d3036..cb0254d27 100644 --- a/crates/matrix-sdk-base/src/client.rs +++ b/crates/matrix-sdk-base/src/client.rs @@ -459,12 +459,30 @@ impl BaseClient { let _sync_lock = self.sync_lock().lock().await; let mut room_info = room.clone_info(); + + // If our previous state was an invite and we're now in the joined state, this + // means that the user has explicitly accepted the invite. Let's + // remember when this has happened. + // + // This is somewhat of a workaround for our lack of cryptographic membership. + // Later on we will decide if historic room keys should be accepted + // based on this info. If a user has accepted an invite and we receive a room + // key bundle shortly after, we might accept it. If we don't do + // this, the homeserver could trick us into accepting any historic room key + // bundle. + if room.state() == RoomState::Invited { + room_info.set_invite_accepted_now(); + } + room_info.mark_as_joined(); room_info.mark_state_partially_synced(); room_info.mark_members_missing(); // the own member event changed + let mut changes = StateChanges::default(); changes.add_room(room_info.clone()); + self.state_store.save_changes(&changes).await?; // Update the store + room.set_room_info(room_info, RoomInfoNotableUpdateReasons::MEMBERSHIP); } diff --git a/crates/matrix-sdk-base/src/room/room_info.rs b/crates/matrix-sdk-base/src/room/room_info.rs index 2dd2f7a43..525de26b5 100644 --- a/crates/matrix-sdk-base/src/room/room_info.rs +++ b/crates/matrix-sdk-base/src/room/room_info.rs @@ -46,8 +46,8 @@ use ruma::{ }, room::RoomType, serde::Raw, - EventId, MxcUri, OwnedEventId, OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, - RoomAliasId, RoomId, RoomVersionId, UserId, + EventId, MilliSecondsSinceUnixEpoch, MxcUri, OwnedEventId, OwnedMxcUri, OwnedRoomAliasId, + OwnedRoomId, OwnedUserId, RoomAliasId, RoomId, RoomVersionId, UserId, }; use serde::{Deserialize, Serialize}; use tracing::{debug, field::debug, info, instrument, warn}; @@ -464,6 +464,14 @@ pub struct RoomInfo { /// more accurate than relying on the latest event. #[serde(default)] pub(crate) recency_stamp: Option, + + /// A timestamp remembering when we observed the user accepting an invite on + /// this current device. + /// + /// This is useful to remember if the user accepted this a join on this + /// specific client. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub(crate) invite_accepted_at: Option, } impl RoomInfo { @@ -486,6 +494,7 @@ impl RoomInfo { cached_display_name: None, cached_user_defined_notification_mode: None, recency_stamp: None, + invite_accepted_at: None, } } @@ -749,6 +758,22 @@ impl RoomInfo { self.summary.invited_member_count = count; } + /// Mark that the user has accepted an invite and remember when this has + /// happened using a timestamp set to [`MilliSecondsSinceUnixEpoch::now()`]. + pub(crate) fn set_invite_accepted_now(&mut self) { + self.invite_accepted_at = Some(MilliSecondsSinceUnixEpoch::now()); + } + + /// Returns the timestamp when an invite to this room has been accepted by + /// this specific client. + /// + /// # Returns + /// - `Some` if the invite has been accepted by this specific client. + /// - `None` if the invite has not been accepted + pub fn invite_accepted_at(&self) -> Option { + self.invite_accepted_at + } + /// Updates the room heroes. pub(crate) fn update_heroes(&mut self, heroes: Vec) { self.summary.room_heroes = heroes; @@ -1173,6 +1198,7 @@ mod tests { owned_mxc_uri, owned_user_id, room_id, serde::Raw, }; use serde_json::json; + use similar_asserts::assert_eq; use super::{BaseRoomInfo, RoomInfo, SyncInfo}; use crate::{ @@ -1221,6 +1247,7 @@ mod tests { cached_display_name: None, cached_user_defined_notification_mode: None, recency_stamp: Some(42), + invite_accepted_at: None, }; let info_json = json!({ diff --git a/crates/matrix-sdk-base/src/store/migration_helpers.rs b/crates/matrix-sdk-base/src/store/migration_helpers.rs index 36a459c67..0006a390f 100644 --- a/crates/matrix-sdk-base/src/store/migration_helpers.rs +++ b/crates/matrix-sdk-base/src/store/migration_helpers.rs @@ -121,6 +121,7 @@ impl RoomInfoV1 { cached_display_name: None, cached_user_defined_notification_mode: None, recency_stamp: None, + invite_accepted_at: None, } } }