Skip to content

Commit ea8664c

Browse files
authored
Merge pull request #4780 from matrix-org/stefan/invitesRoomSummaryFallback
Invites room summary fallback
2 parents c8536e9 + ca025f8 commit ea8664c

File tree

7 files changed

+100
-38
lines changed

7 files changed

+100
-38
lines changed

bindings/matrix-sdk-ffi/src/client.rs

+18
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,24 @@ impl Client {
886886
self.inner.rooms().into_iter().map(|room| Arc::new(Room::new(room))).collect()
887887
}
888888

889+
/// Get a room by its ID.
890+
///
891+
/// # Arguments
892+
///
893+
/// * `room_id` - The ID of the room to get.
894+
///
895+
/// # Returns
896+
///
897+
/// A `Result` containing an optional room, or a `ClientError`.
898+
/// This method will not initialize the room's timeline or populate it with
899+
/// events.
900+
pub fn get_room(&self, room_id: String) -> Result<Option<Arc<Room>>, ClientError> {
901+
let room_id = RoomId::parse(room_id)?;
902+
let sdk_room = self.inner.get_room(&room_id);
903+
let room = sdk_room.map(|room| Arc::new(Room::new(room)));
904+
Ok(room)
905+
}
906+
889907
pub fn get_dm_room(&self, user_id: String) -> Result<Option<Arc<Room>>, ClientError> {
890908
let user_id = UserId::parse(user_id)?;
891909
let sdk_room = self.inner.get_dm_room(&user_id);

bindings/matrix-sdk-ffi/src/room.rs

-15
Original file line numberDiff line numberDiff line change
@@ -161,21 +161,6 @@ impl Room {
161161
self.inner.active_room_call_participants().iter().map(|u| u.to_string()).collect()
162162
}
163163

164-
/// For rooms one is invited to, retrieves the room member information for
165-
/// the user who invited the logged-in user to a room.
166-
pub async fn inviter(&self) -> Option<RoomMember> {
167-
if self.inner.state() == RoomState::Invited {
168-
self.inner
169-
.invite_details()
170-
.await
171-
.ok()
172-
.and_then(|a| a.inviter)
173-
.and_then(|m| m.try_into().ok())
174-
} else {
175-
None
176-
}
177-
}
178-
179164
/// Forces the currently active room key, which is used to encrypt messages,
180165
/// to be rotated.
181166
///

bindings/matrix-sdk-ffi/src/room_list.rs

-18
Original file line numberDiff line numberDiff line change
@@ -573,24 +573,6 @@ impl RoomListItem {
573573
self.inner.inner_room().state().into()
574574
}
575575

576-
/// Builds a `Room` FFI from an invited room without initializing its
577-
/// internal timeline.
578-
///
579-
/// An error will be returned if the room is a state different than invited.
580-
///
581-
/// ⚠️ Holding on to this room instance after it has been joined is not
582-
/// safe. Use `full_room` instead.
583-
#[deprecated(note = "Please use `preview_room` instead.")]
584-
fn invited_room(&self) -> Result<Arc<Room>, RoomListError> {
585-
if !matches!(self.membership(), Membership::Invited) {
586-
return Err(RoomListError::IncorrectRoomMembership {
587-
expected: vec![Membership::Invited],
588-
actual: self.membership(),
589-
});
590-
}
591-
Ok(Arc::new(Room::new(self.inner.inner_room().clone())))
592-
}
593-
594576
/// Builds a `RoomPreview` from a room list item. This is intended for
595577
/// invited, knocked or banned rooms.
596578
async fn preview_room(&self, via: Vec<String>) -> Result<Arc<RoomPreview>, ClientError> {

bindings/matrix-sdk-ffi/src/room_preview.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,23 @@ impl RoomPreview {
5151
/// Leave the room if the room preview state is either joined, invited or
5252
/// knocked.
5353
///
54+
/// If rejecting an invite then also forget it as an extra layer of
55+
/// protection against spam attacks.
56+
///
5457
/// Will return an error otherwise.
5558
pub async fn leave(&self) -> Result<(), ClientError> {
5659
let room =
5760
self.client.get_room(&self.inner.room_id).context("missing room for a room preview")?;
58-
room.leave().await.map_err(Into::into)
61+
62+
let should_forget = matches!(room.state(), matrix_sdk::RoomState::Invited);
63+
64+
room.leave().await.map_err(ClientError::from)?;
65+
66+
if should_forget {
67+
_ = self.forget().await;
68+
}
69+
70+
Ok(())
5971
}
6072

6173
/// Get the user who created the invite, if any.

crates/matrix-sdk/src/room_preview.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use ruma::{
3131
use tokio::try_join;
3232
use tracing::{instrument, warn};
3333

34-
use crate::{room_directory_search::RoomDirectorySearch, Client, Room};
34+
use crate::{room_directory_search::RoomDirectorySearch, Client, Error, Room};
3535

3636
/// The preview of a room, be it invited/joined/left, or not.
3737
#[derive(Debug, Clone)]
@@ -172,8 +172,21 @@ impl RoomPreview {
172172
}
173173
}
174174

175-
// Resort to using the room state endpoint, as well as the joined members one.
176-
Self::from_state_events(client, &room_id).await
175+
// Try using the room state endpoint, as well as the joined members one.
176+
match Self::from_state_events(client, &room_id).await {
177+
Ok(res) => return Ok(res),
178+
Err(err) => {
179+
warn!("error when building room preview from state events: {err}");
180+
}
181+
}
182+
183+
// Finally, if everything else fails, try to build the room from information
184+
// that the client itself might have about it.
185+
if let Some(room) = client.get_room(&room_id) {
186+
Ok(Self::from_known_room(&room).await)
187+
} else {
188+
Err(Error::InsufficientData)
189+
}
177190
}
178191

179192
/// Get a [`RoomPreview`] by searching in the room directory for the

crates/matrix-sdk/src/test_utils/mocks/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,13 @@ impl MatrixMockServer {
989989
.and(path_regex(r"^/_matrix/client/v3/keys/signatures/upload"));
990990
self.mock_endpoint(mock, UploadCrossSigningSignaturesEndpoint).expect_default_access_token()
991991
}
992+
993+
/// Creates a prebuilt mock for the endpoint used to leave a room.
994+
pub fn mock_room_leave(&self) -> MockEndpoint<'_, RoomLeaveEndpoint> {
995+
let mock =
996+
Mock::given(method("POST")).and(path_regex(r"^/_matrix/client/v3/rooms/.*/leave"));
997+
self.mock_endpoint(mock, RoomLeaveEndpoint).expect_default_access_token()
998+
}
992999
}
9931000

