Remove duplicate code from 'sdo.py', removed STIXDomainObject

Apply proper 'spec_version' constraints to v21 objects
stix2.1
Emmanuelle Vargas-Gonzalez 2018-07-10 15:22:21 -04:00
parent 54268ae7dd
commit 023603d86f
2 changed files with 60 additions and 119 deletions

View File

@ -2,21 +2,16 @@
""" """
from collections import OrderedDict from collections import OrderedDict
import re import itertools
from ..base import _STIXBase from ..core import STIXDomainObject
from ..core import _register_type from ..custom import custom_object_builder
from ..markings import _MarkingsMixin from ..properties import (BooleanProperty, IDProperty, IntegerProperty,
from ..utils import NOW, TYPE_REGEX ListProperty, ObservableProperty, PatternProperty,
ReferenceProperty, StringProperty, TimestampProperty,
TypeProperty)
from ..utils import NOW
from .common import ExternalReference, GranularMarking, KillChainPhase 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): class AttackPattern(STIXDomainObject):
@ -327,6 +322,8 @@ def CustomObject(type='x-custom-type', properties=None):
"""Custom STIX Object type decorator. """Custom STIX Object type decorator.
Example: Example:
>>> from stix2.v20 import CustomObject
>>> from stix2.properties import IntegerProperty, StringProperty
>>> @CustomObject('x-type-name', [ >>> @CustomObject('x-type-name', [
... ('property1', StringProperty(required=True)), ... ('property1', StringProperty(required=True)),
... ('property2', IntegerProperty()), ... ('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. type. Don't call ``super().__init__()`` though - doing so will cause an error.
Example: Example:
>>> from stix2.v20 import CustomObject
>>> from stix2.properties import IntegerProperty, StringProperty
>>> @CustomObject('x-type-name', [ >>> @CustomObject('x-type-name', [
... ('property1', StringProperty(required=True)), ... ('property1', StringProperty(required=True)),
... ('property2', IntegerProperty()), ... ('property2', IntegerProperty()),
@ -346,56 +345,27 @@ def CustomObject(type='x-custom-type', properties=None):
... def __init__(self, property2=None, **kwargs): ... def __init__(self, property2=None, **kwargs):
... if property2 and property2 < 10: ... if property2 and property2 < 10:
... raise ValueError("'property2' is too small.") ... raise ValueError("'property2' is too small.")
""" """
def wrapper(cls):
def custom_builder(cls): _properties = list(itertools.chain.from_iterable([
[
class _Custom(cls, STIXDomainObject): ('type', TypeProperty(type)),
('id', IDProperty(type)),
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)),
('created_by_ref', ReferenceProperty(type='identity')), ('created_by_ref', ReferenceProperty(type='identity')),
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond'))
]) ],
[x for x in properties if not x[0].startswith('x_')],
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([
('revoked', BooleanProperty(default=lambda: False)), ('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty)), ('labels', ListProperty(StringProperty)),
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))), ('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))),
('granular_markings', ListProperty(GranularMarking)), ('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. return wrapper
_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

View File

@ -1,23 +1,19 @@
"""STIX 2.1 Domain Objects""" """STIX 2.1 Domain Objects"""
from collections import OrderedDict from collections import OrderedDict
import re import itertools
from ..base import _STIXBase from ..base import _STIXBase
from ..core import _register_type from ..core import STIXDomainObject
from ..markings import _MarkingsMixin from ..custom import custom_object_builder
from ..utils import NOW, TYPE_REGEX 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 .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): class AttackPattern(STIXDomainObject):
@ -234,9 +230,9 @@ class AnalysisType(_STIXBase):
_properties = OrderedDict([ _properties = OrderedDict([
('start_time', TimestampProperty()), ('start_time', TimestampProperty()),
('end_time', TimestampProperty()), ('end_time', TimestampProperty()),
('analysis_tools', ObservableProperty()), ('analysis_tools', ObservableProperty(spec_version='2.1')),
('analysis_environment', DictionaryProperty()), ('analysis_environment', DictionaryProperty(spec_version='2.1')),
('results', DictionaryProperty(required=True)) ('results', DictionaryProperty(spec_version='2.1', required=True))
]) ])
@ -283,7 +279,7 @@ class Malware(STIXDomainObject):
('os_execution_envs', ListProperty(StringProperty)), ('os_execution_envs', ListProperty(StringProperty)),
('architecture_execution_envs', ListProperty(StringProperty)), ('architecture_execution_envs', ListProperty(StringProperty)),
('implementation_languages', ListProperty(StringProperty)), ('implementation_languages', ListProperty(StringProperty)),
('samples', ObservableProperty()), ('samples', ObservableProperty(spec_version='2.1')),
('static_analysis_results', ListProperty(EmbeddedObjectProperty(AnalysisType))), ('static_analysis_results', ListProperty(EmbeddedObjectProperty(AnalysisType))),
('dynamic_analysis_results', ListProperty(EmbeddedObjectProperty(AnalysisType))), ('dynamic_analysis_results', ListProperty(EmbeddedObjectProperty(AnalysisType))),
('av_results', ListProperty(EmbeddedObjectProperty(AVResultsType))), ('av_results', ListProperty(EmbeddedObjectProperty(AVResultsType))),
@ -336,7 +332,7 @@ class ObservedData(STIXDomainObject):
('first_observed', TimestampProperty(required=True)), ('first_observed', TimestampProperty(required=True)),
('last_observed', TimestampProperty(required=True)), ('last_observed', TimestampProperty(required=True)),
('number_observed', IntegerProperty(required=True)), ('number_observed', IntegerProperty(required=True)),
('objects', ObservableProperty(required=True)), ('objects', ObservableProperty(spec_version='2.1', required=True)),
('revoked', BooleanProperty(default=lambda: False)), ('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty)), ('labels', ListProperty(StringProperty)),
('confidence', IntegerProperty()), ('confidence', IntegerProperty()),
@ -507,6 +503,8 @@ def CustomObject(type='x-custom-type', properties=None):
"""Custom STIX Object type decorator. """Custom STIX Object type decorator.
Example: Example:
>>> from stix2.v21 import CustomObject
>>> from stix2.properties import IntegerProperty, StringProperty
>>> @CustomObject('x-type-name', [ >>> @CustomObject('x-type-name', [
... ('property1', StringProperty(required=True)), ... ('property1', StringProperty(required=True)),
... ('property2', IntegerProperty()), ... ('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. type. Don't call ``super().__init__()`` though - doing so will cause an error.
Example: Example:
>>> from stix2.v21 import CustomObject
>>> from stix2.properties import IntegerProperty, StringProperty
>>> @CustomObject('x-type-name', [ >>> @CustomObject('x-type-name', [
... ('property1', StringProperty(required=True)), ... ('property1', StringProperty(required=True)),
... ('property2', IntegerProperty()), ... ('property2', IntegerProperty()),
@ -526,35 +526,20 @@ def CustomObject(type='x-custom-type', properties=None):
... def __init__(self, property2=None, **kwargs): ... def __init__(self, property2=None, **kwargs):
... if property2 and property2 < 10: ... if property2 and property2 < 10:
... raise ValueError("'property2' is too small.") ... raise ValueError("'property2' is too small.")
""" """
def wrapper(cls):
def custom_builder(cls): _properties = list(itertools.chain.from_iterable([
[
class _Custom(cls, STIXDomainObject): ('type', TypeProperty(type)),
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)),
('spec_version', StringProperty(fixed='2.1')), ('spec_version', StringProperty(fixed='2.1')),
('id', IDProperty(_type)), ('id', IDProperty(type)),
('created_by_ref', ReferenceProperty(type='identity')), ('created_by_ref', ReferenceProperty(type='identity')),
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
]) ],
[x for x in properties if not x[0].startswith('x_')],
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([
('revoked', BooleanProperty(default=lambda: False)), ('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty)), ('labels', ListProperty(StringProperty)),
('confidence', IntegerProperty()), ('confidence', IntegerProperty()),
@ -562,23 +547,9 @@ def CustomObject(type='x-custom-type', properties=None):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))), ('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))),
('granular_markings', ListProperty(GranularMarking)), ('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. return wrapper
_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