diff options
-rw-r--r-- | changelog.d/4895.feature | 1 | ||||
-rw-r--r-- | changelog.d/4896.feature | 1 | ||||
-rw-r--r-- | changelog.d/4905.misc | 1 | ||||
-rw-r--r-- | docs/sample_config.yaml | 11 | ||||
-rw-r--r-- | synapse/config/room_directory.py | 10 | ||||
-rw-r--r-- | synapse/config/user_directory.py | 9 | ||||
-rw-r--r-- | synapse/handlers/directory.py | 8 | ||||
-rw-r--r-- | synapse/handlers/room_list.py | 14 | ||||
-rw-r--r-- | synapse/rest/client/v2_alpha/user_directory.py | 6 | ||||
-rw-r--r-- | tests/handlers/test_directory.py | 59 | ||||
-rw-r--r-- | tests/handlers/test_user_directory.py | 52 | ||||
-rw-r--r-- | tests/server.py | 9 | ||||
-rw-r--r-- | tests/utils.py | 2 |
13 files changed, 172 insertions, 11 deletions
diff --git a/changelog.d/4895.feature b/changelog.d/4895.feature new file mode 100644 index 0000000000..5dd7c68194 --- /dev/null +++ b/changelog.d/4895.feature @@ -0,0 +1 @@ +Add option to disable searching the user directory. diff --git a/changelog.d/4896.feature b/changelog.d/4896.feature new file mode 100644 index 0000000000..46ac49a4b4 --- /dev/null +++ b/changelog.d/4896.feature @@ -0,0 +1 @@ +Add option to disable searching of local and remote public room lists. diff --git a/changelog.d/4905.misc b/changelog.d/4905.misc new file mode 100644 index 0000000000..0f00d5a3d5 --- /dev/null +++ b/changelog.d/4905.misc @@ -0,0 +1 @@ +Log requests which are simulated by the unit tests. diff --git a/docs/sample_config.yaml b/docs/sample_config.yaml index d72b90a37b..4ada0fba0e 100644 --- a/docs/sample_config.yaml +++ b/docs/sample_config.yaml @@ -962,6 +962,10 @@ password_config: # User Directory configuration # +# 'enabled' defines whether users can search the user directory. If +# false then empty responses are returned to all queries. Defaults to +# true. +# # 'search_all_users' defines whether to search all users visible to your HS # when searching the user directory, rather than limiting to users visible # in public rooms. Defaults to false. If you set it True, you'll have to run @@ -969,6 +973,7 @@ password_config: # on your database to tell it to rebuild the user_directory search indexes. # #user_directory: +# enabled: true # search_all_users: false @@ -1044,6 +1049,12 @@ password_config: +# Uncomment to disable searching the public room list. When disabled +# blocks searching local and remote room lists for local and remote +# users by always returning an empty list for all queries. +# +#enable_room_list_search: false + # The `alias_creation` option controls who's allowed to create aliases # on this server. # diff --git a/synapse/config/room_directory.py b/synapse/config/room_directory.py index 9b897abe3c..8a9fded4c5 100644 --- a/synapse/config/room_directory.py +++ b/synapse/config/room_directory.py @@ -20,6 +20,10 @@ from ._base import Config, ConfigError class RoomDirectoryConfig(Config): def read_config(self, config): + self.enable_room_list_search = config.get( + "enable_room_list_search", True, + ) + alias_creation_rules = config.get("alias_creation_rules") if alias_creation_rules is not None: @@ -54,6 +58,12 @@ class RoomDirectoryConfig(Config): def default_config(self, config_dir_path, server_name, **kwargs): return """ + # Uncomment to disable searching the public room list. When disabled + # blocks searching local and remote room lists for local and remote + # users by always returning an empty list for all queries. + # + #enable_room_list_search: false + # The `alias_creation` option controls who's allowed to create aliases # on this server. # diff --git a/synapse/config/user_directory.py b/synapse/config/user_directory.py index fab3a7d1c8..142754a7dc 100644 --- a/synapse/config/user_directory.py +++ b/synapse/config/user_directory.py @@ -22,9 +22,13 @@ class UserDirectoryConfig(Config): """ def read_config(self, config): + self.user_directory_search_enabled = True self.user_directory_search_all_users = False user_directory_config = config.get("user_directory", None) if user_directory_config: + self.user_directory_search_enabled = ( + user_directory_config.get("enabled", True) + ) self.user_directory_search_all_users = ( user_directory_config.get("search_all_users", False) ) @@ -33,6 +37,10 @@ class UserDirectoryConfig(Config): return """ # User Directory configuration # + # 'enabled' defines whether users can search the user directory. If + # false then empty responses are returned to all queries. Defaults to + # true. + # # 'search_all_users' defines whether to search all users visible to your HS # when searching the user directory, rather than limiting to users visible # in public rooms. Defaults to false. If you set it True, you'll have to run @@ -40,5 +48,6 @@ class UserDirectoryConfig(Config): # on your database to tell it to rebuild the user_directory search indexes. # #user_directory: + # enabled: true # search_all_users: false """ diff --git a/synapse/handlers/directory.py b/synapse/handlers/directory.py index 8b113307d2..fe128d9c88 100644 --- a/synapse/handlers/directory.py +++ b/synapse/handlers/directory.py @@ -44,6 +44,7 @@ class DirectoryHandler(BaseHandler): self.appservice_handler = hs.get_application_service_handler() self.event_creation_handler = hs.get_event_creation_handler() self.config = hs.config + self.enable_room_list_search = hs.config.enable_room_list_search self.federation = hs.get_federation_client() hs.get_federation_registry().register_query_handler( @@ -411,6 +412,13 @@ class DirectoryHandler(BaseHandler): if visibility not in ["public", "private"]: raise SynapseError(400, "Invalid visibility setting") + if visibility == "public" and not self.enable_room_list_search: + # The room list has been disabled. + raise AuthError( + 403, + "This user is not permitted to publish rooms to the room list" + ) + room = yield self.store.get_room(room_id) if room is None: raise SynapseError(400, "Unknown room") diff --git a/synapse/handlers/room_list.py b/synapse/handlers/room_list.py index afa508d729..d6c9d56007 100644 --- a/synapse/handlers/room_list.py +++ b/synapse/handlers/room_list.py @@ -44,6 +44,7 @@ EMPTY_THIRD_PARTY_ID = ThirdPartyInstanceID(None, None) class RoomListHandler(BaseHandler): def __init__(self, hs): super(RoomListHandler, self).__init__(hs) + self.enable_room_list_search = hs.config.enable_room_list_search self.response_cache = ResponseCache(hs, "room_list") self.remote_response_cache = ResponseCache(hs, "remote_room_list", timeout_ms=30 * 1000) @@ -66,10 +67,17 @@ class RoomListHandler(BaseHandler): appservice and network id to use an appservice specific one. Setting to None returns all public rooms across all lists. """ + if not self.enable_room_list_search: + return defer.succeed({ + "chunk": [], + "total_room_count_estimate": 0, + }) + logger.info( "Getting public room list: limit=%r, since=%r, search=%r, network=%r", limit, since_token, bool(search_filter), network_tuple, ) + if search_filter: # We explicitly don't bother caching searches or requests for # appservice specific lists. @@ -441,6 +449,12 @@ class RoomListHandler(BaseHandler): def get_remote_public_room_list(self, server_name, limit=None, since_token=None, search_filter=None, include_all_networks=False, third_party_instance_id=None,): + if not self.enable_room_list_search: + defer.returnValue({ + "chunk": [], + "total_room_count_estimate": 0, + }) + if search_filter: # We currently don't support searching across federation, so we have # to do it manually without pagination diff --git a/synapse/rest/client/v2_alpha/user_directory.py b/synapse/rest/client/v2_alpha/user_directory.py index cac0624ba7..36b02de37f 100644 --- a/synapse/rest/client/v2_alpha/user_directory.py +++ b/synapse/rest/client/v2_alpha/user_directory.py @@ -59,6 +59,12 @@ class UserDirectorySearchRestServlet(RestServlet): requester = yield self.auth.get_user_by_req(request, allow_guest=False) user_id = requester.user.to_string() + if not self.hs.config.user_directory_search_enabled: + defer.returnValue((200, { + "limited": False, + "results": [], + })) + body = parse_json_object_from_request(request) limit = body.get("limit", 10) diff --git a/tests/handlers/test_directory.py b/tests/handlers/test_directory.py index 9bf395e923..5b2105bc76 100644 --- a/tests/handlers/test_directory.py +++ b/tests/handlers/test_directory.py @@ -111,7 +111,7 @@ class TestCreateAliasACL(unittest.HomeserverTestCase): servlets = [directory.register_servlets, room.register_servlets] - def prepare(self, hs, reactor, clock): + def prepare(self, reactor, clock, hs): # We cheekily override the config to add custom alias creation rules config = {} config["alias_creation_rules"] = [ @@ -151,3 +151,60 @@ class TestCreateAliasACL(unittest.HomeserverTestCase): ) self.render(request) self.assertEquals(200, channel.code, channel.result) + + +class TestRoomListSearchDisabled(unittest.HomeserverTestCase): + user_id = "@test:test" + + servlets = [directory.register_servlets, room.register_servlets] + + def prepare(self, reactor, clock, hs): + room_id = self.helper.create_room_as(self.user_id) + + request, channel = self.make_request( + "PUT", + b"directory/list/room/%s" % (room_id.encode('ascii'),), + b'{}', + ) + self.render(request) + self.assertEquals(200, channel.code, channel.result) + + self.room_list_handler = hs.get_room_list_handler() + self.directory_handler = hs.get_handlers().directory_handler + + return hs + + def test_disabling_room_list(self): + self.room_list_handler.enable_room_list_search = True + self.directory_handler.enable_room_list_search = True + + # Room list is enabled so we should get some results + request, channel = self.make_request( + "GET", + b"publicRooms", + ) + self.render(request) + self.assertEquals(200, channel.code, channel.result) + self.assertTrue(len(channel.json_body["chunk"]) > 0) + + self.room_list_handler.enable_room_list_search = False + self.directory_handler.enable_room_list_search = False + + # Room list disabled so we should get no results + request, channel = self.make_request( + "GET", + b"publicRooms", + ) + self.render(request) + self.assertEquals(200, channel.code, channel.result) + self.assertTrue(len(channel.json_body["chunk"]) == 0) + + # Room list disabled so we shouldn't be allowed to publish rooms + room_id = self.helper.create_room_as(self.user_id) + request, channel = self.make_request( + "PUT", + b"directory/list/room/%s" % (room_id.encode('ascii'),), + b'{}', + ) + self.render(request) + self.assertEquals(403, channel.code, channel.result) diff --git a/tests/handlers/test_user_directory.py b/tests/handlers/test_user_directory.py index aefe11ac28..f1d0aa42b6 100644 --- a/tests/handlers/test_user_directory.py +++ b/tests/handlers/test_user_directory.py @@ -16,6 +16,7 @@ from mock import Mock from synapse.api.constants import UserTypes from synapse.rest.client.v1 import admin, login, room +from synapse.rest.client.v2_alpha import user_directory from synapse.storage.roommember import ProfileInfo from tests import unittest @@ -317,3 +318,54 @@ class UserDirectoryTestCase(unittest.HomeserverTestCase): u4 = self.register_user("user4", "pass") s = self.get_success(self.handler.search_users(u1, u4, 10)) self.assertEqual(len(s["results"]), 1) + + +class TestUserDirSearchDisabled(unittest.HomeserverTestCase): + user_id = "@test:test" + + servlets = [ + user_directory.register_servlets, + room.register_servlets, + login.register_servlets, + admin.register_servlets, + ] + + def make_homeserver(self, reactor, clock): + config = self.default_config() + config.update_user_directory = True + hs = self.setup_test_homeserver(config=config) + + self.config = hs.config + + return hs + + def test_disabling_room_list(self): + self.config.user_directory_search_enabled = True + + # First we create a room with another user so that user dir is non-empty + # for our user + self.helper.create_room_as(self.user_id) + u2 = self.register_user("user2", "pass") + room = self.helper.create_room_as(self.user_id) + self.helper.join(room, user=u2) + + # Assert user directory is not empty + request, channel = self.make_request( + "POST", + b"user_directory/search", + b'{"search_term":"user2"}', + ) + self.render(request) + self.assertEquals(200, channel.code, channel.result) + self.assertTrue(len(channel.json_body["results"]) > 0) + + # Disable user directory and check search returns nothing + self.config.user_directory_search_enabled = False + request, channel = self.make_request( + "POST", + b"user_directory/search", + b'{"search_term":"user2"}', + ) + self.render(request) + self.assertEquals(200, channel.code, channel.result) + self.assertTrue(len(channel.json_body["results"]) == 0) diff --git a/tests/server.py b/tests/server.py index 37069afdda..ea26dea623 100644 --- a/tests/server.py +++ b/tests/server.py @@ -119,14 +119,7 @@ class FakeSite: server_version_string = b"1" site_tag = "test" - - @property - def access_logger(self): - class FakeLogger: - def info(self, *args, **kwargs): - pass - - return FakeLogger() + access_logger = logging.getLogger("synapse.access.http.fake") def make_request( diff --git a/tests/utils.py b/tests/utils.py index eeb4bce5a2..d4ab4209ed 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -280,7 +280,6 @@ def setup_test_homeserver( db_config=config.database_config, version_string="Synapse/tests", database_engine=db_engine, - room_list_handler=object(), tls_server_context_factory=Mock(), tls_client_options_factory=Mock(), reactor=reactor, @@ -351,7 +350,6 @@ def setup_test_homeserver( config=config, version_string="Synapse/tests", database_engine=db_engine, - room_list_handler=object(), tls_server_context_factory=Mock(), tls_client_options_factory=Mock(), reactor=reactor, |