diff --git a/stix2/base.py b/stix2/base.py index f23da74..cca5a1f 100644 --- a/stix2/base.py +++ b/stix2/base.py @@ -61,12 +61,13 @@ class _STIXBase(collections.Mapping): kwargs[prop_name] = prop_metadata['fixed'] if prop_metadata.get('validate'): - if not prop_metadata['validate'](cls, kwargs[prop_name]): + if (prop_name in kwargs and + not prop_metadata['validate'](cls, kwargs[prop_name])): msg = prop_metadata.get('error_msg', DEFAULT_ERROR).format( type=class_name, field=prop_name, expected=prop_metadata.get('expected', - prop_metadata['default'])(cls), + prop_metadata.get('default', lambda x: ''))(cls), ) raise ValueError(msg) elif prop_metadata.get('fixed'): diff --git a/stix2/common.py b/stix2/common.py index 924210a..e9cea44 100644 --- a/stix2/common.py +++ b/stix2/common.py @@ -1,5 +1,6 @@ """STIX 2 Common Data Types and Properties""" +import re from .base import _STIXBase from .utils import NOW @@ -15,6 +16,14 @@ ID_PROPERTY = { 'error_msg': "{type} {field} values must begin with '{expected}'." } +ref_regex = ("^[a-z][a-z-]+[a-z]--[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}" + "-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$") + +REF_PROPERTY = { + 'validate': (lambda x, val: re.match(ref_regex, val)), + 'error_msg': "{type} {field} values must consist of a valid STIX type name and a valid UUID, separated by '--'." +} + COMMON_PROPERTIES = { 'type': TYPE_PROPERTY, 'id': ID_PROPERTY, @@ -24,6 +33,7 @@ COMMON_PROPERTIES = { 'modified': { 'default': NOW, }, + 'created_by_ref': REF_PROPERTY } diff --git a/stix2/test/test_stix2.py b/stix2/test/test_stix2.py index 164aca9..9f6934b 100644 --- a/stix2/test/test_stix2.py +++ b/stix2/test/test_stix2.py @@ -54,6 +54,7 @@ def test_my_uuid4_fixture(uuid4): INDICATOR_ID = "indicator--01234567-89ab-cdef-0123-456789abcdef" MALWARE_ID = "malware--fedcba98-7654-3210-fedc-ba9876543210" RELATIONSHIP_ID = "relationship--00000000-1111-2222-3333-444444444444" +IDENTITY_ID = "identity--d4d765ce-cff7-40e8-b7a6-e205d005ac2c" # Minimum required args for an Indicator instance INDICATOR_KWARGS = dict( @@ -175,6 +176,12 @@ def test_indicator_required_field_pattern(): assert str(excinfo.value) == "Missing required field(s) for Indicator: (pattern)." +def test_indicator_created_ref_invalid_format(): + with pytest.raises(ValueError) as excinfo: + indicator = stix2.Indicator(created_by_ref='myprefix--12345678', **INDICATOR_KWARGS) + assert str(excinfo.value) == "Indicator created_by_ref values must consist of a valid STIX type name and a valid UUID, separated by '--'." + + def test_cannot_assign_to_indicator_attributes(indicator): with pytest.raises(ValueError) as excinfo: indicator.valid_from = dt.datetime.now()