summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--synapse/config/room_directory.py12
-rw-r--r--synapse/federation/transport/server.py3
-rw-r--r--synapse/groups/groups_server.py4
-rw-r--r--synapse/handlers/room_list.py50
4 files changed, 57 insertions, 12 deletions
diff --git a/synapse/config/room_directory.py b/synapse/config/room_directory.py
index 9b897abe3c..3322cf2eea 100644
--- a/synapse/config/room_directory.py
+++ b/synapse/config/room_directory.py
@@ -52,6 +52,10 @@ class RoomDirectoryConfig(Config):
                 )
             ]
 
+        self.allow_non_federated_in_public_rooms = config.get(
+            "allow_non_federated_in_public_rooms", True,
+        )
+
     def default_config(self, config_dir_path, server_name, **kwargs):
         return """
         # The `alias_creation` option controls who's allowed to create aliases
@@ -110,6 +114,14 @@ class RoomDirectoryConfig(Config):
         #    alias: "*"
         #    room_id: "*"
         #    action: allow
+
+        # Specify whether rooms that only allow local users to join should be
+        # shown in the federation public room directory.
+        #
+        # Note that this does not affect the room directory shown to users on
+        # this homeserver, only those on other homeservers.
+        #
+        #allow_non_federated_in_public_rooms: True
         """
 
     def is_alias_creation_allowed(self, user_id, room_id, alias):
diff --git a/synapse/federation/transport/server.py b/synapse/federation/transport/server.py
index a2396ab466..5ba94be2ec 100644
--- a/synapse/federation/transport/server.py
+++ b/synapse/federation/transport/server.py
@@ -736,7 +736,8 @@ class PublicRoomList(BaseFederationServlet):
 
         data = yield self.handler.get_local_public_room_list(
             limit, since_token,
-            network_tuple=network_tuple
+            network_tuple=network_tuple,
+            from_federation=True,
         )
         defer.returnValue((200, data))
 
diff --git a/synapse/groups/groups_server.py b/synapse/groups/groups_server.py
index 633c865ed8..691752a30c 100644
--- a/synapse/groups/groups_server.py
+++ b/synapse/groups/groups_server.py
@@ -113,7 +113,7 @@ class GroupsServerHandler(object):
             room_id = room_entry["room_id"]
             joined_users = yield self.store.get_users_in_room(room_id)
             entry = yield self.room_list_handler.generate_room_entry(
-                room_id, len(joined_users),
+                room_id, True, len(joined_users),
                 with_alias=False, allow_private=True,
             )
             entry = dict(entry)  # so we don't change whats cached
@@ -544,7 +544,7 @@ class GroupsServerHandler(object):
 
             joined_users = yield self.store.get_users_in_room(room_id)
             entry = yield self.room_list_handler.generate_room_entry(
-                room_id, len(joined_users),
+                room_id, True, len(joined_users),
                 with_alias=False, allow_private=True,
             )
 
diff --git a/synapse/handlers/room_list.py b/synapse/handlers/room_list.py
index 13e212d669..810c624c2b 100644
--- a/synapse/handlers/room_list.py
+++ b/synapse/handlers/room_list.py
@@ -47,10 +47,12 @@ class RoomListHandler(BaseHandler):
         self.response_cache = ResponseCache(hs, "room_list")
         self.remote_response_cache = ResponseCache(hs, "remote_room_list",
                                                    timeout_ms=30 * 1000)
