mirror of
https://github.com/element-hq/synapse.git
synced 2024-11-26 19:47:05 +03:00
Add some assertions about outliers (#10773)
I think I have finally teased apart the codepaths which handle outliers, and those that handle non-outliers. Let's add some assertions to demonstrate my newfound knowledge.
This commit is contained in:
parent
5724883ac2
commit
aacdce8fc0
2 changed files with 83 additions and 76 deletions
1
changelog.d/10773.misc
Normal file
1
changelog.d/10773.misc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Clean up some of the federation event authentication code for clarity.
|
|
@ -173,6 +173,9 @@ class FederationEventHandler:
|
||||||
pdu: received PDU
|
pdu: received PDU
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# We should never see any outliers here.
|
||||||
|
assert not pdu.internal_metadata.outlier
|
||||||
|
|
||||||
room_id = pdu.room_id
|
room_id = pdu.room_id
|
||||||
event_id = pdu.event_id
|
event_id = pdu.event_id
|
||||||
|
|
||||||
|
@ -232,77 +235,71 @@ class FederationEventHandler:
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Check that the event passes auth based on the state at the event. This is
|
# Try to fetch any missing prev events to fill in gaps in the graph
|
||||||
# done for events that are to be added to the timeline (non-outliers).
|
prevs = set(pdu.prev_event_ids())
|
||||||
#
|
seen = await self._store.have_events_in_timeline(prevs)
|
||||||
# Get missing pdus if necessary:
|
missing_prevs = prevs - seen
|
||||||
# - Fetching any missing prev events to fill in gaps in the graph
|
|
||||||
# - Fetching state if we have a hole in the graph
|
if missing_prevs:
|
||||||
if not pdu.internal_metadata.is_outlier():
|
# We only backfill backwards to the min depth.
|
||||||
prevs = set(pdu.prev_event_ids())
|
min_depth = await self.get_min_depth_for_context(pdu.room_id)
|
||||||
seen = await self._store.have_events_in_timeline(prevs)
|
logger.debug("min_depth: %d", min_depth)
|
||||||
missing_prevs = prevs - seen
|
|
||||||
|
if min_depth is not None and pdu.depth > min_depth:
|
||||||
|
# If we're missing stuff, ensure we only fetch stuff one
|
||||||
|
# at a time.
|
||||||
|
logger.info(
|
||||||
|
"Acquiring room lock to fetch %d missing prev_events: %s",
|
||||||
|
len(missing_prevs),
|
||||||
|
shortstr(missing_prevs),
|
||||||
|
)
|
||||||
|
with (await self._room_pdu_linearizer.queue(pdu.room_id)):
|
||||||
|
logger.info(
|
||||||
|
"Acquired room lock to fetch %d missing prev_events",
|
||||||
|
len(missing_prevs),
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await self._get_missing_events_for_pdu(
|
||||||
|
origin, pdu, prevs, min_depth
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(
|
||||||
|
"Error fetching missing prev_events for %s: %s"
|
||||||
|
% (event_id, e)
|
||||||
|
) from e
|
||||||
|
|
||||||
|
# Update the set of things we've seen after trying to
|
||||||
|
# fetch the missing stuff
|
||||||
|
seen = await self._store.have_events_in_timeline(prevs)
|
||||||
|
missing_prevs = prevs - seen
|
||||||
|
|
||||||
|
if not missing_prevs:
|
||||||
|
logger.info("Found all missing prev_events")
|
||||||
|
|
||||||
if missing_prevs:
|
if missing_prevs:
|
||||||
# We only backfill backwards to the min depth.
|
# since this event was pushed to us, it is possible for it to
|
||||||
min_depth = await self.get_min_depth_for_context(pdu.room_id)
|
# become the only forward-extremity in the room, and we would then
|
||||||
logger.debug("min_depth: %d", min_depth)
|
# trust its state to be the state for the whole room. This is very
|
||||||
|
# bad. Further, if the event was pushed to us, there is no excuse
|
||||||
if min_depth is not None and pdu.depth > min_depth:
|
# for us not to have all the prev_events. (XXX: apart from
|
||||||
# If we're missing stuff, ensure we only fetch stuff one
|
# min_depth?)
|
||||||
# at a time.
|
#
|
||||||
logger.info(
|
# We therefore reject any such events.
|
||||||
"Acquiring room lock to fetch %d missing prev_events: %s",
|
logger.warning(
|
||||||
len(missing_prevs),
|
"Rejecting: failed to fetch %d prev events: %s",
|
||||||
shortstr(missing_prevs),
|
len(missing_prevs),
|
||||||
)
|
shortstr(missing_prevs),
|
||||||
with (await self._room_pdu_linearizer.queue(pdu.room_id)):
|
)
|
||||||
logger.info(
|
raise FederationError(
|
||||||
"Acquired room lock to fetch %d missing prev_events",
|
"ERROR",
|
||||||
len(missing_prevs),
|
403,
|
||||||
)
|
(
|
||||||
|
"Your server isn't divulging details about prev_events "
|
||||||
try:
|
"referenced in this event."
|
||||||
await self._get_missing_events_for_pdu(
|
),
|
||||||
origin, pdu, prevs, min_depth
|
affected=pdu.event_id,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
|
||||||
raise Exception(
|
|
||||||
"Error fetching missing prev_events for %s: %s"
|
|
||||||
% (event_id, e)
|
|
||||||
) from e
|
|
||||||
|
|
||||||
# Update the set of things we've seen after trying to
|
|
||||||
# fetch the missing stuff
|
|
||||||
seen = await self._store.have_events_in_timeline(prevs)
|
|
||||||
missing_prevs = prevs - seen
|
|
||||||
|
|
||||||
if not missing_prevs:
|
|
||||||
logger.info("Found all missing prev_events")
|
|
||||||
|
|
||||||
if missing_prevs:
|
|
||||||
# since this event was pushed to us, it is possible for it to
|
|
||||||
# become the only forward-extremity in the room, and we would then
|
|
||||||
# trust its state to be the state for the whole room. This is very
|
|
||||||
# bad. Further, if the event was pushed to us, there is no excuse
|
|
||||||
# for us not to have all the prev_events. (XXX: apart from
|
|
||||||
# min_depth?)
|
|
||||||
#
|
|
||||||
# We therefore reject any such events.
|
|
||||||
logger.warning(
|
|
||||||
"Rejecting: failed to fetch %d prev events: %s",
|
|
||||||
len(missing_prevs),
|
|
||||||
shortstr(missing_prevs),
|
|
||||||
)
|
|
||||||
raise FederationError(
|
|
||||||
"ERROR",
|
|
||||||
403,
|
|
||||||
(
|
|
||||||
"Your server isn't divulging details about prev_events "
|
|
||||||
"referenced in this event."
|
|
||||||
),
|
|
||||||
affected=pdu.event_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
await self._process_received_pdu(origin, pdu, state=None)
|
await self._process_received_pdu(origin, pdu, state=None)
|
||||||
|
|
||||||
|
@ -885,8 +882,13 @@ class FederationEventHandler:
|
||||||
state: Optional[Iterable[EventBase]],
|
state: Optional[Iterable[EventBase]],
|
||||||
backfilled: bool = False,
|
backfilled: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Called when we have a new pdu. We need to do auth checks and put it
|
"""Called when we have a new non-outlier event.
|
||||||
through the StateHandler.
|
|
||||||
|
This is called when we have a new event to add to the room DAG - either directly
|
||||||
|
via a /send request, retrieved via get_missing_events after a /send request, or
|
||||||
|
backfilled after a client request.
|
||||||
|
|
||||||
|
We need to do auth checks and put it through the StateHandler.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
origin: server sending the event
|
origin: server sending the event
|
||||||
|
@ -901,6 +903,7 @@ class FederationEventHandler:
|
||||||
notification to clients, and validation of device keys.)
|
notification to clients, and validation of device keys.)
|
||||||
"""
|
"""
|
||||||
logger.debug("Processing event: %s", event)
|
logger.debug("Processing event: %s", event)
|
||||||
|
assert not event.internal_metadata.outlier
|
||||||
|
|
||||||
try:
|
try:
|
||||||
context = await self._state_handler.compute_event_context(
|
context = await self._state_handler.compute_event_context(
|
||||||
|
@ -1263,11 +1266,13 @@ class FederationEventHandler:
|
||||||
Possibly incomplete, and possibly including events that are not yet
|
Possibly incomplete, and possibly including events that are not yet
|
||||||
persisted, or authed, or in the right room.
|
persisted, or authed, or in the right room.
|
||||||
|
|
||||||
Only populated where we may not already have persisted these events -
|
Only populated when populating outliers.
|
||||||
for example, when populating outliers.
|
|
||||||
|
|
||||||
backfilled: True if the event was backfilled.
|
backfilled: True if the event was backfilled.
|
||||||
"""
|
"""
|
||||||
|
# claimed_auth_event_map should be given iff the event is an outlier
|
||||||
|
assert bool(claimed_auth_event_map) == event.internal_metadata.outlier
|
||||||
|
|
||||||
context = await self._check_event_auth(
|
context = await self._check_event_auth(
|
||||||
origin,
|
origin,
|
||||||
event,
|
event,
|
||||||
|
@ -1306,15 +1311,16 @@ class FederationEventHandler:
|
||||||
Possibly incomplete, and possibly including events that are not yet
|
Possibly incomplete, and possibly including events that are not yet
|
||||||
persisted, or authed, or in the right room.
|
persisted, or authed, or in the right room.
|
||||||
|
|
||||||
Only populated where we may not already have persisted these events -
|
Only populated when populating outliers.
|
||||||
for example, when populating outliers, or the state for a backwards
|
|
||||||
extremity.
|
|
||||||
|
|
||||||
backfilled: True if the event was backfilled.
|
backfilled: True if the event was backfilled.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The updated context object.
|
The updated context object.
|
||||||
"""
|
"""
|
||||||
|
# claimed_auth_event_map should be given iff the event is an outlier
|
||||||
|
assert bool(claimed_auth_event_map) == event.internal_metadata.outlier
|
||||||
|
|
||||||
room_version = await self._store.get_room_version_id(event.room_id)
|
room_version = await self._store.get_room_version_id(event.room_id)
|
||||||
room_version_obj = KNOWN_ROOM_VERSIONS[room_version]
|
room_version_obj = KNOWN_ROOM_VERSIONS[room_version]
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue