From 01ba190525639791389a1698fab3e478f233d84b Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Fri, 27 Mar 2020 02:40:42 -0400 Subject: [PATCH] Reorganize bases, use isinstance to check version Renamed STIXDomainObject -> _DomainObject. Renamed STIXRelationshipObject -> _RelationshipObject. --- stix2/base.py | 24 ++++++++++++++++-------- stix2/core.py | 11 +---------- stix2/properties.py | 2 +- stix2/v20/__init__.py | 3 +++ stix2/v20/base.py | 11 ++++++----- stix2/v20/sdo.py | 28 ++++++++++++++-------------- stix2/v20/sro.py | 6 +++--- stix2/v21/__init__.py | 3 +++ stix2/v21/base.py | 11 ++++++----- stix2/v21/sdo.py | 42 +++++++++++++++++++++--------------------- stix2/v21/sro.py | 6 +++--- 11 files changed, 77 insertions(+), 70 deletions(-) diff --git a/stix2/base.py b/stix2/base.py index 5af3607..a1229ca 100644 --- a/stix2/base.py +++ b/stix2/base.py @@ -8,6 +8,7 @@ import uuid import simplejson as json import six +import stix2 from stix2.canonicalization.Canonicalize import canonicalize from .exceptions import ( @@ -15,6 +16,7 @@ from .exceptions import ( ImmutableError, InvalidObjRefError, InvalidValueError, MissingPropertiesError, MutuallyExclusivePropertiesError, ) +from .markings import _MarkingsMixin from .markings.utils import validate from .utils import ( NOW, PREFIX_21_REGEX, find_property_index, format_datetime, get_timestamp, @@ -160,17 +162,15 @@ 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) - else: - # because allow_custom is true, any extra kwargs are custom - extra_kwargs = list(set(kwargs) - set(self._properties)) + 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 self._spec_version == "2.1": + 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: @@ -321,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/core.py b/stix2/core.py index 055a4a6..7dedc15 100644 --- a/stix2/core.py +++ b/stix2/core.py @@ -7,9 +7,8 @@ import re import stix2 -from .base import _Observable, _STIXBase +from .base import _Observable from .exceptions import ParseError -from .markings import _MarkingsMixin from .utils import ( EXT_21_REGEX, PREFIX_21_REGEX, TYPE_21_REGEX, TYPE_REGEX, _get_dict, ) @@ -17,14 +16,6 @@ from .utils import ( 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. diff --git a/stix2/properties.py b/stix2/properties.py index b013b7e..e02f96b 100644 --- a/stix2/properties.py +++ b/stix2/properties.py @@ -639,7 +639,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/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 index e32069a..b5437ca 100644 --- a/stix2/v20/base.py +++ b/stix2/v20/base.py @@ -1,11 +1,12 @@ """Base classes for STIX 2.0 type definitions.""" -from ..base import _Extension, _Observable, _STIXBase -from ..core import STIXDomainObject, STIXRelationshipObject +from ..base import ( + _DomainObject, _Extension, _Observable, _RelationshipObject, _STIXBase, +) class _STIXBase20(_STIXBase): - _spec_version = "2.0" + pass class _Observable(_Observable, _STIXBase20): @@ -16,9 +17,9 @@ class _Extension(_Extension, _STIXBase20): pass -class STIXDomainObject(STIXDomainObject, _STIXBase20): +class _DomainObject(_DomainObject, _STIXBase20): pass -class STIXRelationshipObject(STIXRelationshipObject, _STIXBase20): +class _RelationshipObject(_RelationshipObject, _STIXBase20): pass diff --git a/stix2/v20/sdo.py b/stix2/v20/sdo.py index b083e42..cb5ba04 100644 --- a/stix2/v20/sdo.py +++ b/stix2/v20/sdo.py @@ -13,11 +13,11 @@ from ..properties import ( TimestampProperty, TypeProperty, ) from ..utils import NOW -from .base import STIXDomainObject +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 `__. """ @@ -40,7 +40,7 @@ class AttackPattern(STIXDomainObject): ]) -class Campaign(STIXDomainObject): +class Campaign(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -66,7 +66,7 @@ class Campaign(STIXDomainObject): ]) -class CourseOfAction(STIXDomainObject): +class CourseOfAction(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -88,7 +88,7 @@ class CourseOfAction(STIXDomainObject): ]) -class Identity(STIXDomainObject): +class Identity(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -113,7 +113,7 @@ class Identity(STIXDomainObject): ]) -class Indicator(STIXDomainObject): +class Indicator(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -144,7 +144,7 @@ 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 `__. """ @@ -173,7 +173,7 @@ class IntrusionSet(STIXDomainObject): ]) -class Malware(STIXDomainObject): +class Malware(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -196,7 +196,7 @@ class Malware(STIXDomainObject): ]) -class ObservedData(STIXDomainObject): +class ObservedData(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -226,7 +226,7 @@ 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 `__. """ @@ -250,7 +250,7 @@ class Report(STIXDomainObject): ]) -class ThreatActor(STIXDomainObject): +class ThreatActor(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -280,7 +280,7 @@ class ThreatActor(STIXDomainObject): ]) -class Tool(STIXDomainObject): +class Tool(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -304,7 +304,7 @@ class Tool(STIXDomainObject): ]) -class Vulnerability(STIXDomainObject): +class Vulnerability(_DomainObject): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. """ @@ -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', STIXDomainObject) + 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 0a07969..b7d1ad3 100644 --- a/stix2/v20/sro.py +++ b/stix2/v20/sro.py @@ -7,11 +7,11 @@ from ..properties import ( ReferenceProperty, StringProperty, TimestampProperty, TypeProperty, ) from ..utils import NOW -from .base import STIXRelationshipObject +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 `__. """ @@ -52,7 +52,7 @@ 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 `__. """ 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 index bfe1d5e..8b5a5f1 100644 --- a/stix2/v21/base.py +++ b/stix2/v21/base.py @@ -1,11 +1,12 @@ """Base classes for STIX 2.1 type definitions.""" -from ..base import _Extension, _Observable, _STIXBase -from ..core import STIXDomainObject, STIXRelationshipObject +from ..base import ( + _DomainObject, _Extension, _Observable, _RelationshipObject, _STIXBase, +) class _STIXBase21(_STIXBase): - _spec_version = "2.1" + pass class _Observable(_Observable, _STIXBase21): @@ -16,9 +17,9 @@ class _Extension(_Extension, _STIXBase21): pass -class STIXDomainObject(STIXDomainObject, _STIXBase21): +class _DomainObject(_DomainObject, _STIXBase21): pass -class STIXRelationshipObject(STIXRelationshipObject, _STIXBase21): +class _RelationshipObject(_RelationshipObject, _STIXBase21): pass diff --git a/stix2/v21/sdo.py b/stix2/v21/sdo.py index 42c58e4..1e9633e 100644 --- a/stix2/v21/sdo.py +++ b/stix2/v21/sdo.py @@ -17,11 +17,11 @@ from ..properties import ( StringProperty, TimestampProperty, TypeProperty, ) from ..utils import NOW -from .base import STIXDomainObject +from .base import _DomainObject from .common import ExternalReference, GranularMarking, KillChainPhase -class AttackPattern(STIXDomainObject): +class AttackPattern(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -49,7 +49,7 @@ class AttackPattern(STIXDomainObject): ]) -class Campaign(STIXDomainObject): +class Campaign(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -89,7 +89,7 @@ class Campaign(STIXDomainObject): raise ValueError(msg.format(self)) -class CourseOfAction(STIXDomainObject): +class CourseOfAction(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -115,7 +115,7 @@ class CourseOfAction(STIXDomainObject): ]) -class Grouping(STIXDomainObject): +class Grouping(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -143,7 +143,7 @@ class Grouping(STIXDomainObject): ]) -class Identity(STIXDomainObject): +class Identity(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -173,7 +173,7 @@ class Identity(STIXDomainObject): ]) -class Indicator(STIXDomainObject): +class Indicator(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -210,7 +210,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() @@ -233,7 +233,7 @@ class Indicator(STIXDomainObject): raise InvalidValueError(self.__class__, 'pattern', str(errors[0])) -class Infrastructure(STIXDomainObject): +class Infrastructure(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -274,7 +274,7 @@ class Infrastructure(STIXDomainObject): raise ValueError(msg.format(self)) -class IntrusionSet(STIXDomainObject): +class IntrusionSet(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -317,7 +317,7 @@ class IntrusionSet(STIXDomainObject): raise ValueError(msg.format(self)) -class Location(STIXDomainObject): +class Location(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -425,7 +425,7 @@ class Location(STIXDomainObject): return final_url -class Malware(STIXDomainObject): +class Malware(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -478,7 +478,7 @@ class Malware(STIXDomainObject): ) -class MalwareAnalysis(STIXDomainObject): +class MalwareAnalysis(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -523,7 +523,7 @@ class MalwareAnalysis(STIXDomainObject): self._check_at_least_one_property(["result", "analysis_sco_refs"]) -class Note(STIXDomainObject): +class Note(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -551,7 +551,7 @@ class Note(STIXDomainObject): ]) -class ObservedData(STIXDomainObject): +class ObservedData(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -607,7 +607,7 @@ class ObservedData(STIXDomainObject): ) -class Opinion(STIXDomainObject): +class Opinion(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -645,7 +645,7 @@ class Opinion(STIXDomainObject): ]) -class Report(STIXDomainObject): +class Report(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -674,7 +674,7 @@ class Report(STIXDomainObject): ]) -class ThreatActor(STIXDomainObject): +class ThreatActor(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -721,7 +721,7 @@ class ThreatActor(STIXDomainObject): raise ValueError(msg.format(self)) -class Tool(STIXDomainObject): +class Tool(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -751,7 +751,7 @@ class Tool(STIXDomainObject): ]) -class Vulnerability(STIXDomainObject): +class Vulnerability(_DomainObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -828,6 +828,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', STIXDomainObject) + 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 91b8b80..3ffdd77 100644 --- a/stix2/v21/sro.py +++ b/stix2/v21/sro.py @@ -7,11 +7,11 @@ from ..properties import ( ReferenceProperty, StringProperty, TimestampProperty, TypeProperty, ) from ..utils import NOW -from .base import STIXRelationshipObject +from .base import _RelationshipObject from .common import ExternalReference, GranularMarking -class Relationship(STIXRelationshipObject): +class Relationship(_RelationshipObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. @@ -68,7 +68,7 @@ class Relationship(STIXRelationshipObject): raise ValueError(msg.format(self)) -class Sighting(STIXRelationshipObject): +class Sighting(_RelationshipObject): # TODO: Add link """For more detailed information on this object's properties, see `the STIX 2.1 specification `__.