mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-05-03 02:44:53 -04:00
Implement soft fail
This commit is contained in:
parent
16c8b4ecbd
commit
a9de04be72
4 changed files with 95 additions and 1 deletions
|
@ -45,6 +45,7 @@ from synapse.api.errors import (
|
|||
SynapseError,
|
||||
)
|
||||
from synapse.crypto.event_signing import compute_event_signature
|
||||
from synapse.event_auth import auth_types_for_event
|
||||
from synapse.events.validator import EventValidator
|
||||
from synapse.replication.http.federation import (
|
||||
ReplicationCleanRoomRestServlet,
|
||||
|
@ -1628,6 +1629,7 @@ class FederationHandler(BaseHandler):
|
|||
origin, event,
|
||||
state=state,
|
||||
auth_events=auth_events,
|
||||
backfilled=backfilled,
|
||||
)
|
||||
|
||||
# reraise does not allow inlineCallbacks to preserve the stacktrace, so we
|
||||
|
@ -1672,6 +1674,7 @@ class FederationHandler(BaseHandler):
|
|||
event,
|
||||
state=ev_info.get("state"),
|
||||
auth_events=ev_info.get("auth_events"),
|
||||
backfilled=backfilled,
|
||||
)
|
||||
defer.returnValue(res)
|
||||
|
||||
|
@ -1794,7 +1797,7 @@ class FederationHandler(BaseHandler):
|
|||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _prep_event(self, origin, event, state=None, auth_events=None):
|
||||
def _prep_event(self, origin, event, state, auth_events, backfilled):
|
||||
"""
|
||||
|
||||
Args:
|
||||
|
@ -1802,6 +1805,7 @@ class FederationHandler(BaseHandler):
|
|||
event:
|
||||
state:
|
||||
auth_events:
|
||||
backfilled (bool)
|
||||
|
||||
Returns:
|
||||
Deferred, which resolves to synapse.events.snapshot.EventContext
|
||||
|
@ -1843,6 +1847,77 @@ class FederationHandler(BaseHandler):
|
|||
|
||||
context.rejected = RejectedReason.AUTH_ERROR
|
||||
|
||||
# For new (non-backfilled and non-outlier) events we check if the event
|
||||
# passes auth based on the current state. If it doesn't then we
|
||||
# "soft-fail" the event.
|
||||
do_soft_fail_check = not backfilled and not event.internal_metadata.is_outlier()
|
||||
if do_soft_fail_check:
|
||||
extrem_ids = yield self.store.get_latest_event_ids_in_room(
|
||||
event.room_id,
|
||||
)
|
||||
|
||||
extrem_ids = set(extrem_ids)
|
||||
prev_event_ids = set(event.prev_event_ids())
|
||||
|
||||
if extrem_ids == prev_event_ids:
|
||||
# If they're the same then the current state is the same as the
|
||||
# state at the event, so no point rechecking auth for soft fail.
|
||||
do_soft_fail_check = False
|
||||
|
||||
if do_soft_fail_check:
|
||||
room_version = yield self.store.get_room_version(event.room_id)
|
||||
|
||||
# Calculate the "current state".
|
||||
if state is not None:
|
||||
# If we're explicitly given the state then we won't have all the
|
||||
# prev events, and so we have a gap in the graph. In this case
|
||||
# we want to be a little careful as we might have been down for
|
||||
# a while and have an incorrect view of the current state,
|
||||
# however we still want to do checks as gaps are easy to
|
||||
# maliciously manufacture.
|
||||
#
|
||||
# So we use a "current state" that is actually a state
|
||||
# resolution across the current forward extremities and the
|
||||
# given state at the event. This should correctly handle cases
|
||||
# like bans, especially with state res v2.
|
||||
|
||||
state_sets = yield self.store.get_state_groups(
|
||||
event.room_id, extrem_ids,
|
||||
)
|
||||
state_sets = list(state_sets.values())
|
||||
state_sets.append(state)
|
||||
current_state_ids = yield self.state_handler.resolve_events(
|
||||
room_version, state_sets, event,
|
||||
)
|
||||
current_state_ids = {
|
||||
k: e.event_id for k, e in iteritems(current_state_ids)
|
||||
}
|
||||
else:
|
||||
current_state_ids = yield self.state_handler.get_current_state_ids(
|
||||
event.room_id, latest_event_ids=extrem_ids,
|
||||
)
|
||||
|
||||
# Now check if event pass auth against said current state
|
||||
auth_types = auth_types_for_event(event)
|
||||
current_state_ids = [
|
||||
e for k, e in iteritems(current_state_ids)
|
||||
if k in auth_types
|
||||
]
|
||||
|
||||
current_auth_events = yield self.store.get_events(current_state_ids)
|
||||
current_auth_events = {
|
||||
(e.type, e.state_key): e for e in current_auth_events.values()
|
||||
}
|
||||
|
||||
try:
|
||||
self.auth.check(room_version, event, auth_events=current_auth_events)
|
||||
except AuthError as e:
|
||||
logger.warn(
|
||||
"Failed current state auth resolution for %r because %s",
|
||||
event, e,
|
||||
)
|
||||
event.internal_metadata.soft_failed = True
|
||||
|
||||
if event.type == EventTypes.GuestAccess and not context.rejected:
|
||||
yield self.maybe_kick_guest_users(event)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue