Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Fix backfilled events being rejected for no state_groups #10439

Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions synapse/event_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ def check(
return

# 3. If event does not have a m.room.create in its auth_events, reject.
logger.info("event_auth: event_id=%s auth_events=%s", event.event_id, auth_events)
creation_event = auth_events.get((EventTypes.Create, ""), None)
if not creation_event:
raise AuthError(403, "No create event in auth events")
Expand Down
8 changes: 6 additions & 2 deletions synapse/handlers/federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2680,6 +2680,8 @@ async def _update_auth_events_and_context_for_auth(
remote_auth_chain = await self.federation_client.get_event_auth(
origin, event.room_id, event.event_id
)
logger.info("remote_auth_chain %s", remote_auth_chain)
logger.info("asdf %s", remote_auth_chain[0].auth_events)
except RequestSendFailed as e1:
# The other side isn't around or doesn't implement the
# endpoint, so lets just bail out.
Expand Down Expand Up @@ -2711,9 +2713,11 @@ async def _update_auth_events_and_context_for_auth(
event.event_id,
e.event_id,
)
context = await self.state_handler.compute_event_context(e)
missing_auth_context = (
await self.state_handler.compute_event_context(e)
)
await self._auth_and_persist_event(
origin, e, context, auth_events=auth
origin, e, missing_auth_context, auth_events=auth
)

if e.event_id in event_auth_events:
Expand Down
106 changes: 105 additions & 1 deletion tests/handlers/test_federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,19 @@
# limitations under the License.
import logging
from unittest import TestCase
from unittest.mock import Mock
from twisted.internet import defer

from synapse.api.constants import EventTypes
from synapse.api.errors import AuthError, Codes, LimitExceededError, SynapseError
from synapse.api.room_versions import RoomVersions
from synapse.events import EventBase
from synapse.federation.federation_base import event_from_pdu_json
from synapse.federation.units import Transaction
from synapse.logging.context import LoggingContext, run_in_background
from synapse.rest import admin
from synapse.rest.client.v1 import login, room
from synapse.util.stringutils import random_string

from tests import unittest

Expand All @@ -36,9 +40,14 @@ class FederationTestCase(unittest.HomeserverTestCase):
]

def make_homeserver(self, reactor, clock):
hs = self.setup_test_homeserver(federation_http_client=None)
# we mock out the federation client too
self.mock_federation_client = Mock()
hs = self.setup_test_homeserver(
federation_http_client=self.mock_federation_client
)
self.handler = hs.get_federation_handler()
self.store = hs.get_datastore()
self.state_store = hs.get_storage().state
return hs

def test_exchange_revoked_invite(self):
Expand Down Expand Up @@ -190,6 +199,101 @@ def test_rejected_state_event_state(self):

self.assertEqual(sg, sg2)

def test_floating_outlier_membership_auth(self):
"""
Check that we can properly process an event with auth_events that
include a floating membership event.

Regression test for #TODO(PR).
"""
OTHER_SERVER = "otherserver"
OTHER_USER = "@otheruser:" + OTHER_SERVER

# create the room
user_id = self.register_user("kermit", "test")
tok = self.login("kermit", "test")
room_id = self.helper.create_room_as(room_creator=user_id, tok=tok)
room_version = self.get_success(self.store.get_room_version(room_id))

prev_event_ids = self.get_success(self.store.get_prev_events_for_room(room_id))
(
most_recent_prev_event_id,
most_recent_prev_event_depth,
) = self.get_success(self.store.get_max_depth_of(prev_event_ids))
# mapping from (type, state_key) -> state_event_id
prev_state_map = self.get_success(
self.state_store.get_state_ids_for_event(most_recent_prev_event_id)
)
# List of state event ID's
prev_state_ids = list(prev_state_map.values())
auth_event_ids = prev_state_ids

auth_events = self.get_success(self.store.get_events(auth_event_ids))
logger.info("auth_event_ids %s\nauth_events=%s", auth_event_ids, auth_events)

# build a floating outlier member state event
fake_prev_event_id = "$" + random_string(43)
member_event = event_from_pdu_json(
{
"type": EventTypes.Member,
"content": {
"membership": "join",
},
"state_key": OTHER_USER,
"room_id": room_id,
"sender": OTHER_USER,
"depth": most_recent_prev_event_depth,
"prev_events": [fake_prev_event_id],
"auth_events": auth_event_ids.copy(),
"origin_server_ts": self.clock.time_msec(),
"signatures": {
OTHER_SERVER: {"ed25519:key_version": "SomeSignatureHere"}
},
},
room_version,
)
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved

# build and send an event authed based on the member event
ev = event_from_pdu_json(
{
"type": EventTypes.Message,
"content": {},
"room_id": room_id,
"sender": OTHER_USER,
"depth": most_recent_prev_event_depth,
"prev_events": prev_event_ids.copy(),
"auth_events": auth_event_ids.copy() + [member_event.event_id],
"origin_server_ts": self.clock.time_msec(),
"signatures": {
OTHER_SERVER: {"ed25519:key_version": "SomeSignatureHere"}
},
},
room_version,
)

# Stub the event_auth responds from the OTHER_SERVER
self.handler.federation_client.get_event_auth = (
lambda destination, room_id, event_id: defer.succeed([member_event])
)
# self.handler.federation_client.get_event_auth = Mock(
# return_value=defer.succeed(None)
# )
res = Transaction(
origin=OTHER_SERVER,
pdus=[member_event],
origin_server_ts=self.clock.time_msec(),
destination=None,
).get_dict()
self.mock_federation_client.get_json.return_value = defer.succeed((200, res))

# TODO: need to do backfill request instead
d = run_in_background(self.handler.on_receive_pdu, OTHER_SERVER, ev)
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved
self.get_success(d)

# Try and get the events
stored_event = self.get_success(self.store.get_event(ev.event_id))
self.assertEqual(stored_event.event_id, ev.event_id)

@unittest.override_config(
{"rc_invites": {"per_user": {"per_second": 0.5, "burst_count": 3}}}
)
Expand Down