+        self.config = hs.get_config()
 
     def get_local_public_room_list(self, limit=None, since_token=None,
                                    search_filter=None,
-                                   network_tuple=EMPTY_THIRD_PARTY_ID,):
+                                   network_tuple=EMPTY_THIRD_PARTY_ID,
+                                   from_federation=False):
         """Generate a local public room list.
 
         There are multiple different lists: the main one plus one per third
@@ -87,14 +89,15 @@ class RoomListHandler(BaseHandler):
         return self.response_cache.wrap(
             key,
             self._get_public_room_list,
-            limit, since_token, network_tuple=network_tuple,
+            limit, since_token,
+            network_tuple=network_tuple, from_federation=from_federation,
         )
 
     @defer.inlineCallbacks
     def _get_public_room_list(self, limit=None, since_token=None,
                               search_filter=None,
                               network_tuple=EMPTY_THIRD_PARTY_ID,
-                              timeout=None,):
+                              from_federation=False, timeout=None,):
         if since_token and since_token != "END":
             since_token = RoomListNextBatch.from_token(since_token)
         else:
@@ -217,7 +220,8 @@ class RoomListHandler(BaseHandler):
             yield concurrently_execute(
                 lambda r: self._append_room_entry_to_chunk(
                     r, rooms_to_num_joined[r],
-                    chunk, limit, search_filter
+                    chunk, limit, search_filter,
+                    from_federation=from_federation,
                 ),
                 batch, 5,
             )
@@ -288,7 +292,7 @@ class RoomListHandler(BaseHandler):
 
     @defer.inlineCallbacks
     def _append_room_entry_to_chunk(self, room_id, num_joined_users, chunk, limit,
-                                    search_filter):
+                                    search_filter, from_federation=False):
         """Generate the entry for a room in the public room list and append it
         to the `chunk` if it matches the search filter
         """
@@ -296,15 +300,33 @@ class RoomListHandler(BaseHandler):
             # We've already got enough, so lets just drop it.
             return
 
-        result = yield self.generate_room_entry(room_id, num_joined_users)
+        if from_federation:
+            result = yield self.generate_room_entry(room_id,
+                self.config.allow_non_federated_in_public_rooms,
+                num_joined_users)
+        else:
+            result = yield self.generate_room_entry(room_id, True, num_joined_users)
 
         if result and _matches_room_entry(result, search_filter):
             chunk.append(result)
 
-    @cachedInlineCallbacks(num_args=1, cache_context=True)
-    def generate_room_entry(self, room_id, num_joined_users, cache_context,
-                            with_alias=True, allow_private=False):
+    @cachedInlineCallbacks(num_args=2, cache_context=True)
+    def generate_room_entry(self, room_id, allow_non_federated, num_joined_users,
+                            cache_context, with_alias=True, allow_private=False):
         """Returns the entry for a room
+
+        Args:
+            room_id (str): The room's ID.
+            allow_non_federated (bool): Whether rooms with federation
+            disabled should be shown.
+            num_joined_users (int): Number of users in the room.
+            cache_context: Information for cached responses.
+            with_alias (bool): Whether to return the room's aliases in the result.
+            allow_private (bool): Whether invite-only rooms should be shown.
+
+        Returns:
+            Deferred[dict|None]: Returns a room entry as a dictionary, or None if this
+            room was determined not to be shown publicly.
         """
         result = {
             "room_id": room_id,
@@ -318,6 +340,7 @@ class RoomListHandler(BaseHandler):
         event_map = yield self.store.get_events([
             event_id for key, event_id in iteritems(current_state_ids)
             if key[0] in (
+                EventTypes.Create,
                 EventTypes.JoinRules,
                 EventTypes.Name,
                 EventTypes.Topic,
@@ -334,12 +357,21 @@ class RoomListHandler(BaseHandler):
         }
 
         # Double check that this is actually a public room.
+
         join_rules_event = current_state.get((EventTypes.JoinRules, ""))
         if join_rules_event:
             join_rule = join_rules_event.content.get("join_rule", None)
             if not allow_private and join_rule and join_rule != JoinRules.PUBLIC:
                 defer.returnValue(None)
 
+        if not allow_non_federated:
+            # Disallow non-federated from appearing
+            create_event = current_state.get((EventTypes.Create, ""))
+            if create_event:
+                federate = create_event.content.get("m.federate", True)
+                if federate == False:
+                    defer.returnValue(None)
+
         if with_alias:
             aliases = yield self.store.get_aliases_for_room(
                 room_id, on_invalidate=cache_context.invalidate