Only check history visibility when filtering

When filtering events to send to server we check more than just history
visibility. However when deciding whether to backfill or not we only
care about the history visibility.
pull/4699/head
Erik Johnston 2019-03-04 14:34:34 +00:00
parent 8b63fe4c26
commit d1523aed6b
2 changed files with 46 additions and 35 deletions

View File

@ -891,9 +891,11 @@ class FederationHandler(BaseHandler):
get_prev_content=False, get_prev_content=False,
) )
# We set `check_history_visibility_only` as we might otherwise get false
# positives from users having been erased.
filtered_extremities = yield filter_events_for_server( filtered_extremities = yield filter_events_for_server(
self.store, self.server_name, list(extremities_events.values()), self.store, self.server_name, list(extremities_events.values()),
redact=False, redact=False, check_history_visibility_only=True,
) )
if not filtered_extremities: if not filtered_extremities:

View File

@ -216,7 +216,8 @@ def filter_events_for_client(store, user_id, events, is_peeking=False,
@defer.inlineCallbacks @defer.inlineCallbacks
def filter_events_for_server(store, server_name, events, redact=True): def filter_events_for_server(store, server_name, events, redact=True,
check_history_visibility_only=False):
"""Filter a list of events based on whether given server is allowed to """Filter a list of events based on whether given server is allowed to
see them. see them.
@ -226,34 +227,25 @@ def filter_events_for_server(store, server_name, events, redact=True):
events (iterable[FrozenEvent]) events (iterable[FrozenEvent])
redact (bool): Whether to return a redacted version of the event, or redact (bool): Whether to return a redacted version of the event, or
to filter them out entirely. to filter them out entirely.
check_history_visibility_only (bool): Whether to only check the
history visibility, rather than things like if the sender has been
erased. This is used e.g. during pagination to decide whether to
backfill or not.
Returns Returns
Deferred[list[FrozenEvent]] Deferred[list[FrozenEvent]]
""" """
# Whatever else we do, we need to check for senders which have requested
# erasure of their data.
erased_senders = yield store.are_users_erased(
(e.sender for e in events),
)
def redact_disallowed(event, state): def is_sender_erased(event, erased_senders):
# if the sender has been gdpr17ed, always return a redacted
# copy of the event.
if erased_senders[event.sender]: if erased_senders[event.sender]:
logger.info( logger.info(
"Sender of %s has been erased, redacting", "Sender of %s has been erased, redacting",
event.event_id, event.event_id,
) )
if redact: return True
return prune_event(event) return False
else:
return None
# state will be None if we decided we didn't need to filter by
# room membership.
if not state:
return event
def check_event_is_visible(event, state):
history = state.get((EventTypes.RoomHistoryVisibility, ''), None) history = state.get((EventTypes.RoomHistoryVisibility, ''), None)
if history: if history:
visibility = history.content.get("history_visibility", "shared") visibility = history.content.get("history_visibility", "shared")
@ -275,18 +267,15 @@ def filter_events_for_server(store, server_name, events, redact=True):
memtype = ev.membership memtype = ev.membership
if memtype == Membership.JOIN: if memtype == Membership.JOIN:
return event return True
elif memtype == Membership.INVITE: elif memtype == Membership.INVITE:
if visibility == "invited": if visibility == "invited":
return event return True
else: else:
# server has no users in the room: redact # server has no users in the room: redact
if redact: return False
return prune_event(event)
else:
return None
return event return True
# Next lets check to see if all the events have a history visibility # Next lets check to see if all the events have a history visibility
# of "shared" or "world_readable". If thats the case then we don't # of "shared" or "world_readable". If thats the case then we don't
@ -315,16 +304,31 @@ def filter_events_for_server(store, server_name, events, redact=True):
for e in itervalues(event_map) for e in itervalues(event_map)
) )
if not check_history_visibility_only:
erased_senders = yield store.are_users_erased(
(e.sender for e in events),
)
else:
# We don't want to check whether users are erased, which is equivalent
# to no users having been erased.
erased_senders = {}
if all_open: if all_open:
# all the history_visibility state affecting these events is open, so # all the history_visibility state affecting these events is open, so
# we don't need to filter by membership state. We *do* need to check # we don't need to filter by membership state. We *do* need to check
# for user erasure, though. # for user erasure, though.
if erased_senders: if erased_senders:
events = [ to_return = []
redact_disallowed(e, None) for e in events:
for e in events if not is_sender_erased(e, erased_senders):
] to_return.append(e)
elif redact:
to_return.append(prune_event(e))
defer.returnValue(to_return)
# If there are no erased users then we can just return the given list
# of events without having to copy it.
defer.returnValue(events) defer.returnValue(events)
# Ok, so we're dealing with events that have non-trivial visibility # Ok, so we're dealing with events that have non-trivial visibility
@ -380,8 +384,13 @@ def filter_events_for_server(store, server_name, events, redact=True):
for e_id, key_to_eid in iteritems(event_to_state_ids) for e_id, key_to_eid in iteritems(event_to_state_ids)
} }
to_return = ( to_return = []
redact_disallowed(e, event_to_state[e.event_id]) for e in events:
for e in events erased = is_sender_erased(e, erased_senders)
) visible = check_event_is_visible(e, event_to_state[e.event_id])
defer.returnValue([e for e in to_return if e is not None]) if visible and not erased:
to_return.append(e)
elif redact:
to_return.append(prune_event(e))
defer.returnValue(to_return)