diff --git a/stix2/parsing.py b/stix2/parsing.py index b81a07d..db0c693 100644 --- a/stix2/parsing.py +++ b/stix2/parsing.py @@ -200,6 +200,11 @@ def _register_object(new_type, version=None): version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If None, use latest version. + Raises: + ValueError: If the class being registered wasn't created with the + @CustomObject decorator. + DuplicateRegistrationError: If the class has already been registered. + """ if not issubclass(new_type, _DomainObject): @@ -208,8 +213,6 @@ def _register_object(new_type, version=None): new_type.__name__, ) - new_type._properties['type'].clean(new_type._type) - if version: v = 'v' + version.replace('.', '') else: @@ -232,8 +235,11 @@ def _register_marking(new_marking, version=None): """ + mark_type = new_marking._type properties = new_marking._properties + stix2.properties._validate_type(mark_type, version) + if version == "2.1": for prop_name, prop_value in properties.items(): if not re.match(PREFIX_21_REGEX, prop_name): @@ -246,9 +252,9 @@ def _register_marking(new_marking, version=None): v = 'v' + stix2.DEFAULT_VERSION.replace('.', '') OBJ_MAP_MARKING = STIX2_OBJ_MAPS[v]['markings'] - if new_marking._type in OBJ_MAP_MARKING.keys(): - raise DuplicateRegistrationError("STIX Marking", new_marking._type) - OBJ_MAP_MARKING[new_marking._type] = new_marking + if mark_type in OBJ_MAP_MARKING.keys(): + raise DuplicateRegistrationError("STIX Marking", mark_type) + OBJ_MAP_MARKING[mark_type] = new_marking def _register_observable(new_observable, version=None): @@ -261,8 +267,6 @@ def _register_observable(new_observable, version=None): """ - new_observable._properties['type'].clean(new_observable._type) - if version: v = 'v' + version.replace('.', '') else: @@ -296,8 +300,7 @@ def _register_observable_extension( if not issubclass(obs_class, _Observable): raise ValueError("'observable' must be a valid Observable class!") - temp_prop = stix2.properties.TypeProperty(ext_type, spec_version=version) - temp_prop.clean(ext_type) + stix2.properties._validate_type(ext_type, version) if not new_extension._properties: raise ValueError( diff --git a/stix2/properties.py b/stix2/properties.py index 4ccfa89..39c409c 100644 --- a/stix2/properties.py +++ b/stix2/properties.py @@ -84,6 +84,36 @@ def _validate_id(id_, spec_version, required_prefix): raise ValueError(ERROR_INVALID_ID.format(id_)) +def _validate_type(type_, spec_version): + """ + Check the STIX type name for correctness, raise an exception if there are + errors. + + :param type_: The STIX type name + :param spec_version: The STIX specification version to use + :raises ValueError: If there are any errors with the identifier + """ + if spec_version == "2.0": + if not re.match(TYPE_REGEX, type_): + raise ValueError( + "Invalid type name '%s': must only contain the " + "characters a-z (lowercase ASCII), 0-9, and hyphen (-)." % + type_, + ) + else: # 2.1+ + if not re.match(TYPE_21_REGEX, type_): + raise ValueError( + "Invalid type name '%s': must only contain the " + "characters a-z (lowercase ASCII), 0-9, and hyphen (-) " + "and must begin with an a-z character" % type_, + ) + + if len(type_) < 3 or len(type_) > 250: + raise ValueError( + "Invalid type name '%s': must be between 3 and 250 characters." % type_, + ) + + class Property(object): """Represent a property of STIX data type. @@ -236,32 +266,10 @@ class StringProperty(Property): class TypeProperty(Property): def __init__(self, type, spec_version=stix2.DEFAULT_VERSION): + _validate_type(type, spec_version) self.spec_version = spec_version super(TypeProperty, self).__init__(fixed=type) - def clean(self, value): - if self.spec_version == "2.0": - if not re.match(TYPE_REGEX, type): - raise ValueError( - "Invalid type name '%s': must only contain the " - "characters a-z (lowercase ASCII), 0-9, and hyphen (-)." % - type, - ) - else: # 2.1+ - if not re.match(TYPE_21_REGEX, type): - raise ValueError( - "Invalid type name '%s': must only contain the " - "characters a-z (lowercase ASCII), 0-9, and hyphen (-) " - "and must begin with an a-z character" % type, - ) - - if len(type) < 3 or len(type) > 250: - raise ValueError( - "Invalid type name '%s': must be between 3 and 250 characters." % type, - ) - - return value - class IDProperty(Property): diff --git a/stix2/test/v20/test_custom.py b/stix2/test/v20/test_custom.py index 8342fec..57f8aac 100644 --- a/stix2/test/v20/test_custom.py +++ b/stix2/test/v20/test_custom.py @@ -483,7 +483,7 @@ def test_custom_observable_object_invalid_type_name(): ) class NewObs(object): pass # pragma: no cover - assert "Invalid observable type name 'x':" in str(excinfo.value) + assert "Invalid type name 'x':" in str(excinfo.value) with pytest.raises(ValueError) as excinfo: @stix2.v20.CustomObservable( @@ -493,7 +493,7 @@ def test_custom_observable_object_invalid_type_name(): ) class NewObs2(object): pass # pragma: no cover - assert "Invalid observable type name 'x_new_obs':" in str(excinfo.value) + assert "Invalid type name 'x_new_obs':" in str(excinfo.value) def test_custom_observable_object_invalid_ref_property(): @@ -808,7 +808,7 @@ def test_custom_extension_invalid_type_name(): ) class FooExtension(): pass # pragma: no cover - assert "Invalid extension type name 'x':" in str(excinfo.value) + assert "Invalid type name 'x':" in str(excinfo.value) with pytest.raises(ValueError) as excinfo: @stix2.v20.CustomExtension( @@ -818,7 +818,7 @@ def test_custom_extension_invalid_type_name(): ) class BlaExtension(): pass # pragma: no cover - assert "Invalid extension type name 'x_new_ext':" in str(excinfo.value) + assert "Invalid type name 'x_new_ext':" in str(excinfo.value) def test_custom_extension_no_properties(): @@ -968,9 +968,8 @@ def test_register_custom_object(): class CustomObject2(object): _type = 'awesome-object' - stix2.parsing._register_object(CustomObject2, version="2.0") - # Note that we will always check against newest OBJ_MAP. - assert (CustomObject2._type, CustomObject2) in stix2.v20.OBJ_MAP.items() + with pytest.raises(ValueError): + stix2.parsing._register_object(CustomObject2, version="2.0") def test_extension_property_location(): diff --git a/stix2/test/v21/test_custom.py b/stix2/test/v21/test_custom.py index 59eb53e..3646f11 100644 --- a/stix2/test/v21/test_custom.py +++ b/stix2/test/v21/test_custom.py @@ -375,7 +375,7 @@ def test_custom_marking_invalid_type_name(): ) class NewObj(object): pass # pragma: no cover - assert "Invalid marking type name 'x': " in str(excinfo.value) + assert "Invalid type name 'x': " in str(excinfo.value) with pytest.raises(ValueError) as excinfo: @stix2.v21.CustomMarking( @@ -385,7 +385,7 @@ def test_custom_marking_invalid_type_name(): ) class NewObj2(object): pass # pragma: no cover - assert "Invalid marking type name 'x_new_marking':" in str(excinfo.value) + assert "Invalid type name 'x_new_marking':" in str(excinfo.value) with pytest.raises(ValueError) as excinfo: @stix2.v21.CustomMarking( @@ -395,7 +395,7 @@ def test_custom_marking_invalid_type_name(): ) class NewObj3(object): pass # pragma: no cover - assert "Invalid marking type name '7x-new-marking':" in str(excinfo.value) + assert "Invalid type name '7x-new-marking':" in str(excinfo.value) # Custom Objects @@ -619,7 +619,7 @@ def test_custom_observable_object_invalid_type_name(): ) class NewObs(object): pass # pragma: no cover - assert "Invalid observable type name 'x':" in str(excinfo.value) + assert "Invalid type name 'x':" in str(excinfo.value) with pytest.raises(ValueError) as excinfo: @stix2.v21.CustomObservable( @@ -629,7 +629,7 @@ def test_custom_observable_object_invalid_type_name(): ) class NewObs2(object): pass # pragma: no cover - assert "Invalid observable type name 'x_new_obs':" in str(excinfo.value) + assert "Invalid type name 'x_new_obs':" in str(excinfo.value) with pytest.raises(ValueError) as excinfo: @stix2.v21.CustomObservable( @@ -639,7 +639,7 @@ def test_custom_observable_object_invalid_type_name(): ) class NewObs3(object): pass # pragma: no cover - assert "Invalid observable type name '7x-new-obs':" in str(excinfo.value) + assert "Invalid type name '7x-new-obs':" in str(excinfo.value) def test_custom_observable_object_invalid_ref_property(): @@ -1005,7 +1005,7 @@ def test_custom_extension_invalid_type_name(): ) class FooExtension(): pass # pragma: no cover - assert "Invalid extension type name 'x':" in str(excinfo.value) + assert "Invalid type name 'x':" in str(excinfo.value) with pytest.raises(ValueError) as excinfo: @stix2.v21.CustomExtension( @@ -1015,7 +1015,7 @@ def test_custom_extension_invalid_type_name(): ) class BlaExtension(): pass # pragma: no cover - assert "Invalid extension type name 'x_new_ext':" in str(excinfo.value) + assert "Invalid type name 'x_new_ext':" in str(excinfo.value) with pytest.raises(ValueError) as excinfo: @stix2.v21.CustomExtension( @@ -1025,7 +1025,7 @@ def test_custom_extension_invalid_type_name(): ) class Bla2Extension(): pass # pragma: no cover - assert "Invalid extension type name '7x-new-ext':" in str(excinfo.value) + assert "Invalid type name '7x-new-ext':" in str(excinfo.value) def test_custom_extension_no_properties():