Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow room creation but not publishing to continue if room publication rules are violated when creating a new room. #16811

Merged
merged 6 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions changelog.d/16811.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Allow room creation but not publishing to continue if room publication rules are violated when creating
a new room.
3 changes: 3 additions & 0 deletions docs/usage/configuration/config_documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -3959,6 +3959,9 @@ The first rule that matches decides if the request is allowed or denied. If no
rule matches, the request is denied. In particular, this means that configuring
an empty list of rules will deny every alias creation request.

Requests to create a public (public as in published to the room directory) room which violates
the configured rules will result in the room being created but not published to the room directory.

Each rule is a YAML object containing four fields, each of which is an optional string:

* `user_id`: a glob pattern that matches against the user publishing the room.
Expand Down
6 changes: 2 additions & 4 deletions synapse/handlers/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -916,10 +916,8 @@ async def create_room(
if not self.config.roomdirectory.is_publishing_room_allowed(
user_id, room_id, room_aliases
):
# Let's just return a generic message, as there may be all sorts of
# reasons why we said no. TODO: Allow configurable error messages
# per alias creation rule?
raise SynapseError(403, "Not allowed to publish room")
# allow room creation to continue but do not publish room
await self.store.set_room_is_public(room_id, False)

directory_handler = self.hs.get_directory_handler()
if room_alias:
Expand Down
37 changes: 35 additions & 2 deletions tests/config/test_room_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,31 @@
# [This file includes modifications made by New Vector Limited]
#
#

import yaml

from twisted.test.proto_helpers import MemoryReactor

import synapse.rest.admin
import synapse.rest.client.login
import synapse.rest.client.room
from synapse.config.room_directory import RoomDirectoryConfig
from synapse.server import HomeServer
from synapse.util import Clock

from tests import unittest
from tests.unittest import override_config


class RoomDirectoryConfigTestCase(unittest.HomeserverTestCase):
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
self.store = hs.get_datastores().main

servlets = [
synapse.rest.admin.register_servlets,
synapse.rest.client.login.register_servlets,
synapse.rest.client.room.register_servlets,
]

class RoomDirectoryConfigTestCase(unittest.TestCase):
def test_alias_creation_acl(self) -> None:
config = yaml.safe_load(
"""
Expand Down Expand Up @@ -167,3 +183,20 @@ def test_room_publish_acl(self) -> None:
aliases=["#unofficial_st:example.com", "#blah:example.com"],
)
)

@override_config({"room_list_publication_rules": []})
def test_room_creation_when_publishing_denied(self) -> None:
"""
Test that when room publishing is denied via the config that new rooms can
still be created and that the newly created room is not public.
"""

user = self.register_user("alice", "pass")
token = self.login("alice", "pass")
room_id = self.helper.create_room_as(user, is_public=True, tok=token)

res = self.get_success(self.store.get_room(room_id))
assert res is not None
is_public, _ = res

self.assertFalse(is_public)
51 changes: 23 additions & 28 deletions tests/handlers/test_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,19 +496,27 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
self.denied_user_id = self.register_user("denied", "pass")
self.denied_access_token = self.login("denied", "pass")

self.store = hs.get_datastores().main

def test_denied_without_publication_permission(self) -> None:
"""
Try to create a room, register an alias for it, and publish it,
Try to create a room, register a valid alias for it, and publish it,
as a user without permission to publish rooms.
(This is used as both a standalone test & as a helper function.)
The room should be created but not published.
"""
self.helper.create_room_as(
room_id = self.helper.create_room_as(
self.denied_user_id,
tok=self.denied_access_token,
extra_content=self.data,
is_public=True,
expect_code=403,
expect_code=200,
)
res = self.get_success(self.store.get_room(room_id))
assert res is not None
is_public, _ = res

# room creation completes but room is not published to directory
self.assertEqual(is_public, False)

def test_allowed_when_creating_private_room(self) -> None:
"""
Expand All @@ -526,9 +534,8 @@ def test_allowed_when_creating_private_room(self) -> None:

def test_allowed_with_publication_permission(self) -> None:
"""
Try to create a room, register an alias for it, and publish it,
Try to create a room, register a valid alias for it, and publish it,
as a user WITH permission to publish rooms.
(This is used as both a standalone test & as a helper function.)
"""
self.helper.create_room_as(
self.allowed_user_id,
Expand All @@ -540,38 +547,26 @@ def test_allowed_with_publication_permission(self) -> None:

def test_denied_publication_with_invalid_alias(self) -> None:
"""
Try to create a room, register an alias for it, and publish it,
Try to create a room, register an invalid alias for it, and publish it,
as a user WITH permission to publish rooms.
"""
self.helper.create_room_as(
room_id = self.helper.create_room_as(
self.allowed_user_id,
tok=self.allowed_access_token,
extra_content={"room_alias_name": "foo"},
is_public=True,
expect_code=403,
expect_code=200,
)

def test_can_create_as_private_room_after_rejection(self) -> None:
"""
After failing to publish a room with an alias as a user without publish permission,
retry as the same user, but without publishing the room.
# the room is created with the requested alias, but the room is not published
res = self.get_success(self.store.get_room(room_id))
assert res is not None
is_public, _ = res

This should pass, but used to fail because the alias was registered by the first
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rationale for removing this test is that it tested behavior specific to when a room is not created due to room list publication rules, which this PR changes.

request, even though the room creation was denied.
"""
self.test_denied_without_publication_permission()
self.test_allowed_when_creating_private_room()

def test_can_create_with_permission_after_rejection(self) -> None:
"""
After failing to publish a room with an alias as a user without publish permission,
retry as someone with permission, using the same alias.
self.assertFalse(is_public)

This also used to fail because of the alias having been registered by the first
request, leaving it unavailable for any other user's new rooms.
"""
self.test_denied_without_publication_permission()
self.test_allowed_with_publication_permission()
aliases = self.get_success(self.store.get_aliases_for_room(room_id))
self.assertEqual(aliases[0], "#foo:test")


class TestRoomListSearchDisabled(unittest.HomeserverTestCase):
Expand Down
Loading