mirror of
https://mau.dev/maunium/synapse.git
synced 2024-12-13 13:03:27 +01:00
Move some event auth checks out to a different method (#13065)
* Add auth events to events used in tests * Move some event auth checks out to a different method Some of the event auth checks apply to an event's auth_events, rather than the state at the event - which means they can play no part in state resolution. Move them out to a separate method. * Rename check_auth_rules_for_event Now it only checks the state-dependent auth rules, it needs a better name.
This commit is contained in:
parent
cba1c5cbc2
commit
8ecf6be1e1
7 changed files with 219 additions and 98 deletions
1
changelog.d/13065.misc
Normal file
1
changelog.d/13065.misc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Avoid rechecking event auth rules which are independent of room state.
|
|
@ -15,11 +15,12 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import typing
|
import typing
|
||||||
from typing import Any, Dict, Iterable, List, Optional, Set, Tuple, Union
|
from typing import Any, Collection, Dict, Iterable, List, Optional, Set, Tuple, Union
|
||||||
|
|
||||||
from canonicaljson import encode_canonical_json
|
from canonicaljson import encode_canonical_json
|
||||||
from signedjson.key import decode_verify_key_bytes
|
from signedjson.key import decode_verify_key_bytes
|
||||||
from signedjson.sign import SignatureVerifyException, verify_signed_json
|
from signedjson.sign import SignatureVerifyException, verify_signed_json
|
||||||
|
from typing_extensions import Protocol
|
||||||
from unpaddedbase64 import decode_base64
|
from unpaddedbase64 import decode_base64
|
||||||
|
|
||||||
from synapse.api.constants import (
|
from synapse.api.constants import (
|
||||||
|
@ -35,7 +36,8 @@ from synapse.api.room_versions import (
|
||||||
EventFormatVersions,
|
EventFormatVersions,
|
||||||
RoomVersion,
|
RoomVersion,
|
||||||
)
|
)
|
||||||
from synapse.types import StateMap, UserID, get_domain_from_id
|
from synapse.storage.databases.main.events_worker import EventRedactBehaviour
|
||||||
|
from synapse.types import MutableStateMap, StateMap, UserID, get_domain_from_id
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
# conditional imports to avoid import cycle
|
# conditional imports to avoid import cycle
|
||||||
|
@ -45,6 +47,17 @@ if typing.TYPE_CHECKING:
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class _EventSourceStore(Protocol):
|
||||||
|
async def get_events(
|
||||||
|
self,
|
||||||
|
event_ids: Collection[str],
|
||||||
|
redact_behaviour: EventRedactBehaviour,
|
||||||
|
get_prev_content: bool = False,
|
||||||
|
allow_rejected: bool = False,
|
||||||
|
) -> Dict[str, "EventBase"]:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
def validate_event_for_room_version(event: "EventBase") -> None:
|
def validate_event_for_room_version(event: "EventBase") -> None:
|
||||||
"""Ensure that the event complies with the limits, and has the right signatures
|
"""Ensure that the event complies with the limits, and has the right signatures
|
||||||
|
|
||||||
|
@ -112,47 +125,52 @@ def validate_event_for_room_version(event: "EventBase") -> None:
|
||||||
raise AuthError(403, "Event not signed by authorising server")
|
raise AuthError(403, "Event not signed by authorising server")
|
||||||
|
|
||||||
|
|
||||||
def check_auth_rules_for_event(
|
async def check_state_independent_auth_rules(
|
||||||
|
store: _EventSourceStore,
|
||||||
event: "EventBase",
|
event: "EventBase",
|
||||||
auth_events: Iterable["EventBase"],
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Check that an event complies with the auth rules
|
"""Check that an event complies with auth rules that are independent of room state
|
||||||
|
|
||||||
Checks whether an event passes the auth rules with a given set of state events
|
Runs through the first few auth rules, which are independent of room state. (Which
|
||||||
|
means that we only need to them once for each received event)
|
||||||
Assumes that we have already checked that the event is the right shape (it has
|
|
||||||
enough signatures, has a room ID, etc). In other words:
|
|
||||||
|
|
||||||
- it's fine for use in state resolution, when we have already decided whether to
|
|
||||||
accept the event or not, and are now trying to decide whether it should make it
|
|
||||||
into the room state
|
|
||||||
|
|
||||||
- when we're doing the initial event auth, it is only suitable in combination with
|
|
||||||
a bunch of other tests.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
store: the datastore; used to fetch the auth events for validation
|
||||||
event: the event being checked.
|
event: the event being checked.
|
||||||
auth_events: the room state to check the events against.
|
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
AuthError if the checks fail
|
AuthError if the checks fail
|
||||||
"""
|
"""
|
||||||
# We need to ensure that the auth events are actually for the same room, to
|
# Check the auth events.
|
||||||
# stop people from using powers they've been granted in other rooms for
|
auth_events = await store.get_events(
|
||||||
# example.
|
event.auth_event_ids(),
|
||||||
#
|
redact_behaviour=EventRedactBehaviour.as_is,
|
||||||
# Arguably we don't need to do this when we're just doing state res, as presumably
|
allow_rejected=True,
|
||||||
# the state res algorithm isn't silly enough to give us events from different rooms.
|
)
|
||||||
# Still, it's easier to do it anyway.
|
|
||||||
room_id = event.room_id
|
room_id = event.room_id
|
||||||
for auth_event in auth_events:
|
auth_dict: MutableStateMap[str] = {}
|
||||||
|
for auth_event_id in event.auth_event_ids():
|
||||||
|
auth_event = auth_events.get(auth_event_id)
|
||||||
|
|
||||||
|
# we should have all the auth events by now, so if we do not, that suggests
|
||||||
|
# a synapse programming error
|
||||||
|
if auth_event is None:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Event {event.event_id} has unknown auth event {auth_event_id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# We need to ensure that the auth events are actually for the same room, to
|
||||||
|
# stop people from using powers they've been granted in other rooms for
|
||||||
|
# example.
|
||||||
if auth_event.room_id != room_id:
|
if auth_event.room_id != room_id:
|
||||||
raise AuthError(
|
raise AuthError(
|
||||||
403,
|
403,
|
||||||
"During auth for event %s in room %s, found event %s in the state "
|
"During auth for event %s in room %s, found event %s in the state "
|
||||||
"which is in room %s"
|
"which is in room %s"
|
||||||
% (event.event_id, room_id, auth_event.event_id, auth_event.room_id),
|
% (event.event_id, room_id, auth_event_id, auth_event.room_id),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# We also need to check that the auth event itself is not rejected.
|
||||||
if auth_event.rejected_reason:
|
if auth_event.rejected_reason:
|
||||||
raise AuthError(
|
raise AuthError(
|
||||||
403,
|
403,
|
||||||
|
@ -160,6 +178,8 @@ def check_auth_rules_for_event(
|
||||||
% (event.event_id, auth_event.event_id),
|
% (event.event_id, auth_event.event_id),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
auth_dict[(auth_event.type, auth_event.state_key)] = auth_event_id
|
||||||
|
|
||||||
# Implementation of https://matrix.org/docs/spec/rooms/v1#authorization-rules
|
# Implementation of https://matrix.org/docs/spec/rooms/v1#authorization-rules
|
||||||
#
|
#
|
||||||
# 1. If type is m.room.create:
|
# 1. If type is m.room.create:
|
||||||
|
@ -181,16 +201,46 @@ def check_auth_rules_for_event(
|
||||||
"room appears to have unsupported version %s" % (room_version_prop,),
|
"room appears to have unsupported version %s" % (room_version_prop,),
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.debug("Allowing! %s", event)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
auth_dict = {(e.type, e.state_key): e for e in auth_events}
|
|
||||||
|
|
||||||
# 3. If event does not have a m.room.create in its auth_events, reject.
|
# 3. If event does not have a m.room.create in its auth_events, reject.
|
||||||
creation_event = auth_dict.get((EventTypes.Create, ""), None)
|
creation_event = auth_dict.get((EventTypes.Create, ""), None)
|
||||||
if not creation_event:
|
if not creation_event:
|
||||||
raise AuthError(403, "No create event in auth events")
|
raise AuthError(403, "No create event in auth events")
|
||||||
|
|
||||||
|
|
||||||
|
def check_state_dependent_auth_rules(
|
||||||
|
event: "EventBase",
|
||||||
|
auth_events: Iterable["EventBase"],
|
||||||
|
) -> None:
|
||||||
|
"""Check that an event complies with auth rules that depend on room state
|
||||||
|
|
||||||
|
Runs through the parts of the auth rules that check an event against bits of room
|
||||||
|
state.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
|
||||||
|
- it's fine for use in state resolution, when we have already decided whether to
|
||||||
|
accept the event or not, and are now trying to decide whether it should make it
|
||||||
|
into the room state
|
||||||
|
|
||||||
|
- when we're doing the initial event auth, it is only suitable in combination with
|
||||||
|
a bunch of other tests (including, but not limited to, check_state_independent_auth_rules).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
event: the event being checked.
|
||||||
|
auth_events: the room state to check the events against.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
AuthError if the checks fail
|
||||||
|
"""
|
||||||
|
# there are no state-dependent auth rules for create events.
|
||||||
|
if event.type == EventTypes.Create:
|
||||||
|
logger.debug("Allowing! %s", event)
|
||||||
|
return
|
||||||
|
|
||||||
|
auth_dict = {(e.type, e.state_key): e for e in auth_events}
|
||||||
|
|
||||||
# additional check for m.federate
|
# additional check for m.federate
|
||||||
creating_domain = get_domain_from_id(event.room_id)
|
creating_domain = get_domain_from_id(event.room_id)
|
||||||
originating_domain = get_domain_from_id(event.sender)
|
originating_domain = get_domain_from_id(event.sender)
|
||||||
|
|
|
@ -23,7 +23,10 @@ from synapse.api.constants import (
|
||||||
)
|
)
|
||||||
from synapse.api.errors import AuthError, Codes, SynapseError
|
from synapse.api.errors import AuthError, Codes, SynapseError
|
||||||
from synapse.api.room_versions import RoomVersion
|
from synapse.api.room_versions import RoomVersion
|
||||||
from synapse.event_auth import check_auth_rules_for_event
|
from synapse.event_auth import (
|
||||||
|
check_state_dependent_auth_rules,
|
||||||
|
check_state_independent_auth_rules,
|
||||||
|
)
|
||||||
from synapse.events import EventBase
|
from synapse.events import EventBase
|
||||||
from synapse.events.builder import EventBuilder
|
from synapse.events.builder import EventBuilder
|
||||||
from synapse.events.snapshot import EventContext
|
from synapse.events.snapshot import EventContext
|
||||||
|
@ -52,9 +55,10 @@ class EventAuthHandler:
|
||||||
context: EventContext,
|
context: EventContext,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Check an event passes the auth rules at its own auth events"""
|
"""Check an event passes the auth rules at its own auth events"""
|
||||||
|
await check_state_independent_auth_rules(self._store, event)
|
||||||
auth_event_ids = event.auth_event_ids()
|
auth_event_ids = event.auth_event_ids()
|
||||||
auth_events_by_id = await self._store.get_events(auth_event_ids)
|
auth_events_by_id = await self._store.get_events(auth_event_ids)
|
||||||
check_auth_rules_for_event(event, auth_events_by_id.values())
|
check_state_dependent_auth_rules(event, auth_events_by_id.values())
|
||||||
|
|
||||||
def compute_auth_events(
|
def compute_auth_events(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -50,7 +50,8 @@ from synapse.api.errors import (
|
||||||
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS, RoomVersion, RoomVersions
|
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS, RoomVersion, RoomVersions
|
||||||
from synapse.event_auth import (
|
from synapse.event_auth import (
|
||||||
auth_types_for_event,
|
auth_types_for_event,
|
||||||
check_auth_rules_for_event,
|
check_state_dependent_auth_rules,
|
||||||
|
check_state_independent_auth_rules,
|
||||||
validate_event_for_room_version,
|
validate_event_for_room_version,
|
||||||
)
|
)
|
||||||
from synapse.events import EventBase
|
from synapse.events import EventBase
|
||||||
|
@ -1430,7 +1431,9 @@ class FederationEventHandler:
|
||||||
allow_rejected=True,
|
allow_rejected=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
def prep(event: EventBase) -> Optional[Tuple[EventBase, EventContext]]:
|
events_and_contexts_to_persist: List[Tuple[EventBase, EventContext]] = []
|
||||||
|
|
||||||
|
async def prep(event: EventBase) -> None:
|
||||||
with nested_logging_context(suffix=event.event_id):
|
with nested_logging_context(suffix=event.event_id):
|
||||||
auth = []
|
auth = []
|
||||||
for auth_event_id in event.auth_event_ids():
|
for auth_event_id in event.auth_event_ids():
|
||||||
|
@ -1444,7 +1447,7 @@ class FederationEventHandler:
|
||||||
event,
|
event,
|
||||||
auth_event_id,
|
auth_event_id,
|
||||||
)
|
)
|
||||||
return None
|
return
|
||||||
auth.append(ae)
|
auth.append(ae)
|
||||||
|
|
||||||
# we're not bothering about room state, so flag the event as an outlier.
|
# we're not bothering about room state, so flag the event as an outlier.
|
||||||
|
@ -1453,17 +1456,20 @@ class FederationEventHandler:
|
||||||
context = EventContext.for_outlier(self._storage_controllers)
|
context = EventContext.for_outlier(self._storage_controllers)
|
||||||
try:
|
try:
|
||||||
validate_event_for_room_version(event)
|
validate_event_for_room_version(event)
|
||||||
check_auth_rules_for_event(event, auth)
|
await check_state_independent_auth_rules(self._store, event)
|
||||||
|
check_state_dependent_auth_rules(event, auth)
|
||||||
except AuthError as e:
|
except AuthError as e:
|
||||||
logger.warning("Rejecting %r because %s", event, e)
|
logger.warning("Rejecting %r because %s", event, e)
|
||||||
context.rejected = RejectedReason.AUTH_ERROR
|
context.rejected = RejectedReason.AUTH_ERROR
|
||||||
|
|
||||||
return event, context
|
events_and_contexts_to_persist.append((event, context))
|
||||||
|
|
||||||
|
for event in fetched_events:
|
||||||
|
await prep(event)
|
||||||
|
|
||||||
events_to_persist = (x for x in (prep(event) for event in fetched_events) if x)
|
|
||||||
await self.persist_events_and_notify(
|
await self.persist_events_and_notify(
|
||||||
room_id,
|
room_id,
|
||||||
tuple(events_to_persist),
|
events_and_contexts_to_persist,
|
||||||
# Mark these events backfilled as they're historic events that will
|
# Mark these events backfilled as they're historic events that will
|
||||||
# eventually be backfilled. For example, missing events we fetch
|
# eventually be backfilled. For example, missing events we fetch
|
||||||
# during backfill should be marked as backfilled as well.
|
# during backfill should be marked as backfilled as well.
|
||||||
|
@ -1515,7 +1521,8 @@ class FederationEventHandler:
|
||||||
|
|
||||||
# ... and check that the event passes auth at those auth events.
|
# ... and check that the event passes auth at those auth events.
|
||||||
try:
|
try:
|
||||||
check_auth_rules_for_event(event, claimed_auth_events)
|
await check_state_independent_auth_rules(self._store, event)
|
||||||
|
check_state_dependent_auth_rules(event, claimed_auth_events)
|
||||||
except AuthError as e:
|
except AuthError as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"While checking auth of %r against auth_events: %s", event, e
|
"While checking auth of %r against auth_events: %s", event, e
|
||||||
|
@ -1563,7 +1570,7 @@ class FederationEventHandler:
|
||||||
auth_events_for_auth = calculated_auth_event_map
|
auth_events_for_auth = calculated_auth_event_map
|
||||||
|
|
||||||
try:
|
try:
|
||||||
check_auth_rules_for_event(event, auth_events_for_auth.values())
|
check_state_dependent_auth_rules(event, auth_events_for_auth.values())
|
||||||
except AuthError as e:
|
except AuthError as e:
|
||||||
logger.warning("Failed auth resolution for %r because %s", event, e)
|
logger.warning("Failed auth resolution for %r because %s", event, e)
|
||||||
context.rejected = RejectedReason.AUTH_ERROR
|
context.rejected = RejectedReason.AUTH_ERROR
|
||||||
|
@ -1663,7 +1670,7 @@ class FederationEventHandler:
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
check_auth_rules_for_event(event, current_auth_events)
|
check_state_dependent_auth_rules(event, current_auth_events)
|
||||||
except AuthError as e:
|
except AuthError as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Soft-failing %r (from %s) because %s",
|
"Soft-failing %r (from %s) because %s",
|
||||||
|
|
|
@ -330,7 +330,7 @@ def _resolve_auth_events(
|
||||||
auth_events[(prev_event.type, prev_event.state_key)] = prev_event
|
auth_events[(prev_event.type, prev_event.state_key)] = prev_event
|
||||||
try:
|
try:
|
||||||
# The signatures have already been checked at this point
|
# The signatures have already been checked at this point
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
event,
|
event,
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -347,7 +347,7 @@ def _resolve_normal_events(
|
||||||
for event in _ordered_events(events):
|
for event in _ordered_events(events):
|
||||||
try:
|
try:
|
||||||
# The signatures have already been checked at this point
|
# The signatures have already been checked at this point
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
event,
|
event,
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -573,7 +573,7 @@ async def _iterative_auth_checks(
|
||||||
auth_events[key] = event_map[ev_id]
|
auth_events[key] = event_map[ev_id]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
event,
|
event,
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright 2018 New Vector Ltd
|
# Copyright 2018-2022 The Matrix.org Foundation C.I.C.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from typing import Optional
|
from typing import Collection, Dict, Iterable, List, Optional
|
||||||
|
|
||||||
from parameterized import parameterized
|
from parameterized import parameterized
|
||||||
|
|
||||||
|
@ -22,8 +22,41 @@ from synapse.api.constants import EventContentFields
|
||||||
from synapse.api.errors import AuthError
|
from synapse.api.errors import AuthError
|
||||||
from synapse.api.room_versions import EventFormatVersions, RoomVersion, RoomVersions
|
from synapse.api.room_versions import EventFormatVersions, RoomVersion, RoomVersions
|
||||||
from synapse.events import EventBase, make_event_from_dict
|
from synapse.events import EventBase, make_event_from_dict
|
||||||
|
from synapse.storage.databases.main.events_worker import EventRedactBehaviour
|
||||||
from synapse.types import JsonDict, get_domain_from_id
|
from synapse.types import JsonDict, get_domain_from_id
|
||||||
|
|
||||||
|
from tests.test_utils import get_awaitable_result
|
||||||
|
|
||||||
|
|
||||||
|
class _StubEventSourceStore:
|
||||||
|
"""A stub implementation of the EventSourceStore"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._store: Dict[str, EventBase] = {}
|
||||||
|
|
||||||
|
def add_event(self, event: EventBase):
|
||||||
|
self._store[event.event_id] = event
|
||||||
|
|
||||||
|
def add_events(self, events: Iterable[EventBase]):
|
||||||
|
for event in events:
|
||||||
|
self._store[event.event_id] = event
|
||||||
|
|
||||||
|
async def get_events(
|
||||||
|
self,
|
||||||
|
event_ids: Collection[str],
|
||||||
|
redact_behaviour: EventRedactBehaviour,
|
||||||
|
get_prev_content: bool = False,
|
||||||
|
allow_rejected: bool = False,
|
||||||
|
) -> Dict[str, EventBase]:
|
||||||
|
assert allow_rejected
|
||||||
|
assert not get_prev_content
|
||||||
|
assert redact_behaviour == EventRedactBehaviour.as_is
|
||||||
|
results = {}
|
||||||
|
for e in event_ids:
|
||||||
|
if e in self._store:
|
||||||
|
results[e] = self._store[e]
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
class EventAuthTestCase(unittest.TestCase):
|
class EventAuthTestCase(unittest.TestCase):
|
||||||
def test_rejected_auth_events(self):
|
def test_rejected_auth_events(self):
|
||||||
|
@ -36,11 +69,15 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
_join_event(RoomVersions.V9, creator),
|
_join_event(RoomVersions.V9, creator),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
event_store = _StubEventSourceStore()
|
||||||
|
event_store.add_events(auth_events)
|
||||||
|
|
||||||
# creator should be able to send state
|
# creator should be able to send state
|
||||||
event_auth.check_auth_rules_for_event(
|
event = _random_state_event(RoomVersions.V9, creator, auth_events)
|
||||||
_random_state_event(RoomVersions.V9, creator),
|
get_awaitable_result(
|
||||||
auth_events,
|
event_auth.check_state_independent_auth_rules(event_store, event)
|
||||||
)
|
)
|
||||||
|
event_auth.check_state_dependent_auth_rules(event, auth_events)
|
||||||
|
|
||||||
# ... but a rejected join_rules event should cause it to be rejected
|
# ... but a rejected join_rules event should cause it to be rejected
|
||||||
rejected_join_rules = _join_rules_event(
|
rejected_join_rules = _join_rules_event(
|
||||||
|
@ -50,23 +87,27 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
)
|
)
|
||||||
rejected_join_rules.rejected_reason = "stinky"
|
rejected_join_rules.rejected_reason = "stinky"
|
||||||
auth_events.append(rejected_join_rules)
|
auth_events.append(rejected_join_rules)
|
||||||
|
event_store.add_event(rejected_join_rules)
|
||||||
|
|
||||||
self.assertRaises(
|
with self.assertRaises(AuthError):
|
||||||
AuthError,
|
get_awaitable_result(
|
||||||
event_auth.check_auth_rules_for_event,
|
event_auth.check_state_independent_auth_rules(
|
||||||
_random_state_event(RoomVersions.V9, creator),
|
event_store,
|
||||||
auth_events,
|
_random_state_event(RoomVersions.V9, creator),
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# ... even if there is *also* a good join rules
|
# ... even if there is *also* a good join rules
|
||||||
auth_events.append(_join_rules_event(RoomVersions.V9, creator, "public"))
|
auth_events.append(_join_rules_event(RoomVersions.V9, creator, "public"))
|
||||||
|
event_store.add_event(rejected_join_rules)
|
||||||
|
|
||||||
self.assertRaises(
|
with self.assertRaises(AuthError):
|
||||||
AuthError,
|
get_awaitable_result(
|
||||||
event_auth.check_auth_rules_for_event,
|
event_auth.check_state_independent_auth_rules(
|
||||||
_random_state_event(RoomVersions.V9, creator),
|
event_store,
|
||||||
auth_events,
|
_random_state_event(RoomVersions.V9, creator),
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def test_random_users_cannot_send_state_before_first_pl(self):
|
def test_random_users_cannot_send_state_before_first_pl(self):
|
||||||
"""
|
"""
|
||||||
|
@ -82,7 +123,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
]
|
]
|
||||||
|
|
||||||
# creator should be able to send state
|
# creator should be able to send state
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_random_state_event(RoomVersions.V1, creator),
|
_random_state_event(RoomVersions.V1, creator),
|
||||||
auth_events,
|
auth_events,
|
||||||
)
|
)
|
||||||
|
@ -90,7 +131,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
# joiner should not be able to send state
|
# joiner should not be able to send state
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
AuthError,
|
AuthError,
|
||||||
event_auth.check_auth_rules_for_event,
|
event_auth.check_state_dependent_auth_rules,
|
||||||
_random_state_event(RoomVersions.V1, joiner),
|
_random_state_event(RoomVersions.V1, joiner),
|
||||||
auth_events,
|
auth_events,
|
||||||
)
|
)
|
||||||
|
@ -119,13 +160,13 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
# pleb should not be able to send state
|
# pleb should not be able to send state
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
AuthError,
|
AuthError,
|
||||||
event_auth.check_auth_rules_for_event,
|
event_auth.check_state_dependent_auth_rules,
|
||||||
_random_state_event(RoomVersions.V1, pleb),
|
_random_state_event(RoomVersions.V1, pleb),
|
||||||
auth_events,
|
auth_events,
|
||||||
),
|
),
|
||||||
|
|
||||||
# king should be able to send state
|
# king should be able to send state
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_random_state_event(RoomVersions.V1, king),
|
_random_state_event(RoomVersions.V1, king),
|
||||||
auth_events,
|
auth_events,
|
||||||
)
|
)
|
||||||
|
@ -140,27 +181,27 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
]
|
]
|
||||||
|
|
||||||
# creator should be able to send aliases
|
# creator should be able to send aliases
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_alias_event(RoomVersions.V1, creator),
|
_alias_event(RoomVersions.V1, creator),
|
||||||
auth_events,
|
auth_events,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Reject an event with no state key.
|
# Reject an event with no state key.
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_alias_event(RoomVersions.V1, creator, state_key=""),
|
_alias_event(RoomVersions.V1, creator, state_key=""),
|
||||||
auth_events,
|
auth_events,
|
||||||
)
|
)
|
||||||
|
|
||||||
# If the domain of the sender does not match the state key, reject.
|
# If the domain of the sender does not match the state key, reject.
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_alias_event(RoomVersions.V1, creator, state_key="test.com"),
|
_alias_event(RoomVersions.V1, creator, state_key="test.com"),
|
||||||
auth_events,
|
auth_events,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Note that the member does *not* need to be in the room.
|
# Note that the member does *not* need to be in the room.
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_alias_event(RoomVersions.V1, other),
|
_alias_event(RoomVersions.V1, other),
|
||||||
auth_events,
|
auth_events,
|
||||||
)
|
)
|
||||||
|
@ -175,24 +216,24 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
]
|
]
|
||||||
|
|
||||||
# creator should be able to send aliases
|
# creator should be able to send aliases
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_alias_event(RoomVersions.V6, creator),
|
_alias_event(RoomVersions.V6, creator),
|
||||||
auth_events,
|
auth_events,
|
||||||
)
|
)
|
||||||
|
|
||||||
# No particular checks are done on the state key.
|
# No particular checks are done on the state key.
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_alias_event(RoomVersions.V6, creator, state_key=""),
|
_alias_event(RoomVersions.V6, creator, state_key=""),
|
||||||
auth_events,
|
auth_events,
|
||||||
)
|
)
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_alias_event(RoomVersions.V6, creator, state_key="test.com"),
|
_alias_event(RoomVersions.V6, creator, state_key="test.com"),
|
||||||
auth_events,
|
auth_events,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Per standard auth rules, the member must be in the room.
|
# Per standard auth rules, the member must be in the room.
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_alias_event(RoomVersions.V6, other),
|
_alias_event(RoomVersions.V6, other),
|
||||||
auth_events,
|
auth_events,
|
||||||
)
|
)
|
||||||
|
@ -220,12 +261,12 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
|
|
||||||
# on room V1, pleb should be able to modify the notifications power level.
|
# on room V1, pleb should be able to modify the notifications power level.
|
||||||
if allow_modification:
|
if allow_modification:
|
||||||
event_auth.check_auth_rules_for_event(pl_event, auth_events)
|
event_auth.check_state_dependent_auth_rules(pl_event, auth_events)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# But an MSC2209 room rejects this change.
|
# But an MSC2209 room rejects this change.
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(pl_event, auth_events)
|
event_auth.check_state_dependent_auth_rules(pl_event, auth_events)
|
||||||
|
|
||||||
def test_join_rules_public(self):
|
def test_join_rules_public(self):
|
||||||
"""
|
"""
|
||||||
|
@ -243,14 +284,14 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check join.
|
# Check join.
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V6, pleb),
|
_join_event(RoomVersions.V6, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
|
||||||
# A user cannot be force-joined to a room.
|
# A user cannot be force-joined to a room.
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_member_event(RoomVersions.V6, pleb, "join", sender=creator),
|
_member_event(RoomVersions.V6, pleb, "join", sender=creator),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -260,7 +301,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
RoomVersions.V6, pleb, "ban"
|
RoomVersions.V6, pleb, "ban"
|
||||||
)
|
)
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V6, pleb),
|
_join_event(RoomVersions.V6, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -269,7 +310,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
auth_events[("m.room.member", pleb)] = _member_event(
|
auth_events[("m.room.member", pleb)] = _member_event(
|
||||||
RoomVersions.V6, pleb, "leave"
|
RoomVersions.V6, pleb, "leave"
|
||||||
)
|
)
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V6, pleb),
|
_join_event(RoomVersions.V6, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -278,7 +319,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
auth_events[("m.room.member", pleb)] = _member_event(
|
auth_events[("m.room.member", pleb)] = _member_event(
|
||||||
RoomVersions.V6, pleb, "join"
|
RoomVersions.V6, pleb, "join"
|
||||||
)
|
)
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V6, pleb),
|
_join_event(RoomVersions.V6, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -287,7 +328,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
auth_events[("m.room.member", pleb)] = _member_event(
|
auth_events[("m.room.member", pleb)] = _member_event(
|
||||||
RoomVersions.V6, pleb, "invite", sender=creator
|
RoomVersions.V6, pleb, "invite", sender=creator
|
||||||
)
|
)
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V6, pleb),
|
_join_event(RoomVersions.V6, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -309,14 +350,14 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
|
|
||||||
# A join without an invite is rejected.
|
# A join without an invite is rejected.
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V6, pleb),
|
_join_event(RoomVersions.V6, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
|
||||||
# A user cannot be force-joined to a room.
|
# A user cannot be force-joined to a room.
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_member_event(RoomVersions.V6, pleb, "join", sender=creator),
|
_member_event(RoomVersions.V6, pleb, "join", sender=creator),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -326,7 +367,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
RoomVersions.V6, pleb, "ban"
|
RoomVersions.V6, pleb, "ban"
|
||||||
)
|
)
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V6, pleb),
|
_join_event(RoomVersions.V6, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -336,7 +377,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
RoomVersions.V6, pleb, "leave"
|
RoomVersions.V6, pleb, "leave"
|
||||||
)
|
)
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V6, pleb),
|
_join_event(RoomVersions.V6, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -345,7 +386,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
auth_events[("m.room.member", pleb)] = _member_event(
|
auth_events[("m.room.member", pleb)] = _member_event(
|
||||||
RoomVersions.V6, pleb, "join"
|
RoomVersions.V6, pleb, "join"
|
||||||
)
|
)
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V6, pleb),
|
_join_event(RoomVersions.V6, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -354,7 +395,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
auth_events[("m.room.member", pleb)] = _member_event(
|
auth_events[("m.room.member", pleb)] = _member_event(
|
||||||
RoomVersions.V6, pleb, "invite", sender=creator
|
RoomVersions.V6, pleb, "invite", sender=creator
|
||||||
)
|
)
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V6, pleb),
|
_join_event(RoomVersions.V6, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -376,7 +417,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V6, pleb),
|
_join_event(RoomVersions.V6, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -413,7 +454,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
EventContentFields.AUTHORISING_USER: "@creator:example.com"
|
EventContentFields.AUTHORISING_USER: "@creator:example.com"
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
authorised_join_event,
|
authorised_join_event,
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -429,7 +470,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
pl_auth_events[("m.room.member", "@inviter:foo.test")] = _join_event(
|
pl_auth_events[("m.room.member", "@inviter:foo.test")] = _join_event(
|
||||||
RoomVersions.V8, "@inviter:foo.test"
|
RoomVersions.V8, "@inviter:foo.test"
|
||||||
)
|
)
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(
|
_join_event(
|
||||||
RoomVersions.V8,
|
RoomVersions.V8,
|
||||||
pleb,
|
pleb,
|
||||||
|
@ -442,7 +483,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
|
|
||||||
# A join which is missing an authorised server is rejected.
|
# A join which is missing an authorised server is rejected.
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V8, pleb),
|
_join_event(RoomVersions.V8, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -455,7 +496,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
{"invite": 100, "users": {"@other:example.com": 150}},
|
{"invite": 100, "users": {"@other:example.com": 150}},
|
||||||
)
|
)
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(
|
_join_event(
|
||||||
RoomVersions.V8,
|
RoomVersions.V8,
|
||||||
pleb,
|
pleb,
|
||||||
|
@ -469,7 +510,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
# A user cannot be force-joined to a room. (This uses an event which
|
# A user cannot be force-joined to a room. (This uses an event which
|
||||||
# *would* be valid, but is sent be a different user.)
|
# *would* be valid, but is sent be a different user.)
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_member_event(
|
_member_event(
|
||||||
RoomVersions.V8,
|
RoomVersions.V8,
|
||||||
pleb,
|
pleb,
|
||||||
|
@ -487,7 +528,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
RoomVersions.V8, pleb, "ban"
|
RoomVersions.V8, pleb, "ban"
|
||||||
)
|
)
|
||||||
with self.assertRaises(AuthError):
|
with self.assertRaises(AuthError):
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
authorised_join_event,
|
authorised_join_event,
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -496,7 +537,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
auth_events[("m.room.member", pleb)] = _member_event(
|
auth_events[("m.room.member", pleb)] = _member_event(
|
||||||
RoomVersions.V8, pleb, "leave"
|
RoomVersions.V8, pleb, "leave"
|
||||||
)
|
)
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
authorised_join_event,
|
authorised_join_event,
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -506,7 +547,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
auth_events[("m.room.member", pleb)] = _member_event(
|
auth_events[("m.room.member", pleb)] = _member_event(
|
||||||
RoomVersions.V8, pleb, "join"
|
RoomVersions.V8, pleb, "join"
|
||||||
)
|
)
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V8, pleb),
|
_join_event(RoomVersions.V8, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -516,7 +557,7 @@ class EventAuthTestCase(unittest.TestCase):
|
||||||
auth_events[("m.room.member", pleb)] = _member_event(
|
auth_events[("m.room.member", pleb)] = _member_event(
|
||||||
RoomVersions.V8, pleb, "invite", sender=creator
|
RoomVersions.V8, pleb, "invite", sender=creator
|
||||||
)
|
)
|
||||||
event_auth.check_auth_rules_for_event(
|
event_auth.check_state_dependent_auth_rules(
|
||||||
_join_event(RoomVersions.V8, pleb),
|
_join_event(RoomVersions.V8, pleb),
|
||||||
auth_events.values(),
|
auth_events.values(),
|
||||||
)
|
)
|
||||||
|
@ -539,6 +580,7 @@ def _create_event(
|
||||||
"state_key": "",
|
"state_key": "",
|
||||||
"sender": user_id,
|
"sender": user_id,
|
||||||
"content": {"creator": user_id},
|
"content": {"creator": user_id},
|
||||||
|
"auth_events": [],
|
||||||
},
|
},
|
||||||
room_version=room_version,
|
room_version=room_version,
|
||||||
)
|
)
|
||||||
|
@ -559,6 +601,7 @@ def _member_event(
|
||||||
"sender": sender or user_id,
|
"sender": sender or user_id,
|
||||||
"state_key": user_id,
|
"state_key": user_id,
|
||||||
"content": {"membership": membership, **(additional_content or {})},
|
"content": {"membership": membership, **(additional_content or {})},
|
||||||
|
"auth_events": [],
|
||||||
"prev_events": [],
|
"prev_events": [],
|
||||||
},
|
},
|
||||||
room_version=room_version,
|
room_version=room_version,
|
||||||
|
@ -609,7 +652,22 @@ def _alias_event(room_version: RoomVersion, sender: str, **kwargs) -> EventBase:
|
||||||
return make_event_from_dict(data, room_version=room_version)
|
return make_event_from_dict(data, room_version=room_version)
|
||||||
|
|
||||||
|
|
||||||
def _random_state_event(room_version: RoomVersion, sender: str) -> EventBase:
|
def _build_auth_dict_for_room_version(
|
||||||
|
room_version: RoomVersion, auth_events: Iterable[EventBase]
|
||||||
|
) -> List:
|
||||||
|
if room_version.event_format == EventFormatVersions.V1:
|
||||||
|
return [(e.event_id, "not_used") for e in auth_events]
|
||||||
|
else:
|
||||||
|
return [e.event_id for e in auth_events]
|
||||||
|
|
||||||
|
|
||||||
|
def _random_state_event(
|
||||||
|
room_version: RoomVersion,
|
||||||
|
sender: str,
|
||||||
|
auth_events: Optional[Iterable[EventBase]] = None,
|
||||||
|
) -> EventBase:
|
||||||
|
if auth_events is None:
|
||||||
|
auth_events = []
|
||||||
return make_event_from_dict(
|
return make_event_from_dict(
|
||||||
{
|
{
|
||||||
"room_id": TEST_ROOM_ID,
|
"room_id": TEST_ROOM_ID,
|
||||||
|
@ -618,6 +676,7 @@ def _random_state_event(room_version: RoomVersion, sender: str) -> EventBase:
|
||||||
"sender": sender,
|
"sender": sender,
|
||||||
"state_key": "",
|
"state_key": "",
|
||||||
"content": {"membership": "join"},
|
"content": {"membership": "join"},
|
||||||
|
"auth_events": _build_auth_dict_for_room_version(room_version, auth_events),
|
||||||
},
|
},
|
||||||
room_version=room_version,
|
room_version=room_version,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue