Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Option to allow server admins to join complex rooms #7902

Merged
merged 5 commits into from
Jul 28, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/7902.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add option to allow server admins to join too complex rooms. Contributed by @lugino-emeritus.
lugino-emeritus marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 4 additions & 0 deletions docs/sample_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,10 @@ limit_remote_rooms:
#
#complexity_error: "This room is too complex."

# allow server admins to join complex rooms. Default is false.
#
#admins_can_join: true

# Whether to require a user to be in the room to add an alias to it.
# Defaults to 'true'.
#
Expand Down
7 changes: 7 additions & 0 deletions synapse/config/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,9 @@ class LimitRemoteRoomsConfig(object):
validator=attr.validators.instance_of(str),
default=ROOM_COMPLEXITY_TOO_GREAT,
)
admins_can_join = attr.ib(
validator=attr.validators.instance_of(bool), default=False
)

self.limit_remote_rooms = LimitRemoteRoomsConfig(
**(config.get("limit_remote_rooms") or {})
Expand Down Expand Up @@ -893,6 +896,10 @@ def generate_config_section(
#
#complexity_error: "This room is too complex."

# allow server admins to join complex rooms. Default is false.
#
#admins_can_join: true

# Whether to require a user to be in the room to add an alias to it.
# Defaults to 'true'.
#
Expand Down
8 changes: 6 additions & 2 deletions synapse/handlers/room_member.py
Original file line number Diff line number Diff line change
Expand Up @@ -952,7 +952,11 @@ async def _remote_join(
if len(remote_room_hosts) == 0:
raise SynapseError(404, "No known servers")

if self.hs.config.limit_remote_rooms.enabled:
check_complexity = self.hs.config.limit_remote_rooms.enabled
if check_complexity and self.hs.config.limit_remote_rooms.admins_can_join:
check_complexity = not await self.hs.auth.is_server_admin(user)

if check_complexity:
# Fetch the room complexity
too_complex = await self._is_remote_room_too_complex(
room_id, remote_room_hosts
Expand All @@ -975,7 +979,7 @@ async def _remote_join(

# Check the room we just joined wasn't too large, if we didn't fetch the
# complexity of it before.
if self.hs.config.limit_remote_rooms.enabled:
if check_complexity:
if too_complex is False:
# We checked, and we're under the limit.
return event_id, stream_id
Expand Down
101 changes: 101 additions & 0 deletions tests/federation/test_complexity.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,104 @@ def test_join_too_large_once_joined(self):
f = self.get_failure(d, SynapseError)
self.assertEqual(f.value.code, 400)
self.assertEqual(f.value.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)

def test_join_too_large_admin(self):
u1 = self.register_user("u1", "pass", admin=True)

handler = self.hs.get_room_member_handler()
fed_transport = self.hs.get_federation_transport_client()

# Mock out some things, because we don't want to test the whole join
fed_transport.client.get_json = Mock(return_value=defer.succeed({"v1": 9999}))
handler.federation_handler.do_invite_join = Mock(
return_value=defer.succeed(("", 1))
)

d = handler._remote_join(
None,
["other.example.com"],
"roomid",
UserID.from_string(u1),
{"membership": "join"},
)

self.pump()

# The request failed with a SynapseError saying the resource limit was
# exceeded.
f = self.get_failure(d, SynapseError)
self.assertEqual(f.value.code, 400, f.value)
self.assertEqual(f.value.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)


class RoomComplexityAdminTests(unittest.FederatingHomeserverTestCase):

servlets = [
admin.register_servlets,
room.register_servlets,
login.register_servlets,
]

def default_config(self):
config = super().default_config()
config["limit_remote_rooms"] = {
"enabled": True,
"complexity": 0.05,
"admins_can_join": True,
}
return config

def test_join_too_large_noadmin(self):

u1 = self.register_user("u1", "pass")

handler = self.hs.get_room_member_handler()
fed_transport = self.hs.get_federation_transport_client()

# Mock out some things, because we don't want to test the whole join
fed_transport.client.get_json = Mock(return_value=defer.succeed({"v1": 9999}))
handler.federation_handler.do_invite_join = Mock(
return_value=defer.succeed(("", 1))
)

d = handler._remote_join(
None,
["other.example.com"],
"roomid",
UserID.from_string(u1),
{"membership": "join"},
)

self.pump()

# The request failed with a SynapseError saying the resource limit was
# exceeded.
f = self.get_failure(d, SynapseError)
self.assertEqual(f.value.code, 400, f.value)
self.assertEqual(f.value.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)

def test_join_too_large_admin(self):
u1 = self.register_user("u1", "pass", admin=True)

handler = self.hs.get_room_member_handler()
fed_transport = self.hs.get_federation_transport_client()

# Mock out some things, because we don't want to test the whole join
fed_transport.client.get_json = Mock(return_value=defer.succeed({"v1": 9999}))
handler.federation_handler.do_invite_join = Mock(
return_value=defer.succeed(("", 1))
)

d = handler._remote_join(
None,
["other.example.com"],
"roomid",
UserID.from_string(u1),
{"membership": "join"},
)

self.pump()

# The request success since the user is an admin
res = self.get_success(d)
self.assertEqual(res, ("", 1))