diff --git a/stix2/__init__.py b/stix2/__init__.py index c9384a0..f3e02b4 100644 --- a/stix2/__init__.py +++ b/stix2/__init__.py @@ -23,7 +23,6 @@ DEFAULT_VERSION = '2.0' # Default version will always be the latest STIX 2.X version from .confidence import scales -from .core import _collect_stix2_mappings, parse, parse_observable from .datastore import CompositeDataSource from .datastore.filesystem import ( FileSystemSink, FileSystemSource, FileSystemStore, @@ -38,6 +37,7 @@ from .markings import ( add_markings, clear_markings, get_markings, is_marked, remove_markings, set_markings, ) +from .parsing import _collect_stix2_mappings, parse, parse_observable from .patterns import ( AndBooleanExpression, AndObservationExpression, BasicObjectPathComponent, BinaryConstant, BooleanConstant, EqualityComparisonExpression, diff --git a/stix2/base.py b/stix2/base.py index 4248075..a1229ca 100644 --- a/stix2/base.py +++ b/stix2/base.py @@ -2,11 +2,13 @@ import copy import datetime as dt +import re import uuid import simplejson as json import six +import stix2 from stix2.canonicalization.Canonicalize import canonicalize from .exceptions import ( @@ -14,8 +16,11 @@ from .exceptions import ( ImmutableError, InvalidObjRefError, InvalidValueError, MissingPropertiesError, MutuallyExclusivePropertiesError, ) +from .markings import _MarkingsMixin from .markings.utils import validate -from .utils import NOW, find_property_index, format_datetime, get_timestamp +from .utils import ( + NOW, PREFIX_21_REGEX, find_property_index, format_datetime, get_timestamp, +) from .utils import new_version as _new_version from .utils import revoke as _revoke @@ -157,12 +162,23 @@ class _STIXBase(Mapping): custom_props = kwargs.pop('custom_properties', {}) if custom_props and not isinstance(custom_props, dict): raise ValueError("'custom_properties' must be a dictionary") - if not self._allow_custom: - extra_kwargs = list(set(kwargs) - set(self._properties)) - if extra_kwargs: - raise ExtraPropertiesError(cls, extra_kwargs) - if custom_props: + + extra_kwargs = list(set(kwargs) - set(self._properties)) + if extra_kwargs and not self._allow_custom: + raise ExtraPropertiesError(cls, extra_kwargs) + + # because allow_custom is true, any extra kwargs are custom + if custom_props or extra_kwargs: self._allow_custom = True + if isinstance(self, stix2.v21._STIXBase21): + all_custom_prop_names = extra_kwargs + all_custom_prop_names.extend(list(custom_props.keys())) + for prop_name in all_custom_prop_names: + if not re.match(PREFIX_21_REGEX, prop_name): + raise InvalidValueError( + self.__class__, prop_name, + reason="Property name '%s' must begin with an alpha character." % prop_name, + ) # Remove any keyword arguments whose value is None or [] (i.e. empty list) setting_kwargs = {} @@ -305,6 +321,14 @@ class _STIXBase(Mapping): return json.dumps(self, cls=STIXJSONEncoder, **kwargs) +class _DomainObject(_STIXBase, _MarkingsMixin): + pass + + +class _RelationshipObject(_STIXBase, _MarkingsMixin): + pass + + class _Observable(_STIXBase): def __init__(self, **kwargs): diff --git a/stix2/custom.py b/stix2/custom.py index f3c89cf..f749b04 100644 --- a/stix2/custom.py +++ b/stix2/custom.py @@ -1,140 +1,91 @@ from collections import OrderedDict -import re import six -from .base import _cls_init, _Extension, _Observable, _STIXBase -from .core import ( - STIXDomainObject, _register_marking, _register_object, - _register_observable, _register_observable_extension, +from .base import _cls_init +from .parsing import ( + _register_marking, _register_object, _register_observable, + _register_observable_extension, ) -from .utils import TYPE_REGEX, get_class_hierarchy_names -def _custom_object_builder(cls, type, properties, version): - class _CustomObject(cls, STIXDomainObject): - - 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, - ) - elif len(type) < 3 or len(type) > 250: - raise ValueError( - "Invalid type name '%s': must be between 3 and 250 characters." % type, - ) - - if not properties or not isinstance(properties, list): - raise ValueError("Must supply a list, containing tuples. For example, [('property1', IntegerProperty())]") - - _type = type - _properties = OrderedDict(properties) - - def __init__(self, **kwargs): - _STIXBase.__init__(self, **kwargs) - _cls_init(cls, self, kwargs) - - _register_object(_CustomObject, version=version) - return _CustomObject - - -def _custom_marking_builder(cls, type, properties, version): - class _CustomMarking(cls, _STIXBase): - - if not properties or not isinstance(properties, list): - raise ValueError("Must supply a list, containing tuples. For example, [('property1', IntegerProperty())]") - - _type = type - _properties = OrderedDict(properties) - - def __init__(self, **kwargs): - _STIXBase.__init__(self, **kwargs) - _cls_init(cls, self, kwargs) - - _register_marking(_CustomMarking, version=version) - return _CustomMarking - - -def _custom_observable_builder(cls, type, properties, version, id_contrib_props=None): - if id_contrib_props is None: - id_contrib_props = [] - - class _CustomObservable(cls, _Observable): - - if not re.match(TYPE_REGEX, type): - raise ValueError( - "Invalid observable type name '%s': must only contain the " - "characters a-z (lowercase ASCII), 0-9, and hyphen (-)." % type, - ) - elif len(type) < 3 or len(type) > 250: - raise ValueError("Invalid observable type name '%s': must be between 3 and 250 characters." % type) - - if not properties or not isinstance(properties, list): - raise ValueError("Must supply a list, containing tuples. For example, [('property1', IntegerProperty())]") - - if version == "2.0": - # If using STIX2.0, check properties ending in "_ref/s" are ObjectReferenceProperties - for prop_name, prop in properties: - if prop_name.endswith('_ref') and ('ObjectReferenceProperty' not in get_class_hierarchy_names(prop)): - raise ValueError( - "'%s' is named like an object reference property but " - "is not an ObjectReferenceProperty." % prop_name, - ) - elif (prop_name.endswith('_refs') and ('ListProperty' not in get_class_hierarchy_names(prop) or - 'ObjectReferenceProperty' not in get_class_hierarchy_names(prop.contained))): - raise ValueError( - "'%s' is named like an object reference list property but " - "is not a ListProperty containing ObjectReferenceProperty." % prop_name, - ) - else: - # If using STIX2.1 (or newer...), check properties ending in "_ref/s" are ReferenceProperties - for prop_name, prop in properties: - if prop_name.endswith('_ref') and ('ReferenceProperty' not in get_class_hierarchy_names(prop)): - raise ValueError( - "'%s' is named like a reference property but " - "is not a ReferenceProperty." % prop_name, - ) - elif (prop_name.endswith('_refs') and ('ListProperty' not in get_class_hierarchy_names(prop) or - 'ReferenceProperty' not in get_class_hierarchy_names(prop.contained))): - raise ValueError( - "'%s' is named like a reference list property but " - "is not a ListProperty containing ReferenceProperty." % prop_name, - ) - - _type = type - _properties = OrderedDict(properties) - if version != '2.0': - _id_contributing_properties = id_contrib_props - - def __init__(self, **kwargs): - _Observable.__init__(self, **kwargs) - _cls_init(cls, self, kwargs) - - _register_observable(_CustomObservable, version=version) - return _CustomObservable - - -def _custom_extension_builder(cls, observable, type, properties, version): - +def _get_properties_dict(properties): try: - prop_dict = OrderedDict(properties) + return OrderedDict(properties) except TypeError as e: six.raise_from( ValueError( - "Extension properties must be dict-like, e.g. a list " + "properties must be dict-like, e.g. a list " "containing tuples. For example, " "[('property1', IntegerProperty())]", ), e, ) - class _CustomExtension(cls, _Extension): + +def _custom_object_builder(cls, type, properties, version, base_class): + prop_dict = _get_properties_dict(properties) + + class _CustomObject(cls, base_class): _type = type _properties = prop_dict def __init__(self, **kwargs): - _Extension.__init__(self, **kwargs) + base_class.__init__(self, **kwargs) + _cls_init(cls, self, kwargs) + + _register_object(_CustomObject, version=version) + return _CustomObject + + +def _custom_marking_builder(cls, type, properties, version, base_class): + prop_dict = _get_properties_dict(properties) + + class _CustomMarking(cls, base_class): + + _type = type + _properties = prop_dict + + def __init__(self, **kwargs): + base_class.__init__(self, **kwargs) + _cls_init(cls, self, kwargs) + + _register_marking(_CustomMarking, version=version) + return _CustomMarking + + +def _custom_observable_builder(cls, type, properties, version, base_class, id_contrib_props=None): + if id_contrib_props is None: + id_contrib_props = [] + + prop_dict = _get_properties_dict(properties) + + class _CustomObservable(cls, base_class): + + _type = type + _properties = prop_dict + if version != '2.0': + _id_contributing_properties = id_contrib_props + + def __init__(self, **kwargs): + base_class.__init__(self, **kwargs) + _cls_init(cls, self, kwargs) + + _register_observable(_CustomObservable, version=version) + return _CustomObservable + + +def _custom_extension_builder(cls, observable, type, properties, version, base_class): + prop_dict = _get_properties_dict(properties) + + class _CustomExtension(cls, base_class): + + _type = type + _properties = prop_dict + + def __init__(self, **kwargs): + base_class.__init__(self, **kwargs) _cls_init(cls, self, kwargs) _register_observable_extension(observable, _CustomExtension, version=version) diff --git a/stix2/datastore/filesystem.py b/stix2/datastore/filesystem.py index d5acc24..5a5844a 100644 --- a/stix2/datastore/filesystem.py +++ b/stix2/datastore/filesystem.py @@ -10,11 +10,11 @@ import six from stix2 import v20, v21 from stix2.base import _STIXBase -from stix2.core import parse from stix2.datastore import ( DataSink, DataSource, DataSourceError, DataStoreMixin, ) from stix2.datastore.filters import Filter, FilterSet, apply_common_filters +from stix2.parsing import parse from stix2.utils import format_datetime, get_type_from_id diff --git a/stix2/datastore/memory.py b/stix2/datastore/memory.py index 52da168..f71b763 100644 --- a/stix2/datastore/memory.py +++ b/stix2/datastore/memory.py @@ -7,9 +7,9 @@ import os from stix2 import v20, v21 from stix2.base import _STIXBase -from stix2.core import parse from stix2.datastore import DataSink, DataSource, DataStoreMixin from stix2.datastore.filters import FilterSet, apply_common_filters +from stix2.parsing import parse def _add(store, stix_data, allow_custom=True, version=None): diff --git a/stix2/datastore/taxii.py b/stix2/datastore/taxii.py index 08d0e14..b5c0827 100644 --- a/stix2/datastore/taxii.py +++ b/stix2/datastore/taxii.py @@ -4,11 +4,11 @@ from requests.exceptions import HTTPError from stix2 import v20, v21 from stix2.base import _STIXBase -from stix2.core import parse from stix2.datastore import ( DataSink, DataSource, DataSourceError, DataStoreMixin, ) from stix2.datastore.filters import Filter, FilterSet, apply_common_filters +from stix2.parsing import parse from stix2.utils import deduplicate try: diff --git a/stix2/environment.py b/stix2/environment.py index ada5f33..6e3c76a 100644 --- a/stix2/environment.py +++ b/stix2/environment.py @@ -4,8 +4,8 @@ import copy import logging import time -from .core import parse as _parse from .datastore import CompositeDataSource, DataStoreMixin +from .parsing import parse as _parse from .utils import STIXdatetime, parse_into_datetime logger = logging.getLogger(__name__) diff --git a/stix2/core.py b/stix2/parsing.py similarity index 75% rename from stix2/core.py rename to stix2/parsing.py index dd7aac1..baa3b7b 100644 --- a/stix2/core.py +++ b/stix2/parsing.py @@ -7,22 +7,13 @@ import re import stix2 -from .base import _Observable, _STIXBase +from .base import _DomainObject, _Observable from .exceptions import DuplicateRegistrationError, ParseError -from .markings import _MarkingsMixin -from .utils import SCO21_EXT_REGEX, TYPE_REGEX, _get_dict +from .utils import PREFIX_21_REGEX, _get_dict, get_class_hierarchy_names STIX2_OBJ_MAPS = {} -class STIXDomainObject(_STIXBase, _MarkingsMixin): - pass - - -class STIXRelationshipObject(_STIXBase, _MarkingsMixin): - pass - - def parse(data, allow_custom=False, version=None): """Convert a string, dict or file-like object into a STIX object. @@ -201,7 +192,7 @@ def parse_observable(data, _valid_refs=None, allow_custom=False, version=None): return obj_class(allow_custom=allow_custom, **obj) -def _register_object(new_type, version=None): +def _register_object(new_type, version=stix2.DEFAULT_VERSION): """Register a custom STIX Object type. Args: @@ -209,7 +200,26 @@ 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): + raise ValueError( + "'%s' must be created with the @CustomObject decorator." % + new_type.__name__, + ) + + properties = new_type._properties + + if version == "2.1": + for prop_name, prop in properties.items(): + if not re.match(PREFIX_21_REGEX, prop_name): + raise ValueError("Property name '%s' must begin with an alpha character" % prop_name) + if version: v = 'v' + version.replace('.', '') else: @@ -222,7 +232,7 @@ def _register_object(new_type, version=None): OBJ_MAP[new_type._type] = new_type -def _register_marking(new_marking, version=None): +def _register_marking(new_marking, version=stix2.DEFAULT_VERSION): """Register a custom STIX Marking Definition type. Args: @@ -231,6 +241,17 @@ def _register_marking(new_marking, version=None): None, use latest version. """ + + 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): + raise ValueError("Property name '%s' must begin with an alpha character." % prop_name) + if version: v = 'v' + version.replace('.', '') else: @@ -238,12 +259,12 @@ 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): +def _register_observable(new_observable, version=stix2.DEFAULT_VERSION): """Register a custom STIX Cyber Observable type. Args: @@ -252,6 +273,39 @@ def _register_observable(new_observable, version=None): None, use latest version. """ + properties = new_observable._properties + + if version == "2.0": + # If using STIX2.0, check properties ending in "_ref/s" are ObjectReferenceProperties + for prop_name, prop in properties.items(): + if prop_name.endswith('_ref') and ('ObjectReferenceProperty' not in get_class_hierarchy_names(prop)): + raise ValueError( + "'%s' is named like an object reference property but " + "is not an ObjectReferenceProperty." % prop_name, + ) + elif (prop_name.endswith('_refs') and ('ListProperty' not in get_class_hierarchy_names(prop) or + 'ObjectReferenceProperty' not in get_class_hierarchy_names(prop.contained))): + raise ValueError( + "'%s' is named like an object reference list property but " + "is not a ListProperty containing ObjectReferenceProperty." % prop_name, + ) + else: + # If using STIX2.1 (or newer...), check properties ending in "_ref/s" are ReferenceProperties + for prop_name, prop in properties.items(): + if not re.match(PREFIX_21_REGEX, prop_name): + raise ValueError("Property name '%s' must begin with an alpha character." % prop_name) + elif prop_name.endswith('_ref') and ('ReferenceProperty' not in get_class_hierarchy_names(prop)): + raise ValueError( + "'%s' is named like a reference property but " + "is not a ReferenceProperty." % prop_name, + ) + elif (prop_name.endswith('_refs') and ('ListProperty' not in get_class_hierarchy_names(prop) or + 'ReferenceProperty' not in get_class_hierarchy_names(prop.contained))): + raise ValueError( + "'%s' is named like a reference list property but " + "is not a ListProperty containing ReferenceProperty." % prop_name, + ) + if version: v = 'v' + version.replace('.', '') else: @@ -280,30 +334,12 @@ def _register_observable_extension( obs_class = observable if isinstance(observable, type) else \ type(observable) ext_type = new_extension._type + properties = new_extension._properties if not issubclass(obs_class, _Observable): raise ValueError("'observable' must be a valid Observable class!") - if version == "2.0": - if not re.match(TYPE_REGEX, ext_type): - raise ValueError( - "Invalid extension type name '%s': must only contain the " - "characters a-z (lowercase ASCII), 0-9, and hyphen (-)." % - ext_type, - ) - else: # 2.1+ - if not re.match(SCO21_EXT_REGEX, ext_type): - raise ValueError( - "Invalid extension type name '%s': must only contain the " - "characters a-z (lowercase ASCII), 0-9, hyphen (-), and end " - "with '-ext'." % ext_type, - ) - - if len(ext_type) < 3 or len(ext_type) > 250: - raise ValueError( - "Invalid extension type name '%s': must be between 3 and 250" - " characters." % ext_type, - ) + stix2.properties._validate_type(ext_type, version) if not new_extension._properties: raise ValueError( @@ -311,6 +347,17 @@ def _register_observable_extension( ext_type, ) + if version == "2.1": + if not ext_type.endswith('-ext'): + raise ValueError( + "Invalid extension type name '%s': must end with '-ext'." % + ext_type, + ) + + for prop_name, prop_value in properties.items(): + if not re.match(PREFIX_21_REGEX, prop_name): + raise ValueError("Property name '%s' must begin with an alpha character." % prop_name) + v = 'v' + version.replace('.', '') try: diff --git a/stix2/properties.py b/stix2/properties.py index 0bb1f0e..060d9ca 100644 --- a/stix2/properties.py +++ b/stix2/properties.py @@ -12,12 +12,15 @@ from six import string_types, text_type import stix2 from .base import _STIXBase -from .core import STIX2_OBJ_MAPS, parse, parse_observable from .exceptions import ( CustomContentError, DictionaryKeyError, MissingPropertiesError, MutuallyExclusivePropertiesError, ) -from .utils import _get_dict, get_class_hierarchy_names, parse_into_datetime +from .parsing import STIX2_OBJ_MAPS, parse, parse_observable +from .utils import ( + TYPE_21_REGEX, TYPE_REGEX, _get_dict, get_class_hierarchy_names, + parse_into_datetime, +) try: from collections.abc import Mapping @@ -81,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. @@ -232,7 +265,9 @@ class StringProperty(Property): class TypeProperty(Property): - def __init__(self, type): + 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) @@ -643,7 +678,7 @@ class STIXObjectProperty(Property): def clean(self, value): # Any STIX Object (SDO, SRO, or Marking Definition) can be added to # a bundle with no further checks. - if any(x in ('STIXDomainObject', 'STIXRelationshipObject', 'MarkingDefinition') + if any(x in ('_DomainObject', '_RelationshipObject', 'MarkingDefinition') for x in get_class_hierarchy_names(value)): # A simple "is this a spec version 2.1+ object" test. For now, # limit 2.0 bundles to 2.0 objects. It's not possible yet to diff --git a/stix2/test/test_spec_version_detect.py b/stix2/test/test_spec_version_detect.py index d2a9da8..7039024 100644 --- a/stix2/test/test_spec_version_detect.py +++ b/stix2/test/test_spec_version_detect.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals import pytest -from stix2.core import _detect_spec_version +from stix2.parsing import _detect_spec_version @pytest.mark.parametrize( diff --git a/stix2/test/v20/test_custom.py b/stix2/test/v20/test_custom.py index 346f06b..57f8aac 100644 --- a/stix2/test/v20/test_custom.py +++ b/stix2/test/v20/test_custom.py @@ -1,7 +1,7 @@ import pytest import stix2 -from stix2 import core +from stix2 import parsing import stix2.v20 from ...exceptions import DuplicateRegistrationError, InvalidValueError @@ -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.core._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(): @@ -1030,10 +1029,10 @@ def test_register_custom_object_with_version(): "id": "x-new-type-2--00000000-0000-4000-8000-000000000007", } - cust_obj_1 = core.dict_to_stix2(custom_obj_1, version='2.0') + cust_obj_1 = parsing.dict_to_stix2(custom_obj_1, version='2.0') v = 'v20' - assert cust_obj_1.type in core.STIX2_OBJ_MAPS[v]['objects'] + assert cust_obj_1.type in parsing.STIX2_OBJ_MAPS[v]['objects'] # spec_version is not in STIX 2.0, and is required in 2.1, so this # suffices as a test for a STIX 2.0 object. assert "spec_version" not in cust_obj_1 @@ -1065,7 +1064,7 @@ def test_register_observable_with_version(): custom_obs = NewObservable2(property1="Test Observable") v = 'v20' - assert custom_obs.type in core.STIX2_OBJ_MAPS[v]['observables'] + assert custom_obs.type in parsing.STIX2_OBJ_MAPS[v]['observables'] def test_register_duplicate_observable_with_version(): @@ -1091,7 +1090,7 @@ def test_register_marking_with_version(): v = 'v20' no = NewObj2(property1='something') - assert no._type in core.STIX2_OBJ_MAPS[v]['markings'] + assert no._type in parsing.STIX2_OBJ_MAPS[v]['markings'] def test_register_observable_extension_with_version(): @@ -1106,7 +1105,7 @@ def test_register_observable_extension_with_version(): v = 'v20' example = SomeCustomExtension2(keys='test123') - assert example._type in core.STIX2_OBJ_MAPS[v]['observable-extensions']['user-account'] + assert example._type in parsing.STIX2_OBJ_MAPS[v]['observable-extensions']['user-account'] def test_register_duplicate_observable_extension(): diff --git a/stix2/test/v20/test_markings.py b/stix2/test/v20/test_markings.py index b34ef43..0753e86 100644 --- a/stix2/test/v20/test_markings.py +++ b/stix2/test/v20/test_markings.py @@ -249,14 +249,12 @@ def test_not_registered_marking_raises_exception(): def test_marking_wrong_type_construction(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): # Test passing wrong type for properties. @stix2.v20.CustomMarking('x-new-marking-type2', ("a", "b")) class NewObject3(object): pass - assert str(excinfo.value) == "Must supply a list, containing tuples. For example, [('property1', IntegerProperty())]" - def test_campaign_add_markings(): campaign = stix2.v20.Campaign( diff --git a/stix2/test/v20/test_core.py b/stix2/test/v20/test_parsing.py similarity index 84% rename from stix2/test/v20/test_core.py rename to stix2/test/v20/test_parsing.py index 080c6f6..32c3e8b 100644 --- a/stix2/test/v20/test_core.py +++ b/stix2/test/v20/test_parsing.py @@ -1,7 +1,7 @@ import pytest import stix2 -from stix2 import core, exceptions +from stix2 import exceptions, parsing BUNDLE = { "type": "bundle", @@ -44,14 +44,14 @@ BUNDLE = { def test_dict_to_stix2_bundle_with_version(): with pytest.raises(exceptions.ExtraPropertiesError) as excinfo: - core.dict_to_stix2(BUNDLE, version='2.1') + parsing.dict_to_stix2(BUNDLE, version='2.1') assert str(excinfo.value) == "Unexpected properties for Bundle: (spec_version)." def test_parse_observable_with_version(): observable = {"type": "file", "name": "foo.exe"} - obs_obj = core.parse_observable(observable, version='2.0') + obs_obj = parsing.parse_observable(observable, version='2.0') v = 'v20' assert v in str(obs_obj.__class__) @@ -60,15 +60,15 @@ def test_parse_observable_with_version(): @pytest.mark.xfail(reason="The default version is no longer 2.0", condition=stix2.DEFAULT_VERSION != "2.0") def test_parse_observable_with_no_version(): observable = {"type": "file", "name": "foo.exe"} - obs_obj = core.parse_observable(observable) + obs_obj = parsing.parse_observable(observable) v = 'v20' assert v in str(obs_obj.__class__) def test_register_marking_with_version(): - core._register_marking(stix2.v20.TLP_WHITE.__class__, version='2.0') + parsing._register_marking(stix2.v20.TLP_WHITE.__class__, version='2.0') v = 'v20' - assert stix2.v20.TLP_WHITE.definition._type in core.STIX2_OBJ_MAPS[v]['markings'] + assert stix2.v20.TLP_WHITE.definition._type in parsing.STIX2_OBJ_MAPS[v]['markings'] assert v in str(stix2.v20.TLP_WHITE.__class__) diff --git a/stix2/test/v21/test_custom.py b/stix2/test/v21/test_custom.py index 4522463..3646f11 100644 --- a/stix2/test/v21/test_custom.py +++ b/stix2/test/v21/test_custom.py @@ -9,6 +9,8 @@ import stix2.v21 from ...exceptions import DuplicateRegistrationError, InvalidValueError from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID +# Custom Properties in SDOs + IDENTITY_CUSTOM_PROP = stix2.v21.Identity( name="John Smith", identity_class="individual", @@ -18,6 +20,18 @@ IDENTITY_CUSTOM_PROP = stix2.v21.Identity( def test_identity_custom_property(): + identity = stix2.v21.Identity( + id=IDENTITY_ID, + created="2015-12-21T19:59:11Z", + modified="2015-12-21T19:59:11Z", + name="John Smith", + identity_class="individual", + custom_properties={ + "foo": "bar", + }, + ) + assert identity.foo == "bar" + with pytest.raises(ValueError) as excinfo: stix2.v21.Identity( id=IDENTITY_ID, @@ -43,17 +57,47 @@ def test_identity_custom_property(): ) assert "Unexpected properties for Identity" in str(excinfo.value) - identity = stix2.v21.Identity( - id=IDENTITY_ID, - created="2015-12-21T19:59:11Z", - modified="2015-12-21T19:59:11Z", - name="John Smith", - identity_class="individual", - custom_properties={ - "foo": "bar", - }, - ) - assert identity.foo == "bar" + # leading numeric character is illegal in 2.1 + + with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: + stix2.v21.Identity( + id=IDENTITY_ID, + created="2015-12-21T19:59:11Z", + modified="2015-12-21T19:59:11Z", + name="John Smith", + identity_class="individual", + custom_properties={ + "7foo": "bar", + }, + ) + assert "must begin with an alpha character." in str(excinfo.value) + + # leading "_" is illegal in 2.1 + + with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: + stix2.v21.Identity( + id=IDENTITY_ID, + created="2015-12-21T19:59:11Z", + modified="2015-12-21T19:59:11Z", + name="John Smith", + identity_class="individual", + custom_properties={ + "_foo": "bar", + }, + ) + assert "must begin with an alpha character." in str(excinfo.value) + + with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: + identity = stix2.v21.Identity( + id=IDENTITY_ID, + created="2015-12-21T19:59:11Z", + modified="2015-12-21T19:59:11Z", + name="John Smith", + identity_class="individual", + _x_foo="bar", + allow_custom=True, + ) + assert "must begin with an alpha character." in str(excinfo.value) def test_identity_custom_property_invalid(): @@ -165,6 +209,8 @@ def test_custom_properties_dict_in_bundled_object(): assert bundle.objects[0].x_foo == "bar" assert '"x_foo": "bar"' in str(bundle) +# Custom properties in SCOs + def test_custom_property_in_observed_data(): artifact = stix2.v21.File( @@ -184,6 +230,18 @@ def test_custom_property_in_observed_data(): assert '"x_foo": "bar"' in str(observed_data) +def test_invalid_custom_property_in_observed_data(): + with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: + stix2.v21.File( + custom_properties={"8foo": 1}, + allow_custom=True, + name='test', + x_foo='bar', + ) + + assert "must begin with an alpha character." in str(excinfo.value) + + def test_custom_property_object_in_observable_extension(): ntfs = stix2.v21.NTFSExt( allow_custom=True, @@ -245,6 +303,8 @@ def test_identity_custom_property_revoke(): identity = IDENTITY_CUSTOM_PROP.revoke() assert identity.x_foo == "bar" +# Custom markings + def test_identity_custom_property_edit_markings(): marking_obj = stix2.v21.MarkingDefinition( @@ -267,6 +327,19 @@ def test_identity_custom_property_edit_markings(): identity2.clear_markings('x_foo') +def test_invalid_custom_property_in_marking(): + with pytest.raises(ValueError) as excinfo: + @stix2.v21.CustomMarking( + 'x-new-obj', [ + ('9property1', stix2.properties.StringProperty(required=True)), + ], + ) + class NewObj(): + pass + + assert "must begin with an alpha character." in str(excinfo.value) + + def test_custom_marking_no_init_1(): @stix2.v21.CustomMarking( 'x-new-obj', [ @@ -293,6 +366,40 @@ def test_custom_marking_no_init_2(): assert no2.property1 == 'something' +def test_custom_marking_invalid_type_name(): + with pytest.raises(ValueError) as excinfo: + @stix2.v21.CustomMarking( + 'x', [ + ('property1', stix2.properties.StringProperty(required=True)), + ], + ) + class NewObj(object): + pass # pragma: no cover + assert "Invalid type name 'x': " in str(excinfo.value) + + with pytest.raises(ValueError) as excinfo: + @stix2.v21.CustomMarking( + 'x_new_marking', [ + ('property1', stix2.properties.StringProperty(required=True)), + ], + ) + class NewObj2(object): + pass # pragma: no cover + assert "Invalid type name 'x_new_marking':" in str(excinfo.value) + + with pytest.raises(ValueError) as excinfo: + @stix2.v21.CustomMarking( + '7x-new-marking', [ + ('property1', stix2.properties.StringProperty(required=True)), + ], + ) + class NewObj3(object): + pass # pragma: no cover + assert "Invalid type name '7x-new-marking':" in str(excinfo.value) + +# Custom Objects + + @stix2.v21.CustomObject( 'x-new-type', [ ('property1', stix2.properties.StringProperty(required=True)), @@ -374,6 +481,16 @@ def test_custom_object_invalid_type_name(): pass # pragma: no cover assert "Invalid type name 'x_new_object':" in str(excinfo.value) + with pytest.raises(ValueError) as excinfo: + @stix2.v21.CustomObject( + '7x-new-object', [ + ('property1', stix2.properties.StringProperty(required=True)), + ], + ) + class NewObj3(object): + pass # pragma: no cover + assert "Invalid type name '7x-new-object':" in str(excinfo.value) + def test_parse_custom_object_type(): nt_string = """{ @@ -412,6 +529,8 @@ def test_parse_unregistered_custom_object_type_w_allow_custom(): custom_obj = stix2.parse(nt_string, version="2.1", allow_custom=True) assert custom_obj["type"] == "x-foobar-observable" +# Custom SCOs + @stix2.v21.CustomObservable( 'x-new-observable', [ @@ -479,6 +598,18 @@ def test_custom_observable_object_no_init_2(): assert no2.property1 == 'something' +def test_invalid_custom_property_in_custom_observable_object(): + with pytest.raises(ValueError) as excinfo: + @stix2.v21.CustomObservable( + 'x-new-sco', [ + ('5property1', stix2.properties.StringProperty()), + ], + ) + class NewObs(object): + pass # pragma: no cover + assert "must begin with an alpha character." in str(excinfo.value) + + def test_custom_observable_object_invalid_type_name(): with pytest.raises(ValueError) as excinfo: @stix2.v21.CustomObservable( @@ -488,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( @@ -498,7 +629,17 @@ 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( + '7x-new-obs', [ + ('property1', stix2.properties.StringProperty()), + ], + ) + class NewObs3(object): + pass # pragma: no cover + assert "Invalid type name '7x-new-obs':" in str(excinfo.value) def test_custom_observable_object_invalid_ref_property(): @@ -736,6 +877,8 @@ def test_custom_observable_object_no_id_contrib_props(): assert uuid_obj.variant == uuid.RFC_4122 assert uuid_obj.version == 4 +# Custom Extensions + @stix2.v21.CustomExtension( stix2.v21.DomainName, 'x-new-ext', [ @@ -862,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( @@ -872,7 +1015,17 @@ 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( + stix2.v21.File, '7x-new-ext', { + 'property1': stix2.properties.StringProperty(required=True), + }, + ) + class Bla2Extension(): + pass # pragma: no cover + assert "Invalid type name '7x-new-ext':" in str(excinfo.value) def test_custom_extension_no_properties(): @@ -922,6 +1075,19 @@ def test_custom_extension_no_init_2(): assert ne2.property1 == "foobar" +def test_invalid_custom_property_in_extension(): + with pytest.raises(ValueError) as excinfo: + @stix2.v21.CustomExtension( + stix2.v21.DomainName, 'x-new3-ext', [ + ('6property1', stix2.properties.StringProperty(required=True)), + ], + ) + class NewExt(): + pass + + assert "must begin with an alpha character." in str(excinfo.value) + + def test_parse_observable_with_custom_extension(): input_str = """{ "type": "domain-name", @@ -1020,9 +1186,9 @@ def test_register_custom_object(): class CustomObject2(object): _type = 'awesome-object' - stix2.core._register_object(CustomObject2, version="2.1") - # Note that we will always check against newest OBJ_MAP. - assert (CustomObject2._type, CustomObject2) in stix2.v21.OBJ_MAP.items() + with pytest.raises(ValueError) as excinfo: + stix2.parsing._register_object(CustomObject2, version="2.1") + assert '@CustomObject decorator' in str(excinfo) def test_extension_property_location(): @@ -1084,10 +1250,10 @@ def test_register_custom_object_with_version(): "spec_version": "2.1", } - cust_obj_1 = stix2.core.dict_to_stix2(custom_obj_1, version='2.1') + cust_obj_1 = stix2.parsing.dict_to_stix2(custom_obj_1, version='2.1') v = 'v21' - assert cust_obj_1.type in stix2.core.STIX2_OBJ_MAPS[v]['objects'] + assert cust_obj_1.type in stix2.parsing.STIX2_OBJ_MAPS[v]['objects'] assert cust_obj_1.spec_version == "2.1" @@ -1117,7 +1283,7 @@ def test_register_observable(): custom_obs = NewObservable3(property1="Test Observable") v = 'v21' - assert custom_obs.type in stix2.core.STIX2_OBJ_MAPS[v]['observables'] + assert custom_obs.type in stix2.parsing.STIX2_OBJ_MAPS[v]['observables'] def test_register_duplicate_observable(): @@ -1145,8 +1311,8 @@ def test_register_observable_custom_extension(): example = NewExtension2(property1="Hi there") v = 'v21' - assert 'domain-name' in stix2.core.STIX2_OBJ_MAPS[v]['observables'] - assert example._type in stix2.core.STIX2_OBJ_MAPS[v]['observable-extensions']['domain-name'] + assert 'domain-name' in stix2.parsing.STIX2_OBJ_MAPS[v]['observables'] + assert example._type in stix2.parsing.STIX2_OBJ_MAPS[v]['observable-extensions']['domain-name'] def test_register_duplicate_observable_extension(): diff --git a/stix2/test/v21/test_markings.py b/stix2/test/v21/test_markings.py index a2fca51..b0a0d09 100644 --- a/stix2/test/v21/test_markings.py +++ b/stix2/test/v21/test_markings.py @@ -277,14 +277,12 @@ def test_not_registered_marking_raises_exception(): def test_marking_wrong_type_construction(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): # Test passing wrong type for properties. @stix2.v21.CustomMarking('x-new-marking-type2', ("a", "b")) class NewObject3(object): pass - assert str(excinfo.value) == "Must supply a list, containing tuples. For example, [('property1', IntegerProperty())]" - def test_campaign_add_markings(): campaign = stix2.v21.Campaign( diff --git a/stix2/test/v21/test_core.py b/stix2/test/v21/test_parsing.py similarity index 83% rename from stix2/test/v21/test_core.py rename to stix2/test/v21/test_parsing.py index 78e492a..1d930e6 100644 --- a/stix2/test/v21/test_core.py +++ b/stix2/test/v21/test_parsing.py @@ -1,7 +1,7 @@ import pytest import stix2 -from stix2 import core, exceptions +from stix2 import exceptions, parsing BUNDLE = { "type": "bundle", @@ -48,7 +48,7 @@ BUNDLE = { def test_dict_to_stix2_bundle_with_version(): with pytest.raises(exceptions.InvalidValueError) as excinfo: - core.dict_to_stix2(BUNDLE, version='2.0') + parsing.dict_to_stix2(BUNDLE, version='2.0') msg = "Invalid value for Bundle 'objects': Spec version 2.0 bundles don't yet support containing objects of a different spec version." assert str(excinfo.value) == msg @@ -56,7 +56,7 @@ def test_dict_to_stix2_bundle_with_version(): def test_parse_observable_with_version(): observable = {"type": "file", "name": "foo.exe"} - obs_obj = core.parse_observable(observable, version='2.1') + obs_obj = parsing.parse_observable(observable, version='2.1') v = 'v21' assert v in str(obs_obj.__class__) @@ -65,25 +65,25 @@ def test_parse_observable_with_version(): @pytest.mark.xfail(reason="The default version is not 2.1", condition=stix2.DEFAULT_VERSION != "2.1") def test_parse_observable_with_no_version(): observable = {"type": "file", "name": "foo.exe"} - obs_obj = core.parse_observable(observable) + obs_obj = parsing.parse_observable(observable) v = 'v21' assert v in str(obs_obj.__class__) def test_register_marking_with_version(): - core._register_marking(stix2.v21.TLP_WHITE.__class__, version='2.1') + parsing._register_marking(stix2.v21.TLP_WHITE.__class__, version='2.1') v = 'v21' - assert stix2.v21.TLP_WHITE.definition._type in core.STIX2_OBJ_MAPS[v]['markings'] + assert stix2.v21.TLP_WHITE.definition._type in parsing.STIX2_OBJ_MAPS[v]['markings'] assert v in str(stix2.v21.TLP_WHITE.__class__) @pytest.mark.xfail(reason="The default version is not 2.1", condition=stix2.DEFAULT_VERSION != "2.1") def test_register_marking_with_no_version(): # Uses default version (2.0 in this case) - core._register_marking(stix2.v21.TLP_WHITE.__class__) + parsing._register_marking(stix2.v21.TLP_WHITE.__class__) v = 'v21' - assert stix2.v21.TLP_WHITE.definition._type in core.STIX2_OBJ_MAPS[v]['markings'] + assert stix2.v21.TLP_WHITE.definition._type in parsing.STIX2_OBJ_MAPS[v]['markings'] assert v in str(stix2.v21.TLP_WHITE.__class__) diff --git a/stix2/utils.py b/stix2/utils.py index 9b98d88..47e89a1 100644 --- a/stix2/utils.py +++ b/stix2/utils.py @@ -8,12 +8,13 @@ import copy import datetime as dt import enum import json +import re from dateutil import parser import pytz import six -import stix2.base +import stix2 from .exceptions import ( InvalidValueError, RevokeError, UnmodifiablePropertyError, @@ -27,8 +28,9 @@ NOW = object() # STIX object properties that cannot be modified STIX_UNMOD_PROPERTIES = ['created', 'created_by_ref', 'id', 'type'] -TYPE_REGEX = r'^\-?[a-z0-9]+(-[a-z0-9]+)*\-?$' -SCO21_EXT_REGEX = r'^\-?[a-z0-9]+(-[a-z0-9]+)*\-ext$' +TYPE_REGEX = re.compile(r'^\-?[a-z0-9]+(-[a-z0-9]+)*\-?$') +TYPE_21_REGEX = re.compile(r'^([a-z][a-z0-9]*)+(-[a-z0-9]+)*\-?$') +PREFIX_21_REGEX = re.compile(r'^[a-z].*') class Precision(enum.Enum): @@ -360,14 +362,12 @@ def find_property_index(obj, search_key, search_value): Returns: int: An index; -1 if the key and value aren't found """ - from .base import _STIXBase - # Special-case keys which are numbers-as-strings, e.g. for cyber-observable # mappings. Use the int value of the key as the index. if search_key.isdigit(): return int(search_key) - if isinstance(obj, _STIXBase): + if isinstance(obj, stix2.base._STIXBase): if search_key in obj and obj[search_key] == search_value: idx = _find(obj.object_properties(), search_key) else: diff --git a/stix2/v20/__init__.py b/stix2/v20/__init__.py index 4d0a98f..b77d46c 100644 --- a/stix2/v20/__init__.py +++ b/stix2/v20/__init__.py @@ -14,6 +14,9 @@ # flake8: noqa +from .base import ( + _DomainObject, _Extension, _Observable, _RelationshipObject, _STIXBase20, +) from .bundle import Bundle from .common import ( TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference, diff --git a/stix2/v20/base.py b/stix2/v20/base.py new file mode 100644 index 0000000..b5437ca --- /dev/null +++ b/stix2/v20/base.py @@ -0,0 +1,25 @@ +"""Base classes for STIX 2.0 type definitions.""" + +from ..base import ( + _DomainObject, _Extension, _Observable, _RelationshipObject, _STIXBase, +) + + +class _STIXBase20(_STIXBase): + pass + + +class _Observable(_Observable, _STIXBase20): + pass + + +class _Extension(_Extension, _STIXBase20): + pass + + +class _DomainObject(_DomainObject, _STIXBase20): + pass + + +class _RelationshipObject(_RelationshipObject, _STIXBase20): + pass diff --git a/stix2/v20/bundle.py b/stix2/v20/bundle.py index ffd70ea..25b948d 100644 --- a/stix2/v20/bundle.py +++ b/stix2/v20/bundle.py @@ -2,20 +2,20 @@ from collections import OrderedDict -from ..base import _STIXBase from ..properties import ( IDProperty, ListProperty, STIXObjectProperty, StringProperty, TypeProperty, ) +from .base import _STIXBase20 -class Bundle(_STIXBase): +class Bundle(_STIXBase20): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'bundle' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), # Not technically correct: STIX 2.0 spec doesn't say spec_version must # have this value, but it's all we support for now. diff --git a/stix2/v20/common.py b/stix2/v20/common.py index a1ffa60..a92f81d 100644 --- a/stix2/v20/common.py +++ b/stix2/v20/common.py @@ -5,7 +5,6 @@ import copy import six -from ..base import _STIXBase from ..custom import _custom_marking_builder from ..markings import _MarkingsMixin from ..markings.utils import check_tlp_marking @@ -14,6 +13,7 @@ from ..properties import ( SelectorProperty, StringProperty, TimestampProperty, TypeProperty, ) from ..utils import NOW, _get_dict +from .base import _STIXBase20 def _should_set_millisecond(cr, marking_type): @@ -31,7 +31,7 @@ def _should_set_millisecond(cr, marking_type): return False -class ExternalReference(_STIXBase): +class ExternalReference(_STIXBase20): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -49,7 +49,7 @@ class ExternalReference(_STIXBase): self._check_at_least_one_property(['description', 'external_id', 'url']) -class KillChainPhase(_STIXBase): +class KillChainPhase(_STIXBase20): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -60,7 +60,7 @@ class KillChainPhase(_STIXBase): ]) -class GranularMarking(_STIXBase): +class GranularMarking(_STIXBase20): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -71,7 +71,7 @@ class GranularMarking(_STIXBase): ]) -class TLPMarking(_STIXBase): +class TLPMarking(_STIXBase20): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -83,7 +83,7 @@ class TLPMarking(_STIXBase): ]) -class StatementMarking(_STIXBase): +class StatementMarking(_STIXBase20): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -113,14 +113,14 @@ class MarkingProperty(Property): raise ValueError("must be a Statement, TLP Marking or a registered marking.") -class MarkingDefinition(_STIXBase, _MarkingsMixin): +class MarkingDefinition(_STIXBase20, _MarkingsMixin): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'marking-definition' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW)), @@ -182,7 +182,7 @@ def CustomMarking(type='x-custom-marking', properties=None): """ def wrapper(cls): - return _custom_marking_builder(cls, type, properties, '2.0') + return _custom_marking_builder(cls, type, properties, '2.0', _STIXBase20) return wrapper diff --git a/stix2/v20/observables.py b/stix2/v20/observables.py index 81e2c48..3491c47 100644 --- a/stix2/v20/observables.py +++ b/stix2/v20/observables.py @@ -1,14 +1,13 @@ """STIX 2.0 Cyber Observable Objects. Embedded observable object types, such as Email MIME Component, which is -embedded in Email Message objects, inherit from ``_STIXBase`` instead of -Observable and do not have a ``_type`` attribute. +embedded in Email Message objects, inherit from ``_STIXBase20`` instead of +_Observable and do not have a ``_type`` attribute. """ from collections import OrderedDict import itertools -from ..base import _Extension, _Observable, _STIXBase from ..custom import _custom_extension_builder, _custom_observable_builder from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError from ..properties import ( @@ -17,6 +16,7 @@ from ..properties import ( HashesProperty, HexProperty, IntegerProperty, ListProperty, ObjectReferenceProperty, StringProperty, TimestampProperty, TypeProperty, ) +from .base import _Extension, _Observable, _STIXBase20 class Artifact(_Observable): @@ -26,7 +26,7 @@ class Artifact(_Observable): _type = 'artifact' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('mime_type', StringProperty()), ('payload_bin', BinaryProperty()), ('url', StringProperty()), @@ -47,7 +47,7 @@ class AutonomousSystem(_Observable): _type = 'autonomous-system' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('number', IntegerProperty(required=True)), ('name', StringProperty()), ('rir', StringProperty()), @@ -62,7 +62,7 @@ class Directory(_Observable): _type = 'directory' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('path', StringProperty(required=True)), ('path_enc', StringProperty()), # these are not the created/modified timestamps of the object itself @@ -81,7 +81,7 @@ class DomainName(_Observable): _type = 'domain-name' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('value', StringProperty(required=True)), ('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types=['ipv4-addr', 'ipv6-addr', 'domain-name']))), ('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), @@ -95,7 +95,7 @@ class EmailAddress(_Observable): _type = 'email-addr' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('value', StringProperty(required=True)), ('display_name', StringProperty()), ('belongs_to_ref', ObjectReferenceProperty(valid_types='user-account')), @@ -103,7 +103,7 @@ class EmailAddress(_Observable): ]) -class EmailMIMEComponent(_STIXBase): +class EmailMIMEComponent(_STIXBase20): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ # noqa @@ -127,7 +127,7 @@ class EmailMessage(_Observable): _type = 'email-message' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('is_multipart', BooleanProperty(required=True)), ('date', TimestampProperty()), ('content_type', StringProperty()), @@ -166,7 +166,7 @@ class ArchiveExt(_Extension): ]) -class AlternateDataStream(_STIXBase): +class AlternateDataStream(_STIXBase20): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ # noqa @@ -220,7 +220,7 @@ class RasterImageExt(_Extension): ]) -class WindowsPEOptionalHeaderType(_STIXBase): +class WindowsPEOptionalHeaderType(_STIXBase20): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ # noqa @@ -264,7 +264,7 @@ class WindowsPEOptionalHeaderType(_STIXBase): self._check_at_least_one_property() -class WindowsPESection(_STIXBase): +class WindowsPESection(_STIXBase20): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ # noqa @@ -306,7 +306,7 @@ class File(_Observable): _type = 'file' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('hashes', HashesProperty()), ('size', IntegerProperty()), ('name', StringProperty()), @@ -339,7 +339,7 @@ class IPv4Address(_Observable): _type = 'ipv4-addr' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('value', StringProperty(required=True)), ('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types='mac-addr'))), ('belongs_to_refs', ListProperty(ObjectReferenceProperty(valid_types='autonomous-system'))), @@ -354,7 +354,7 @@ class IPv6Address(_Observable): _type = 'ipv6-addr' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('value', StringProperty(required=True)), ('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types='mac-addr'))), ('belongs_to_refs', ListProperty(ObjectReferenceProperty(valid_types='autonomous-system'))), @@ -369,7 +369,7 @@ class MACAddress(_Observable): _type = 'mac-addr' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('value', StringProperty(required=True)), ('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ]) @@ -382,7 +382,7 @@ class Mutex(_Observable): _type = 'mutex' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('name', StringProperty(required=True)), ('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ]) @@ -483,7 +483,7 @@ class NetworkTraffic(_Observable): _type = 'network-traffic' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('start', TimestampProperty()), ('end', TimestampProperty()), ('is_active', BooleanProperty()), @@ -575,7 +575,7 @@ class Process(_Observable): _type = 'process' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('is_hidden', BooleanProperty()), ('pid', IntegerProperty()), ('name', StringProperty()), @@ -615,7 +615,7 @@ class Software(_Observable): _type = 'software' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('name', StringProperty(required=True)), ('cpe', StringProperty()), ('languages', ListProperty(StringProperty)), @@ -632,7 +632,7 @@ class URL(_Observable): _type = 'url' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('value', StringProperty(required=True)), ('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ]) @@ -659,7 +659,7 @@ class UserAccount(_Observable): _type = 'user-account' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('user_id', StringProperty(required=True)), ('account_login', StringProperty()), ('account_type', StringProperty()), # open vocab @@ -677,7 +677,7 @@ class UserAccount(_Observable): ]) -class WindowsRegistryValueType(_STIXBase): +class WindowsRegistryValueType(_STIXBase20): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ # noqa @@ -713,7 +713,7 @@ class WindowsRegistryKey(_Observable): _type = 'windows-registry-key' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('key', StringProperty(required=True)), ('values', ListProperty(EmbeddedObjectProperty(type=WindowsRegistryValueType))), # this is not the modified timestamps of the object itself @@ -724,7 +724,7 @@ class WindowsRegistryKey(_Observable): ]) -class X509V3ExtenstionsType(_STIXBase): +class X509V3ExtenstionsType(_STIXBase20): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ # noqa @@ -757,7 +757,7 @@ class X509Certificate(_Observable): _type = 'x509-certificate' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('is_self_signed', BooleanProperty()), ('hashes', HashesProperty()), ('version', StringProperty()), @@ -791,11 +791,11 @@ def CustomObservable(type='x-custom-observable', properties=None): """ def wrapper(cls): _properties = list(itertools.chain.from_iterable([ - [('type', TypeProperty(type))], + [('type', TypeProperty(type, spec_version='2.0'))], properties, [('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=type))], ])) - return _custom_observable_builder(cls, type, _properties, '2.0') + return _custom_observable_builder(cls, type, _properties, '2.0', _Observable) return wrapper @@ -803,5 +803,5 @@ def CustomExtension(observable=None, type='x-custom-observable-ext', properties= """Decorator for custom extensions to STIX Cyber Observables. """ def wrapper(cls): - return _custom_extension_builder(cls, observable, type, properties, '2.0') + return _custom_extension_builder(cls, observable, type, properties, '2.0', _Extension) return wrapper diff --git a/stix2/v20/sdo.py b/stix2/v20/sdo.py index 430bfc0..8cbd94b 100644 --- a/stix2/v20/sdo.py +++ b/stix2/v20/sdo.py @@ -5,7 +5,6 @@ import itertools from stix2patterns.validator import run_validator -from ..core import STIXDomainObject from ..custom import _custom_object_builder from ..exceptions import InvalidValueError from ..properties import ( @@ -14,17 +13,18 @@ from ..properties import ( TimestampProperty, TypeProperty, ) from ..utils import NOW +from .base import _DomainObject from .common import ExternalReference, GranularMarking, KillChainPhase -class AttackPattern(STIXDomainObject): +class AttackPattern(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'attack-pattern' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -40,14 +40,14 @@ class AttackPattern(STIXDomainObject): ]) -class Campaign(STIXDomainObject): +class Campaign(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'campaign' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -66,14 +66,14 @@ class Campaign(STIXDomainObject): ]) -class CourseOfAction(STIXDomainObject): +class CourseOfAction(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'course-of-action' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -88,14 +88,14 @@ class CourseOfAction(STIXDomainObject): ]) -class Identity(STIXDomainObject): +class Identity(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'identity' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -113,14 +113,14 @@ class Identity(STIXDomainObject): ]) -class Indicator(STIXDomainObject): +class Indicator(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'indicator' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -144,14 +144,14 @@ class Indicator(STIXDomainObject): raise InvalidValueError(self.__class__, 'pattern', str(errors[0])) -class IntrusionSet(STIXDomainObject): +class IntrusionSet(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'intrusion-set' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -173,14 +173,14 @@ class IntrusionSet(STIXDomainObject): ]) -class Malware(STIXDomainObject): +class Malware(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'malware' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -196,14 +196,14 @@ class Malware(STIXDomainObject): ]) -class ObservedData(STIXDomainObject): +class ObservedData(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'observed-data' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -226,14 +226,14 @@ class ObservedData(STIXDomainObject): super(ObservedData, self).__init__(*args, **kwargs) -class Report(STIXDomainObject): +class Report(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'report' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -250,14 +250,14 @@ class Report(STIXDomainObject): ]) -class ThreatActor(STIXDomainObject): +class ThreatActor(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'threat-actor' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -280,14 +280,14 @@ class ThreatActor(STIXDomainObject): ]) -class Tool(STIXDomainObject): +class Tool(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'tool' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -304,14 +304,14 @@ class Tool(STIXDomainObject): ]) -class Vulnerability(STIXDomainObject): +class Vulnerability(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'vulnerability' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -358,7 +358,7 @@ def CustomObject(type='x-custom-type', properties=None): def wrapper(cls): _properties = list(itertools.chain.from_iterable([ [ - ('type', TypeProperty(type)), + ('type', TypeProperty(type, spec_version='2.0')), ('id', IDProperty(type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -374,5 +374,5 @@ def CustomObject(type='x-custom-type', properties=None): ], sorted([x for x in properties if x[0].startswith('x_')], key=lambda x: x[0]), ])) - return _custom_object_builder(cls, type, _properties, '2.0') + return _custom_object_builder(cls, type, _properties, '2.0', _DomainObject) return wrapper diff --git a/stix2/v20/sro.py b/stix2/v20/sro.py index b85eb68..1372a5e 100644 --- a/stix2/v20/sro.py +++ b/stix2/v20/sro.py @@ -2,16 +2,16 @@ from collections import OrderedDict -from ..core import STIXRelationshipObject from ..properties import ( BooleanProperty, IDProperty, IntegerProperty, ListProperty, ReferenceProperty, StringProperty, TimestampProperty, TypeProperty, ) from ..utils import NOW +from .base import _RelationshipObject from .common import ExternalReference, GranularMarking -class Relationship(STIXRelationshipObject): +class Relationship(_RelationshipObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -20,7 +20,7 @@ class Relationship(STIXRelationshipObject): _type = 'relationship' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), @@ -52,14 +52,14 @@ class Relationship(STIXRelationshipObject): super(Relationship, self).__init__(**kwargs) -class Sighting(STIXRelationshipObject): +class Sighting(_RelationshipObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ _type = 'sighting' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.0')), ('id', IDProperty(_type, spec_version='2.0')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), diff --git a/stix2/v21/__init__.py b/stix2/v21/__init__.py index b2451d2..eea61dd 100644 --- a/stix2/v21/__init__.py +++ b/stix2/v21/__init__.py @@ -14,6 +14,9 @@ # flake8: noqa +from .base import ( + _DomainObject, _Extension, _Observable, _RelationshipObject, _STIXBase21, +) from .bundle import Bundle from .common import ( TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference, diff --git a/stix2/v21/base.py b/stix2/v21/base.py new file mode 100644 index 0000000..8b5a5f1 --- /dev/null +++ b/stix2/v21/base.py @@ -0,0 +1,25 @@ +"""Base classes for STIX 2.1 type definitions.""" + +from ..base import ( + _DomainObject, _Extension, _Observable, _RelationshipObject, _STIXBase, +) + + +class _STIXBase21(_STIXBase): + pass + + +class _Observable(_Observable, _STIXBase21): + pass + + +class _Extension(_Extension, _STIXBase21): + pass + + +class _DomainObject(_DomainObject, _STIXBase21): + pass + + +class _RelationshipObject(_RelationshipObject, _STIXBase21): + pass diff --git a/stix2/v21/bundle.py b/stix2/v21/bundle.py index 574ab48..a1ca054 100644 --- a/stix2/v21/bundle.py +++ b/stix2/v21/bundle.py @@ -2,20 +2,20 @@ from collections import OrderedDict -from ..base import _STIXBase from ..properties import ( IDProperty, ListProperty, STIXObjectProperty, TypeProperty, ) +from .base import _STIXBase21 -class Bundle(_STIXBase): +class Bundle(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'bundle' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('objects', ListProperty(STIXObjectProperty(spec_version='2.1'))), ]) diff --git a/stix2/v21/common.py b/stix2/v21/common.py index 9e7929b..1f228af 100644 --- a/stix2/v21/common.py +++ b/stix2/v21/common.py @@ -2,7 +2,6 @@ from collections import OrderedDict -from ..base import _STIXBase from ..custom import _custom_marking_builder from ..exceptions import InvalidValueError from ..markings import _MarkingsMixin @@ -13,9 +12,10 @@ from ..properties import ( SelectorProperty, StringProperty, TimestampProperty, TypeProperty, ) from ..utils import NOW, _get_dict +from .base import _STIXBase21 -class ExternalReference(_STIXBase): +class ExternalReference(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ @@ -49,7 +49,7 @@ class ExternalReference(_STIXBase): ) -class KillChainPhase(_STIXBase): +class KillChainPhase(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ @@ -60,7 +60,7 @@ class KillChainPhase(_STIXBase): ]) -class GranularMarking(_STIXBase): +class GranularMarking(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ @@ -76,14 +76,14 @@ class GranularMarking(_STIXBase): self._check_at_least_one_property(['lang', 'marking_ref']) -class LanguageContent(_STIXBase): +class LanguageContent(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'language-content' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -103,7 +103,7 @@ class LanguageContent(_STIXBase): ]) -class TLPMarking(_STIXBase): +class TLPMarking(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ @@ -114,7 +114,7 @@ class TLPMarking(_STIXBase): ]) -class StatementMarking(_STIXBase): +class StatementMarking(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ @@ -144,14 +144,14 @@ class MarkingProperty(Property): raise ValueError("must be a Statement, TLP Marking or a registered marking.") -class MarkingDefinition(_STIXBase, _MarkingsMixin): +class MarkingDefinition(_STIXBase21, _MarkingsMixin): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'marking-definition' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type)), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -208,7 +208,7 @@ def CustomMarking(type='x-custom-marking', properties=None): """ def wrapper(cls): - return _custom_marking_builder(cls, type, properties, '2.1') + return _custom_marking_builder(cls, type, properties, '2.1', _STIXBase21) return wrapper diff --git a/stix2/v21/observables.py b/stix2/v21/observables.py index 89de0fc..d73c1cf 100644 --- a/stix2/v21/observables.py +++ b/stix2/v21/observables.py @@ -1,14 +1,13 @@ """STIX 2.1 Cyber Observable Objects. Embedded observable object types, such as Email MIME Component, which is -embedded in Email Message objects, inherit from ``_STIXBase`` instead of -Observable and do not have a ``_type`` attribute. +embedded in Email Message objects, inherit from ``_STIXBase21`` instead of +_Observable and do not have a ``_type`` attribute. """ from collections import OrderedDict import itertools -from ..base import _Extension, _Observable, _STIXBase from ..custom import _custom_extension_builder, _custom_observable_builder from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError from ..properties import ( @@ -18,6 +17,7 @@ from ..properties import ( ObjectReferenceProperty, ReferenceProperty, StringProperty, TimestampProperty, TypeProperty, ) +from .base import _Extension, _Observable, _STIXBase21 from .common import GranularMarking @@ -28,7 +28,7 @@ class Artifact(_Observable): _type = 'artifact' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('mime_type', StringProperty()), ('payload_bin', BinaryProperty()), @@ -57,7 +57,7 @@ class AutonomousSystem(_Observable): _type = 'autonomous-system' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('number', IntegerProperty(required=True)), ('name', StringProperty()), @@ -78,7 +78,7 @@ class Directory(_Observable): _type = 'directory' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('path', StringProperty(required=True)), ('path_enc', StringProperty()), @@ -103,7 +103,7 @@ class DomainName(_Observable): _type = 'domain-name' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('value', StringProperty(required=True)), ('resolves_to_refs', ListProperty(ReferenceProperty(valid_types=['ipv4-addr', 'ipv6-addr', 'domain-name'], spec_version='2.1'))), @@ -123,7 +123,7 @@ class EmailAddress(_Observable): _type = 'email-addr' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('value', StringProperty(required=True)), ('display_name', StringProperty()), @@ -137,7 +137,7 @@ class EmailAddress(_Observable): _id_contributing_properties = ["value"] -class EmailMIMEComponent(_STIXBase): +class EmailMIMEComponent(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ @@ -161,7 +161,7 @@ class EmailMessage(_Observable): _type = 'email-message' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('is_multipart', BooleanProperty(required=True)), ('date', TimestampProperty()), @@ -206,7 +206,7 @@ class ArchiveExt(_Extension): ]) -class AlternateDataStream(_STIXBase): +class AlternateDataStream(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ @@ -259,7 +259,7 @@ class RasterImageExt(_Extension): ]) -class WindowsPEOptionalHeaderType(_STIXBase): +class WindowsPEOptionalHeaderType(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ @@ -303,7 +303,7 @@ class WindowsPEOptionalHeaderType(_STIXBase): self._check_at_least_one_property() -class WindowsPESection(_STIXBase): +class WindowsPESection(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ @@ -345,7 +345,7 @@ class File(_Observable): _type = 'file' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('hashes', HashesProperty(spec_version='2.1')), ('size', IntegerProperty(min=0)), @@ -380,7 +380,7 @@ class IPv4Address(_Observable): _type = 'ipv4-addr' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('value', StringProperty(required=True)), ('resolves_to_refs', ListProperty(ReferenceProperty(valid_types='mac-addr', spec_version='2.1'))), @@ -401,7 +401,7 @@ class IPv6Address(_Observable): _type = 'ipv6-addr' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('value', StringProperty(required=True)), ('resolves_to_refs', ListProperty(ReferenceProperty(valid_types='mac-addr', spec_version='2.1'))), @@ -422,7 +422,7 @@ class MACAddress(_Observable): _type = 'mac-addr' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('value', StringProperty(required=True)), ('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), @@ -441,7 +441,7 @@ class Mutex(_Observable): _type = 'mutex' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('name', StringProperty(required=True)), ('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), @@ -562,7 +562,7 @@ class NetworkTraffic(_Observable): _type = 'network-traffic' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('start', TimestampProperty()), ('end', TimestampProperty()), @@ -684,7 +684,7 @@ class Process(_Observable): _type = 'process' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('is_hidden', BooleanProperty()), ('pid', IntegerProperty()), @@ -728,7 +728,7 @@ class Software(_Observable): _type = 'software' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('name', StringProperty(required=True)), ('cpe', StringProperty()), @@ -752,7 +752,7 @@ class URL(_Observable): _type = 'url' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('value', StringProperty(required=True)), ('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), @@ -785,7 +785,7 @@ class UserAccount(_Observable): _type = 'user-account' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('user_id', StringProperty()), ('credential', StringProperty()), @@ -810,7 +810,7 @@ class UserAccount(_Observable): _id_contributing_properties = ["account_type", "user_id", "account_login"] -class WindowsRegistryValueType(_STIXBase): +class WindowsRegistryValueType(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ @@ -846,7 +846,7 @@ class WindowsRegistryKey(_Observable): _type = 'windows-registry-key' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('key', StringProperty()), ('values', ListProperty(EmbeddedObjectProperty(type=WindowsRegistryValueType))), @@ -863,7 +863,7 @@ class WindowsRegistryKey(_Observable): _id_contributing_properties = ["key", "values"] -class X509V3ExtenstionsType(_STIXBase): +class X509V3ExtenstionsType(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ @@ -896,7 +896,7 @@ class X509Certificate(_Observable): _type = 'x509-certificate' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('is_self_signed', BooleanProperty()), ('hashes', HashesProperty(spec_version='2.1')), @@ -948,12 +948,12 @@ def CustomObservable(type='x-custom-observable', properties=None, id_contrib_pro """ def wrapper(cls): _properties = list(itertools.chain.from_iterable([ - [('type', TypeProperty(type))], + [('type', TypeProperty(type, spec_version='2.1'))], [('id', IDProperty(type, spec_version='2.1'))], properties, [('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=type))], ])) - return _custom_observable_builder(cls, type, _properties, '2.1', id_contrib_props) + return _custom_observable_builder(cls, type, _properties, '2.1', _Observable, id_contrib_props) return wrapper @@ -961,5 +961,5 @@ def CustomExtension(observable=None, type='x-custom-observable-ext', properties= """Decorator for custom extensions to STIX Cyber Observables. """ def wrapper(cls): - return _custom_extension_builder(cls, observable, type, properties, '2.1') + return _custom_extension_builder(cls, observable, type, properties, '2.1', _Extension) return wrapper diff --git a/stix2/v21/sdo.py b/stix2/v21/sdo.py index 1709cb0..6961423 100644 --- a/stix2/v21/sdo.py +++ b/stix2/v21/sdo.py @@ -7,7 +7,6 @@ import warnings from six.moves.urllib.parse import quote_plus from stix2patterns.validator import run_validator -from ..core import STIXDomainObject from ..custom import _custom_object_builder from ..exceptions import ( InvalidValueError, PropertyPresenceError, STIXDeprecationWarning, @@ -18,17 +17,18 @@ from ..properties import ( StringProperty, TimestampProperty, TypeProperty, ) from ..utils import NOW +from .base import _DomainObject from .common import ExternalReference, GranularMarking, KillChainPhase -class AttackPattern(STIXDomainObject): +class AttackPattern(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'attack-pattern' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -48,14 +48,14 @@ class AttackPattern(STIXDomainObject): ]) -class Campaign(STIXDomainObject): +class Campaign(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'campaign' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -87,14 +87,14 @@ class Campaign(STIXDomainObject): raise ValueError(msg.format(self)) -class CourseOfAction(STIXDomainObject): +class CourseOfAction(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'course-of-action' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -112,14 +112,14 @@ class CourseOfAction(STIXDomainObject): ]) -class Grouping(STIXDomainObject): +class Grouping(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'grouping' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')), @@ -139,14 +139,14 @@ class Grouping(STIXDomainObject): ]) -class Identity(STIXDomainObject): +class Identity(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'identity' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -168,14 +168,14 @@ class Identity(STIXDomainObject): ]) -class Indicator(STIXDomainObject): +class Indicator(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'indicator' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -204,7 +204,7 @@ class Indicator(STIXDomainObject): if kwargs.get('pattern') and kwargs.get('pattern_type') == 'stix' and not kwargs.get('pattern_version'): kwargs['pattern_version'] = '2.1' - super(STIXDomainObject, self).__init__(*args, **kwargs) + super(_DomainObject, self).__init__(*args, **kwargs) def _check_object_constraints(self): super(Indicator, self)._check_object_constraints() @@ -227,14 +227,14 @@ class Indicator(STIXDomainObject): raise InvalidValueError(self.__class__, 'pattern', str(errors[0])) -class Infrastructure(STIXDomainObject): +class Infrastructure(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'infrastructure' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -267,14 +267,14 @@ class Infrastructure(STIXDomainObject): raise ValueError(msg.format(self)) -class IntrusionSet(STIXDomainObject): +class IntrusionSet(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'intrusion-set' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -309,14 +309,14 @@ class IntrusionSet(STIXDomainObject): raise ValueError(msg.format(self)) -class Location(STIXDomainObject): +class Location(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'location' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -416,14 +416,14 @@ class Location(STIXDomainObject): return final_url -class Malware(STIXDomainObject): +class Malware(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'malware' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -468,14 +468,14 @@ class Malware(STIXDomainObject): ) -class MalwareAnalysis(STIXDomainObject): +class MalwareAnalysis(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'malware-analysis' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')), @@ -512,14 +512,14 @@ class MalwareAnalysis(STIXDomainObject): self._check_at_least_one_property(["result", "analysis_sco_refs"]) -class Note(STIXDomainObject): +class Note(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'note' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -539,14 +539,14 @@ class Note(STIXDomainObject): ]) -class ObservedData(STIXDomainObject): +class ObservedData(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'observed-data' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -594,14 +594,14 @@ class ObservedData(STIXDomainObject): ) -class Opinion(STIXDomainObject): +class Opinion(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'opinion' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -631,14 +631,14 @@ class Opinion(STIXDomainObject): ]) -class Report(STIXDomainObject): +class Report(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'report' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -659,14 +659,14 @@ class Report(STIXDomainObject): ]) -class ThreatActor(STIXDomainObject): +class ThreatActor(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'threat-actor' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -705,14 +705,14 @@ class ThreatActor(STIXDomainObject): raise ValueError(msg.format(self)) -class Tool(STIXDomainObject): +class Tool(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'tool' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -734,14 +734,14 @@ class Tool(STIXDomainObject): ]) -class Vulnerability(STIXDomainObject): +class Vulnerability(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'vulnerability' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -791,7 +791,7 @@ def CustomObject(type='x-custom-type', properties=None): def wrapper(cls): _properties = list(itertools.chain.from_iterable([ [ - ('type', TypeProperty(type)), + ('type', TypeProperty(type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -810,6 +810,6 @@ def CustomObject(type='x-custom-type', properties=None): ], sorted([x for x in properties if x[0].startswith('x_')], key=lambda x: x[0]), ])) - return _custom_object_builder(cls, type, _properties, '2.1') + return _custom_object_builder(cls, type, _properties, '2.1', _DomainObject) return wrapper diff --git a/stix2/v21/sro.py b/stix2/v21/sro.py index 88ea228..d287373 100644 --- a/stix2/v21/sro.py +++ b/stix2/v21/sro.py @@ -2,16 +2,16 @@ from collections import OrderedDict -from ..core import STIXRelationshipObject from ..properties import ( BooleanProperty, IDProperty, IntegerProperty, ListProperty, ReferenceProperty, StringProperty, TimestampProperty, TypeProperty, ) from ..utils import NOW +from .base import _RelationshipObject from .common import ExternalReference, GranularMarking -class Relationship(STIXRelationshipObject): +class Relationship(_RelationshipObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ @@ -20,7 +20,7 @@ class Relationship(STIXRelationshipObject): _type = 'relationship' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), @@ -67,14 +67,14 @@ class Relationship(STIXRelationshipObject): raise ValueError(msg.format(self)) -class Sighting(STIXRelationshipObject): +class Sighting(_RelationshipObject): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ _type = 'sighting' _properties = OrderedDict([ - ('type', TypeProperty(_type)), + ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')), ('id', IDProperty(_type, spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),