Factored out more of the STIX identifier validity checking,

partly inspired by PR #263.  This resulted in some error message
format changes (an improvement, I think), which caused some
unit test breakage.  Removed those asserts from the unit tests,
since tests shouldn't be testing human-targeted error messages.
master
Michael Chisholm 2019-06-13 18:37:21 -04:00
parent ed106f23ff
commit da5978d317
7 changed files with 34 additions and 47 deletions

View File

@ -41,6 +41,38 @@ def _check_uuid(uuid_str, spec_version):
return ok
def _validate_id(id_, spec_version, required_prefix):
"""
Check the STIX identifier for correctness, raise an exception if there are
errors.
:param id_: The STIX identifier
:param spec_version: The STIX specification version to use
:param required_prefix: The required prefix on the identifier, if any.
This function doesn't add a "--" suffix to the prefix, so callers must
add it if it is important. Pass None to skip the prefix check.
:raises ValueError: If there are any errors with the identifier
"""
if required_prefix:
if not id_.startswith(required_prefix):
raise ValueError("must start with '{}'.".format(required_prefix))
try:
if required_prefix:
uuid_part = id_[len(required_prefix):]
else:
idx = id_.index("--")
uuid_part = id_[idx+2:]
result = _check_uuid(uuid_part, spec_version)
except ValueError:
# replace their ValueError with ours
raise ValueError(ERROR_INVALID_ID.format(id_))
if not result:
raise ValueError(ERROR_INVALID_ID.format(id_))
class Property(object):
"""Represent a property of STIX data type.
@ -198,19 +230,7 @@ class IDProperty(Property):
super(IDProperty, self).__init__()
def clean(self, value):
if not value.startswith(self.required_prefix):
raise ValueError("must start with '{}'.".format(self.required_prefix))
uuid_part = value[len(self.required_prefix):]
try:
result = _check_uuid(uuid_part, self.spec_version)
except ValueError:
# replace their ValueError with ours
raise ValueError(ERROR_INVALID_ID.format(value))
if not result:
raise ValueError(ERROR_INVALID_ID.format(value))
_validate_id(value, self.spec_version, self.required_prefix)
return value
def default(self):
@ -396,26 +416,7 @@ class ReferenceProperty(Property):
value = value.id
value = str(value)
if self.required_prefix:
if not value.startswith(self.required_prefix):
raise ValueError(
"must start with '{}'.".format(self.required_prefix),
)
try:
if self.required_prefix:
uuid_part = value[len(self.required_prefix):]
else:
idx = value.index("--")
uuid_part = value[idx+2:]
result = _check_uuid(uuid_part, self.spec_version)
except ValueError:
# replace their ValueError with ours
raise ValueError(ERROR_INVALID_ID.format(value))
if not result:
raise ValueError(ERROR_INVALID_ID.format(value))
_validate_id(value, self.spec_version, self.required_prefix)
return value

View File

@ -112,8 +112,6 @@ def test_indicator_created_ref_invalid_format():
assert excinfo.value.cls == stix2.v20.Indicator
assert excinfo.value.prop_name == "created_by_ref"
assert excinfo.value.reason == "must start with 'identity'."
assert str(excinfo.value) == "Invalid value for Indicator 'created_by_ref': must start with 'identity'."
def test_indicator_revoked_invalid():

View File

@ -87,8 +87,6 @@ def test_report_example_objects_in_object_refs_with_bad_id():
assert excinfo.value.cls == stix2.v20.Report
assert excinfo.value.prop_name == "object_refs"
assert excinfo.value.reason == stix2.properties.ERROR_INVALID_ID
assert str(excinfo.value) == "Invalid value for Report 'object_refs': " + stix2.properties.ERROR_INVALID_ID
@pytest.mark.parametrize(

View File

@ -59,8 +59,6 @@ def test_sighting_bad_where_sighted_refs():
assert excinfo.value.cls == stix2.v20.Sighting
assert excinfo.value.prop_name == "where_sighted_refs"
assert excinfo.value.reason == "must start with 'identity'."
assert str(excinfo.value) == "Invalid value for Sighting 'where_sighted_refs': must start with 'identity'."
def test_sighting_type_must_be_sightings():
@ -69,8 +67,6 @@ def test_sighting_type_must_be_sightings():
assert excinfo.value.cls == stix2.v20.Sighting
assert excinfo.value.prop_name == "type"
assert excinfo.value.reason == "must equal 'sighting'."
assert str(excinfo.value) == "Invalid value for Sighting 'type': must equal 'sighting'."
def test_invalid_kwarg_to_sighting():

View File

@ -116,8 +116,6 @@ def test_indicator_created_ref_invalid_format():
assert excinfo.value.cls == stix2.v21.Indicator
assert excinfo.value.prop_name == "created_by_ref"
assert excinfo.value.reason == "must start with 'identity'."
assert str(excinfo.value) == "Invalid value for Indicator 'created_by_ref': must start with 'identity'."
def test_indicator_revoked_invalid():

View File

@ -88,8 +88,6 @@ def test_report_example_objects_in_object_refs_with_bad_id():
assert excinfo.value.cls == stix2.v21.Report
assert excinfo.value.prop_name == "object_refs"
assert excinfo.value.reason == stix2.properties.ERROR_INVALID_ID
assert str(excinfo.value) == "Invalid value for Report 'object_refs': " + stix2.properties.ERROR_INVALID_ID
@pytest.mark.parametrize(

View File

@ -61,8 +61,6 @@ def test_sighting_bad_where_sighted_refs():
assert excinfo.value.cls == stix2.v21.Sighting
assert excinfo.value.prop_name == "where_sighted_refs"
assert excinfo.value.reason == "must start with 'identity'."
assert str(excinfo.value) == "Invalid value for Sighting 'where_sighted_refs': must start with 'identity'."
def test_sighting_type_must_be_sightings():