9941001
/// Parameter to [`MatrixMockServer::sync_room`].
@@ -2498,3 +2505,16 @@ impl<'a> MockEndpoint<'a, UploadCrossSigningSignaturesEndpoint> {
24982505
self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
24992506
}
25002507
}
2508+
2509+
/// A prebuilt mock for the room leave endpoint.
2510+
pub struct RoomLeaveEndpoint;
2511+
2512+
impl<'a> MockEndpoint<'a, RoomLeaveEndpoint> {
2513+
/// Returns a successful response with some default data for the given room
2514+
/// id.
2515+
pub fn ok(self, room_id: &RoomId) -> MatrixMock<'a> {
2516+
self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
2517+
"room_id": room_id,
2518+
})))
2519+
}
2520+
}

crates/matrix-sdk/tests/integration/room_preview.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
use assert_matches::assert_matches;
12
use js_int::uint;
2-
use matrix_sdk::{config::SyncSettings, test_utils::logged_in_client_with_server};
3+
use matrix_sdk::{
4+
config::SyncSettings,
5+
test_utils::{logged_in_client_with_server, mocks::MatrixMockServer},
6+
};
37
use matrix_sdk_base::RoomState;
48
use matrix_sdk_test::{
59
async_test, InvitedRoomBuilder, JoinedRoomBuilder, KnockedRoomBuilder, SyncResponseBuilder,
@@ -50,6 +54,34 @@ async fn test_room_preview_leave_invited() {
5054
assert_eq!(client.get_room(room_id).unwrap().state(), RoomState::Left);
5155
}
5256

57+
#[async_test]
58+
async fn test_room_preview_invite_leave_room_summary_msc3266_disabled() {
59+
let server = MatrixMockServer::new().await;
60+
let client = server.client_builder().build().await;
61+
let room_id = room_id!("!room:localhost");
62+
63+
server.sync_room(&client, InvitedRoomBuilder::new(room_id)).await;
64+
65+
// A preview should be built from the sync data above
66+
let preview = client
67+
.get_room_preview(room_id.into(), Vec::new())
68+
.await
69+
.expect("Room preview should be retrieved");
70+
71+
assert_eq!(preview.room_id, room_id);
72+
assert_matches!(preview.state.unwrap(), RoomState::Invited);
73+
74+
server.mock_room_leave().ok(room_id).expect(1).mount().await;
75+
76+
client.get_room(room_id).unwrap().leave().await.unwrap();
77+
78+
assert_matches!(client.get_room(room_id).unwrap().state(), RoomState::Left);
79+
assert_matches!(
80+
client.get_room_preview(room_id.into(), Vec::new()).await.unwrap().state.unwrap(),
81+
RoomState::Left
82+
);
83+
}
84+
5385
#[async_test]
5486
async fn test_room_preview_leave_knocked() {
5587
let (client, server) = logged_in_client_with_server().await;

0 commit comments

Comments
 (0)