Store room_versions in EventBase objects (#6875)
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.
This commit is contained in:
parent
fe678a0900
commit
78a15b1f9d
|
@ -0,0 +1 @@
|
||||||
|
Refactoring work in preparation for changing the event redaction algorithm.
|
|
@ -15,9 +15,10 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import abc
|
||||||
import os
|
import os
|
||||||
from distutils.util import strtobool
|
from distutils.util import strtobool
|
||||||
from typing import Optional, Type
|
from typing import Dict, Optional, Type
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
@ -199,15 +200,25 @@ class _EventInternalMetadata(object):
|
||||||
return self._dict.get("redacted", False)
|
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__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
event_dict,
|
event_dict: JsonDict,
|
||||||
signatures={},
|
room_version: RoomVersion,
|
||||||
unsigned={},
|
signatures: Dict[str, Dict[str, str]],
|
||||||
internal_metadata_dict={},
|
unsigned: JsonDict,
|
||||||
rejected_reason=None,
|
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.signatures = signatures
|
||||||
self.unsigned = unsigned
|
self.unsigned = unsigned
|
||||||
self.rejected_reason = rejected_reason
|
self.rejected_reason = rejected_reason
|
||||||
|
@ -303,7 +314,13 @@ class EventBase(object):
|
||||||
class FrozenEvent(EventBase):
|
class FrozenEvent(EventBase):
|
||||||
format_version = EventFormatVersions.V1 # All events of this type are V1
|
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)
|
event_dict = dict(event_dict)
|
||||||
|
|
||||||
# Signatures is a dict of dicts, and this is faster than doing a
|
# Signatures is a dict of dicts, and this is faster than doing a
|
||||||
|
@ -326,8 +343,9 @@ class FrozenEvent(EventBase):
|
||||||
|
|
||||||
self._event_id = event_dict["event_id"]
|
self._event_id = event_dict["event_id"]
|
||||||
|
|
||||||
super(FrozenEvent, self).__init__(
|
super().__init__(
|
||||||
frozen_dict,
|
frozen_dict,
|
||||||
|
room_version=room_version,
|
||||||
signatures=signatures,
|
signatures=signatures,
|
||||||
unsigned=unsigned,
|
unsigned=unsigned,
|
||||||
internal_metadata_dict=internal_metadata_dict,
|
internal_metadata_dict=internal_metadata_dict,
|
||||||
|
@ -352,7 +370,13 @@ class FrozenEvent(EventBase):
|
||||||
class FrozenEventV2(EventBase):
|
class FrozenEventV2(EventBase):
|
||||||
format_version = EventFormatVersions.V2 # All events of this type are V2
|
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)
|
event_dict = dict(event_dict)
|
||||||
|
|
||||||
# Signatures is a dict of dicts, and this is faster than doing a
|
# Signatures is a dict of dicts, and this is faster than doing a
|
||||||
|
@ -377,8 +401,9 @@ class FrozenEventV2(EventBase):
|
||||||
|
|
||||||
self._event_id = None
|
self._event_id = None
|
||||||
|
|
||||||
super(FrozenEventV2, self).__init__(
|
super().__init__(
|
||||||
frozen_dict,
|
frozen_dict,
|
||||||
|
room_version=room_version,
|
||||||
signatures=signatures,
|
signatures=signatures,
|
||||||
unsigned=unsigned,
|
unsigned=unsigned,
|
||||||
internal_metadata_dict=internal_metadata_dict,
|
internal_metadata_dict=internal_metadata_dict,
|
||||||
|
@ -445,7 +470,7 @@ class FrozenEventV3(FrozenEventV2):
|
||||||
return self._event_id
|
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
|
"""Returns the python type to use to construct an Event object for the
|
||||||
given event format version.
|
given event format version.
|
||||||
|
|
||||||
|
@ -474,5 +499,5 @@ def make_event_from_dict(
|
||||||
rejected_reason: Optional[str] = None,
|
rejected_reason: Optional[str] = None,
|
||||||
) -> EventBase:
|
) -> EventBase:
|
||||||
"""Construct an EventBase from the given event dict"""
|
"""Construct an EventBase from the given event dict"""
|
||||||
event_type = event_type_from_format_version(room_version.event_format)
|
event_type = _event_type_from_format_version(room_version.event_format)
|
||||||
return event_type(event_dict, internal_metadata_dict, rejected_reason)
|
return event_type(event_dict, room_version, internal_metadata_dict, rejected_reason)
|
||||||
|
|
|
@ -35,26 +35,20 @@ from . import EventBase
|
||||||
SPLIT_FIELD_REGEX = re.compile(r"(?<!\\)\.")
|
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
|
""" Returns a pruned version of the given event, which removes all keys we
|
||||||
don't know about or think could potentially be dodgy.
|
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
|
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
|
the user has specified, but we do want to keep necessary information like
|
||||||
type, state_key etc.
|
type, state_key etc.
|
||||||
|
|
||||||
Args:
|
|
||||||
event (FrozenEvent)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
FrozenEvent
|
|
||||||
"""
|
"""
|
||||||
pruned_event_dict = prune_event_dict(event.get_dict())
|
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 = make_event_from_dict(
|
||||||
pruned_event_dict, event.internal_metadata.get_dict()
|
pruned_event_dict, event.room_version, event.internal_metadata.get_dict()
|
||||||
)
|
)
|
||||||
|
|
||||||
# Mark the event as redacted
|
# Mark the event as redacted
|
||||||
|
|
|
@ -18,7 +18,7 @@ import logging
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
|
||||||
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
|
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.events.snapshot import EventContext
|
||||||
from synapse.http.servlet import parse_json_object_from_request
|
from synapse.http.servlet import parse_json_object_from_request
|
||||||
from synapse.replication.http._base import ReplicationEndpoint
|
from synapse.replication.http._base import ReplicationEndpoint
|
||||||
|
@ -38,6 +38,9 @@ class ReplicationFederationSendEventsRestServlet(ReplicationEndpoint):
|
||||||
{
|
{
|
||||||
"events": [{
|
"events": [{
|
||||||
"event": { .. serialized event .. },
|
"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 .. },
|
"internal_metadata": { .. serialized internal_metadata .. },
|
||||||
"rejected_reason": .., // The event.rejected_reason field
|
"rejected_reason": .., // The event.rejected_reason field
|
||||||
"context": { .. serialized event context .. },
|
"context": { .. serialized event context .. },
|
||||||
|
@ -73,6 +76,7 @@ class ReplicationFederationSendEventsRestServlet(ReplicationEndpoint):
|
||||||
event_payloads.append(
|
event_payloads.append(
|
||||||
{
|
{
|
||||||
"event": event.get_pdu_json(),
|
"event": event.get_pdu_json(),
|
||||||
|
"room_version": event.room_version.identifier,
|
||||||
"event_format_version": event.format_version,
|
"event_format_version": event.format_version,
|
||||||
"internal_metadata": event.internal_metadata.get_dict(),
|
"internal_metadata": event.internal_metadata.get_dict(),
|
||||||
"rejected_reason": event.rejected_reason,
|
"rejected_reason": event.rejected_reason,
|
||||||
|
@ -95,12 +99,13 @@ class ReplicationFederationSendEventsRestServlet(ReplicationEndpoint):
|
||||||
event_and_contexts = []
|
event_and_contexts = []
|
||||||
for event_payload in event_payloads:
|
for event_payload in event_payloads:
|
||||||
event_dict = event_payload["event"]
|
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"]
|
internal_metadata = event_payload["internal_metadata"]
|
||||||
rejected_reason = event_payload["rejected_reason"]
|
rejected_reason = event_payload["rejected_reason"]
|
||||||
|
|
||||||
EventType = event_type_from_format_version(format_ver)
|
event = make_event_from_dict(
|
||||||
event = EventType(event_dict, internal_metadata, rejected_reason)
|
event_dict, room_ver, internal_metadata, rejected_reason
|
||||||
|
)
|
||||||
|
|
||||||
context = EventContext.deserialize(
|
context = EventContext.deserialize(
|
||||||
self.storage, event_payload["context"]
|
self.storage, event_payload["context"]
|
||||||
|
|
|
@ -17,7 +17,8 @@ import logging
|
||||||
|
|
||||||
from twisted.internet import defer
|
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.events.snapshot import EventContext
|
||||||
from synapse.http.servlet import parse_json_object_from_request
|
from synapse.http.servlet import parse_json_object_from_request
|
||||||
from synapse.replication.http._base import ReplicationEndpoint
|
from synapse.replication.http._base import ReplicationEndpoint
|
||||||
|
@ -37,6 +38,9 @@ class ReplicationSendEventRestServlet(ReplicationEndpoint):
|
||||||
|
|
||||||
{
|
{
|
||||||
"event": { .. serialized event .. },
|
"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 .. },
|
"internal_metadata": { .. serialized internal_metadata .. },
|
||||||
"rejected_reason": .., // The event.rejected_reason field
|
"rejected_reason": .., // The event.rejected_reason field
|
||||||
"context": { .. serialized event context .. },
|
"context": { .. serialized event context .. },
|
||||||
|
@ -77,6 +81,7 @@ class ReplicationSendEventRestServlet(ReplicationEndpoint):
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
"event": event.get_pdu_json(),
|
"event": event.get_pdu_json(),
|
||||||
|
"room_version": event.room_version.identifier,
|
||||||
"event_format_version": event.format_version,
|
"event_format_version": event.format_version,
|
||||||
"internal_metadata": event.internal_metadata.get_dict(),
|
"internal_metadata": event.internal_metadata.get_dict(),
|
||||||
"rejected_reason": event.rejected_reason,
|
"rejected_reason": event.rejected_reason,
|
||||||
|
@ -93,12 +98,13 @@ class ReplicationSendEventRestServlet(ReplicationEndpoint):
|
||||||
content = parse_json_object_from_request(request)
|
content = parse_json_object_from_request(request)
|
||||||
|
|
||||||
event_dict = content["event"]
|
event_dict = content["event"]
|
||||||
format_ver = content["event_format_version"]
|
room_ver = KNOWN_ROOM_VERSIONS[content["room_version"]]
|
||||||
internal_metadata = content["internal_metadata"]
|
internal_metadata = content["internal_metadata"]
|
||||||
rejected_reason = content["rejected_reason"]
|
rejected_reason = content["rejected_reason"]
|
||||||
|
|
||||||
EventType = event_type_from_format_version(format_ver)
|
event = make_event_from_dict(
|
||||||
event = EventType(event_dict, internal_metadata, rejected_reason)
|
event_dict, room_ver, internal_metadata, rejected_reason
|
||||||
|
)
|
||||||
|
|
||||||
requester = Requester.deserialize(self.store, content["requester"])
|
requester = Requester.deserialize(self.store, content["requester"])
|
||||||
context = EventContext.deserialize(self.storage, content["context"])
|
context = EventContext.deserialize(self.storage, content["context"])
|
||||||
|
|
Loading…
Reference in New Issue