Split up event validation between event and builder

The validator was being run on the EventBuilder objects, and so the
validator only checked a subset of fields. With the upcoming
EventBuilder refactor even fewer fields will be there to validate.

To get around this we split the validation into those that can be run
against an EventBuilder and those run against a fully fledged event.
This commit is contained in:
Erik Johnston 2019-01-28 17:00:14 +00:00
parent 7072fe3084
commit b872c7b1b4
3 changed files with 63 additions and 25 deletions

View File

@ -24,14 +24,13 @@ class EventValidator(object):
def validate(self, event): def validate(self, event):
EventID.from_string(event.event_id) EventID.from_string(event.event_id)
RoomID.from_string(event.room_id)
required = [ required = [
# "auth_events", "auth_events",
"content", "content",
# "hashes", "hashes",
"origin", "origin",
# "prev_events", "prev_events",
"sender", "sender",
"type", "type",
] ]
@ -43,31 +42,19 @@ class EventValidator(object):
# Check that the following keys have string values # Check that the following keys have string values
strings = [ strings = [
"origin", "origin",
"sender",
"type",
] ]
if hasattr(event, "state_key"):
strings.append("state_key")
for s in strings: for s in strings:
if not isinstance(getattr(event, s), string_types): if not isinstance(getattr(event, s), string_types):
raise SynapseError(400, "Not '%s' a string type" % (s,)) raise SynapseError(400, "Not '%s' a string type" % (s,))
if event.type == EventTypes.Member:
if "membership" not in event.content:
raise SynapseError(400, "Content has not membership key")
if event.content["membership"] not in Membership.LIST:
raise SynapseError(400, "Invalid membership key")
# Check that the following keys have dictionary values
# TODO
# Check that the following keys have the correct format for DAGs
# TODO
def validate_new(self, event): def validate_new(self, event):
"""Validates the event has roughly the right format
Args:
event (FrozenEvent)
"""
self.validate_builder(event)
self.validate(event) self.validate(event)
UserID.from_string(event.sender) UserID.from_string(event.sender)
@ -86,6 +73,52 @@ class EventValidator(object):
elif event.type == EventTypes.Name: elif event.type == EventTypes.Name:
self._ensure_strings(event.content, ["name"]) self._ensure_strings(event.content, ["name"])
def validate_builder(self, event):
"""Validates that the builder/event has roughly the right format. Only
checks values that we expect a proto event to have, rather than all the
fields an event would have
Args:
event (EventBuilder|FrozenEvent)
"""
strings = [
"room_id",
"sender",
"type",
]
if hasattr(event, "state_key"):
strings.append("state_key")
for s in strings:
if not isinstance(getattr(event, s), string_types):
raise SynapseError(400, "Not '%s' a string type" % (s,))
RoomID.from_string(event.room_id)
UserID.from_string(event.sender)
if event.type == EventTypes.Message:
strings = [
"body",
"msgtype",
]
self._ensure_strings(event.content, strings)
elif event.type == EventTypes.Topic:
self._ensure_strings(event.content, ["topic"])
elif event.type == EventTypes.Name:
self._ensure_strings(event.content, ["name"])
elif event.type == EventTypes.Member:
if "membership" not in event.content:
raise SynapseError(400, "Content has not membership key")
if event.content["membership"] not in Membership.LIST:
raise SynapseError(400, "Invalid membership key")
def _ensure_strings(self, d, keys): def _ensure_strings(self, d, keys):
for s in keys: for s in keys:
if s not in d: if s not in d:

View File

@ -2278,7 +2278,7 @@ class FederationHandler(BaseHandler):
room_version = yield self.store.get_room_version(room_id) room_version = yield self.store.get_room_version(room_id)
builder = self.event_builder_factory.new(room_version, event_dict) builder = self.event_builder_factory.new(room_version, event_dict)
EventValidator().validate_new(builder) EventValidator().validate_builder(builder)
event, context = yield self.event_creation_handler.create_new_client_event( event, context = yield self.event_creation_handler.create_new_client_event(
builder=builder builder=builder
) )
@ -2287,6 +2287,8 @@ class FederationHandler(BaseHandler):
room_version, event_dict, event, context room_version, event_dict, event, context
) )
EventValidator().validate_new(event)
try: try:
yield self.auth.check_from_context(event, context) yield self.auth.check_from_context(event, context)
except AuthError as e: except AuthError as e:
@ -2372,10 +2374,11 @@ class FederationHandler(BaseHandler):
# auth check code will explode appropriately. # auth check code will explode appropriately.
builder = self.event_builder_factory.new(room_version, event_dict) builder = self.event_builder_factory.new(room_version, event_dict)
EventValidator().validate_new(builder) EventValidator().validate_builder(builder)
event, context = yield self.event_creation_handler.create_new_client_event( event, context = yield self.event_creation_handler.create_new_client_event(
builder=builder, builder=builder,
) )
EventValidator().validate_new(event)
defer.returnValue((event, context)) defer.returnValue((event, context))
@defer.inlineCallbacks @defer.inlineCallbacks

View File

@ -288,7 +288,7 @@ class EventCreationHandler(object):
builder = self.event_builder_factory.new(room_version, event_dict) builder = self.event_builder_factory.new(room_version, event_dict)
self.validator.validate_new(builder) self.validator.validate_builder(builder)
if builder.type == EventTypes.Member: if builder.type == EventTypes.Member:
membership = builder.content.get("membership", None) membership = builder.content.get("membership", None)
@ -326,6 +326,8 @@ class EventCreationHandler(object):
prev_events_and_hashes=prev_events_and_hashes, prev_events_and_hashes=prev_events_and_hashes,
) )
self.validator.validate_new(event)
defer.returnValue((event, context)) defer.returnValue((event, context))
def _is_exempt_from_privacy_policy(self, builder, requester): def _is_exempt_from_privacy_policy(self, builder, requester):