pass room version into FederationClient.send_join (#6854)

... which allows us to sanity-check the create event.
This commit is contained in:
Richard van der Hoff 2020-02-06 15:50:39 +00:00 committed by GitHub
parent bce557175b
commit b0c8bdd49d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 30 deletions

1
changelog.d/6854.misc Normal file
View File

@ -0,0 +1 @@
Refactoring work in preparation for changing the event redaction algorithm.

View File

@ -516,7 +516,7 @@ class FederationClient(FederationBase):
) )
async def send_join( async def send_join(
self, destinations: Iterable[str], pdu: EventBase, event_format_version: int self, destinations: Iterable[str], pdu: EventBase, room_version: RoomVersion
) -> Dict[str, Any]: ) -> Dict[str, Any]:
"""Sends a join event to one of a list of homeservers. """Sends a join event to one of a list of homeservers.
@ -527,7 +527,8 @@ class FederationClient(FederationBase):
destinations: Candidate homeservers which are probably destinations: Candidate homeservers which are probably
participating in the room. participating in the room.
pdu: event to be sent pdu: event to be sent
event_format_version: The event format version room_version: the version of the room (according to the server that
did the make_join)
Returns: Returns:
a dict with members ``origin`` (a string a dict with members ``origin`` (a string
@ -540,58 +541,51 @@ class FederationClient(FederationBase):
RuntimeError: if no servers were reachable. RuntimeError: if no servers were reachable.
""" """
def check_authchain_validity(signed_auth_chain):
for e in signed_auth_chain:
if e.type == EventTypes.Create:
create_event = e
break
else:
raise InvalidResponseError("no %s in auth chain" % (EventTypes.Create,))
# the room version should be sane.
room_version = create_event.content.get("room_version", "1")
if room_version not in KNOWN_ROOM_VERSIONS:
# This shouldn't be possible, because the remote server should have
# rejected the join attempt during make_join.
raise InvalidResponseError(
"room appears to have unsupported version %s" % (room_version,)
)
async def send_request(destination) -> Dict[str, Any]: async def send_request(destination) -> Dict[str, Any]:
content = await self._do_send_join(destination, pdu) content = await self._do_send_join(destination, pdu)
logger.debug("Got content: %s", content) logger.debug("Got content: %s", content)
state = [ state = [
event_from_pdu_json(p, event_format_version, outlier=True) event_from_pdu_json(p, room_version.event_format, outlier=True)
for p in content.get("state", []) for p in content.get("state", [])
] ]
auth_chain = [ auth_chain = [
event_from_pdu_json(p, event_format_version, outlier=True) event_from_pdu_json(p, room_version.event_format, outlier=True)
for p in content.get("auth_chain", []) for p in content.get("auth_chain", [])
] ]
pdus = {p.event_id: p for p in itertools.chain(state, auth_chain)} pdus = {p.event_id: p for p in itertools.chain(state, auth_chain)}
room_version = None create_event = None
for e in state: for e in state:
if (e.type, e.state_key) == (EventTypes.Create, ""): if (e.type, e.state_key) == (EventTypes.Create, ""):
room_version = e.content.get( create_event = e
"room_version", RoomVersions.V1.identifier
)
break break
if room_version is None: if create_event is None:
# If the state doesn't have a create event then the room is # If the state doesn't have a create event then the room is
# invalid, and it would fail auth checks anyway. # invalid, and it would fail auth checks anyway.
raise SynapseError(400, "No create event in state") raise SynapseError(400, "No create event in state")
# the room version should be sane.
create_room_version = create_event.content.get(
"room_version", RoomVersions.V1.identifier
)
if create_room_version != room_version.identifier:
# either the server that fulfilled the make_join, or the server that is
# handling the send_join, is lying.
raise InvalidResponseError(
"Unexpected room version %s in create event"
% (create_room_version,)
)
valid_pdus = await self._check_sigs_and_hash_and_fetch( valid_pdus = await self._check_sigs_and_hash_and_fetch(
destination, destination,
list(pdus.values()), list(pdus.values()),
outlier=True, outlier=True,
room_version=room_version, room_version=room_version.identifier,
) )
valid_pdus_map = {p.event_id: p for p in valid_pdus} valid_pdus_map = {p.event_id: p for p in valid_pdus}
@ -615,7 +609,17 @@ class FederationClient(FederationBase):
for s in signed_state: for s in signed_state:
s.internal_metadata = copy.deepcopy(s.internal_metadata) s.internal_metadata = copy.deepcopy(s.internal_metadata)
check_authchain_validity(signed_auth) # double-check that the same create event has ended up in the auth chain
auth_chain_create_events = [
e.event_id
for e in signed_auth
if (e.type, e.state_key) == (EventTypes.Create, "")
]
if auth_chain_create_events != [create_event.event_id]:
raise InvalidResponseError(
"Unexpected create event(s) in auth chain"
% (auth_chain_create_events,)
)
return { return {
"state": signed_state, "state": signed_state,

View File

@ -1305,9 +1305,8 @@ class FederationHandler(BaseHandler):
except ValueError: except ValueError:
pass pass
event_format_version = room_version_obj.event_format
ret = await self.federation_client.send_join( ret = await self.federation_client.send_join(
target_hosts, event, event_format_version target_hosts, event, room_version_obj
) )
origin = ret["origin"] origin = ret["origin"]