Skip to content
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
47 changes: 40 additions & 7 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import logging
from collections.abc import Iterable
from http import HTTPStatus
from random import random
from typing import TYPE_CHECKING, Any, ClassVar
from unittest.mock import AsyncMock, Mock, patch

Expand Down Expand Up @@ -216,7 +217,8 @@ class FakeInviteResponse:
class FederatingModuleApiTestCase(synapsetest.FederatingHomeserverTestCase):
server_name_for_this_server = SERVER_NAME_FROM_LIST
OTHER_SERVER_NAME = INSURANCE_DOMAIN_IN_LIST
ROOM_VERSION = "10"
DEFAULT_ROOM_VERSION = "10"
ALLOWED_ROOM_VERSIONS = ["9", "10"]
TIM_VERSION = TimVersion.V1_1

@classmethod
Expand Down Expand Up @@ -298,13 +300,18 @@ def make_homeserver(self, reactor: MemoryReactor, clock: Clock) -> HomeServer:

def default_config(self) -> dict[str, Any]:
conf = super().default_config()
assert (
self.DEFAULT_ROOM_VERSION in KNOWN_ROOM_VERSIONS
), f"Requested default room version unknown: {self.DEFAULT_ROOM_VERSION}"
conf["default_room_version"] = self.DEFAULT_ROOM_VERSION
if "modules" not in conf:
conf["modules"] = [
{
"module": "synapse_invite_checker.InviteChecker",
"config": {
"tim-type": "pro",
"tim_version": self.TIM_VERSION.value,
"allowed_room_versions": self.ALLOWED_ROOM_VERSIONS,
"federation_list_url": "http://dummy.test/FederationList/federationList.jws",
"federation_localization_url": "http://dummy.test/localization",
"federation_list_client_cert": "tests/certs/client.pem",
Expand All @@ -330,13 +337,15 @@ def add_permission_to_a_user(self, user_to_permit: str, owning_user: str) -> Non
self.inv_checker.permissions_handler.update_permissions(owning_user, perms)
)

def _make_join(self, user_id: str, room_id: str) -> FakeChannel:
def _make_join(
self, user_id: str, room_id: str, room_version_str: str | None = None
) -> FakeChannel:
"""Generate the make_join template"""
users_domain = UserID.from_string(user_id).domain
return self.make_signed_federation_request(
"GET",
f"/_matrix/federation/v1/make_join/{room_id}/{user_id}"
f"?ver={self.ROOM_VERSION}",
f"?ver={room_version_str or self.DEFAULT_ROOM_VERSION}",
from_server=users_domain,
)

Expand All @@ -346,13 +355,14 @@ def send_join(
room_id: str,
make_join_expected_code: int = HTTPStatus.OK,
send_join_expected_code: int = HTTPStatus.OK,
room_version_str: str | None = None,
) -> None:
"""
Join a remote user to a local server. Should be a complete make_join/send_join
handshake
"""
# First create the make_join that will need to be signed by the 'remote server'
join_result_channel = self._make_join(joining_user, room_id)
join_result_channel = self._make_join(joining_user, room_id, room_version_str)
assert (
join_result_channel.code == make_join_expected_code
), f"make_join: {join_result_channel.json_body}"
Expand All @@ -368,7 +378,7 @@ def send_join(
joining_users_domain = UserID.from_string(joining_user).domain
self.add_hashes_and_signatures_from_other_server(
join_event_dict,
KNOWN_ROOM_VERSIONS[self.ROOM_VERSION],
KNOWN_ROOM_VERSIONS[room_version_str or self.DEFAULT_ROOM_VERSION],
joining_users_domain,
)
channel = self.make_signed_federation_request(
Expand Down Expand Up @@ -415,6 +425,16 @@ def send_leave(self, leaving_user: str, room_id: str) -> None:
def create_remote_room(
self, creator_id: str, room_version: str, is_public: bool
) -> str:
# Creating a room before version "12" means the room gets a randomly generated
# room id. Starting with "12" the room is based on the create event itself. To
# avoid arbitrary errors when doing tests that repeatedly create rooms
# rapid-fire, let's introduce a small time advance so that the timestamp on the
# room is just different enough to have a different hash than a previously
# created room. This should help stop errors like
# "store_room with room_id=!dE_jLFdFgPIHXZuc1wZ3qVANUu4R0y8zimGAzqmbqOg failed:
# UNIQUE constraint failed: rooms.room_id".
self.reactor.advance(random() * 2)
Comment thread
FrenchGithubUser marked this conversation as resolved.

domain = UserID.from_string(creator_id).domain
assert (
domain in self.map_server_name_to_signing_key
Expand Down Expand Up @@ -614,9 +634,11 @@ def login(
def create_local_room(
self,
creating_user: str,
invitee_list: list[str],
is_public: bool,
invitee_list: list[str] | None = None,
override_content: dict[str, Any] | None = None,
room_version: str | None = None,
expected_code: int = HTTPStatus.OK,
) -> str | None:
"""
Custom helper to send an api request with a full set of required additional room
Expand All @@ -629,10 +651,19 @@ def create_local_room(
Returns a room_id if successful or None if not, allowing tests to give the
assertion errors they want instead of the http response which is not useful
"""
# Creating a room before version "12" means the room gets a randomly generated
# room id. Starting with "12" the room is based on the create event itself. To
# avoid arbitrary errors when doing tests that repeatedly create rooms
# rapid-fire, let's introduce a small time advance so that the timestamp on the
# room is just different enough to have a different hash than a previously
# created room. This should help stop errors like
# "store_room with room_id=!dE_jLFdFgPIHXZuc1wZ3qVANUu4R0y8zimGAzqmbqOg failed:
# UNIQUE constraint failed: rooms.room_id".
self.reactor.advance(random() * 2)

# First create the extra content, then let override_content replace/merge items.
# extra_content will be passed to the room creation helper function
extra_content = construct_extra_content(creating_user, invitee_list)
extra_content = construct_extra_content(creating_user, invitee_list or [])
if override_content:
for key, value in override_content.items():
# initial_state is special, it's a list so we don't override it as much
Expand All @@ -658,8 +689,10 @@ def create_local_room(
return self.helper.create_room_as(
creating_user,
is_public=is_public,
room_version=room_version or self.DEFAULT_ROOM_VERSION,
tok=self.map_user_id_to_token[creating_user],
extra_content=extra_content,
expect_code=expected_code,
)
except AssertionError as e:
logger.warning(
Expand Down
63 changes: 42 additions & 21 deletions tests/test_createrooms_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from http import HTTPStatus
from typing import Any

from parameterized import parameterized
from parameterized import parameterized, parameterized_class
from synapse.api.constants import EventTypes, HistoryVisibility, JoinRules
from synapse.server import HomeServer
from synapse.util.clock import Clock
Expand All @@ -25,12 +25,23 @@
from tests.test_utils import INSURANCE_DOMAIN_IN_LIST_FOR_LOCAL


@parameterized_class(
("DEFAULT_ROOM_VERSION",),
[
("9",),
("10",),
("11",),
("12",),
],
)
class LocalProModeCreateRoomTest(FederatingModuleApiTestCase):
"""
These PRO server tests are for room creation process, including invite checking for
local users and special cases that should be allowed or prevented.
"""

ALLOWED_ROOM_VERSIONS = ["9", "10", "11", "12"]

def prepare(self, reactor: MemoryReactor, clock: Clock, homeserver: HomeServer):
super().prepare(reactor, clock, homeserver)
self.pro_user_a = self.register_user("a", "password")
Expand Down Expand Up @@ -65,8 +76,8 @@ def test_create_room(self, label: str, is_public: bool) -> None:
]:
room_id = self.create_local_room(
self.pro_user_a,
[invitee],
is_public=is_public,
invitee_list=[invitee],
)
assert (
room_id
Expand All @@ -78,8 +89,8 @@ def test_create_room(self, label: str, is_public: bool) -> None:
]:
room_id = self.create_local_room(
self.pro_user_b,
[invitee],
is_public=is_public,
invitee_list=[invitee],
)
assert (
room_id
Expand All @@ -91,8 +102,8 @@ def test_create_room(self, label: str, is_public: bool) -> None:
]:
room_id = self.create_local_room(
self.pro_user_d,
[invitee],
is_public=is_public,
invitee_list=[invitee],
)
assert (
room_id
Expand All @@ -112,8 +123,8 @@ def test_create_room_with_two_invites_fails(
]:
room_id = self.create_local_room(
self.pro_user_a,
invitee_list,
is_public=is_public,
invitee_list=invitee_list,
)
assert (
room_id is None
Expand Down Expand Up @@ -143,7 +154,7 @@ def test_create_room_then_modify_join_rules(
Test that a misbehaving client can not accidentally make their room public after
the room was created
"""
room_id = self.create_local_room(self.pro_user_a, [], is_public=is_public)
room_id = self.create_local_room(self.pro_user_a, is_public=is_public)
assert room_id, f"{label} room should be created"
# This should be ALLOWED for an already public room, it's silly but is idempotent
self.helper.send_state(
Expand All @@ -162,7 +173,7 @@ def test_create_room_then_modify_history_visibility(
Test that a misbehaving client can not accidentally make their room visible
after the room was created
"""
room_id = self.create_local_room(self.pro_user_a, [], is_public=is_public)
room_id = self.create_local_room(self.pro_user_a, is_public=is_public)
assert room_id, f"{label} room should be created"
# This should be BAD_REQUEST for any room
self.helper.send_state(
Expand All @@ -179,7 +190,7 @@ def test_create_room_default_history_visibility_invited(self) -> None:
but users can override this setting during room creation
"""
# Test 1: Private room created without explicit history_visibility should default to "invited"
room_id_private = self.create_local_room(self.pro_user_a, [], is_public=False)
room_id_private = self.create_local_room(self.pro_user_a, is_public=False)
assert room_id_private, "Private room should be created"

# Get the history visibility state event
Expand All @@ -193,7 +204,7 @@ def test_create_room_default_history_visibility_invited(self) -> None:
), "Default history visibility should be 'invited'"

# Test 2: Public room created without explicit history_visibility should default to "invited"
room_id_public = self.create_local_room(self.pro_user_a, [], is_public=True)
room_id_public = self.create_local_room(self.pro_user_a, is_public=True)
assert room_id_public, "Public room should be created"

# Get the history visibility state event
Expand All @@ -215,7 +226,7 @@ def test_create_room_default_history_visibility_invited(self) -> None:
override_content = {"initial_state": [custom_history_visibility]}

room_id_private_custom = self.create_local_room(
self.pro_user_a, [], is_public=False, override_content=override_content
self.pro_user_a, is_public=False, override_content=override_content
)
assert (
room_id_private_custom
Expand All @@ -240,7 +251,7 @@ def test_create_room_default_history_visibility_invited(self) -> None:
override_content = {"initial_state": [custom_history_visibility]}

room_id_public_custom = self.create_local_room(
self.pro_user_a, [], is_public=True, override_content=override_content
self.pro_user_a, is_public=True, override_content=override_content
)
assert (
room_id_public_custom
Expand All @@ -262,21 +273,31 @@ def test_create_room_with_v2_room_type_rejected(self) -> None:
"""
room_id = self.create_local_room(
self.pro_user_a,
[self.pro_user_b],
is_public=False,
invitee_list=[self.pro_user_b],
override_content={"type": "de.gematik.tim.roomtype.default.v2"},
)
assert (
room_id is None
), "Room with de.gematik.tim.roomtype.default.v2 type should not be created"


@parameterized_class(
("DEFAULT_ROOM_VERSION",),
[
("9",),
("10",),
("11",),
("12",),
],
)
class LocalEpaModeCreateRoomTest(FederatingModuleApiTestCase):
"""
These EPA server tests are for room creation process, including invite checking for
local users and special cases that should be allowed or prevented.
"""

ALLOWED_ROOM_VERSIONS = ["9", "10", "11", "12"]
server_name_for_this_server = INSURANCE_DOMAIN_IN_LIST_FOR_LOCAL

def prepare(self, reactor: MemoryReactor, clock: Clock, homeserver: HomeServer):
Expand Down Expand Up @@ -310,8 +331,8 @@ def test_create_room_fails(self, label: str, is_public: bool) -> None:
]:
room_id = self.create_local_room(
self.epa_user_d,
[invitee],
is_public=is_public,
invitee_list=[invitee],
)
assert (
room_id is None
Expand All @@ -328,8 +349,8 @@ def test_create_room_with_two_invites_fails(
invitee_list = [self.epa_user_e, self.epa_user_f]
room_id = self.create_local_room(
self.epa_user_d,
invitee_list,
is_public=is_public,
invitee_list=invitee_list,
)
assert (
room_id is None
Expand All @@ -356,7 +377,7 @@ def test_create_room_with_modified_join_rules(self, join_rule: str) -> None:
initial_state = {"initial_state": [join_rule_event]}

room_id = self.create_local_room(
self.epa_user_d, [], is_public=False, override_content=initial_state
self.epa_user_d, is_public=False, override_content=initial_state
)
assert (
room_id is None
Expand All @@ -374,7 +395,7 @@ def test_create_room_with_modified_history_visibility(self) -> None:
initial_state = {"initial_state": [history_visibility]}

room_id = self.create_local_room(
self.epa_user_d, [], is_public=False, override_content=initial_state
self.epa_user_d, is_public=False, override_content=initial_state
)
# Without the blocking put in place, this fails for private rooms
assert room_id is None, "Private room should NOT have been created"
Expand All @@ -394,7 +415,7 @@ def test_create_room_then_modify_join_rules(
Test that a misbehaving insurance client can not set forbidden join rules
after room was created
"""
room_id = self.create_local_room(self.epa_user_d, [], is_public=False)
room_id = self.create_local_room(self.epa_user_d, is_public=False)
assert room_id, "Private room should be created"
# This should be BAD_REQUEST
self.helper.send_state(
Expand All @@ -410,7 +431,7 @@ def test_create_room_then_modify_history_visibility(self) -> None:
Test that a misbehaving insurance client can not accidentally make their room
world_readable after room was created. Expects 400 M_INVALID_ROOM_STATE.
"""
room_id = self.create_local_room(self.epa_user_d, [], is_public=False)
room_id = self.create_local_room(self.epa_user_d, is_public=False)
assert room_id, "Private room should be created"
# This should be BAD_REQUEST
self.helper.send_state(
Expand Down Expand Up @@ -447,7 +468,7 @@ def test_create_room_default_history_visibility_invited(self) -> None:
but users can override this setting during room creation
"""
# Test 1: Room created without explicit history_visibility should default to "invited"
room_id = self.create_local_room(self.epa_user_d, [], is_public=False)
room_id = self.create_local_room(self.epa_user_d, is_public=False)
assert room_id, "Room should be created"

# Get the history visibility state event
Expand All @@ -469,7 +490,7 @@ def test_create_room_default_history_visibility_invited(self) -> None:
override_content = {"initial_state": [custom_history_visibility]}

room_id_custom = self.create_local_room(
self.epa_user_d, [], is_public=False, override_content=override_content
self.epa_user_d, is_public=False, override_content=override_content
)
assert room_id_custom, "Room with custom history visibility should be created"

Expand All @@ -489,8 +510,8 @@ def test_create_room_with_v2_room_type_rejected(self) -> None:
"""
room_id = self.create_local_room(
self.epa_user_d,
[self.epa_user_e],
is_public=False,
invitee_list=[self.epa_user_e],
override_content={"type": "de.gematik.tim.roomtype.default.v2"},
)
assert (
Expand Down
Loading
Loading