Disallow missing 'type' property with allow_custom
There was a bug where if you allowed custom content the library would parse an object without the required 'type' property.stix2.0
parent
91376586d4
commit
fc6a33b23e
|
@ -6,11 +6,11 @@ import datetime as dt
|
||||||
|
|
||||||
import simplejson as json
|
import simplejson as json
|
||||||
|
|
||||||
from .exceptions import (AtLeastOnePropertyError, DependentPropertiesError,
|
from .exceptions import (AtLeastOnePropertyError, CustomContentError,
|
||||||
ExtraPropertiesError, ImmutableError,
|
DependentPropertiesError, ExtraPropertiesError,
|
||||||
InvalidObjRefError, InvalidValueError,
|
ImmutableError, InvalidObjRefError, InvalidValueError,
|
||||||
MissingPropertiesError,
|
MissingPropertiesError,
|
||||||
MutuallyExclusivePropertiesError, ParseError)
|
MutuallyExclusivePropertiesError)
|
||||||
from .markings.utils import validate
|
from .markings.utils import validate
|
||||||
from .utils import NOW, find_property_index, format_datetime, get_timestamp
|
from .utils import NOW, find_property_index, format_datetime, get_timestamp
|
||||||
from .utils import new_version as _new_version
|
from .utils import new_version as _new_version
|
||||||
|
@ -61,7 +61,7 @@ class _STIXBase(collections.Mapping):
|
||||||
try:
|
try:
|
||||||
kwargs[prop_name] = prop.clean(kwargs[prop_name])
|
kwargs[prop_name] = prop.clean(kwargs[prop_name])
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
if self.__allow_custom and isinstance(exc, ParseError):
|
if self.__allow_custom and isinstance(exc, CustomContentError):
|
||||||
return
|
return
|
||||||
raise InvalidValueError(self.__class__, prop_name, reason=str(exc))
|
raise InvalidValueError(self.__class__, prop_name, reason=str(exc))
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,13 @@ class ParseError(STIXError, ValueError):
|
||||||
super(ParseError, self).__init__(msg)
|
super(ParseError, self).__init__(msg)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomContentError(STIXError, ValueError):
|
||||||
|
"""Custom STIX Content (SDO, Observable, Extension, etc.) detected."""
|
||||||
|
|
||||||
|
def __init__(self, msg):
|
||||||
|
super(CustomContentError, self).__init__(msg)
|
||||||
|
|
||||||
|
|
||||||
class InvalidSelectorError(STIXError, AssertionError):
|
class InvalidSelectorError(STIXError, AssertionError):
|
||||||
"""Granular Marking selector violation. The selector must resolve into an existing STIX object property."""
|
"""Granular Marking selector violation. The selector must resolve into an existing STIX object property."""
|
||||||
|
|
||||||
|
|
|
@ -373,7 +373,7 @@ def test_parse_unregistered_custom_observable_object():
|
||||||
"property1": "something"
|
"property1": "something"
|
||||||
}"""
|
}"""
|
||||||
|
|
||||||
with pytest.raises(stix2.exceptions.ParseError) as excinfo:
|
with pytest.raises(stix2.exceptions.CustomContentError) as excinfo:
|
||||||
stix2.parse_observable(nt_string)
|
stix2.parse_observable(nt_string)
|
||||||
assert "Can't parse unknown observable type" in str(excinfo.value)
|
assert "Can't parse unknown observable type" in str(excinfo.value)
|
||||||
|
|
||||||
|
@ -384,6 +384,16 @@ def test_parse_unregistered_custom_observable_object():
|
||||||
assert not isinstance(parsed_custom, stix2.core._STIXBase)
|
assert not isinstance(parsed_custom, stix2.core._STIXBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_unregistered_custom_observable_object_with_no_type():
|
||||||
|
nt_string = """{
|
||||||
|
"property1": "something"
|
||||||
|
}"""
|
||||||
|
|
||||||
|
with pytest.raises(stix2.exceptions.ParseError) as excinfo:
|
||||||
|
stix2.parse_observable(nt_string, allow_custom=True)
|
||||||
|
assert "Can't parse observable with no 'type' property" in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
def test_parse_observed_data_with_custom_observable():
|
def test_parse_observed_data_with_custom_observable():
|
||||||
input_str = """{
|
input_str = """{
|
||||||
"type": "observed-data",
|
"type": "observed-data",
|
||||||
|
|
|
@ -8,8 +8,8 @@ Observable and do not have a ``_type`` attribute.
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from ..base import _Extension, _Observable, _STIXBase
|
from ..base import _Extension, _Observable, _STIXBase
|
||||||
from ..exceptions import (AtLeastOnePropertyError, DependentPropertiesError,
|
from ..exceptions import (AtLeastOnePropertyError, CustomContentError,
|
||||||
ParseError)
|
DependentPropertiesError, ParseError)
|
||||||
from ..properties import (BinaryProperty, BooleanProperty, DictionaryProperty,
|
from ..properties import (BinaryProperty, BooleanProperty, DictionaryProperty,
|
||||||
EmbeddedObjectProperty, EnumProperty, FloatProperty,
|
EmbeddedObjectProperty, EnumProperty, FloatProperty,
|
||||||
HashesProperty, HexProperty, IntegerProperty,
|
HashesProperty, HexProperty, IntegerProperty,
|
||||||
|
@ -67,7 +67,7 @@ class ExtensionsProperty(DictionaryProperty):
|
||||||
else:
|
else:
|
||||||
raise ValueError("Cannot determine extension type.")
|
raise ValueError("Cannot determine extension type.")
|
||||||
else:
|
else:
|
||||||
raise ParseError("Can't parse unknown extension type: {}".format(key))
|
raise CustomContentError("Can't parse unknown extension type: {}".format(key))
|
||||||
else:
|
else:
|
||||||
raise ValueError("The enclosing type '%s' has no extensions defined" % self.enclosing_type)
|
raise ValueError("The enclosing type '%s' has no extensions defined" % self.enclosing_type)
|
||||||
return dictified
|
return dictified
|
||||||
|
@ -927,8 +927,8 @@ def parse_observable(data, _valid_refs=None, allow_custom=False):
|
||||||
# flag allows for unknown custom objects too, but will not
|
# flag allows for unknown custom objects too, but will not
|
||||||
# be parsed into STIX observable object, just returned as is
|
# be parsed into STIX observable object, just returned as is
|
||||||
return obj
|
return obj
|
||||||
raise ParseError("Can't parse unknown observable type '%s'! For custom observables, "
|
raise CustomContentError("Can't parse unknown observable type '%s'! For custom observables, "
|
||||||
"use the CustomObservable decorator." % obj['type'])
|
"use the CustomObservable decorator." % obj['type'])
|
||||||
|
|
||||||
if 'extensions' in obj and obj['type'] in EXT_MAP:
|
if 'extensions' in obj and obj['type'] in EXT_MAP:
|
||||||
for name, ext in obj['extensions'].items():
|
for name, ext in obj['extensions'].items():
|
||||||
|
@ -936,7 +936,8 @@ def parse_observable(data, _valid_refs=None, allow_custom=False):
|
||||||
ext_class = EXT_MAP[obj['type']][name]
|
ext_class = EXT_MAP[obj['type']][name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if not allow_custom:
|
if not allow_custom:
|
||||||
raise ParseError("Can't parse unknown extension type '%s' for observable type '%s'!" % (name, obj['type']))
|
raise CustomContentError("Can't parse unknown extension type '%s'"
|
||||||
|
"for observable type '%s'!" % (name, obj['type']))
|
||||||
else: # extension was found
|
else: # extension was found
|
||||||
obj['extensions'][name] = ext_class(allow_custom=allow_custom, **obj['extensions'][name])
|
obj['extensions'][name] = ext_class(allow_custom=allow_custom, **obj['extensions'][name])
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue