@@ -52,7 +52,7 @@ func setupRestrictedRoom(t *testing.T, deployment *docker.Deployment) (*client.C
5252 room := alice .CreateRoom (t , map [string ]interface {}{
5353 "preset" : "public_chat" ,
5454 "name" : "Room" ,
55- "room_version" : "org.matrix.msc3083" ,
55+ "room_version" : "org.matrix.msc3083.v2 " ,
5656 "initial_state" : []map [string ]interface {}{
5757 {
5858 "type" : "m.room.join_rules" ,
@@ -90,6 +90,9 @@ func checkRestrictedRoom(t *testing.T, alice *client.CSAPI, bob *client.CSAPI, s
9090 bob .JoinRoom (t , space , []string {"hs1" })
9191 bob .JoinRoom (t , room , []string {"hs1" })
9292
93+ // Joining the same room again should work fine (e.g. to change your display name).
94+ bob .JoinRoom (t , room , []string {"hs1" })
95+
9396 // Leaving the room works and the user is unable to re-join.
9497 bob .LeaveRoom (t , room )
9598 bob .LeaveRoom (t , space )
@@ -181,6 +184,131 @@ func TestRestrictedRoomsRemoteJoin(t *testing.T) {
181184 checkRestrictedRoom (t , alice , bob , space , room )
182185}
183186
187+ // A server will do a remote join for a local user if it is unable to to issue
188+ // joins in a restricted room it is already participating in.
189+ func TestRestrictedRoomsRemoteJoinLocalUser (t * testing.T ) {
190+ deployment := Deploy (t , b .BlueprintFederationTwoLocalOneRemote )
191+ defer deployment .Destroy (t )
192+
193+ // Charlie sets up the space so it is on the other server.
194+ charlie := deployment .Client (t , "hs2" , "@charlie:hs2" )
195+ space := charlie .CreateRoom (t , map [string ]interface {}{
196+ "preset" : "public_chat" ,
197+ "name" : "Space" ,
198+ "creation_content" : map [string ]interface {}{
199+ "type" : "m.space" ,
200+ },
201+ })
202+ // The room is an unstable room version which supports the restricted join_rule.
203+ room := charlie .CreateRoom (t , map [string ]interface {}{
204+ "preset" : "public_chat" ,
205+ "name" : "Room" ,
206+ "room_version" : "org.matrix.msc3083.v2" ,
207+ "initial_state" : []map [string ]interface {}{
208+ {
209+ "type" : "m.room.join_rules" ,
210+ "state_key" : "" ,
211+ "content" : map [string ]interface {}{
212+ "join_rule" : "restricted" ,
213+ "allow" : []map [string ]interface {}{
214+ {
215+ "type" : "m.room_membership" ,
216+ "room_id" : & space ,
217+ "via" : []string {"hs2" },
218+ },
219+ },
220+ },
221+ },
222+ },
223+ })
224+ charlie .SendEventSynced (t , space , b.Event {
225+ Type : "m.space.child" ,
226+ StateKey : & room ,
227+ Content : map [string ]interface {}{
228+ "via" : []string {"hs2" },
229+ },
230+ })
231+
232+ // Invite alice manually and accept it.
233+ alice := deployment .Client (t , "hs1" , "@alice:hs1" )
234+ charlie .InviteRoom (t , room , alice .UserID )
235+ alice .JoinRoom (t , room , []string {"hs2" })
236+
237+ // Confirm that Alice cannot issue invites (due to the default power levels).
238+ bob := deployment .Client (t , "hs1" , "@bob:hs1" )
239+ body := map [string ]interface {}{
240+ "user_id" : bob .UserID ,
241+ }
242+ res := alice .DoFunc (
243+ t ,
244+ "POST" ,
245+ []string {"_matrix" , "client" , "r0" , "rooms" , room , "invite" },
246+ client .WithJSONBody (t , body ),
247+ )
248+ must .MatchResponse (t , res , match.HTTPResponse {
249+ StatusCode : 403 ,
250+ })
251+
252+ // Bob cannot join the room.
253+ failJoinRoom (t , bob , room , "hs1" )
254+
255+ // Join the space via hs2.
256+ bob .JoinRoom (t , space , []string {"hs2" })
257+ // Joining the room should work, although we're joining via hs1, it will end up
258+ // as a remote join through hs2.
259+ bob .JoinRoom (t , room , []string {"hs1" })
260+
261+ // Ensure that the join comes down sync on hs2. Note that we want to ensure hs2
262+ // accepted the event.
263+ charlie .SyncUntilTimelineHas (
264+ t ,
265+ room ,
266+ func (ev gjson.Result ) bool {
267+ if ev .Get ("type" ).Str != "m.room.member" || ev .Get ("state_key" ).Str != bob .UserID {
268+ return false
269+ }
270+ must .EqualStr (t , ev .Get ("sender" ).Str , bob .UserID , "Bob should have joined by himself" )
271+ must .EqualStr (t , ev .Get ("content" ).Get ("membership" ).Str , "join" , "Bob failed to join the room" )
272+
273+ return true
274+ },
275+ )
276+
277+ // Raise the power level so that users on hs1 can invite people and then leave
278+ // the room.
279+ state_key := ""
280+ charlie .SendEventSynced (t , room , b.Event {
281+ Type : "m.room.power_levels" ,
282+ StateKey : & state_key ,
283+ Content : map [string ]interface {}{
284+ "invite" : 0 ,
285+ "users" : map [string ]interface {}{
286+ charlie .UserID : 100 ,
287+ },
288+ },
289+ })
290+ charlie .LeaveRoom (t , room )
291+
292+ // Ensure the events have synced to hs1.
293+ alice .SyncUntilTimelineHas (
294+ t ,
295+ room ,
296+ func (ev gjson.Result ) bool {
297+ if ev .Get ("type" ).Str != "m.room.member" || ev .Get ("state_key" ).Str != charlie .UserID {
298+ return false
299+ }
300+ must .EqualStr (t , ev .Get ("content" ).Get ("membership" ).Str , "leave" , "Charlie failed to leave the room" )
301+
302+ return true
303+ },
304+ )
305+
306+ // Have bob leave and rejoin. This should still work even though hs2 isn't in
307+ // the room anymore!
308+ bob .LeaveRoom (t , room )
309+ bob .JoinRoom (t , room , []string {"hs1" })
310+ }
311+
184312// Request the room summary and ensure the expected rooms are in the response.
185313func requestAndAssertSummary (t * testing.T , user * client.CSAPI , space string , expected_rooms []interface {}) {
186314 t .Helper ()
@@ -229,7 +357,7 @@ func TestRestrictedRoomsSpacesSummary(t *testing.T) {
229357 room := alice .CreateRoom (t , map [string ]interface {}{
230358 "preset" : "public_chat" ,
231359 "name" : "Room" ,
232- "room_version" : "org.matrix.msc3083" ,
360+ "room_version" : "org.matrix.msc3083.v2 " ,
233361 "initial_state" : []map [string ]interface {}{
234362 {
235363 "type" : "m.room.join_rules" ,
@@ -312,7 +440,7 @@ func TestRestrictedRoomsSpacesSummaryFederation(t *testing.T) {
312440 room := charlie .CreateRoom (t , map [string ]interface {}{
313441 "preset" : "public_chat" ,
314442 "name" : "Room" ,
315- "room_version" : "org.matrix.msc3083" ,
443+ "room_version" : "org.matrix.msc3083.v2 " ,
316444 "initial_state" : []map [string ]interface {}{
317445 {
318446 "type" : "m.room.join_rules" ,
0 commit comments