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:
parent
7072fe3084
commit
b872c7b1b4
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue