@@ -361,6 +361,7 @@ async def on_send_membership_event(
361361 # need to.
362362 await self ._event_creation_handler .cache_joined_hosts_for_event (event , context )
363363
364+ await self ._check_for_soft_fail (event , None , origin = origin )
364365 await self ._run_push_actions_and_persist_event (event , context )
365366 return event , context
366367
@@ -402,29 +403,28 @@ async def process_remote_join(
402403 """Persists the events returned by a send_join
403404
404405 Checks the auth chain is valid (and passes auth checks) for the
405- state and event. Then persists the auth chain and state atomically.
406- Persists the event separately. Notifies about the persisted events
407- where appropriate.
408-
409- Will attempt to fetch missing auth events.
406+ state and event. Then persists all of the events.
407+ Notifies about the persisted events where appropriate.
410408
411409 Args:
412410 origin: Where the events came from
413- room_id,
411+ room_id:
414412 auth_events
415413 state
416414 event
417415 room_version: The room version we expect this room to have, and
418416 will raise if it doesn't match the version in the create event.
417+
418+ Returns:
419+ The stream ID after which all events have been persisted.
420+
421+ Raises:
422+ SynapseError if the response is in some way invalid.
419423 """
420- events_to_context = {}
421424 for e in itertools .chain (auth_events , state ):
422425 e .internal_metadata .outlier = True
423- events_to_context [e .event_id ] = EventContext .for_outlier ()
424426
425- event_map = {
426- e .event_id : e for e in itertools .chain (auth_events , state , [event ])
427- }
427+ event_map = {e .event_id : e for e in itertools .chain (auth_events , state )}
428428
429429 create_event = None
430430 for e in auth_events :
@@ -444,64 +444,36 @@ async def process_remote_join(
444444 if room_version .identifier != room_version_id :
445445 raise SynapseError (400 , "Room version mismatch" )
446446
447- missing_auth_events = set ()
448- for e in itertools .chain (auth_events , state , [event ]):
449- for e_id in e .auth_event_ids ():
450- if e_id not in event_map :
451- missing_auth_events .add (e_id )
452-
453- for e_id in missing_auth_events :
454- m_ev = await self ._federation_client .get_pdu (
455- [origin ],
456- e_id ,
457- room_version = room_version ,
458- outlier = True ,
459- timeout = 10000 ,
460- )
461- if m_ev and m_ev .event_id == e_id :
462- event_map [e_id ] = m_ev
463- else :
464- logger .info ("Failed to find auth event %r" , e_id )
465-
466- for e in itertools .chain (auth_events , state , [event ]):
467- auth_for_e = [
468- event_map [e_id ] for e_id in e .auth_event_ids () if e_id in event_map
469- ]
470- if create_event :
471- auth_for_e .append (create_event )
472-
473- try :
474- validate_event_for_room_version (room_version , e )
475- check_auth_rules_for_event (room_version , e , auth_for_e )
476- except SynapseError as err :
477- # we may get SynapseErrors here as well as AuthErrors. For
478- # instance, there are a couple of (ancient) events in some
479- # rooms whose senders do not have the correct sigil; these
480- # cause SynapseErrors in auth.check. We don't want to give up
481- # the attempt to federate altogether in such cases.
482-
483- logger .warning ("Rejecting %s because %s" , e .event_id , err .msg )
484-
485- if e == event :
486- raise
487- events_to_context [e .event_id ].rejected = RejectedReason .AUTH_ERROR
488-
489- if auth_events or state :
490- await self .persist_events_and_notify (
491- room_id ,
492- [
493- (e , events_to_context [e .event_id ])
494- for e in itertools .chain (auth_events , state )
495- ],
447+ # filter out any events we have already seen
448+ seen_remotes = await self ._store .have_seen_events (room_id , event_map .keys ())
449+ for s in seen_remotes :
450+ event_map .pop (s , None )
451+
452+ # persist the auth chain and state events.
453+ #
454+ # any invalid events here will be marked as rejected, and we'll carry on.
455+ #
456+ # any events whose auth events are missing (ie, not in the send_join response,
457+ # and not already in our db) will just be ignored. This is correct behaviour,
458+ # because the reason that auth_events are missing might be due to us being
459+ # unable to validate their signatures. The fact that we can't validate their
460+ # signatures right now doesn't mean that we will *never* be able to, so it
461+ # is premature to reject them.
462+ #
463+ await self ._auth_and_persist_outliers (room_id , event_map .values ())
464+
465+ # and now persist the join event itself.
466+ logger .info ("Peristing join-via-remote %s" , event )
467+ with nested_logging_context (suffix = event .event_id ):
468+ context = await self ._state_handler .compute_event_context (
469+ event , old_state = state
496470 )
497471
498- new_event_context = await self ._state_handler . compute_event_context (
499- event , old_state = state
500- )
472+ context = await self ._check_event_auth ( origin , event , context )
473+ if context . rejected :
474+ raise SynapseError ( 400 , "Join event was rejected" )
501475
502- return await self .persist_events_and_notify (
503- room_id , [(event , new_event_context )]
504- )
476+ return await self .persist_events_and_notify (room_id , [(event , context )])
505477
506478 @log_function
507479 async def backfill (
@@ -974,9 +946,15 @@ async def _process_received_pdu(
974946 ) -> None :
975947 """Called when we have a new non-outlier event.
976948
977- This is called when we have a new event to add to the room DAG - either directly
978- via a /send request, retrieved via get_missing_events after a /send request, or
979- backfilled after a client request.
949+ This is called when we have a new event to add to the room DAG. This can be
950+ due to:
951+ * events received directly via a /send request
952+ * events retrieved via get_missing_events after a /send request
953+ * events backfilled after a client request.
954+
955+ It's not currently used for events received from incoming send_{join,knock,leave}
956+ requests (which go via on_send_membership_event), nor for joins created by a
957+ remote join dance (which go via process_remote_join).
980958
981959 We need to do auth checks and put it through the StateHandler.
982960
@@ -1012,11 +990,19 @@ async def _process_received_pdu(
1012990 logger .exception ("Unexpected AuthError from _check_event_auth" )
1013991 raise FederationError ("ERROR" , e .code , e .msg , affected = event .event_id )
1014992
993+ if not backfilled and not context .rejected :
994+ # For new (non-backfilled and non-outlier) events we check if the event
995+ # passes auth based on the current state. If it doesn't then we
996+ # "soft-fail" the event.
997+ await self ._check_for_soft_fail (event , state , origin = origin )
998+
1015999 await self ._run_push_actions_and_persist_event (event , context , backfilled )
10161000
1017- if backfilled :
1001+ if backfilled or context . rejected :
10181002 return
10191003
1004+ await self ._maybe_kick_guest_users (event )
1005+
10201006 # For encrypted messages we check that we know about the sending device,
10211007 # if we don't then we mark the device cache for that user as stale.
10221008 if event .type == EventTypes .Encrypted :
@@ -1317,14 +1303,14 @@ def prep(event: EventBase) -> Optional[Tuple[EventBase, EventContext]]:
13171303 for auth_event_id in event .auth_event_ids ():
13181304 ae = persisted_events .get (auth_event_id )
13191305 if not ae :
1306+ # the fact we can't find the auth event doesn't mean it doesn't
1307+ # exist, which means it is premature to reject `event`. Instead we
1308+ # just ignore it for now.
13201309 logger .warning (
1321- "Event %s relies on auth_event %s, which could not be found. " ,
1310+ "Dropping event %s, which relies on auth_event %s, which could not be found" ,
13221311 event ,
13231312 auth_event_id ,
13241313 )
1325- # the fact we can't find the auth event doesn't mean it doesn't
1326- # exist, which means it is premature to reject `event`. Instead we
1327- # just ignore it for now.
13281314 return None
13291315 auth .append (ae )
13301316
@@ -1447,10 +1433,6 @@ async def _check_event_auth(
14471433 except AuthError as e :
14481434 logger .warning ("Failed auth resolution for %r because %s" , event , e )
14491435 context .rejected = RejectedReason .AUTH_ERROR
1450- return context
1451-
1452- await self ._check_for_soft_fail (event , state , backfilled , origin = origin )
1453- await self ._maybe_kick_guest_users (event )
14541436
14551437 return context
14561438
@@ -1470,7 +1452,6 @@ async def _check_for_soft_fail(
14701452 self ,
14711453 event : EventBase ,
14721454 state : Optional [Iterable [EventBase ]],
1473- backfilled : bool ,
14741455 origin : str ,
14751456 ) -> None :
14761457 """Checks if we should soft fail the event; if so, marks the event as
@@ -1479,15 +1460,8 @@ async def _check_for_soft_fail(
14791460 Args:
14801461 event
14811462 state: The state at the event if we don't have all the event's prev events
1482- backfilled: Whether the event is from backfill
14831463 origin: The host the event originates from.
14841464 """
1485- # For new (non-backfilled and non-outlier) events we check if the event
1486- # passes auth based on the current state. If it doesn't then we
1487- # "soft-fail" the event.
1488- if backfilled or event .internal_metadata .is_outlier ():
1489- return
1490-
14911465 extrem_ids_list = await self ._store .get_latest_event_ids_in_room (event .room_id )
14921466 extrem_ids = set (extrem_ids_list )
14931467 prev_event_ids = set (event .prev_event_ids ())
0 commit comments