feat(base): Remember when a user explicitly accepted an invite

This commit is contained in:
Damir Jelić
2025-07-01 15:32:06 +02:00
parent 3d6d798ca3
commit 15fdf1e86e
4 changed files with 55 additions and 2 deletions

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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<u64>,
/// 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<MilliSecondsSinceUnixEpoch>,
}
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<MilliSecondsSinceUnixEpoch> {
self.invite_accepted_at
}
/// Updates the room heroes.
pub(crate) fn update_heroes(&mut self, heroes: Vec<RoomHero>) {
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!({

View File

@@ -121,6 +121,7 @@ impl RoomInfoV1 {
cached_display_name: None,
cached_user_defined_notification_mode: None,
recency_stamp: None,
invite_accepted_at: None,
}
}
}