summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--changelog.d/4895.feature1
-rw-r--r--changelog.d/4896.feature1
-rw-r--r--changelog.d/4905.misc1
-rw-r--r--docs/sample_config.yaml11
-rw-r--r--synapse/config/room_directory.py10
-rw-r--r--synapse/config/user_directory.py9
-rw-r--r--synapse/handlers/directory.py8
-rw-r--r--synapse/handlers/room_list.py14
-rw-r--r--synapse/rest/client/v2_alpha/user_directory.py6
-rw-r--r--tests/handlers/test_directory.py59
-rw-r--r--tests/handlers/test_user_directory.py52
-rw-r--r--tests/server.py9
-rw-r--r--tests/utils.py2
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,