@@ -1256,6 +1256,10 @@ async def _check_event_auth(
12561256
12571257 Returns:
12581258 The updated context object.
1259+
1260+ Raises:
1261+ AuthError if we were unable to find copies of the event's auth events.
1262+ (Most other failures just cause us to set `context.rejected`.)
12591263 """
12601264 # This method should only be used for non-outliers
12611265 assert not event .internal_metadata .outlier
@@ -1272,7 +1276,26 @@ async def _check_event_auth(
12721276 context .rejected = RejectedReason .AUTH_ERROR
12731277 return context
12741278
1275- # calculate what the auth events *should* be, to use as a basis for auth.
1279+ # next, check that we have all of the event's auth events.
1280+ #
1281+ # Note that this can raise AuthError, which we want to propagate to the
1282+ # caller rather than swallow with `context.rejected` (since we cannot be
1283+ # certain that there is a permanent problem with the event).
1284+ claimed_auth_events = await self ._load_or_fetch_auth_events_for_event (
1285+ origin , event
1286+ )
1287+
1288+ # ... and check that the event passes auth at those auth events.
1289+ try :
1290+ check_auth_rules_for_event (room_version_obj , event , claimed_auth_events )
1291+ except AuthError as e :
1292+ logger .warning (
1293+ "While checking auth of %r against auth_events: %s" , event , e
1294+ )
1295+ context .rejected = RejectedReason .AUTH_ERROR
1296+ return context
1297+
1298+ # now check auth against what we think the auth events *should* be.
12761299 prev_state_ids = await context .get_prev_state_ids ()
12771300 auth_events_ids = self ._event_auth_handler .compute_auth_events (
12781301 event , prev_state_ids , for_verification = True
@@ -1472,6 +1495,9 @@ async def _update_auth_events_and_context_for_auth(
14721495 # if we have missing events, we need to fetch those events from somewhere.
14731496 #
14741497 # we start by checking if they are in the store, and then try calling /event_auth/.
1498+ #
1499+ # TODO: this code is now redundant, since it should be impossible for us to
1500+ # get here without already having the auth events.
14751501 if missing_auth :
14761502 have_events = await self ._store .have_seen_events (
14771503 event .room_id , missing_auth
@@ -1575,7 +1601,7 @@ async def _update_auth_events_and_context_for_auth(
15751601 logger .info (
15761602 "After state res: updating auth_events with new state %s" ,
15771603 {
1578- ( d . type , d . state_key ): d . event_id
1604+ d
15791605 for d in new_state .values ()
15801606 if auth_events .get ((d .type , d .state_key )) != d
15811607 },
@@ -1589,6 +1615,75 @@ async def _update_auth_events_and_context_for_auth(
15891615
15901616 return context , auth_events
15911617
1618+ async def _load_or_fetch_auth_events_for_event (
1619+ self , destination : str , event : EventBase
1620+ ) -> Collection [EventBase ]:
1621+ """Fetch this event's auth_events, from database or remote
1622+
1623+ Loads any of the auth_events that we already have from the database/cache. If
1624+ there are any that are missing, calls /event_auth to get the complete auth
1625+ chain for the event (and then attempts to load the auth_events again).
1626+
1627+ If any of the auth_events cannot be found, raises an AuthError. This can happen
1628+ for a number of reasons; eg: the events don't exist, or we were unable to talk
1629+ to `destination`, or we couldn't validate the signature on the event (which
1630+ in turn has multiple potential causes).
1631+
1632+ Args:
1633+ destination: where to send the /event_auth request. Typically the server
1634+ that sent us `event` in the first place.
1635+ event: the event whose auth_events we want
1636+
1637+ Returns:
1638+ all of the events in `event.auth_events`, after deduplication
1639+
1640+ Raises:
1641+ AuthError if we were unable to fetch the auth_events for any reason.
1642+ """
1643+ event_auth_event_ids = set (event .auth_event_ids ())
1644+ event_auth_events = await self ._store .get_events (
1645+ event_auth_event_ids , allow_rejected = True
1646+ )
1647+ missing_auth_event_ids = event_auth_event_ids .difference (
1648+ event_auth_events .keys ()
1649+ )
1650+ if not missing_auth_event_ids :
1651+ return event_auth_events .values ()
1652+
1653+ logger .info (
1654+ "Event %s refers to unknown auth events %s: fetching auth chain" ,
1655+ event ,
1656+ missing_auth_event_ids ,
1657+ )
1658+ try :
1659+ await self ._get_remote_auth_chain_for_event (
1660+ destination , event .room_id , event .event_id
1661+ )
1662+ except Exception as e :
1663+ logger .warning ("Failed to get auth chain for %s: %s" , event , e )
1664+ # in this case, it's very likely we still won't have all the auth
1665+ # events - but we pick that up below.
1666+
1667+ # try to fetch the auth events we missed list time.
1668+ extra_auth_events = await self ._store .get_events (
1669+ missing_auth_event_ids , allow_rejected = True
1670+ )
1671+ missing_auth_event_ids .difference_update (extra_auth_events .keys ())
1672+ event_auth_events .update (extra_auth_events )
1673+ if not missing_auth_event_ids :
1674+ return event_auth_events .values ()
1675+
1676+ # we still don't have all the auth events.
1677+ logger .warning (
1678+ "Missing auth events for %s: %s" ,
1679+ event ,
1680+ shortstr (missing_auth_event_ids ),
1681+ )
1682+ # the fact we can't find the auth event doesn't mean it doesn't
1683+ # exist, which means it is premature to store `event` as rejected.
1684+ # instead we raise an AuthError, which will make the caller ignore it.
1685+ raise AuthError (code = HTTPStatus .FORBIDDEN , msg = "Auth events could not be found" )
1686+
15921687 async def _get_remote_auth_chain_for_event (
15931688 self , destination : str , room_id : str , event_id : str
15941689 ) -> None :
0 commit comments