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

Commit f3efa00

Browse files
authored
Move _persist_auth_tree into FederationEventHandler (#11115)
This is just a lift-and-shift, because it fits more naturally here. We do rename it to `process_remote_join` at the same time though.
1 parent 0170774 commit f3efa00

File tree

3 files changed

+120
-125
lines changed

3 files changed

+120
-125
lines changed

changelog.d/11115.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Clean up some of the federation event authentication code for clarity.

synapse/handlers/federation.py

Lines changed: 4 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
"""Contains handlers for federation events."""
1717

18-
import itertools
1918
import logging
2019
from http import HTTPStatus
2120
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Tuple, Union
@@ -27,12 +26,7 @@
2726
from twisted.internet import defer
2827

2928
from synapse import event_auth
30-
from synapse.api.constants import (
31-
EventContentFields,
32-
EventTypes,
33-
Membership,
34-
RejectedReason,
35-
)
29+
from synapse.api.constants import EventContentFields, EventTypes, Membership
3630
from synapse.api.errors import (
3731
AuthError,
3832
CodeMessageException,
@@ -43,12 +37,9 @@
4337
RequestSendFailed,
4438
SynapseError,
4539
)
46-
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS, RoomVersion, RoomVersions
40+
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS, RoomVersion
4741
from synapse.crypto.event_signing import compute_event_signature
48-
from synapse.event_auth import (
49-
check_auth_rules_for_event,
50-
validate_event_for_room_version,
51-
)
42+
from synapse.event_auth import validate_event_for_room_version
5243
from synapse.events import EventBase
5344
from synapse.events.snapshot import EventContext
5445
from synapse.events.validator import EventValidator
@@ -519,7 +510,7 @@ async def do_invite_join(
519510
auth_events=auth_chain,
520511
)
521512

522-
max_stream_id = await self._persist_auth_tree(
513+
max_stream_id = await self._federation_event_handler.process_remote_join(
523514
origin, room_id, auth_chain, state, event, room_version_obj
524515
)
525516

@@ -1095,117 +1086,6 @@ async def get_persisted_pdu(
10951086
else:
10961087
return None
10971088

1098-
async def _persist_auth_tree(
1099-
self,
1100-
origin: str,
1101-
room_id: str,
1102-
auth_events: List[EventBase],
1103-
state: List[EventBase],
1104-
event: EventBase,
1105-
room_version: RoomVersion,
1106-
) -> int:
1107-
"""Checks the auth chain is valid (and passes auth checks) for the
1108-
state and event. Then persists the auth chain and state atomically.
1109-
Persists the event separately. Notifies about the persisted events
1110-
where appropriate.
1111-
1112-
Will attempt to fetch missing auth events.
1113-
1114-
Args:
1115-
origin: Where the events came from
1116-
room_id,
1117-
auth_events
1118-
state
1119-
event
1120-
room_version: The room version we expect this room to have, and
1121-
will raise if it doesn't match the version in the create event.
1122-
"""
1123-
events_to_context = {}
1124-
for e in itertools.chain(auth_events, state):
1125-
e.internal_metadata.outlier = True
1126-
events_to_context[e.event_id] = EventContext.for_outlier()
1127-
1128-
event_map = {
1129-
e.event_id: e for e in itertools.chain(auth_events, state, [event])
1130-
}
1131-
1132-
create_event = None
1133-
for e in auth_events:
1134-
if (e.type, e.state_key) == (EventTypes.Create, ""):
1135-
create_event = e
1136-
break
1137-
1138-
if create_event is None:
1139-
# If the state doesn't have a create event then the room is
1140-
# invalid, and it would fail auth checks anyway.
1141-
raise SynapseError(400, "No create event in state")
1142-
1143-
room_version_id = create_event.content.get(
1144-
"room_version", RoomVersions.V1.identifier
1145-
)
1146-
1147-
if room_version.identifier != room_version_id:
1148-
raise SynapseError(400, "Room version mismatch")
1149-
1150-
missing_auth_events = set()
1151-
for e in itertools.chain(auth_events, state, [event]):
1152-
for e_id in e.auth_event_ids():
1153-
if e_id not in event_map:
1154-
missing_auth_events.add(e_id)
1155-
1156-
for e_id in missing_auth_events:
1157-
m_ev = await self.federation_client.get_pdu(
1158-
[origin],
1159-
e_id,
1160-
room_version=room_version,
1161-
outlier=True,
1162-
timeout=10000,
1163-
)
1164-
if m_ev and m_ev.event_id == e_id:
1165-
event_map[e_id] = m_ev
1166-
else:
1167-
logger.info("Failed to find auth event %r", e_id)
1168-
1169-
for e in itertools.chain(auth_events, state, [event]):
1170-
auth_for_e = [
1171-
event_map[e_id] for e_id in e.auth_event_ids() if e_id in event_map
1172-
]
1173-
if create_event:
1174-
auth_for_e.append(create_event)
1175-
1176-
try:
1177-
validate_event_for_room_version(room_version, e)
1178-
check_auth_rules_for_event(room_version, e, auth_for_e)
1179-
except SynapseError as err:
1180-
# we may get SynapseErrors here as well as AuthErrors. For
1181-
# instance, there are a couple of (ancient) events in some
1182-
# rooms whose senders do not have the correct sigil; these
1183-
# cause SynapseErrors in auth.check. We don't want to give up
1184-
# the attempt to federate altogether in such cases.
1185-
1186-
logger.warning("Rejecting %s because %s", e.event_id, err.msg)
1187-
1188-
if e == event:
1189-
raise
1190-
events_to_context[e.event_id].rejected = RejectedReason.AUTH_ERROR
1191-
1192-
if auth_events or state:
1193-
await self._federation_event_handler.persist_events_and_notify(
1194-
room_id,
1195-
[
1196-
(e, events_to_context[e.event_id])
1197-
for e in itertools.chain(auth_events, state)
1198-
],
1199-
)
1200-
1201-
new_event_context = await self.state_handler.compute_event_context(
1202-
event, old_state=state
1203-
)
1204-
1205-
return await self._federation_event_handler.persist_events_and_notify(
1206-
room_id, [(event, new_event_context)]
1207-
)
1208-
12091089
async def on_get_missing_events(
12101090
self,
12111091
origin: str,

synapse/handlers/federation_event.py

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import itertools
1516
import logging
1617
from http import HTTPStatus
1718
from typing import (
@@ -45,7 +46,7 @@
4546
RequestSendFailed,
4647
SynapseError,
4748
)
48-
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
49+
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS, RoomVersion, RoomVersions
4950
from synapse.event_auth import (
5051
auth_types_for_event,
5152
check_auth_rules_for_event,
@@ -390,6 +391,119 @@ async def check_join_restrictions(
390391
prev_member_event,
391392
)
392393

394+
async def process_remote_join(
395+
self,
396+
origin: str,
397+
room_id: str,
398+
auth_events: List[EventBase],
399+
state: List[EventBase],
400+
event: EventBase,
401+
room_version: RoomVersion,
402+
) -> int:
403+
"""Persists the events returned by a send_join
404+
405+
Checks the auth chain is valid (and passes auth checks) for the
406+
state and event. Then persists the auth chain and state atomically.
407+
Persists the event separately. Notifies about the persisted events
408+
where appropriate.
409+
410+
Will attempt to fetch missing auth events.
411+
412+
Args:
413+
origin: Where the events came from
414+
room_id,
415+
auth_events
416+
state
417+
event
418+
room_version: The room version we expect this room to have, and
419+
will raise if it doesn't match the version in the create event.
420+
"""
421+
events_to_context = {}
422+
for e in itertools.chain(auth_events, state):
423+
e.internal_metadata.outlier = True
424+
events_to_context[e.event_id] = EventContext.for_outlier()
425+
426+
event_map = {
427+
e.event_id: e for e in itertools.chain(auth_events, state, [event])
428+
}
429+
430+
create_event = None
431+
for e in auth_events:
432+
if (e.type, e.state_key) == (EventTypes.Create, ""):
433+
create_event = e
434+
break
435+
436+
if create_event is None:
437+
# If the state doesn't have a create event then the room is
438+
# invalid, and it would fail auth checks anyway.
439+
raise SynapseError(400, "No create event in state")
440+
441+
room_version_id = create_event.content.get(
442+
"room_version", RoomVersions.V1.identifier
443+
)
444+
445+
if room_version.identifier != room_version_id:
446+
raise SynapseError(400, "Room version mismatch")
447+
448+
missing_auth_events = set()
449+
for e in itertools.chain(auth_events, state, [event]):
450+
for e_id in e.auth_event_ids():
451+
if e_id not in event_map:
452+
missing_auth_events.add(e_id)
453+
454+
for e_id in missing_auth_events:
455+
m_ev = await self._federation_client.get_pdu(
456+
[origin],
457+
e_id,
458+
room_version=room_version,
459+
outlier=True,
460+
timeout=10000,
461+
)
462+
if m_ev and m_ev.event_id == e_id:
463+
event_map[e_id] = m_ev
464+
else:
465+
logger.info("Failed to find auth event %r", e_id)
466+
467+
for e in itertools.chain(auth_events, state, [event]):
468+
auth_for_e = [
469+
event_map[e_id] for e_id in e.auth_event_ids() if e_id in event_map
470+
]
471+
if create_event:
472+
auth_for_e.append(create_event)
473+
474+
try:
475+
validate_event_for_room_version(room_version, e)
476+
check_auth_rules_for_event(room_version, e, auth_for_e)
477+
except SynapseError as err:
478+
# we may get SynapseErrors here as well as AuthErrors. For
479+
# instance, there are a couple of (ancient) events in some
480+
# rooms whose senders do not have the correct sigil; these
481+
# cause SynapseErrors in auth.check. We don't want to give up
482+
# the attempt to federate altogether in such cases.
483+
484+
logger.warning("Rejecting %s because %s", e.event_id, err.msg)
485+
486+
if e == event:
487+
raise
488+
events_to_context[e.event_id].rejected = RejectedReason.AUTH_ERROR
489+
490+
if auth_events or state:
491+
await self.persist_events_and_notify(
492+
room_id,
493+
[
494+
(e, events_to_context[e.event_id])
495+
for e in itertools.chain(auth_events, state)
496+
],
497+
)
498+
499+
new_event_context = await self._state_handler.compute_event_context(
500+
event, old_state=state
501+
)
502+
503+
return await self.persist_events_and_notify(
504+
room_id, [(event, new_event_context)]
505+
)
506+
393507
@log_function
394508
async def backfill(
395509
self, dest: str, room_id: str, limit: int, extremities: Iterable[str]

0 commit comments

Comments
 (0)