Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Store room_versions in EventBase objects (#6875)
Browse files Browse the repository at this point in the history
This is a bit fiddly because it all has to be done on one fell swoop:

* Wherever we create a new event, pass in the room version (and check it matches the format version)
* When we prune an event, use the room version of the unpruned event to create the pruned version.
* When we pass an event over the replication protocol, pass the room version over alongside it, and use it when deserialising the event again.
  • Loading branch information
richvdh committed Mar 5, 2020
1 parent fe678a0 commit 78a15b1
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 32 deletions.
1 change: 1 addition & 0 deletions changelog.d/6875.misc
@@ -0,0 +1 @@
Refactoring work in preparation for changing the event redaction algorithm.
53 changes: 39 additions & 14 deletions synapse/events/__init__.py
Expand Up @@ -15,9 +15,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import abc
import os
from distutils.util import strtobool
from typing import Optional, Type
from typing import Dict, Optional, Type

import six

Expand Down Expand Up @@ -199,15 +200,25 @@ def is_redacted(self):
return self._dict.get("redacted", False)


class EventBase(object):
class EventBase(metaclass=abc.ABCMeta):
@property
@abc.abstractmethod
def format_version(self) -> int:
"""The EventFormatVersion implemented by this event"""
...

def __init__(
self,
event_dict,
signatures={},
unsigned={},
internal_metadata_dict={},
rejected_reason=None,
event_dict: JsonDict,
room_version: RoomVersion,
signatures: Dict[str, Dict[str, str]],
unsigned: JsonDict,
internal_metadata_dict: JsonDict,
rejected_reason: Optional[str],
):
assert room_version.event_format == self.format_version

self.room_version = room_version
self.signatures = signatures
self.unsigned = unsigned
self.rejected_reason = rejected_reason
Expand Down Expand Up @@ -303,7 +314,13 @@ def auth_event_ids(self):
class FrozenEvent(EventBase):
format_version = EventFormatVersions.V1 # All events of this type are V1

def __init__(self, event_dict, internal_metadata_dict={}, rejected_reason=None):
def __init__(
self,
event_dict: JsonDict,
room_version: RoomVersion,
internal_metadata_dict: JsonDict = {},
rejected_reason: Optional[str] = None,
):
event_dict = dict(event_dict)

# Signatures is a dict of dicts, and this is faster than doing a
Expand All @@ -326,8 +343,9 @@ def __init__(self, event_dict, internal_metadata_dict={}, rejected_reason=None):

self._event_id = event_dict["event_id"]

super(FrozenEvent, self).__init__(
super().__init__(
frozen_dict,
room_version=room_version,
signatures=signatures,
unsigned=unsigned,
internal_metadata_dict=internal_metadata_dict,
Expand All @@ -352,7 +370,13 @@ def __repr__(self):
class FrozenEventV2(EventBase):
format_version = EventFormatVersions.V2 # All events of this type are V2

def __init__(self, event_dict, internal_metadata_dict={}, rejected_reason=None):
def __init__(
self,
event_dict: JsonDict,
room_version: RoomVersion,
internal_metadata_dict: JsonDict = {},
rejected_reason: Optional[str] = None,
):
event_dict = dict(event_dict)

# Signatures is a dict of dicts, and this is faster than doing a
Expand All @@ -377,8 +401,9 @@ def __init__(self, event_dict, internal_metadata_dict={}, rejected_reason=None):

self._event_id = None

super(FrozenEventV2, self).__init__(
super().__init__(
frozen_dict,
room_version=room_version,
signatures=signatures,
unsigned=unsigned,
internal_metadata_dict=internal_metadata_dict,
Expand Down Expand Up @@ -445,7 +470,7 @@ def event_id(self):
return self._event_id


def event_type_from_format_version(format_version: int) -> Type[EventBase]:
def _event_type_from_format_version(format_version: int) -> Type[EventBase]:
"""Returns the python type to use to construct an Event object for the
given event format version.
Expand Down Expand Up @@ -474,5 +499,5 @@ def make_event_from_dict(
rejected_reason: Optional[str] = None,
) -> EventBase:
"""Construct an EventBase from the given event dict"""
event_type = event_type_from_format_version(room_version.event_format)
return event_type(event_dict, internal_metadata_dict, rejected_reason)
event_type = _event_type_from_format_version(room_version.event_format)
return event_type(event_dict, room_version, internal_metadata_dict, rejected_reason)
14 changes: 4 additions & 10 deletions synapse/events/utils.py
Expand Up @@ -35,26 +35,20 @@
SPLIT_FIELD_REGEX = re.compile(r"(?<!\\)\.")


def prune_event(event):
def prune_event(event: EventBase) -> EventBase:
""" Returns a pruned version of the given event, which removes all keys we
don't know about or think could potentially be dodgy.
This is used when we "redact" an event. We want to remove all fields that
the user has specified, but we do want to keep necessary information like
type, state_key etc.
Args:
event (FrozenEvent)
Returns:
FrozenEvent
"""
pruned_event_dict = prune_event_dict(event.get_dict())

from . import event_type_from_format_version
from . import make_event_from_dict

pruned_event = event_type_from_format_version(event.format_version)(
pruned_event_dict, event.internal_metadata.get_dict()
pruned_event = make_event_from_dict(
pruned_event_dict, event.room_version, event.internal_metadata.get_dict()
)

# Mark the event as redacted
Expand Down
13 changes: 9 additions & 4 deletions synapse/replication/http/federation.py
Expand Up @@ -18,7 +18,7 @@
from twisted.internet import defer

from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
from synapse.events import event_type_from_format_version
from synapse.events import make_event_from_dict
from synapse.events.snapshot import EventContext
from synapse.http.servlet import parse_json_object_from_request
from synapse.replication.http._base import ReplicationEndpoint
Expand All @@ -38,6 +38,9 @@ class ReplicationFederationSendEventsRestServlet(ReplicationEndpoint):
{
"events": [{
"event": { .. serialized event .. },
"room_version": .., // "1", "2", "3", etc: the version of the room
// containing the event
"event_format_version": .., // 1,2,3 etc: the event format version
"internal_metadata": { .. serialized internal_metadata .. },
"rejected_reason": .., // The event.rejected_reason field
"context": { .. serialized event context .. },
Expand Down Expand Up @@ -73,6 +76,7 @@ def _serialize_payload(store, event_and_contexts, backfilled):
event_payloads.append(
{
"event": event.get_pdu_json(),
"room_version": event.room_version.identifier,
"event_format_version": event.format_version,
"internal_metadata": event.internal_metadata.get_dict(),
"rejected_reason": event.rejected_reason,
Expand All @@ -95,12 +99,13 @@ async def _handle_request(self, request):
event_and_contexts = []
for event_payload in event_payloads:
event_dict = event_payload["event"]
format_ver = event_payload["event_format_version"]
room_ver = KNOWN_ROOM_VERSIONS[event_payload["room_version"]]
internal_metadata = event_payload["internal_metadata"]
rejected_reason = event_payload["rejected_reason"]

EventType = event_type_from_format_version(format_ver)
event = EventType(event_dict, internal_metadata, rejected_reason)
event = make_event_from_dict(
event_dict, room_ver, internal_metadata, rejected_reason
)

context = EventContext.deserialize(
self.storage, event_payload["context"]
Expand Down
14 changes: 10 additions & 4 deletions synapse/replication/http/send_event.py
Expand Up @@ -17,7 +17,8 @@

from twisted.internet import defer

from synapse.events import event_type_from_format_version
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
from synapse.events import make_event_from_dict
from synapse.events.snapshot import EventContext
from synapse.http.servlet import parse_json_object_from_request
from synapse.replication.http._base import ReplicationEndpoint
Expand All @@ -37,6 +38,9 @@ class ReplicationSendEventRestServlet(ReplicationEndpoint):
{
"event": { .. serialized event .. },
"room_version": .., // "1", "2", "3", etc: the version of the room
// containing the event
"event_format_version": .., // 1,2,3 etc: the event format version
"internal_metadata": { .. serialized internal_metadata .. },
"rejected_reason": .., // The event.rejected_reason field
"context": { .. serialized event context .. },
Expand Down Expand Up @@ -77,6 +81,7 @@ def _serialize_payload(

payload = {
"event": event.get_pdu_json(),
"room_version": event.room_version.identifier,
"event_format_version": event.format_version,
"internal_metadata": event.internal_metadata.get_dict(),
"rejected_reason": event.rejected_reason,
Expand All @@ -93,12 +98,13 @@ async def _handle_request(self, request, event_id):
content = parse_json_object_from_request(request)

event_dict = content["event"]
format_ver = content["event_format_version"]
room_ver = KNOWN_ROOM_VERSIONS[content["room_version"]]
internal_metadata = content["internal_metadata"]
rejected_reason = content["rejected_reason"]

EventType = event_type_from_format_version(format_ver)
event = EventType(event_dict, internal_metadata, rejected_reason)
event = make_event_from_dict(
event_dict, room_ver, internal_metadata, rejected_reason
)

requester = Requester.deserialize(self.store, content["requester"])
context = EventContext.deserialize(self.storage, content["context"])
Expand Down

0 comments on commit 78a15b1

Please sign in to comment.