0
0
Fork 1
mirror of https://mau.dev/maunium/synapse.git synced 2024-12-16 09:53:52 +01:00

Implement rechecking of redactions

This commit is contained in:
Erik Johnston 2019-01-28 21:09:45 +00:00
parent 7a3ec5b022
commit 7709d2bd16
5 changed files with 53 additions and 10 deletions

View file

@ -627,7 +627,7 @@ class Auth(object):
defer.returnValue(auth_ids) defer.returnValue(auth_ids)
def check_redaction(self, event, auth_events): def check_redaction(self, room_version, event, auth_events):
"""Check whether the event sender is allowed to redact the target event. """Check whether the event sender is allowed to redact the target event.
Returns: Returns:
@ -640,7 +640,7 @@ class Auth(object):
AuthError if the event sender is definitely not allowed to redact AuthError if the event sender is definitely not allowed to redact
the target event. the target event.
""" """
return event_auth.check_redaction(event, auth_events) return event_auth.check_redaction(room_version, event, auth_events)
@defer.inlineCallbacks @defer.inlineCallbacks
def check_can_change_room_list(self, room_id, user): def check_can_change_room_list(self, room_id, user):

View file

@ -20,7 +20,13 @@ from signedjson.key import decode_verify_key_bytes
from signedjson.sign import SignatureVerifyException, verify_signed_json from signedjson.sign import SignatureVerifyException, verify_signed_json
from unpaddedbase64 import decode_base64 from unpaddedbase64 import decode_base64
from synapse.api.constants import KNOWN_ROOM_VERSIONS, EventTypes, JoinRules, Membership from synapse.api.constants import (
KNOWN_ROOM_VERSIONS,
EventTypes,
JoinRules,
Membership,
RoomVersions,
)
from synapse.api.errors import AuthError, EventSizeError, SynapseError from synapse.api.errors import AuthError, EventSizeError, SynapseError
from synapse.types import UserID, get_domain_from_id from synapse.types import UserID, get_domain_from_id
@ -168,7 +174,7 @@ def check(room_version, event, auth_events, do_sig_check=True, do_size_check=Tru
_check_power_levels(event, auth_events) _check_power_levels(event, auth_events)
if event.type == EventTypes.Redaction: if event.type == EventTypes.Redaction:
check_redaction(event, auth_events) check_redaction(room_version, event, auth_events)
logger.debug("Allowing! %s", event) logger.debug("Allowing! %s", event)
@ -422,7 +428,7 @@ def _can_send_event(event, auth_events):
return True return True
def check_redaction(event, auth_events): def check_redaction(room_version, event, auth_events):
"""Check whether the event sender is allowed to redact the target event. """Check whether the event sender is allowed to redact the target event.
Returns: Returns:
@ -442,10 +448,16 @@ def check_redaction(event, auth_events):
if user_level >= redact_level: if user_level >= redact_level:
return False return False
redacter_domain = get_domain_from_id(event.event_id) if room_version in (RoomVersions.V1, RoomVersions.V2, RoomVersions.VDH_TEST):
redactee_domain = get_domain_from_id(event.redacts) redacter_domain = get_domain_from_id(event.event_id)
if redacter_domain == redactee_domain: redactee_domain = get_domain_from_id(event.redacts)
if redacter_domain == redactee_domain:
return True
elif room_version == RoomVersions.V3:
event.internal_metadata.recheck_redaction = True
return True return True
else:
raise RuntimeError("Unrecognized room version %r" % (room_version,))
raise AuthError( raise AuthError(
403, 403,

View file

@ -63,6 +63,9 @@ class _EventInternalMetadata(object):
""" """
return getattr(self, "send_on_behalf_of", None) return getattr(self, "send_on_behalf_of", None)
def need_to_check_redaction(self):
return getattr(self, "recheck_redaction", False)
def _event_dict_property(key): def _event_dict_property(key):
# We want to be able to use hasattr with the event dict properties. # We want to be able to use hasattr with the event dict properties.

View file

@ -767,7 +767,8 @@ class EventCreationHandler(object):
auth_events = { auth_events = {
(e.type, e.state_key): e for e in auth_events.values() (e.type, e.state_key): e for e in auth_events.values()
} }
if self.auth.check_redaction(event, auth_events=auth_events): room_version = yield self.store.get_room_version(event.room_id)
if self.auth.check_redaction(room_version, event, auth_events=auth_events):
original_event = yield self.store.get_event( original_event = yield self.store.get_event(
event.redacts, event.redacts,
check_redacted=False, check_redacted=False,
@ -781,6 +782,9 @@ class EventCreationHandler(object):
"You don't have permission to redact events" "You don't have permission to redact events"
) )
# We've already checked.
event.internal_metadata.recheck_redaction = False
if event.type == EventTypes.Create: if event.type == EventTypes.Create:
prev_state_ids = yield context.get_prev_state_ids(self.store) prev_state_ids = yield context.get_prev_state_ids(self.store)
if prev_state_ids: if prev_state_ids:

View file

@ -21,13 +21,14 @@ from canonicaljson import json
from twisted.internet import defer from twisted.internet import defer
from synapse.api.constants import EventFormatVersions from synapse.api.constants import EventFormatVersions, EventTypes
from synapse.api.errors import NotFoundError from synapse.api.errors import NotFoundError
from synapse.events import FrozenEvent, event_type_from_format_version # noqa: F401 from synapse.events import FrozenEvent, event_type_from_format_version # noqa: F401
# these are only included to make the type annotations work # these are only included to make the type annotations work
from synapse.events.snapshot import EventContext # noqa: F401 from synapse.events.snapshot import EventContext # noqa: F401
from synapse.events.utils import prune_event from synapse.events.utils import prune_event
from synapse.metrics.background_process_metrics import run_as_background_process from synapse.metrics.background_process_metrics import run_as_background_process
from synapse.types import get_domain_from_id
from synapse.util.logcontext import ( from synapse.util.logcontext import (
LoggingContext, LoggingContext,
PreserveLoggingContext, PreserveLoggingContext,
@ -174,6 +175,29 @@ class EventsWorkerStore(SQLBaseStore):
if not entry: if not entry:
continue continue
# Some redactions in room version v3 need to be rechecked if we
# didn't have the redacted event at the time, so we recheck on read
# instead.
if not allow_rejected and entry.event.type == EventTypes.Redaction:
if entry.event.internal_metadata.need_to_check_redaction():
orig = yield self.get_event(
entry.event.redacts,
allow_none=True,
allow_rejected=True,
get_prev_content=False,
)
expected_domain = get_domain_from_id(entry.event.sender)
if orig and get_domain_from_id(orig.sender) == expected_domain:
# This redaction event is allowed. Mark as not needing a
# recheck.
entry.event.recheck_redaction = False
else:
# We don't have the event that is being redacted, so we
# assume that the event isn't authorized for now. (If we
# later receive the event, then we will always redact
# it anyway, since we have this redaction)
continue
if allow_rejected or not entry.event.rejected_reason: if allow_rejected or not entry.event.rejected_reason:
if check_redacted and entry.redacted_event: if check_redacted and entry.redacted_event:
event = entry.redacted_event event = entry.redacted_event