From 023603d86f281c7fb9b83c59a0e13d21f089a174 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Tue, 10 Jul 2018 15:22:21 -0400 Subject: [PATCH] Remove duplicate code from 'sdo.py', removed STIXDomainObject Apply proper 'spec_version' constraints to v21 objects --- stix2/v20/sdo.py | 84 ++++++++++++++---------------------------- stix2/v21/sdo.py | 95 +++++++++++++++++------------------------------- 2 files changed, 60 insertions(+), 119 deletions(-) diff --git a/stix2/v20/sdo.py b/stix2/v20/sdo.py index 142cb4f..5a99c16 100644 --- a/stix2/v20/sdo.py +++ b/stix2/v20/sdo.py @@ -2,21 +2,16 @@ """ from collections import OrderedDict -import re +import itertools -from ..base import _STIXBase -from ..core import _register_type -from ..markings import _MarkingsMixin -from ..utils import NOW, TYPE_REGEX +from ..core import STIXDomainObject +from ..custom import custom_object_builder +from ..properties import (BooleanProperty, IDProperty, IntegerProperty, + ListProperty, ObservableProperty, PatternProperty, + ReferenceProperty, StringProperty, TimestampProperty, + TypeProperty) +from ..utils import NOW from .common import ExternalReference, GranularMarking, KillChainPhase -from .observables import ObservableProperty -from .properties import (BooleanProperty, IDProperty, IntegerProperty, - ListProperty, PatternProperty, ReferenceProperty, - StringProperty, TimestampProperty, TypeProperty) - - -class STIXDomainObject(_STIXBase, _MarkingsMixin): - pass class AttackPattern(STIXDomainObject): @@ -327,6 +322,8 @@ def CustomObject(type='x-custom-type', properties=None): """Custom STIX Object type decorator. Example: + >>> from stix2.v20 import CustomObject + >>> from stix2.properties import IntegerProperty, StringProperty >>> @CustomObject('x-type-name', [ ... ('property1', StringProperty(required=True)), ... ('property2', IntegerProperty()), @@ -338,6 +335,8 @@ def CustomObject(type='x-custom-type', properties=None): type. Don't call ``super().__init__()`` though - doing so will cause an error. Example: + >>> from stix2.v20 import CustomObject + >>> from stix2.properties import IntegerProperty, StringProperty >>> @CustomObject('x-type-name', [ ... ('property1', StringProperty(required=True)), ... ('property2', IntegerProperty()), @@ -346,56 +345,27 @@ def CustomObject(type='x-custom-type', properties=None): ... def __init__(self, property2=None, **kwargs): ... if property2 and property2 < 10: ... raise ValueError("'property2' is too small.") + """ - - def custom_builder(cls): - - class _Custom(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) - - _type = type - _properties = OrderedDict([ - ('type', TypeProperty(_type)), - ('id', IDProperty(_type)), + def wrapper(cls): + _properties = list(itertools.chain.from_iterable([ + [ + ('type', TypeProperty(type)), + ('id', IDProperty(type)), ('created_by_ref', ReferenceProperty(type='identity')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), - ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')), - ]) - - if not properties or not isinstance(properties, list): - raise ValueError("Must supply a list, containing tuples. For example, [('property1', IntegerProperty())]") - - _properties.update([x for x in properties if not x[0].startswith('x_')]) - - # This is to follow the general properties structure. - _properties.update([ + ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')) + ], + [x for x in properties if not x[0].startswith('x_')], + [ ('revoked', BooleanProperty(default=lambda: False)), ('labels', ListProperty(StringProperty)), ('external_references', ListProperty(ExternalReference)), ('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))), ('granular_markings', ListProperty(GranularMarking)), - ]) + ], + 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') - # Put all custom properties at the bottom, sorted alphabetically. - _properties.update(sorted([x for x in properties if x[0].startswith('x_')], key=lambda x: x[0])) - - def __init__(self, **kwargs): - _STIXBase.__init__(self, **kwargs) - try: - cls.__init__(self, **kwargs) - except (AttributeError, TypeError) as e: - # Don't accidentally catch errors raised in a custom __init__() - if ("has no attribute '__init__'" in str(e) or - str(e) == "object.__init__() takes no parameters"): - return - raise e - - _register_type(_Custom, version='2.0') - return _Custom - - return custom_builder + return wrapper diff --git a/stix2/v21/sdo.py b/stix2/v21/sdo.py index 4e45619..ecda6f2 100644 --- a/stix2/v21/sdo.py +++ b/stix2/v21/sdo.py @@ -1,23 +1,19 @@ """STIX 2.1 Domain Objects""" from collections import OrderedDict -import re +import itertools from ..base import _STIXBase -from ..core import _register_type -from ..markings import _MarkingsMixin -from ..utils import NOW, TYPE_REGEX +from ..core import STIXDomainObject +from ..custom import custom_object_builder +from ..properties import (BooleanProperty, DictionaryProperty, + EmbeddedObjectProperty, EnumProperty, FloatProperty, + IDProperty, IntegerProperty, ListProperty, + ObservableProperty, PatternProperty, + ReferenceProperty, StringProperty, TimestampProperty, + TypeProperty) +from ..utils import NOW from .common import ExternalReference, GranularMarking, KillChainPhase -from .observables import ObservableProperty -from .properties import (BooleanProperty, DictionaryProperty, - EmbeddedObjectProperty, EnumProperty, FloatProperty, - IDProperty, IntegerProperty, ListProperty, - PatternProperty, ReferenceProperty, StringProperty, - TimestampProperty, TypeProperty) - - -class STIXDomainObject(_STIXBase, _MarkingsMixin): - pass class AttackPattern(STIXDomainObject): @@ -234,9 +230,9 @@ class AnalysisType(_STIXBase): _properties = OrderedDict([ ('start_time', TimestampProperty()), ('end_time', TimestampProperty()), - ('analysis_tools', ObservableProperty()), - ('analysis_environment', DictionaryProperty()), - ('results', DictionaryProperty(required=True)) + ('analysis_tools', ObservableProperty(spec_version='2.1')), + ('analysis_environment', DictionaryProperty(spec_version='2.1')), + ('results', DictionaryProperty(spec_version='2.1', required=True)) ]) @@ -283,7 +279,7 @@ class Malware(STIXDomainObject): ('os_execution_envs', ListProperty(StringProperty)), ('architecture_execution_envs', ListProperty(StringProperty)), ('implementation_languages', ListProperty(StringProperty)), - ('samples', ObservableProperty()), + ('samples', ObservableProperty(spec_version='2.1')), ('static_analysis_results', ListProperty(EmbeddedObjectProperty(AnalysisType))), ('dynamic_analysis_results', ListProperty(EmbeddedObjectProperty(AnalysisType))), ('av_results', ListProperty(EmbeddedObjectProperty(AVResultsType))), @@ -336,7 +332,7 @@ class ObservedData(STIXDomainObject): ('first_observed', TimestampProperty(required=True)), ('last_observed', TimestampProperty(required=True)), ('number_observed', IntegerProperty(required=True)), - ('objects', ObservableProperty(required=True)), + ('objects', ObservableProperty(spec_version='2.1', required=True)), ('revoked', BooleanProperty(default=lambda: False)), ('labels', ListProperty(StringProperty)), ('confidence', IntegerProperty()), @@ -507,6 +503,8 @@ def CustomObject(type='x-custom-type', properties=None): """Custom STIX Object type decorator. Example: + >>> from stix2.v21 import CustomObject + >>> from stix2.properties import IntegerProperty, StringProperty >>> @CustomObject('x-type-name', [ ... ('property1', StringProperty(required=True)), ... ('property2', IntegerProperty()), @@ -518,6 +516,8 @@ def CustomObject(type='x-custom-type', properties=None): type. Don't call ``super().__init__()`` though - doing so will cause an error. Example: + >>> from stix2.v21 import CustomObject + >>> from stix2.properties import IntegerProperty, StringProperty >>> @CustomObject('x-type-name', [ ... ('property1', StringProperty(required=True)), ... ('property2', IntegerProperty()), @@ -526,35 +526,20 @@ def CustomObject(type='x-custom-type', properties=None): ... def __init__(self, property2=None, **kwargs): ... if property2 and property2 < 10: ... raise ValueError("'property2' is too small.") + """ - - def custom_builder(cls): - - class _Custom(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) - - _type = type - _properties = OrderedDict([ - ('type', TypeProperty(_type)), + def wrapper(cls): + _properties = list(itertools.chain.from_iterable([ + [ + ('type', TypeProperty(type)), ('spec_version', StringProperty(fixed='2.1')), - ('id', IDProperty(_type)), + ('id', IDProperty(type)), ('created_by_ref', ReferenceProperty(type='identity')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')), - ]) - - if not properties or not isinstance(properties, list): - raise ValueError("Must supply a list, containing tuples. For example, [('property1', IntegerProperty())]") - - _properties.update([x for x in properties if not x[0].startswith('x_')]) - - # This is to follow the general properties structure. - _properties.update([ + ], + [x for x in properties if not x[0].startswith('x_')], + [ ('revoked', BooleanProperty(default=lambda: False)), ('labels', ListProperty(StringProperty)), ('confidence', IntegerProperty()), @@ -562,23 +547,9 @@ def CustomObject(type='x-custom-type', properties=None): ('external_references', ListProperty(ExternalReference)), ('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))), ('granular_markings', ListProperty(GranularMarking)), - ]) + ], + 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') - # Put all custom properties at the bottom, sorted alphabetically. - _properties.update(sorted([x for x in properties if x[0].startswith('x_')], key=lambda x: x[0])) - - def __init__(self, **kwargs): - _STIXBase.__init__(self, **kwargs) - try: - cls.__init__(self, **kwargs) - except (AttributeError, TypeError) as e: - # Don't accidentally catch errors raised in a custom __init__() - if ("has no attribute '__init__'" in str(e) or - str(e) == "object.__init__() takes no parameters"): - return - raise e - - _register_type(_Custom, version='2.1') - return _Custom - - return custom_builder + return wrapper