Skip to content

Commit ba1560d

Browse files
committed
fix: Don't attempt to serialize custom join rules
This is not supported by Ruma. The join_rule field, despite being defined as a pure string, can have associated data to it based on the join rule variant. This means that custom and unknown enum variants might lose data when reserializing. Let's just skip the serialization of custom join rules in the RoomInfo, the concrete value is still available in the state store, it's just not kept at hand in the RoomInfo.
1 parent b4d7881 commit ba1560d

File tree

3 files changed

+107
-7
lines changed

3 files changed

+107
-7
lines changed

crates/matrix-sdk-base/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ All notable changes to this project will be documented in this file.
1919

2020
## [0.15.0] - 2025-11-27
2121

22+
### Security Fixes
23+
24+
- Skip the serialization of custom join rules in the `RoomInfo` which prevented
25+
the processing of sync responses containing events with custom join rules.
26+
([#5924](https://github.com/matrix-org/matrix-rust-sdk/pull/5924))
27+
2228
### Refactor
2329

2430
- [**breaking**] Upgrade Ruma to version 0.14.0.

crates/matrix-sdk-base/src/room/room_info.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,15 @@ impl BaseRoomInfo {
217217
AnySyncStateEvent::RoomGuestAccess(g) => {
218218
self.guest_access = Some(g.into());
219219
}
220-
AnySyncStateEvent::RoomJoinRules(c) => {
221-
self.join_rules = Some(c.into());
222-
}
220+
AnySyncStateEvent::RoomJoinRules(c) => match c.join_rule() {
221+
JoinRule::Invite
222+
| JoinRule::Knock
223+
| JoinRule::Private
224+
| JoinRule::Restricted(_)
225+
| JoinRule::KnockRestricted(_)
226+
| JoinRule::Public => self.join_rules = Some(c.into()),
227+
r => warn!("Encountered a custom joine rule {}, skipping", r.as_str()),
228+
},
223229
AnySyncStateEvent::RoomCanonicalAlias(a) => {
224230
self.canonical_alias = Some(a.into());
225231
}
@@ -294,9 +300,15 @@ impl BaseRoomInfo {
294300
AnyStrippedStateEvent::RoomGuestAccess(g) => {
295301
self.guest_access = Some(g.into());
296302
}
297-
AnyStrippedStateEvent::RoomJoinRules(c) => {
298-
self.join_rules = Some(c.into());
299-
}
303+
AnyStrippedStateEvent::RoomJoinRules(c) => match &c.content.join_rule {
304+
JoinRule::Invite
305+
| JoinRule::Knock
306+
| JoinRule::Private
307+
| JoinRule::Restricted(_)
308+
| JoinRule::KnockRestricted(_)
309+
| JoinRule::Public => self.join_rules = Some(c.into()),
310+
r => warn!("Encountered a custom joine rule {}, skipping", r.as_str()),
311+
},
300312
AnyStrippedStateEvent::RoomCanonicalAlias(a) => {
301313
self.canonical_alias = Some(a.into());
302314
}

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

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ use matrix_sdk::{
1717
use matrix_sdk_base::{RoomState, sync::RoomUpdates};
1818
use matrix_sdk_common::executor::spawn;
1919
use matrix_sdk_test::{
20-
DEFAULT_TEST_ROOM_ID, JoinedRoomBuilder, SyncResponseBuilder, async_test,
20+
DEFAULT_TEST_ROOM_ID, InvitedRoomBuilder, JoinedRoomBuilder, StateTestEvent,
21+
StrippedStateTestEvent, SyncResponseBuilder, async_test,
2122
event_factory::EventFactory,
2223
sync_state_event,
2324
test_json::{
@@ -61,6 +62,7 @@ use ruma::{
6162
};
6263
use serde_json::{Value as JsonValue, json};
6364
use stream_assert::{assert_next_matches, assert_pending};
65+
use tempfile::tempdir;
6466
use tokio_stream::wrappers::BroadcastStream;
6567
use wiremock::{
6668
Mock, Request, ResponseTemplate,
@@ -1824,3 +1826,83 @@ async fn test_sync_thread_subscriptions_with_catchup() {
18241826
let sub3 = room1.load_or_fetch_thread_subscription(&thread3).await.unwrap();
18251827
assert_eq!(sub3, Some(matrix_sdk::room::ThreadSubscription { automatic: false }));
18261828
}
1829+
1830+
#[async_test]
1831+
#[cfg(feature = "sqlite")]
1832+
async fn test_sync_processing_of_custom_join_rule() {
1833+
let tempdir = tempdir().unwrap();
1834+
1835+
let room_id = room_id!("!room0:matrix.org");
1836+
1837+
let server = MatrixMockServer::new().await;
1838+
let client = server
1839+
.client_builder()
1840+
.on_builder(|builder| builder.sqlite_store(tempdir.path(), None))
1841+
.build()
1842+
.await;
1843+
1844+
server
1845+
.mock_sync()
1846+
.ok(|builder| {
1847+
builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_state_event(
1848+
StateTestEvent::Custom(json!({
1849+
"content": {
1850+
"join_rule": "my_custom_rule"
1851+
},
1852+
"event_id": "$15139375513VdeRF:localhost",
1853+
"origin_server_ts": 151393755,
1854+
"sender": "@example:localhost",
1855+
"state_key": "",
1856+
"type": "m.room.join_rules",
1857+
})),
1858+
));
1859+
})
1860+
.mock_once()
1861+
.mount()
1862+
.await;
1863+
1864+
client
1865+
.sync_once(Default::default())
1866+
.await
1867+
.expect("We should be able to process the sync despite there being a custom join rule");
1868+
}
1869+
1870+
#[async_test]
1871+
#[cfg(feature = "sqlite")]
1872+
async fn test_sync_processing_of_custom_stripped_join_rule() {
1873+
let tempdir = tempdir().unwrap();
1874+
1875+
let room_id = room_id!("!room0:matrix.org");
1876+
1877+
let server = MatrixMockServer::new().await;
1878+
let client = server
1879+
.client_builder()
1880+
.on_builder(|builder| builder.sqlite_store(tempdir.path(), None))
1881+
.build()
1882+
.await;
1883+
1884+
server
1885+
.mock_sync()
1886+
.ok(|builder| {
1887+
builder.add_invited_room(InvitedRoomBuilder::new(room_id).add_state_event(
1888+
StrippedStateTestEvent::Custom(json!({
1889+
"content": {
1890+
"join_rule": "my_custom_rule"
1891+
},
1892+
"event_id": "$15139375513VdeRF:localhost",
1893+
"origin_server_ts": 151393755,
1894+
"sender": "@example:localhost",
1895+
"state_key": "",
1896+
"type": "m.room.join_rules",
1897+
})),
1898+
));
1899+
})
1900+
.mock_once()
1901+
.mount()
1902+
.await;
1903+
1904+
client
1905+
.sync_once(Default::default())
1906+
.await
1907+
.expect("We should be able to process the sync despite there being a custom join rule");
1908+
}

0 commit comments

Comments
 (0)