Merge branch 'master' of github.com:oasis-open/cti-python-stix2
commit
8e95dbfce2
|
@ -1,4 +1,4 @@
|
||||||
sudo: false
|
os: linux
|
||||||
language: python
|
language: python
|
||||||
cache: pip
|
cache: pip
|
||||||
dist: xenial
|
dist: xenial
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
1.4.0 - 2020-04-03
|
||||||
|
|
||||||
|
* #347, #355, #356, #357, #358, #360, #362, #369, #370, #379, #374, #384 Updates STIX 2.1 support to CS01
|
||||||
|
* #376 Fixes bug where registering object of same name would overwrite it; will
|
||||||
|
now raise an error
|
||||||
|
|
||||||
1.3.1 - 2020-03-06
|
1.3.1 - 2020-03-06
|
||||||
|
|
||||||
* #322 Adds encoding option FileSystemSource and MemorySource
|
* #322 Adds encoding option FileSystemSource and MemorySource
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 1.3.1
|
current_version = 1.4.0
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
|
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -51,6 +51,7 @@ setup(
|
||||||
keywords='stix stix2 json cti cyber threat intelligence',
|
keywords='stix stix2 json cti cyber threat intelligence',
|
||||||
packages=find_packages(exclude=['*.test', '*.test.*']),
|
packages=find_packages(exclude=['*.test', '*.test.*']),
|
||||||
install_requires=[
|
install_requires=[
|
||||||
|
'enum34 ; python_version<"3.4"',
|
||||||
'python-dateutil',
|
'python-dateutil',
|
||||||
'pytz',
|
'pytz',
|
||||||
'requests',
|
'requests',
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
DEFAULT_VERSION = '2.0' # Default version will always be the latest STIX 2.X version
|
DEFAULT_VERSION = '2.0' # Default version will always be the latest STIX 2.X version
|
||||||
|
|
||||||
from .confidence import scales
|
from .confidence import scales
|
||||||
from .core import _collect_stix2_mappings, parse, parse_observable
|
|
||||||
from .datastore import CompositeDataSource
|
from .datastore import CompositeDataSource
|
||||||
from .datastore.filesystem import (
|
from .datastore.filesystem import (
|
||||||
FileSystemSink, FileSystemSource, FileSystemStore,
|
FileSystemSink, FileSystemSource, FileSystemStore,
|
||||||
|
@ -38,6 +37,7 @@ from .markings import (
|
||||||
add_markings, clear_markings, get_markings, is_marked, remove_markings,
|
add_markings, clear_markings, get_markings, is_marked, remove_markings,
|
||||||
set_markings,
|
set_markings,
|
||||||
)
|
)
|
||||||
|
from .parsing import _collect_stix2_mappings, parse, parse_observable
|
||||||
from .patterns import (
|
from .patterns import (
|
||||||
AndBooleanExpression, AndObservationExpression, BasicObjectPathComponent,
|
AndBooleanExpression, AndObservationExpression, BasicObjectPathComponent,
|
||||||
BinaryConstant, BooleanConstant, EqualityComparisonExpression,
|
BinaryConstant, BooleanConstant, EqualityComparisonExpression,
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
|
import re
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import simplejson as json
|
import simplejson as json
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
import stix2
|
||||||
from stix2.canonicalization.Canonicalize import canonicalize
|
from stix2.canonicalization.Canonicalize import canonicalize
|
||||||
|
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
|
@ -14,8 +16,11 @@ from .exceptions import (
|
||||||
ImmutableError, InvalidObjRefError, InvalidValueError,
|
ImmutableError, InvalidObjRefError, InvalidValueError,
|
||||||
MissingPropertiesError, MutuallyExclusivePropertiesError,
|
MissingPropertiesError, MutuallyExclusivePropertiesError,
|
||||||
)
|
)
|
||||||
|
from .markings import _MarkingsMixin
|
||||||
from .markings.utils import validate
|
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 new_version as _new_version
|
||||||
from .utils import revoke as _revoke
|
from .utils import revoke as _revoke
|
||||||
|
|
||||||
|
@ -158,12 +163,23 @@ class _STIXBase(Mapping):
|
||||||
custom_props = kwargs.pop('custom_properties', {})
|
custom_props = kwargs.pop('custom_properties', {})
|
||||||
if custom_props and not isinstance(custom_props, dict):
|
if custom_props and not isinstance(custom_props, dict):
|
||||||
raise ValueError("'custom_properties' must be a dictionary")
|
raise ValueError("'custom_properties' must be a dictionary")
|
||||||
if not self._allow_custom:
|
|
||||||
extra_kwargs = list(set(kwargs) - set(self._properties))
|
extra_kwargs = list(set(kwargs) - set(self._properties))
|
||||||
if extra_kwargs:
|
if extra_kwargs and not self._allow_custom:
|
||||||
raise ExtraPropertiesError(cls, extra_kwargs)
|
raise ExtraPropertiesError(cls, extra_kwargs)
|
||||||
if custom_props:
|
|
||||||
|
# because allow_custom is true, any extra kwargs are custom
|
||||||
|
if custom_props or extra_kwargs:
|
||||||
self._allow_custom = True
|
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)
|
# Remove any keyword arguments whose value is None or [] (i.e. empty list)
|
||||||
setting_kwargs = {}
|
setting_kwargs = {}
|
||||||
|
@ -307,6 +323,14 @@ class _STIXBase(Mapping):
|
||||||
return json.dumps(self, cls=STIXJSONEncoder, **kwargs)
|
return json.dumps(self, cls=STIXJSONEncoder, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class _DomainObject(_STIXBase, _MarkingsMixin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class _RelationshipObject(_STIXBase, _MarkingsMixin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class _Observable(_STIXBase):
|
class _Observable(_STIXBase):
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
|
181
stix2/custom.py
181
stix2/custom.py
|
@ -1,140 +1,91 @@
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import re
|
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from .base import _cls_init, _Extension, _Observable, _STIXBase
|
from .base import _cls_init
|
||||||
from .core import (
|
from .parsing import (
|
||||||
STIXDomainObject, _register_marking, _register_object,
|
_register_marking, _register_object, _register_observable,
|
||||||
_register_observable, _register_observable_extension,
|
_register_observable_extension,
|
||||||
)
|
)
|
||||||
from .utils import TYPE_REGEX, get_class_hierarchy_names
|
|
||||||
|
|
||||||
|
|
||||||
def _custom_object_builder(cls, type, properties, version):
|
def _get_properties_dict(properties):
|
||||||
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):
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
prop_dict = OrderedDict(properties)
|
return OrderedDict(properties)
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
six.raise_from(
|
six.raise_from(
|
||||||
ValueError(
|
ValueError(
|
||||||
"Extension properties must be dict-like, e.g. a list "
|
"properties must be dict-like, e.g. a list "
|
||||||
"containing tuples. For example, "
|
"containing tuples. For example, "
|
||||||
"[('property1', IntegerProperty())]",
|
"[('property1', IntegerProperty())]",
|
||||||
),
|
),
|
||||||
e,
|
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
|
_type = type
|
||||||
_properties = prop_dict
|
_properties = prop_dict
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
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)
|
_cls_init(cls, self, kwargs)
|
||||||
|
|
||||||
_register_observable_extension(observable, _CustomExtension, version=version)
|
_register_observable_extension(observable, _CustomExtension, version=version)
|
||||||
|
|
|
@ -10,11 +10,11 @@ import six
|
||||||
|
|
||||||
from stix2 import v20, v21
|
from stix2 import v20, v21
|
||||||
from stix2.base import _STIXBase
|
from stix2.base import _STIXBase
|
||||||
from stix2.core import parse
|
|
||||||
from stix2.datastore import (
|
from stix2.datastore import (
|
||||||
DataSink, DataSource, DataSourceError, DataStoreMixin,
|
DataSink, DataSource, DataSourceError, DataStoreMixin,
|
||||||
)
|
)
|
||||||
from stix2.datastore.filters import Filter, FilterSet, apply_common_filters
|
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
|
from stix2.utils import format_datetime, get_type_from_id
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,9 @@ import os
|
||||||
|
|
||||||
from stix2 import v20, v21
|
from stix2 import v20, v21
|
||||||
from stix2.base import _STIXBase
|
from stix2.base import _STIXBase
|
||||||
from stix2.core import parse
|
|
||||||
from stix2.datastore import DataSink, DataSource, DataStoreMixin
|
from stix2.datastore import DataSink, DataSource, DataStoreMixin
|
||||||
from stix2.datastore.filters import FilterSet, apply_common_filters
|
from stix2.datastore.filters import FilterSet, apply_common_filters
|
||||||
|
from stix2.parsing import parse
|
||||||
|
|
||||||
|
|
||||||
def _add(store, stix_data, allow_custom=True, version=None):
|
def _add(store, stix_data, allow_custom=True, version=None):
|
||||||
|
|
|
@ -4,15 +4,15 @@ from requests.exceptions import HTTPError
|
||||||
|
|
||||||
from stix2 import v20, v21
|
from stix2 import v20, v21
|
||||||
from stix2.base import _STIXBase
|
from stix2.base import _STIXBase
|
||||||
from stix2.core import parse
|
|
||||||
from stix2.datastore import (
|
from stix2.datastore import (
|
||||||
DataSink, DataSource, DataSourceError, DataStoreMixin,
|
DataSink, DataSource, DataSourceError, DataStoreMixin,
|
||||||
)
|
)
|
||||||
from stix2.datastore.filters import Filter, FilterSet, apply_common_filters
|
from stix2.datastore.filters import Filter, FilterSet, apply_common_filters
|
||||||
|
from stix2.parsing import parse
|
||||||
from stix2.utils import deduplicate
|
from stix2.utils import deduplicate
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from taxii2client import ValidationError
|
from taxii2client.exceptions import ValidationError
|
||||||
_taxii2_client = True
|
_taxii2_client = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
_taxii2_client = False
|
_taxii2_client = False
|
||||||
|
|
|
@ -4,8 +4,8 @@ import copy
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from .core import parse as _parse
|
|
||||||
from .datastore import CompositeDataSource, DataStoreMixin
|
from .datastore import CompositeDataSource, DataStoreMixin
|
||||||
|
from .parsing import parse as _parse
|
||||||
from .utils import STIXdatetime, parse_into_datetime
|
from .utils import STIXdatetime, parse_into_datetime
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
|
@ -233,3 +233,16 @@ class STIXDeprecationWarning(DeprecationWarning):
|
||||||
Represents usage of a deprecated component of a STIX specification.
|
Represents usage of a deprecated component of a STIX specification.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DuplicateRegistrationError(STIXError):
|
||||||
|
"""A STIX object with the same type as an existing object is being registered"""
|
||||||
|
|
||||||
|
def __init__(self, obj_type, reg_obj_type):
|
||||||
|
super(DuplicateRegistrationError, self).__init__()
|
||||||
|
self.obj_type = obj_type
|
||||||
|
self.reg_obj_type = reg_obj_type
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
msg = "A(n) {0} with type '{1}' already exists and cannot be registered again"
|
||||||
|
return msg.format(self.obj_type, self.reg_obj_type)
|
||||||
|
|
|
@ -7,39 +7,13 @@ import re
|
||||||
|
|
||||||
import stix2
|
import stix2
|
||||||
|
|
||||||
from .base import _Observable, _STIXBase
|
from .base import _DomainObject, _Observable
|
||||||
from .exceptions import ParseError
|
from .exceptions import DuplicateRegistrationError, ParseError
|
||||||
from .markings import _MarkingsMixin
|
from .utils import PREFIX_21_REGEX, _get_dict, get_class_hierarchy_names
|
||||||
from .utils import SCO21_EXT_REGEX, TYPE_REGEX, _get_dict
|
|
||||||
|
|
||||||
STIX2_OBJ_MAPS = {}
|
STIX2_OBJ_MAPS = {}
|
||||||
|
|
||||||
|
|
||||||
class STIXDomainObject(_STIXBase, _MarkingsMixin):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
interoperability = kwargs.get('interoperability', False)
|
|
||||||
self.__interoperability = interoperability
|
|
||||||
self._properties['id'].interoperability = interoperability
|
|
||||||
self._properties['created_by_ref'].interoperability = interoperability
|
|
||||||
if kwargs.get('object_marking_refs'):
|
|
||||||
self._properties['object_marking_refs'].contained.interoperability = interoperability
|
|
||||||
|
|
||||||
super(STIXDomainObject, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class STIXRelationshipObject(_STIXBase, _MarkingsMixin):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
interoperability = kwargs.get('interoperability', False)
|
|
||||||
self.__interoperability = interoperability
|
|
||||||
self._properties['id'].interoperability = interoperability
|
|
||||||
if kwargs.get('created_by_ref'):
|
|
||||||
self._properties['created_by_ref'].interoperability = interoperability
|
|
||||||
if kwargs.get('object_marking_refs'):
|
|
||||||
self._properties['object_marking_refs'].contained.interoperability = interoperability
|
|
||||||
|
|
||||||
super(STIXRelationshipObject, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def parse(data, allow_custom=False, interoperability=False, version=None):
|
def parse(data, allow_custom=False, interoperability=False, version=None):
|
||||||
"""Convert a string, dict or file-like object into a STIX object.
|
"""Convert a string, dict or file-like object into a STIX object.
|
||||||
|
|
||||||
|
@ -218,7 +192,7 @@ def parse_observable(data, _valid_refs=None, allow_custom=False, version=None):
|
||||||
return obj_class(allow_custom=allow_custom, **obj)
|
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.
|
"""Register a custom STIX Object type.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -226,7 +200,26 @@ def _register_object(new_type, version=None):
|
||||||
version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If
|
version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If
|
||||||
None, use latest version.
|
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:
|
if version:
|
||||||
v = 'v' + version.replace('.', '')
|
v = 'v' + version.replace('.', '')
|
||||||
else:
|
else:
|
||||||
|
@ -234,10 +227,12 @@ def _register_object(new_type, version=None):
|
||||||
v = 'v' + stix2.DEFAULT_VERSION.replace('.', '')
|
v = 'v' + stix2.DEFAULT_VERSION.replace('.', '')
|
||||||
|
|
||||||
OBJ_MAP = STIX2_OBJ_MAPS[v]['objects']
|
OBJ_MAP = STIX2_OBJ_MAPS[v]['objects']
|
||||||
|
if new_type._type in OBJ_MAP.keys():
|
||||||
|
raise DuplicateRegistrationError("STIX Object", new_type._type)
|
||||||
OBJ_MAP[new_type._type] = new_type
|
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.
|
"""Register a custom STIX Marking Definition type.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -246,6 +241,17 @@ def _register_marking(new_marking, version=None):
|
||||||
None, use latest version.
|
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:
|
if version:
|
||||||
v = 'v' + version.replace('.', '')
|
v = 'v' + version.replace('.', '')
|
||||||
else:
|
else:
|
||||||
|
@ -253,10 +259,12 @@ def _register_marking(new_marking, version=None):
|
||||||
v = 'v' + stix2.DEFAULT_VERSION.replace('.', '')
|
v = 'v' + stix2.DEFAULT_VERSION.replace('.', '')
|
||||||
|
|
||||||
OBJ_MAP_MARKING = STIX2_OBJ_MAPS[v]['markings']
|
OBJ_MAP_MARKING = STIX2_OBJ_MAPS[v]['markings']
|
||||||
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.
|
"""Register a custom STIX Cyber Observable type.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -265,6 +273,39 @@ def _register_observable(new_observable, version=None):
|
||||||
None, use latest version.
|
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:
|
if version:
|
||||||
v = 'v' + version.replace('.', '')
|
v = 'v' + version.replace('.', '')
|
||||||
else:
|
else:
|
||||||
|
@ -272,6 +313,8 @@ def _register_observable(new_observable, version=None):
|
||||||
v = 'v' + stix2.DEFAULT_VERSION.replace('.', '')
|
v = 'v' + stix2.DEFAULT_VERSION.replace('.', '')
|
||||||
|
|
||||||
OBJ_MAP_OBSERVABLE = STIX2_OBJ_MAPS[v]['observables']
|
OBJ_MAP_OBSERVABLE = STIX2_OBJ_MAPS[v]['observables']
|
||||||
|
if new_observable._type in OBJ_MAP_OBSERVABLE.keys():
|
||||||
|
raise DuplicateRegistrationError("Cyber Observable", new_observable._type)
|
||||||
OBJ_MAP_OBSERVABLE[new_observable._type] = new_observable
|
OBJ_MAP_OBSERVABLE[new_observable._type] = new_observable
|
||||||
|
|
||||||
|
|
||||||
|
@ -291,30 +334,12 @@ def _register_observable_extension(
|
||||||
obs_class = observable if isinstance(observable, type) else \
|
obs_class = observable if isinstance(observable, type) else \
|
||||||
type(observable)
|
type(observable)
|
||||||
ext_type = new_extension._type
|
ext_type = new_extension._type
|
||||||
|
properties = new_extension._properties
|
||||||
|
|
||||||
if not issubclass(obs_class, _Observable):
|
if not issubclass(obs_class, _Observable):
|
||||||
raise ValueError("'observable' must be a valid Observable class!")
|
raise ValueError("'observable' must be a valid Observable class!")
|
||||||
|
|
||||||
if version == "2.0":
|
stix2.properties._validate_type(ext_type, version)
|
||||||
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,
|
|
||||||
)
|
|
||||||
|
|
||||||
if not new_extension._properties:
|
if not new_extension._properties:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
@ -322,6 +347,17 @@ def _register_observable_extension(
|
||||||
ext_type,
|
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('.', '')
|
v = 'v' + version.replace('.', '')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -336,6 +372,8 @@ def _register_observable_extension(
|
||||||
EXT_MAP = STIX2_OBJ_MAPS[v]['observable-extensions']
|
EXT_MAP = STIX2_OBJ_MAPS[v]['observable-extensions']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if ext_type in EXT_MAP[observable_type].keys():
|
||||||
|
raise DuplicateRegistrationError("Observable Extension", ext_type)
|
||||||
EXT_MAP[observable_type][ext_type] = new_extension
|
EXT_MAP[observable_type][ext_type] = new_extension
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if observable_type not in OBJ_MAP_OBSERVABLE:
|
if observable_type not in OBJ_MAP_OBSERVABLE:
|
|
@ -2,11 +2,19 @@ import importlib
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
from stix2patterns.exceptions import ParseException
|
from stix2patterns.exceptions import ParseException
|
||||||
from stix2patterns.grammars.STIXPatternParser import (
|
from stix2patterns.grammars.STIXPatternParser import TerminalNode
|
||||||
STIXPatternParser, TerminalNode,
|
from stix2patterns.v20.grammars.STIXPatternParser import \
|
||||||
)
|
STIXPatternParser as STIXPatternParser20
|
||||||
from stix2patterns.grammars.STIXPatternVisitor import STIXPatternVisitor
|
from stix2patterns.v20.grammars.STIXPatternVisitor import \
|
||||||
from stix2patterns.v20.pattern import Pattern
|
STIXPatternVisitor as STIXPatternVisitor20
|
||||||
|
from stix2patterns.v20.pattern import Pattern as Pattern20
|
||||||
|
from stix2patterns.v21.grammars.STIXPatternParser import \
|
||||||
|
STIXPatternParser as STIXPatternParser21
|
||||||
|
from stix2patterns.v21.grammars.STIXPatternVisitor import \
|
||||||
|
STIXPatternVisitor as STIXPatternVisitor21
|
||||||
|
from stix2patterns.v21.pattern import Pattern as Pattern21
|
||||||
|
|
||||||
|
import stix2
|
||||||
|
|
||||||
from .patterns import *
|
from .patterns import *
|
||||||
from .patterns import _BooleanExpression
|
from .patterns import _BooleanExpression
|
||||||
|
@ -32,23 +40,12 @@ def remove_terminal_nodes(parse_tree_nodes):
|
||||||
return values
|
return values
|
||||||
|
|
||||||
|
|
||||||
# This class defines a complete generic visitor for a parse tree produced by STIXPatternParser.
|
|
||||||
|
|
||||||
|
|
||||||
class STIXPatternVisitorForSTIX2(STIXPatternVisitor):
|
|
||||||
|
class STIXPatternVisitorForSTIX2():
|
||||||
classes = {}
|
classes = {}
|
||||||
|
|
||||||
def __init__(self, module_suffix, module_name):
|
|
||||||
if module_suffix and module_name:
|
|
||||||
self.module_suffix = module_suffix
|
|
||||||
if not STIXPatternVisitorForSTIX2.classes:
|
|
||||||
module = importlib.import_module(module_name)
|
|
||||||
for k, c in inspect.getmembers(module, inspect.isclass):
|
|
||||||
STIXPatternVisitorForSTIX2.classes[k] = c
|
|
||||||
else:
|
|
||||||
self.module_suffix = None
|
|
||||||
super(STIXPatternVisitor, self).__init__()
|
|
||||||
|
|
||||||
def get_class(self, class_name):
|
def get_class(self, class_name):
|
||||||
if class_name in STIXPatternVisitorForSTIX2.classes:
|
if class_name in STIXPatternVisitorForSTIX2.classes:
|
||||||
return STIXPatternVisitorForSTIX2.classes[class_name]
|
return STIXPatternVisitorForSTIX2.classes[class_name]
|
||||||
|
@ -106,7 +103,10 @@ class STIXPatternVisitorForSTIX2(STIXPatternVisitor):
|
||||||
# Visit a parse tree produced by STIXPatternParser#observationExpressionCompound.
|
# Visit a parse tree produced by STIXPatternParser#observationExpressionCompound.
|
||||||
def visitObservationExpressionCompound(self, ctx):
|
def visitObservationExpressionCompound(self, ctx):
|
||||||
children = self.visitChildren(ctx)
|
children = self.visitChildren(ctx)
|
||||||
return self.instantiate("ObservationExpression", children[1])
|
if isinstance(children[0], TerminalNode) and children[0].symbol.type == self.parser_class.LPAREN:
|
||||||
|
return self.instantiate("ParentheticalExpression", children[1])
|
||||||
|
else:
|
||||||
|
return self.instantiate("ObservationExpression", children[0])
|
||||||
|
|
||||||
# Visit a parse tree produced by STIXPatternParser#observationExpressionWithin.
|
# Visit a parse tree produced by STIXPatternParser#observationExpressionWithin.
|
||||||
def visitObservationExpressionWithin(self, ctx):
|
def visitObservationExpressionWithin(self, ctx):
|
||||||
|
@ -147,7 +147,7 @@ class STIXPatternVisitorForSTIX2(STIXPatternVisitor):
|
||||||
def visitPropTestEqual(self, ctx):
|
def visitPropTestEqual(self, ctx):
|
||||||
children = self.visitChildren(ctx)
|
children = self.visitChildren(ctx)
|
||||||
operator = children[1].symbol.type
|
operator = children[1].symbol.type
|
||||||
negated = operator != STIXPatternParser.EQ
|
negated = operator != self.parser_class.EQ
|
||||||
return self.instantiate(
|
return self.instantiate(
|
||||||
"EqualityComparisonExpression", children[0], children[3 if len(children) > 3 else 2],
|
"EqualityComparisonExpression", children[0], children[3 if len(children) > 3 else 2],
|
||||||
negated,
|
negated,
|
||||||
|
@ -157,22 +157,22 @@ class STIXPatternVisitorForSTIX2(STIXPatternVisitor):
|
||||||
def visitPropTestOrder(self, ctx):
|
def visitPropTestOrder(self, ctx):
|
||||||
children = self.visitChildren(ctx)
|
children = self.visitChildren(ctx)
|
||||||
operator = children[1].symbol.type
|
operator = children[1].symbol.type
|
||||||
if operator == STIXPatternParser.GT:
|
if operator == self.parser_class.GT:
|
||||||
return self.instantiate(
|
return self.instantiate(
|
||||||
"GreaterThanComparisonExpression", children[0],
|
"GreaterThanComparisonExpression", children[0],
|
||||||
children[3 if len(children) > 3 else 2], False,
|
children[3 if len(children) > 3 else 2], False,
|
||||||
)
|
)
|
||||||
elif operator == STIXPatternParser.LT:
|
elif operator == self.parser_class.LT:
|
||||||
return self.instantiate(
|
return self.instantiate(
|
||||||
"LessThanComparisonExpression", children[0],
|
"LessThanComparisonExpression", children[0],
|
||||||
children[3 if len(children) > 3 else 2], False,
|
children[3 if len(children) > 3 else 2], False,
|
||||||
)
|
)
|
||||||
elif operator == STIXPatternParser.GE:
|
elif operator == self.parser_class.GE:
|
||||||
return self.instantiate(
|
return self.instantiate(
|
||||||
"GreaterThanEqualComparisonExpression", children[0],
|
"GreaterThanEqualComparisonExpression", children[0],
|
||||||
children[3 if len(children) > 3 else 2], False,
|
children[3 if len(children) > 3 else 2], False,
|
||||||
)
|
)
|
||||||
elif operator == STIXPatternParser.LE:
|
elif operator == self.parser_class.LE:
|
||||||
return self.instantiate(
|
return self.instantiate(
|
||||||
"LessThanEqualComparisonExpression", children[0],
|
"LessThanEqualComparisonExpression", children[0],
|
||||||
children[3 if len(children) > 3 else 2], False,
|
children[3 if len(children) > 3 else 2], False,
|
||||||
|
@ -294,22 +294,22 @@ class STIXPatternVisitorForSTIX2(STIXPatternVisitor):
|
||||||
return children[0]
|
return children[0]
|
||||||
|
|
||||||
def visitTerminal(self, node):
|
def visitTerminal(self, node):
|
||||||
if node.symbol.type == STIXPatternParser.IntPosLiteral or node.symbol.type == STIXPatternParser.IntNegLiteral:
|
if node.symbol.type == self.parser_class.IntPosLiteral or node.symbol.type == self.parser_class.IntNegLiteral:
|
||||||
return IntegerConstant(node.getText())
|
return IntegerConstant(node.getText())
|
||||||
elif node.symbol.type == STIXPatternParser.FloatPosLiteral or node.symbol.type == STIXPatternParser.FloatNegLiteral:
|
elif node.symbol.type == self.parser_class.FloatPosLiteral or node.symbol.type == self.parser_class.FloatNegLiteral:
|
||||||
return FloatConstant(node.getText())
|
return FloatConstant(node.getText())
|
||||||
elif node.symbol.type == STIXPatternParser.HexLiteral:
|
elif node.symbol.type == self.parser_class.HexLiteral:
|
||||||
return HexConstant(node.getText(), from_parse_tree=True)
|
return HexConstant(node.getText(), from_parse_tree=True)
|
||||||
elif node.symbol.type == STIXPatternParser.BinaryLiteral:
|
elif node.symbol.type == self.parser_class.BinaryLiteral:
|
||||||
return BinaryConstant(node.getText(), from_parse_tree=True)
|
return BinaryConstant(node.getText(), from_parse_tree=True)
|
||||||
elif node.symbol.type == STIXPatternParser.StringLiteral:
|
elif node.symbol.type == self.parser_class.StringLiteral:
|
||||||
if node.getText()[0] == "'" and node.getText()[-1] == "'":
|
if node.getText()[0] == "'" and node.getText()[-1] == "'":
|
||||||
return StringConstant(node.getText()[1:-1], from_parse_tree=True)
|
return StringConstant(node.getText()[1:-1], from_parse_tree=True)
|
||||||
else:
|
else:
|
||||||
raise ParseException("The pattern does not start and end with a single quote")
|
raise ParseException("The pattern does not start and end with a single quote")
|
||||||
elif node.symbol.type == STIXPatternParser.BoolLiteral:
|
elif node.symbol.type == self.parser_class.BoolLiteral:
|
||||||
return BooleanConstant(node.getText())
|
return BooleanConstant(node.getText())
|
||||||
elif node.symbol.type == STIXPatternParser.TimestampLiteral:
|
elif node.symbol.type == self.parser_class.TimestampLiteral:
|
||||||
return TimestampConstant(node.getText())
|
return TimestampConstant(node.getText())
|
||||||
else:
|
else:
|
||||||
return node
|
return node
|
||||||
|
@ -321,12 +321,51 @@ class STIXPatternVisitorForSTIX2(STIXPatternVisitor):
|
||||||
aggregate = [nextResult]
|
aggregate = [nextResult]
|
||||||
return aggregate
|
return aggregate
|
||||||
|
|
||||||
|
# This class defines a complete generic visitor for a parse tree produced by STIXPatternParser.
|
||||||
|
class STIXPatternVisitorForSTIX21(STIXPatternVisitorForSTIX2, STIXPatternVisitor21):
|
||||||
|
classes = {}
|
||||||
|
|
||||||
def create_pattern_object(pattern, module_suffix="", module_name=""):
|
def __init__(self, module_suffix, module_name):
|
||||||
|
if module_suffix and module_name:
|
||||||
|
self.module_suffix = module_suffix
|
||||||
|
if not STIXPatternVisitorForSTIX2.classes:
|
||||||
|
module = importlib.import_module(module_name)
|
||||||
|
for k, c in inspect.getmembers(module, inspect.isclass):
|
||||||
|
STIXPatternVisitorForSTIX2.classes[k] = c
|
||||||
|
else:
|
||||||
|
self.module_suffix = None
|
||||||
|
self.parser_class = STIXPatternParser21
|
||||||
|
super(STIXPatternVisitor21, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
class STIXPatternVisitorForSTIX20(STIXPatternVisitorForSTIX2, STIXPatternVisitor20):
|
||||||
|
classes = {}
|
||||||
|
|
||||||
|
def __init__(self, module_suffix, module_name):
|
||||||
|
if module_suffix and module_name:
|
||||||
|
self.module_suffix = module_suffix
|
||||||
|
if not STIXPatternVisitorForSTIX2.classes:
|
||||||
|
module = importlib.import_module(module_name)
|
||||||
|
for k, c in inspect.getmembers(module, inspect.isclass):
|
||||||
|
STIXPatternVisitorForSTIX2.classes[k] = c
|
||||||
|
else:
|
||||||
|
self.module_suffix = None
|
||||||
|
self.parser_class = STIXPatternParser20
|
||||||
|
super(STIXPatternVisitor20, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def create_pattern_object(pattern, module_suffix="", module_name="", version=stix2.DEFAULT_VERSION):
|
||||||
"""
|
"""
|
||||||
Create a STIX pattern AST from a pattern string.
|
Create a STIX pattern AST from a pattern string.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pattern_obj = Pattern(pattern)
|
if version == "2.1":
|
||||||
builder = STIXPatternVisitorForSTIX2(module_suffix, module_name)
|
pattern_class = Pattern21
|
||||||
|
visitor_class = STIXPatternVisitorForSTIX21
|
||||||
|
else:
|
||||||
|
pattern_class = Pattern20
|
||||||
|
visitor_class = STIXPatternVisitorForSTIX20
|
||||||
|
|
||||||
|
pattern_obj = pattern_class(pattern)
|
||||||
|
builder = visitor_class(module_suffix, module_name)
|
||||||
return pattern_obj.visit(builder)
|
return pattern_obj.visit(builder)
|
||||||
|
|
|
@ -551,7 +551,7 @@ class ObservationExpression(_PatternExpression):
|
||||||
self.operand = operand
|
self.operand = operand
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "[%s]" % self.operand
|
return "%s" % self.operand if isinstance(self.operand, (ObservationExpression, _CompoundObservationExpression)) else "[%s]" % self.operand
|
||||||
|
|
||||||
|
|
||||||
class _CompoundObservationExpression(_PatternExpression):
|
class _CompoundObservationExpression(_PatternExpression):
|
||||||
|
|
|
@ -12,12 +12,15 @@ from six import string_types, text_type
|
||||||
import stix2
|
import stix2
|
||||||
|
|
||||||
from .base import _STIXBase
|
from .base import _STIXBase
|
||||||
from .core import STIX2_OBJ_MAPS, parse, parse_observable
|
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
CustomContentError, DictionaryKeyError, MissingPropertiesError,
|
CustomContentError, DictionaryKeyError, MissingPropertiesError,
|
||||||
MutuallyExclusivePropertiesError,
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
ID_REGEX_interoperability = re.compile(r"[0-9a-fA-F]{8}-"
|
ID_REGEX_interoperability = re.compile(r"[0-9a-fA-F]{8}-"
|
||||||
"[0-9a-fA-F]{4}-"
|
"[0-9a-fA-F]{4}-"
|
||||||
|
@ -90,6 +93,36 @@ def _validate_id(id_, spec_version, required_prefix, interoperability):
|
||||||
raise ValueError(ERROR_INVALID_ID.format(id_))
|
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):
|
class Property(object):
|
||||||
"""Represent a property of STIX data type.
|
"""Represent a property of STIX data type.
|
||||||
|
|
||||||
|
@ -241,7 +274,9 @@ class StringProperty(Property):
|
||||||
|
|
||||||
class TypeProperty(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)
|
super(TypeProperty, self).__init__(fixed=type)
|
||||||
|
|
||||||
|
|
||||||
|
@ -333,12 +368,16 @@ class BooleanProperty(Property):
|
||||||
|
|
||||||
class TimestampProperty(Property):
|
class TimestampProperty(Property):
|
||||||
|
|
||||||
def __init__(self, precision=None, **kwargs):
|
def __init__(self, precision="any", precision_constraint="exact", **kwargs):
|
||||||
self.precision = precision
|
self.precision = precision
|
||||||
|
self.precision_constraint = precision_constraint
|
||||||
|
|
||||||
super(TimestampProperty, self).__init__(**kwargs)
|
super(TimestampProperty, self).__init__(**kwargs)
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
return parse_into_datetime(value, self.precision)
|
return parse_into_datetime(
|
||||||
|
value, self.precision, self.precision_constraint,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DictionaryProperty(Property):
|
class DictionaryProperty(Property):
|
||||||
|
@ -650,7 +689,7 @@ class STIXObjectProperty(Property):
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
# Any STIX Object (SDO, SRO, or Marking Definition) can be added to
|
# Any STIX Object (SDO, SRO, or Marking Definition) can be added to
|
||||||
# a bundle with no further checks.
|
# 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)):
|
for x in get_class_hierarchy_names(value)):
|
||||||
# A simple "is this a spec version 2.1+ object" test. For now,
|
# 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
|
# limit 2.0 bundles to 2.0 objects. It's not possible yet to
|
||||||
|
|
|
@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from stix2.core import _detect_spec_version
|
from stix2.parsing import _detect_spec_version
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
|
|
@ -114,6 +114,42 @@ def stix_objs1():
|
||||||
return [ind1, ind2, ind3, ind4, ind5]
|
return [ind1, ind2, ind3, ind4, ind5]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stix_objs1_manifests():
|
||||||
|
# Tests against latest medallion (TAXII 2.1)
|
||||||
|
ind1 = {
|
||||||
|
"date_added": "2017-01-27T13:49:53.935Z",
|
||||||
|
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||||
|
"media_type": "application/stix+json;version=2.1",
|
||||||
|
"version": "2017-01-27T13:49:53.935Z",
|
||||||
|
}
|
||||||
|
ind2 = {
|
||||||
|
"date_added": "2017-01-27T13:49:53.935Z",
|
||||||
|
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||||
|
"media_type": "application/stix+json;version=2.1",
|
||||||
|
"version": "2017-01-27T13:49:53.935Z",
|
||||||
|
}
|
||||||
|
ind3 = {
|
||||||
|
"date_added": "2017-01-27T13:49:53.935Z",
|
||||||
|
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||||
|
"media_type": "application/stix+json;version=2.1",
|
||||||
|
"version": "2017-01-27T13:49:53.936Z",
|
||||||
|
}
|
||||||
|
ind4 = {
|
||||||
|
"date_added": "2017-01-27T13:49:53.935Z",
|
||||||
|
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||||
|
"media_type": "application/stix+json;version=2.1",
|
||||||
|
"version": "2017-01-27T13:49:53.935Z",
|
||||||
|
}
|
||||||
|
ind5 = {
|
||||||
|
"date_added": "2017-01-27T13:49:53.935Z",
|
||||||
|
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||||
|
"media_type": "application/stix+json;version=2.1",
|
||||||
|
"version": "2017-01-27T13:49:53.935Z",
|
||||||
|
}
|
||||||
|
return [ind1, ind2, ind3, ind4, ind5]
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def stix_objs2():
|
def stix_objs2():
|
||||||
ind6 = {
|
ind6 = {
|
||||||
|
|
|
@ -1,176 +0,0 @@
|
||||||
import pytest
|
|
||||||
|
|
||||||
import stix2
|
|
||||||
from stix2 import core, exceptions
|
|
||||||
|
|
||||||
from .constants import IDENTITY_ID
|
|
||||||
|
|
||||||
BUNDLE = {
|
|
||||||
"type": "bundle",
|
|
||||||
"spec_version": "2.0",
|
|
||||||
"id": "bundle--00000000-0000-4000-8000-000000000007",
|
|
||||||
"objects": [
|
|
||||||
{
|
|
||||||
"type": "indicator",
|
|
||||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
|
||||||
"created": "2017-01-01T12:34:56.000Z",
|
|
||||||
"modified": "2017-01-01T12:34:56.000Z",
|
|
||||||
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
|
||||||
"valid_from": "2017-01-01T12:34:56Z",
|
|
||||||
"labels": [
|
|
||||||
"malicious-activity",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "malware",
|
|
||||||
"id": "malware--00000000-0000-4000-8000-000000000003",
|
|
||||||
"created": "2017-01-01T12:34:56.000Z",
|
|
||||||
"modified": "2017-01-01T12:34:56.000Z",
|
|
||||||
"name": "Cryptolocker",
|
|
||||||
"labels": [
|
|
||||||
"ransomware",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "relationship",
|
|
||||||
"id": "relationship--00000000-0000-4000-8000-000000000005",
|
|
||||||
"created": "2017-01-01T12:34:56.000Z",
|
|
||||||
"modified": "2017-01-01T12:34:56.000Z",
|
|
||||||
"relationship_type": "indicates",
|
|
||||||
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
|
||||||
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_dict_to_stix2_bundle_with_version():
|
|
||||||
with pytest.raises(exceptions.ExtraPropertiesError) as excinfo:
|
|
||||||
core.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')
|
|
||||||
v = 'v20'
|
|
||||||
|
|
||||||
assert v in str(obs_obj.__class__)
|
|
||||||
|
|
||||||
|
|
||||||
@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)
|
|
||||||
v = 'v20'
|
|
||||||
|
|
||||||
assert v in str(obs_obj.__class__)
|
|
||||||
|
|
||||||
|
|
||||||
def test_register_object_with_version():
|
|
||||||
bundle = core.dict_to_stix2(BUNDLE, version='2.0')
|
|
||||||
core._register_object(bundle.objects[0].__class__, version='2.0')
|
|
||||||
v = 'v20'
|
|
||||||
|
|
||||||
assert bundle.objects[0].type in core.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 bundle.objects[0]
|
|
||||||
|
|
||||||
|
|
||||||
def test_register_marking_with_version():
|
|
||||||
core._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 v in str(stix2.v20.TLP_WHITE.__class__)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail(reason="The default version is no longer 2.0", condition=stix2.DEFAULT_VERSION != "2.0")
|
|
||||||
def test_register_marking_with_no_version():
|
|
||||||
# Uses default version (2.0 in this case)
|
|
||||||
core._register_marking(stix2.v20.TLP_WHITE.__class__)
|
|
||||||
v = 'v20'
|
|
||||||
|
|
||||||
assert stix2.v20.TLP_WHITE.definition._type in core.STIX2_OBJ_MAPS[v]['markings']
|
|
||||||
assert v in str(stix2.v20.TLP_WHITE.__class__)
|
|
||||||
|
|
||||||
|
|
||||||
def test_register_observable_with_version():
|
|
||||||
observed_data = stix2.v20.ObservedData(
|
|
||||||
id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
|
|
||||||
created_by_ref=IDENTITY_ID,
|
|
||||||
created="2016-04-06T19:58:16.000Z",
|
|
||||||
modified="2016-04-06T19:58:16.000Z",
|
|
||||||
first_observed="2015-12-21T19:00:00Z",
|
|
||||||
last_observed="2015-12-21T19:00:00Z",
|
|
||||||
number_observed=50,
|
|
||||||
objects={
|
|
||||||
"0": {
|
|
||||||
"name": "foo.exe",
|
|
||||||
"type": "file",
|
|
||||||
"extensions": {
|
|
||||||
"ntfs-ext": {
|
|
||||||
"alternate_data_streams": [
|
|
||||||
{
|
|
||||||
"name": "second.stream",
|
|
||||||
"size": 25536,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"type": "directory",
|
|
||||||
"path": "/usr/home",
|
|
||||||
"contains_refs": ["0"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
core._register_observable(observed_data.objects['0'].__class__, version='2.0')
|
|
||||||
v = 'v20'
|
|
||||||
|
|
||||||
assert observed_data.objects['0'].type in core.STIX2_OBJ_MAPS[v]['observables']
|
|
||||||
assert v in str(observed_data.objects['0'].__class__)
|
|
||||||
|
|
||||||
|
|
||||||
def test_register_observable_extension_with_version():
|
|
||||||
observed_data = stix2.v20.ObservedData(
|
|
||||||
id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
|
|
||||||
created_by_ref=IDENTITY_ID,
|
|
||||||
created="2016-04-06T19:58:16.000Z",
|
|
||||||
modified="2016-04-06T19:58:16.000Z",
|
|
||||||
first_observed="2015-12-21T19:00:00Z",
|
|
||||||
last_observed="2015-12-21T19:00:00Z",
|
|
||||||
number_observed=50,
|
|
||||||
objects={
|
|
||||||
"0": {
|
|
||||||
"name": "foo.exe",
|
|
||||||
"type": "file",
|
|
||||||
"extensions": {
|
|
||||||
"ntfs-ext": {
|
|
||||||
"alternate_data_streams": [
|
|
||||||
{
|
|
||||||
"name": "second.stream",
|
|
||||||
"size": 25536,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"type": "directory",
|
|
||||||
"path": "/usr/home",
|
|
||||||
"contains_refs": ["0"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
core._register_observable_extension(observed_data.objects['0'], observed_data.objects['0'].extensions['ntfs-ext'].__class__, version='2.0')
|
|
||||||
v = 'v20'
|
|
||||||
|
|
||||||
assert observed_data.objects['0'].type in core.STIX2_OBJ_MAPS[v]['observables']
|
|
||||||
assert v in str(observed_data.objects['0'].__class__)
|
|
||||||
|
|
||||||
assert observed_data.objects['0'].extensions['ntfs-ext']._type in core.STIX2_OBJ_MAPS[v]['observable-extensions']['file']
|
|
||||||
assert v in str(observed_data.objects['0'].extensions['ntfs-ext'].__class__)
|
|
|
@ -1,9 +1,10 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import stix2
|
import stix2
|
||||||
|
from stix2 import parsing
|
||||||
import stix2.v20
|
import stix2.v20
|
||||||
|
|
||||||
from ...exceptions import InvalidValueError
|
from ...exceptions import DuplicateRegistrationError, InvalidValueError
|
||||||
from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID
|
from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID
|
||||||
|
|
||||||
IDENTITY_CUSTOM_PROP = stix2.v20.Identity(
|
IDENTITY_CUSTOM_PROP = stix2.v20.Identity(
|
||||||
|
@ -449,7 +450,7 @@ def test_custom_observable_raises_exception():
|
||||||
|
|
||||||
def test_custom_observable_object_no_init_1():
|
def test_custom_observable_object_no_init_1():
|
||||||
@stix2.v20.CustomObservable(
|
@stix2.v20.CustomObservable(
|
||||||
'x-new-observable', [
|
'x-new-observable-1', [
|
||||||
('property1', stix2.properties.StringProperty()),
|
('property1', stix2.properties.StringProperty()),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -482,7 +483,7 @@ def test_custom_observable_object_invalid_type_name():
|
||||||
)
|
)
|
||||||
class NewObs(object):
|
class NewObs(object):
|
||||||
pass # pragma: no cover
|
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:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
@stix2.v20.CustomObservable(
|
@stix2.v20.CustomObservable(
|
||||||
|
@ -492,7 +493,7 @@ def test_custom_observable_object_invalid_type_name():
|
||||||
)
|
)
|
||||||
class NewObs2(object):
|
class NewObs2(object):
|
||||||
pass # pragma: no cover
|
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():
|
def test_custom_observable_object_invalid_ref_property():
|
||||||
|
@ -807,7 +808,7 @@ def test_custom_extension_invalid_type_name():
|
||||||
)
|
)
|
||||||
class FooExtension():
|
class FooExtension():
|
||||||
pass # pragma: no cover
|
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:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
@stix2.v20.CustomExtension(
|
@stix2.v20.CustomExtension(
|
||||||
|
@ -817,7 +818,7 @@ def test_custom_extension_invalid_type_name():
|
||||||
)
|
)
|
||||||
class BlaExtension():
|
class BlaExtension():
|
||||||
pass # pragma: no cover
|
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():
|
def test_custom_extension_no_properties():
|
||||||
|
@ -967,9 +968,8 @@ def test_register_custom_object():
|
||||||
class CustomObject2(object):
|
class CustomObject2(object):
|
||||||
_type = 'awesome-object'
|
_type = 'awesome-object'
|
||||||
|
|
||||||
stix2.core._register_object(CustomObject2, version="2.0")
|
with pytest.raises(ValueError):
|
||||||
# Note that we will always check against newest OBJ_MAP.
|
stix2.parsing._register_object(CustomObject2, version="2.0")
|
||||||
assert (CustomObject2._type, CustomObject2) in stix2.v20.OBJ_MAP.items()
|
|
||||||
|
|
||||||
|
|
||||||
def test_extension_property_location():
|
def test_extension_property_location():
|
||||||
|
@ -1011,3 +1011,123 @@ def test_custom_object_nested_dictionary(data):
|
||||||
)
|
)
|
||||||
|
|
||||||
assert data == str(example)
|
assert data == str(example)
|
||||||
|
|
||||||
|
|
||||||
|
@stix2.v20.CustomObject(
|
||||||
|
'x-new-type-2', [
|
||||||
|
('property1', stix2.properties.StringProperty()),
|
||||||
|
('property2', stix2.properties.IntegerProperty()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewType2(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_custom_object_with_version():
|
||||||
|
custom_obj_1 = {
|
||||||
|
"type": "x-new-type-2",
|
||||||
|
"id": "x-new-type-2--00000000-0000-4000-8000-000000000007",
|
||||||
|
}
|
||||||
|
|
||||||
|
cust_obj_1 = parsing.dict_to_stix2(custom_obj_1, version='2.0')
|
||||||
|
v = 'v20'
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_duplicate_object_with_version():
|
||||||
|
with pytest.raises(DuplicateRegistrationError) as excinfo:
|
||||||
|
@stix2.v20.CustomObject(
|
||||||
|
'x-new-type-2', [
|
||||||
|
('property1', stix2.properties.StringProperty()),
|
||||||
|
('property2', stix2.properties.IntegerProperty()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewType2(object):
|
||||||
|
pass
|
||||||
|
assert "cannot be registered again" in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
@stix2.v20.CustomObservable(
|
||||||
|
'x-new-observable-2', [
|
||||||
|
('property1', stix2.properties.StringProperty()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewObservable2(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_observable_with_version():
|
||||||
|
custom_obs = NewObservable2(property1="Test Observable")
|
||||||
|
v = 'v20'
|
||||||
|
|
||||||
|
assert custom_obs.type in parsing.STIX2_OBJ_MAPS[v]['observables']
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_duplicate_observable_with_version():
|
||||||
|
with pytest.raises(DuplicateRegistrationError) as excinfo:
|
||||||
|
@stix2.v20.CustomObservable(
|
||||||
|
'x-new-observable-2', [
|
||||||
|
('property1', stix2.properties.StringProperty()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewObservable2(object):
|
||||||
|
pass
|
||||||
|
assert "cannot be registered again" in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_marking_with_version():
|
||||||
|
@stix2.v20.CustomMarking(
|
||||||
|
'x-new-obj-2', [
|
||||||
|
('property1', stix2.properties.StringProperty(required=True)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewObj2():
|
||||||
|
pass
|
||||||
|
v = 'v20'
|
||||||
|
|
||||||
|
no = NewObj2(property1='something')
|
||||||
|
assert no._type in parsing.STIX2_OBJ_MAPS[v]['markings']
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_observable_extension_with_version():
|
||||||
|
@stix2.v20.CustomExtension(
|
||||||
|
stix2.v20.UserAccount, 'some-extension-2', [
|
||||||
|
('keys', stix2.properties.StringProperty(required=True)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class SomeCustomExtension2:
|
||||||
|
pass
|
||||||
|
|
||||||
|
v = 'v20'
|
||||||
|
example = SomeCustomExtension2(keys='test123')
|
||||||
|
|
||||||
|
assert example._type in parsing.STIX2_OBJ_MAPS[v]['observable-extensions']['user-account']
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_duplicate_observable_extension():
|
||||||
|
with pytest.raises(DuplicateRegistrationError) as excinfo:
|
||||||
|
@stix2.v20.CustomExtension(
|
||||||
|
stix2.v20.UserAccount, 'some-extension-2', [
|
||||||
|
('property1', stix2.properties.StringProperty(required=True)),
|
||||||
|
('property2', stix2.properties.IntegerProperty()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewExtension2():
|
||||||
|
pass
|
||||||
|
assert "cannot be registered again" in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_duplicate_marking():
|
||||||
|
with pytest.raises(DuplicateRegistrationError) as excinfo:
|
||||||
|
@stix2.v20.CustomMarking(
|
||||||
|
'x-new-obj-2', [
|
||||||
|
('property1', stix2.properties.StringProperty(required=True)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewObj2():
|
||||||
|
pass
|
||||||
|
assert "cannot be registered again" in str(excinfo.value)
|
||||||
|
|
|
@ -635,7 +635,7 @@ def test_filesystem_object_with_custom_property_in_bundle(fs_store):
|
||||||
|
|
||||||
def test_filesystem_custom_object(fs_store):
|
def test_filesystem_custom_object(fs_store):
|
||||||
@stix2.v20.CustomObject(
|
@stix2.v20.CustomObject(
|
||||||
'x-new-obj', [
|
'x-new-obj-2', [
|
||||||
('property1', stix2.properties.StringProperty(required=True)),
|
('property1', stix2.properties.StringProperty(required=True)),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -650,7 +650,7 @@ def test_filesystem_custom_object(fs_store):
|
||||||
assert newobj_r["property1"] == 'something'
|
assert newobj_r["property1"] == 'something'
|
||||||
|
|
||||||
# remove dir
|
# remove dir
|
||||||
shutil.rmtree(os.path.join(FS_PATH, "x-new-obj"), True)
|
shutil.rmtree(os.path.join(FS_PATH, "x-new-obj-2"), True)
|
||||||
|
|
||||||
|
|
||||||
def test_relationships(rel_fs_store):
|
def test_relationships(rel_fs_store):
|
||||||
|
|
|
@ -329,7 +329,7 @@ def test_memory_store_object_with_custom_property_in_bundle(mem_store):
|
||||||
|
|
||||||
def test_memory_store_custom_object(mem_store):
|
def test_memory_store_custom_object(mem_store):
|
||||||
@CustomObject(
|
@CustomObject(
|
||||||
'x-new-obj', [
|
'x-new-obj-3', [
|
||||||
('property1', properties.StringProperty(required=True)),
|
('property1', properties.StringProperty(required=True)),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,11 +4,13 @@ from medallion.filters.basic_filter import BasicFilter
|
||||||
import pytest
|
import pytest
|
||||||
from requests.models import Response
|
from requests.models import Response
|
||||||
import six
|
import six
|
||||||
from taxii2client import Collection, _filter_kwargs_to_query_params
|
from taxii2client.common import _filter_kwargs_to_query_params
|
||||||
|
from taxii2client.v20 import Collection
|
||||||
|
|
||||||
import stix2
|
import stix2
|
||||||
from stix2.datastore import DataSourceError
|
from stix2.datastore import DataSourceError
|
||||||
from stix2.datastore.filters import Filter
|
from stix2.datastore.filters import Filter
|
||||||
|
from stix2.utils import get_timestamp
|
||||||
|
|
||||||
COLLECTION_URL = 'https://example.com/api1/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/'
|
COLLECTION_URL = 'https://example.com/api1/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/'
|
||||||
|
|
||||||
|
@ -21,6 +23,7 @@ class MockTAXIICollectionEndpoint(Collection):
|
||||||
url, collection_info=collection_info,
|
url, collection_info=collection_info,
|
||||||
)
|
)
|
||||||
self.objects = []
|
self.objects = []
|
||||||
|
self.manifests = []
|
||||||
|
|
||||||
def add_objects(self, bundle):
|
def add_objects(self, bundle):
|
||||||
self._verify_can_write()
|
self._verify_can_write()
|
||||||
|
@ -28,6 +31,14 @@ class MockTAXIICollectionEndpoint(Collection):
|
||||||
bundle = json.loads(bundle, encoding='utf-8')
|
bundle = json.loads(bundle, encoding='utf-8')
|
||||||
for object in bundle.get("objects", []):
|
for object in bundle.get("objects", []):
|
||||||
self.objects.append(object)
|
self.objects.append(object)
|
||||||
|
self.manifests.append(
|
||||||
|
{
|
||||||
|
"date_added": get_timestamp(),
|
||||||
|
"id": object["id"],
|
||||||
|
"media_type": "application/stix+json;version=2.1",
|
||||||
|
"version": object.get("modified", object.get("created", get_timestamp())),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
def get_objects(self, **filter_kwargs):
|
def get_objects(self, **filter_kwargs):
|
||||||
self._verify_can_read()
|
self._verify_can_read()
|
||||||
|
@ -37,8 +48,9 @@ class MockTAXIICollectionEndpoint(Collection):
|
||||||
objs = full_filter.process_filter(
|
objs = full_filter.process_filter(
|
||||||
self.objects,
|
self.objects,
|
||||||
("id", "type", "version"),
|
("id", "type", "version"),
|
||||||
[],
|
self.manifests,
|
||||||
)
|
100,
|
||||||
|
)[0]
|
||||||
if objs:
|
if objs:
|
||||||
return stix2.v20.Bundle(objects=objs)
|
return stix2.v20.Bundle(objects=objs)
|
||||||
else:
|
else:
|
||||||
|
@ -58,8 +70,9 @@ class MockTAXIICollectionEndpoint(Collection):
|
||||||
filtered_objects = full_filter.process_filter(
|
filtered_objects = full_filter.process_filter(
|
||||||
objects,
|
objects,
|
||||||
("version",),
|
("version",),
|
||||||
[],
|
self.manifests,
|
||||||
)
|
100,
|
||||||
|
)[0]
|
||||||
else:
|
else:
|
||||||
filtered_objects = []
|
filtered_objects = []
|
||||||
if filtered_objects:
|
if filtered_objects:
|
||||||
|
@ -71,7 +84,7 @@ class MockTAXIICollectionEndpoint(Collection):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def collection(stix_objs1):
|
def collection(stix_objs1, stix_objs1_manifests):
|
||||||
mock = MockTAXIICollectionEndpoint(
|
mock = MockTAXIICollectionEndpoint(
|
||||||
COLLECTION_URL, {
|
COLLECTION_URL, {
|
||||||
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
||||||
|
@ -86,11 +99,12 @@ def collection(stix_objs1):
|
||||||
)
|
)
|
||||||
|
|
||||||
mock.objects.extend(stix_objs1)
|
mock.objects.extend(stix_objs1)
|
||||||
|
mock.manifests.extend(stix_objs1_manifests)
|
||||||
return mock
|
return mock
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def collection_no_rw_access(stix_objs1):
|
def collection_no_rw_access(stix_objs1, stix_objs1_manifests):
|
||||||
mock = MockTAXIICollectionEndpoint(
|
mock = MockTAXIICollectionEndpoint(
|
||||||
COLLECTION_URL, {
|
COLLECTION_URL, {
|
||||||
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
||||||
|
@ -105,6 +119,7 @@ def collection_no_rw_access(stix_objs1):
|
||||||
)
|
)
|
||||||
|
|
||||||
mock.objects.extend(stix_objs1)
|
mock.objects.extend(stix_objs1)
|
||||||
|
mock.manifests.extend(stix_objs1_manifests)
|
||||||
return mock
|
return mock
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -249,14 +249,12 @@ def test_not_registered_marking_raises_exception():
|
||||||
|
|
||||||
|
|
||||||
def test_marking_wrong_type_construction():
|
def test_marking_wrong_type_construction():
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError):
|
||||||
# Test passing wrong type for properties.
|
# Test passing wrong type for properties.
|
||||||
@stix2.v20.CustomMarking('x-new-marking-type2', ("a", "b"))
|
@stix2.v20.CustomMarking('x-new-marking-type2', ("a", "b"))
|
||||||
class NewObject3(object):
|
class NewObject3(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
assert str(excinfo.value) == "Must supply a list, containing tuples. For example, [('property1', IntegerProperty())]"
|
|
||||||
|
|
||||||
|
|
||||||
def test_campaign_add_markings():
|
def test_campaign_add_markings():
|
||||||
campaign = stix2.v20.Campaign(
|
campaign = stix2.v20.Campaign(
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import stix2
|
||||||
|
from stix2 import exceptions, parsing
|
||||||
|
|
||||||
|
BUNDLE = {
|
||||||
|
"type": "bundle",
|
||||||
|
"spec_version": "2.0",
|
||||||
|
"id": "bundle--00000000-0000-4000-8000-000000000007",
|
||||||
|
"objects": [
|
||||||
|
{
|
||||||
|
"type": "indicator",
|
||||||
|
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||||
|
"created": "2017-01-01T12:34:56.000Z",
|
||||||
|
"modified": "2017-01-01T12:34:56.000Z",
|
||||||
|
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||||
|
"valid_from": "2017-01-01T12:34:56Z",
|
||||||
|
"labels": [
|
||||||
|
"malicious-activity",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "malware",
|
||||||
|
"id": "malware--00000000-0000-4000-8000-000000000003",
|
||||||
|
"created": "2017-01-01T12:34:56.000Z",
|
||||||
|
"modified": "2017-01-01T12:34:56.000Z",
|
||||||
|
"name": "Cryptolocker",
|
||||||
|
"labels": [
|
||||||
|
"ransomware",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "relationship",
|
||||||
|
"id": "relationship--00000000-0000-4000-8000-000000000005",
|
||||||
|
"created": "2017-01-01T12:34:56.000Z",
|
||||||
|
"modified": "2017-01-01T12:34:56.000Z",
|
||||||
|
"relationship_type": "indicates",
|
||||||
|
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||||
|
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_dict_to_stix2_bundle_with_version():
|
||||||
|
with pytest.raises(exceptions.ExtraPropertiesError) as excinfo:
|
||||||
|
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 = parsing.parse_observable(observable, version='2.0')
|
||||||
|
v = 'v20'
|
||||||
|
|
||||||
|
assert v in str(obs_obj.__class__)
|
||||||
|
|
||||||
|
|
||||||
|
@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 = parsing.parse_observable(observable)
|
||||||
|
v = 'v20'
|
||||||
|
|
||||||
|
assert v in str(obs_obj.__class__)
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_marking_with_version():
|
||||||
|
parsing._register_marking(stix2.v20.TLP_WHITE.__class__, version='2.0')
|
||||||
|
v = 'v20'
|
||||||
|
|
||||||
|
assert stix2.v20.TLP_WHITE.definition._type in parsing.STIX2_OBJ_MAPS[v]['markings']
|
||||||
|
assert v in str(stix2.v20.TLP_WHITE.__class__)
|
|
@ -494,13 +494,14 @@ def test_make_constant_already_a_constant():
|
||||||
|
|
||||||
|
|
||||||
def test_parsing_comparison_expression():
|
def test_parsing_comparison_expression():
|
||||||
patt_obj = create_pattern_object("[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f']")
|
patt_obj = create_pattern_object("[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f']", version="2.0")
|
||||||
assert str(patt_obj) == "[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f']"
|
assert str(patt_obj) == "[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f']"
|
||||||
|
|
||||||
|
|
||||||
def test_parsing_qualified_expression():
|
def test_parsing_qualified_expression():
|
||||||
patt_obj = create_pattern_object(
|
patt_obj = create_pattern_object(
|
||||||
"[network-traffic:dst_ref.type = 'domain-name' AND network-traffic:dst_ref.value = 'example.com'] REPEATS 5 TIMES WITHIN 1800 SECONDS",
|
"[network-traffic:dst_ref.type = 'domain-name' AND network-traffic:dst_ref.value = 'example.com'] REPEATS 5 TIMES WITHIN 1800 SECONDS",
|
||||||
|
version="2.0",
|
||||||
)
|
)
|
||||||
assert str(
|
assert str(
|
||||||
patt_obj,
|
patt_obj,
|
||||||
|
@ -508,5 +509,5 @@ def test_parsing_qualified_expression():
|
||||||
|
|
||||||
|
|
||||||
def test_list_constant():
|
def test_list_constant():
|
||||||
patt_obj = create_pattern_object("[network-traffic:src_ref.value IN ('10.0.0.0', '10.0.0.1', '10.0.0.2')]")
|
patt_obj = create_pattern_object("[network-traffic:src_ref.value IN ('10.0.0.0', '10.0.0.1', '10.0.0.2')]", version="2.0")
|
||||||
assert str(patt_obj) == "[network-traffic:src_ref.value IN ('10.0.0.0', '10.0.0.1', '10.0.0.2')]"
|
assert str(patt_obj) == "[network-traffic:src_ref.value IN ('10.0.0.0', '10.0.0.1', '10.0.0.2')]"
|
||||||
|
|
|
@ -392,7 +392,7 @@ def test_dictionary_property_invalid(d):
|
||||||
|
|
||||||
def test_property_list_of_dictionary():
|
def test_property_list_of_dictionary():
|
||||||
@stix2.v20.CustomObject(
|
@stix2.v20.CustomObject(
|
||||||
'x-new-obj', [
|
'x-new-obj-4', [
|
||||||
('property1', ListProperty(DictionaryProperty(spec_version="2.0"), required=True)),
|
('property1', ListProperty(DictionaryProperty(spec_version="2.0"), required=True)),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -135,6 +135,42 @@ def stix_objs1():
|
||||||
return [ind1, ind2, ind3, ind4, ind5]
|
return [ind1, ind2, ind3, ind4, ind5]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def stix_objs1_manifests():
|
||||||
|
# Tests against latest medallion (TAXII 2.1)
|
||||||
|
ind1 = {
|
||||||
|
"date_added": "2017-01-27T13:49:53.935Z",
|
||||||
|
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||||
|
"media_type": "application/stix+json;version=2.1",
|
||||||
|
"version": "2017-01-27T13:49:53.935Z",
|
||||||
|
}
|
||||||
|
ind2 = {
|
||||||
|
"date_added": "2017-01-27T13:49:53.935Z",
|
||||||
|
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||||
|
"media_type": "application/stix+json;version=2.1",
|
||||||
|
"version": "2017-01-27T13:49:53.935Z",
|
||||||
|
}
|
||||||
|
ind3 = {
|
||||||
|
"date_added": "2017-01-27T13:49:53.935Z",
|
||||||
|
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||||
|
"media_type": "application/stix+json;version=2.1",
|
||||||
|
"version": "2017-01-27T13:49:53.936Z",
|
||||||
|
}
|
||||||
|
ind4 = {
|
||||||
|
"date_added": "2017-01-27T13:49:53.935Z",
|
||||||
|
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||||
|
"media_type": "application/stix+json;version=2.1",
|
||||||
|
"version": "2017-01-27T13:49:53.935Z",
|
||||||
|
}
|
||||||
|
ind5 = {
|
||||||
|
"date_added": "2017-01-27T13:49:53.935Z",
|
||||||
|
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||||
|
"media_type": "application/stix+json;version=2.1",
|
||||||
|
"version": "2017-01-27T13:49:53.935Z",
|
||||||
|
}
|
||||||
|
return [ind1, ind2, ind3, ind4, ind5]
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def stix_objs2():
|
def stix_objs2():
|
||||||
ind6 = {
|
ind6 = {
|
||||||
|
|
|
@ -88,8 +88,8 @@ def test_attack_pattern_invalid_labels():
|
||||||
def test_overly_precise_timestamps():
|
def test_overly_precise_timestamps():
|
||||||
ap = stix2.v21.AttackPattern(
|
ap = stix2.v21.AttackPattern(
|
||||||
id=ATTACK_PATTERN_ID,
|
id=ATTACK_PATTERN_ID,
|
||||||
created="2016-05-12T08:17:27.0000342Z",
|
created="2016-05-12T08:17:27.000000342Z",
|
||||||
modified="2016-05-12T08:17:27.000287Z",
|
modified="2016-05-12T08:17:27.000000287Z",
|
||||||
name="Spear Phishing",
|
name="Spear Phishing",
|
||||||
external_references=[{
|
external_references=[{
|
||||||
"source_name": "capec",
|
"source_name": "capec",
|
||||||
|
|
|
@ -1,179 +0,0 @@
|
||||||
import pytest
|
|
||||||
|
|
||||||
import stix2
|
|
||||||
from stix2 import core, exceptions
|
|
||||||
|
|
||||||
from .constants import IDENTITY_ID, OBSERVED_DATA_ID
|
|
||||||
|
|
||||||
BUNDLE = {
|
|
||||||
"type": "bundle",
|
|
||||||
"id": "bundle--00000000-0000-4000-8000-000000000007",
|
|
||||||
"objects": [
|
|
||||||
{
|
|
||||||
"type": "indicator",
|
|
||||||
"spec_version": "2.1",
|
|
||||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
|
||||||
"created": "2017-01-01T12:34:56.000Z",
|
|
||||||
"modified": "2017-01-01T12:34:56.000Z",
|
|
||||||
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
|
||||||
"pattern_type": "stix",
|
|
||||||
"valid_from": "2017-01-01T12:34:56Z",
|
|
||||||
"indicator_types": [
|
|
||||||
"malicious-activity",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "malware",
|
|
||||||
"spec_version": "2.1",
|
|
||||||
"id": "malware--00000000-0000-4000-8000-000000000003",
|
|
||||||
"created": "2017-01-01T12:34:56.000Z",
|
|
||||||
"modified": "2017-01-01T12:34:56.000Z",
|
|
||||||
"name": "Cryptolocker",
|
|
||||||
"malware_types": [
|
|
||||||
"ransomware",
|
|
||||||
],
|
|
||||||
"is_family": False,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "relationship",
|
|
||||||
"spec_version": "2.1",
|
|
||||||
"id": "relationship--00000000-0000-4000-8000-000000000005",
|
|
||||||
"created": "2017-01-01T12:34:56.000Z",
|
|
||||||
"modified": "2017-01-01T12:34:56.000Z",
|
|
||||||
"relationship_type": "indicates",
|
|
||||||
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
|
||||||
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_dict_to_stix2_bundle_with_version():
|
|
||||||
with pytest.raises(exceptions.InvalidValueError) as excinfo:
|
|
||||||
core.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
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_observable_with_version():
|
|
||||||
observable = {"type": "file", "name": "foo.exe"}
|
|
||||||
obs_obj = core.parse_observable(observable, version='2.1')
|
|
||||||
v = 'v21'
|
|
||||||
|
|
||||||
assert v in str(obs_obj.__class__)
|
|
||||||
|
|
||||||
|
|
||||||
@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)
|
|
||||||
v = 'v21'
|
|
||||||
|
|
||||||
assert v in str(obs_obj.__class__)
|
|
||||||
|
|
||||||
|
|
||||||
def test_register_object_with_version():
|
|
||||||
bundle = core.dict_to_stix2(BUNDLE, version='2.1')
|
|
||||||
core._register_object(bundle.objects[0].__class__)
|
|
||||||
v = 'v21'
|
|
||||||
|
|
||||||
assert bundle.objects[0].type in core.STIX2_OBJ_MAPS[v]['objects']
|
|
||||||
assert bundle.objects[0].spec_version == "2.1"
|
|
||||||
|
|
||||||
|
|
||||||
def test_register_marking_with_version():
|
|
||||||
core._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 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__)
|
|
||||||
v = 'v21'
|
|
||||||
|
|
||||||
assert stix2.v21.TLP_WHITE.definition._type in core.STIX2_OBJ_MAPS[v]['markings']
|
|
||||||
assert v in str(stix2.v21.TLP_WHITE.__class__)
|
|
||||||
|
|
||||||
|
|
||||||
def test_register_observable_with_default_version():
|
|
||||||
observed_data = stix2.v21.ObservedData(
|
|
||||||
id=OBSERVED_DATA_ID,
|
|
||||||
created_by_ref=IDENTITY_ID,
|
|
||||||
created="2016-04-06T19:58:16.000Z",
|
|
||||||
modified="2016-04-06T19:58:16.000Z",
|
|
||||||
first_observed="2015-12-21T19:00:00Z",
|
|
||||||
last_observed="2015-12-21T19:00:00Z",
|
|
||||||
number_observed=50,
|
|
||||||
objects={
|
|
||||||
"0": {
|
|
||||||
"name": "foo.exe",
|
|
||||||
"type": "file",
|
|
||||||
"extensions": {
|
|
||||||
"ntfs-ext": {
|
|
||||||
"alternate_data_streams": [
|
|
||||||
{
|
|
||||||
"name": "second.stream",
|
|
||||||
"size": 25536,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"type": "directory",
|
|
||||||
"path": "/usr/home",
|
|
||||||
"contains_refs": ["file--420bc087-8b53-5ae9-8210-20d27d5e96c8"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
core._register_observable(observed_data.objects['0'].__class__)
|
|
||||||
v = 'v21'
|
|
||||||
|
|
||||||
assert observed_data.objects['0'].type in core.STIX2_OBJ_MAPS[v]['observables']
|
|
||||||
assert v in str(observed_data.objects['0'].__class__)
|
|
||||||
|
|
||||||
|
|
||||||
def test_register_observable_extension_with_default_version():
|
|
||||||
observed_data = stix2.v21.ObservedData(
|
|
||||||
id=OBSERVED_DATA_ID,
|
|
||||||
created_by_ref=IDENTITY_ID,
|
|
||||||
created="2016-04-06T19:58:16.000Z",
|
|
||||||
modified="2016-04-06T19:58:16.000Z",
|
|
||||||
first_observed="2015-12-21T19:00:00Z",
|
|
||||||
last_observed="2015-12-21T19:00:00Z",
|
|
||||||
number_observed=50,
|
|
||||||
objects={
|
|
||||||
"0": {
|
|
||||||
"name": "foo.exe",
|
|
||||||
"type": "file",
|
|
||||||
"extensions": {
|
|
||||||
"ntfs-ext": {
|
|
||||||
"alternate_data_streams": [
|
|
||||||
{
|
|
||||||
"name": "second.stream",
|
|
||||||
"size": 25536,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"type": "directory",
|
|
||||||
"path": "/usr/home",
|
|
||||||
"contains_refs": ["file--420bc087-8b53-5ae9-8210-20d27d5e96c8"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
core._register_observable_extension(observed_data.objects['0'], observed_data.objects['0'].extensions['ntfs-ext'].__class__)
|
|
||||||
v = 'v21'
|
|
||||||
|
|
||||||
assert observed_data.objects['0'].type in core.STIX2_OBJ_MAPS[v]['observables']
|
|
||||||
assert v in str(observed_data.objects['0'].__class__)
|
|
||||||
|
|
||||||
assert observed_data.objects['0'].extensions['ntfs-ext']._type in core.STIX2_OBJ_MAPS[v]['observable-extensions']['file']
|
|
||||||
assert v in str(observed_data.objects['0'].extensions['ntfs-ext'].__class__)
|
|
|
@ -6,9 +6,11 @@ import stix2
|
||||||
import stix2.base
|
import stix2.base
|
||||||
import stix2.v21
|
import stix2.v21
|
||||||
|
|
||||||
from ...exceptions import InvalidValueError
|
from ...exceptions import DuplicateRegistrationError, InvalidValueError
|
||||||
from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID
|
from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID
|
||||||
|
|
||||||
|
# Custom Properties in SDOs
|
||||||
|
|
||||||
IDENTITY_CUSTOM_PROP = stix2.v21.Identity(
|
IDENTITY_CUSTOM_PROP = stix2.v21.Identity(
|
||||||
name="John Smith",
|
name="John Smith",
|
||||||
identity_class="individual",
|
identity_class="individual",
|
||||||
|
@ -18,6 +20,18 @@ IDENTITY_CUSTOM_PROP = stix2.v21.Identity(
|
||||||
|
|
||||||
|
|
||||||
def test_identity_custom_property():
|
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:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
stix2.v21.Identity(
|
stix2.v21.Identity(
|
||||||
id=IDENTITY_ID,
|
id=IDENTITY_ID,
|
||||||
|
@ -43,17 +57,47 @@ def test_identity_custom_property():
|
||||||
)
|
)
|
||||||
assert "Unexpected properties for Identity" in str(excinfo.value)
|
assert "Unexpected properties for Identity" in str(excinfo.value)
|
||||||
|
|
||||||
identity = stix2.v21.Identity(
|
# leading numeric character is illegal in 2.1
|
||||||
id=IDENTITY_ID,
|
|
||||||
created="2015-12-21T19:59:11Z",
|
with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo:
|
||||||
modified="2015-12-21T19:59:11Z",
|
stix2.v21.Identity(
|
||||||
name="John Smith",
|
id=IDENTITY_ID,
|
||||||
identity_class="individual",
|
created="2015-12-21T19:59:11Z",
|
||||||
custom_properties={
|
modified="2015-12-21T19:59:11Z",
|
||||||
"foo": "bar",
|
name="John Smith",
|
||||||
},
|
identity_class="individual",
|
||||||
)
|
custom_properties={
|
||||||
assert identity.foo == "bar"
|
"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():
|
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 bundle.objects[0].x_foo == "bar"
|
||||||
assert '"x_foo": "bar"' in str(bundle)
|
assert '"x_foo": "bar"' in str(bundle)
|
||||||
|
|
||||||
|
# Custom properties in SCOs
|
||||||
|
|
||||||
|
|
||||||
def test_custom_property_in_observed_data():
|
def test_custom_property_in_observed_data():
|
||||||
artifact = stix2.v21.File(
|
artifact = stix2.v21.File(
|
||||||
|
@ -184,6 +230,18 @@ def test_custom_property_in_observed_data():
|
||||||
assert '"x_foo": "bar"' in str(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():
|
def test_custom_property_object_in_observable_extension():
|
||||||
ntfs = stix2.v21.NTFSExt(
|
ntfs = stix2.v21.NTFSExt(
|
||||||
allow_custom=True,
|
allow_custom=True,
|
||||||
|
@ -245,6 +303,8 @@ def test_identity_custom_property_revoke():
|
||||||
identity = IDENTITY_CUSTOM_PROP.revoke()
|
identity = IDENTITY_CUSTOM_PROP.revoke()
|
||||||
assert identity.x_foo == "bar"
|
assert identity.x_foo == "bar"
|
||||||
|
|
||||||
|
# Custom markings
|
||||||
|
|
||||||
|
|
||||||
def test_identity_custom_property_edit_markings():
|
def test_identity_custom_property_edit_markings():
|
||||||
marking_obj = stix2.v21.MarkingDefinition(
|
marking_obj = stix2.v21.MarkingDefinition(
|
||||||
|
@ -267,6 +327,19 @@ def test_identity_custom_property_edit_markings():
|
||||||
identity2.clear_markings('x_foo')
|
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():
|
def test_custom_marking_no_init_1():
|
||||||
@stix2.v21.CustomMarking(
|
@stix2.v21.CustomMarking(
|
||||||
'x-new-obj', [
|
'x-new-obj', [
|
||||||
|
@ -293,6 +366,40 @@ def test_custom_marking_no_init_2():
|
||||||
assert no2.property1 == 'something'
|
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(
|
@stix2.v21.CustomObject(
|
||||||
'x-new-type', [
|
'x-new-type', [
|
||||||
('property1', stix2.properties.StringProperty(required=True)),
|
('property1', stix2.properties.StringProperty(required=True)),
|
||||||
|
@ -374,6 +481,16 @@ def test_custom_object_invalid_type_name():
|
||||||
pass # pragma: no cover
|
pass # pragma: no cover
|
||||||
assert "Invalid type name 'x_new_object':" in str(excinfo.value)
|
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():
|
def test_parse_custom_object_type():
|
||||||
nt_string = """{
|
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)
|
custom_obj = stix2.parse(nt_string, version="2.1", allow_custom=True)
|
||||||
assert custom_obj["type"] == "x-foobar-observable"
|
assert custom_obj["type"] == "x-foobar-observable"
|
||||||
|
|
||||||
|
# Custom SCOs
|
||||||
|
|
||||||
|
|
||||||
@stix2.v21.CustomObservable(
|
@stix2.v21.CustomObservable(
|
||||||
'x-new-observable', [
|
'x-new-observable', [
|
||||||
|
@ -455,7 +574,7 @@ def test_custom_observable_raises_exception():
|
||||||
|
|
||||||
def test_custom_observable_object_no_init_1():
|
def test_custom_observable_object_no_init_1():
|
||||||
@stix2.v21.CustomObservable(
|
@stix2.v21.CustomObservable(
|
||||||
'x-new-observable', [
|
'x-new-observable-2', [
|
||||||
('property1', stix2.properties.StringProperty()),
|
('property1', stix2.properties.StringProperty()),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -479,6 +598,18 @@ def test_custom_observable_object_no_init_2():
|
||||||
assert no2.property1 == 'something'
|
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():
|
def test_custom_observable_object_invalid_type_name():
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
@stix2.v21.CustomObservable(
|
@stix2.v21.CustomObservable(
|
||||||
|
@ -488,7 +619,7 @@ def test_custom_observable_object_invalid_type_name():
|
||||||
)
|
)
|
||||||
class NewObs(object):
|
class NewObs(object):
|
||||||
pass # pragma: no cover
|
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:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
@stix2.v21.CustomObservable(
|
@stix2.v21.CustomObservable(
|
||||||
|
@ -498,7 +629,17 @@ def test_custom_observable_object_invalid_type_name():
|
||||||
)
|
)
|
||||||
class NewObs2(object):
|
class NewObs2(object):
|
||||||
pass # pragma: no cover
|
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():
|
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.variant == uuid.RFC_4122
|
||||||
assert uuid_obj.version == 4
|
assert uuid_obj.version == 4
|
||||||
|
|
||||||
|
# Custom Extensions
|
||||||
|
|
||||||
|
|
||||||
@stix2.v21.CustomExtension(
|
@stix2.v21.CustomExtension(
|
||||||
stix2.v21.DomainName, 'x-new-ext', [
|
stix2.v21.DomainName, 'x-new-ext', [
|
||||||
|
@ -862,7 +1005,7 @@ def test_custom_extension_invalid_type_name():
|
||||||
)
|
)
|
||||||
class FooExtension():
|
class FooExtension():
|
||||||
pass # pragma: no cover
|
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:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
@stix2.v21.CustomExtension(
|
@stix2.v21.CustomExtension(
|
||||||
|
@ -872,7 +1015,17 @@ def test_custom_extension_invalid_type_name():
|
||||||
)
|
)
|
||||||
class BlaExtension():
|
class BlaExtension():
|
||||||
pass # pragma: no cover
|
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():
|
def test_custom_extension_no_properties():
|
||||||
|
@ -922,6 +1075,19 @@ def test_custom_extension_no_init_2():
|
||||||
assert ne2.property1 == "foobar"
|
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():
|
def test_parse_observable_with_custom_extension():
|
||||||
input_str = """{
|
input_str = """{
|
||||||
"type": "domain-name",
|
"type": "domain-name",
|
||||||
|
@ -1020,9 +1186,9 @@ def test_register_custom_object():
|
||||||
class CustomObject2(object):
|
class CustomObject2(object):
|
||||||
_type = 'awesome-object'
|
_type = 'awesome-object'
|
||||||
|
|
||||||
stix2.core._register_object(CustomObject2, version="2.1")
|
with pytest.raises(ValueError) as excinfo:
|
||||||
# Note that we will always check against newest OBJ_MAP.
|
stix2.parsing._register_object(CustomObject2, version="2.1")
|
||||||
assert (CustomObject2._type, CustomObject2) in stix2.v21.OBJ_MAP.items()
|
assert '@CustomObject decorator' in str(excinfo)
|
||||||
|
|
||||||
|
|
||||||
def test_extension_property_location():
|
def test_extension_property_location():
|
||||||
|
@ -1065,3 +1231,110 @@ def test_custom_object_nested_dictionary(data):
|
||||||
)
|
)
|
||||||
|
|
||||||
assert data == str(example)
|
assert data == str(example)
|
||||||
|
|
||||||
|
|
||||||
|
@stix2.v21.CustomObject(
|
||||||
|
'x-new-type-2', [
|
||||||
|
('property1', stix2.properties.StringProperty()),
|
||||||
|
('property2', stix2.properties.IntegerProperty()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewType3(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_custom_object_with_version():
|
||||||
|
custom_obj_1 = {
|
||||||
|
"type": "x-new-type-2",
|
||||||
|
"id": "x-new-type-2--00000000-0000-4000-8000-000000000007",
|
||||||
|
"spec_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.parsing.STIX2_OBJ_MAPS[v]['objects']
|
||||||
|
assert cust_obj_1.spec_version == "2.1"
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_duplicate_object_with_version():
|
||||||
|
with pytest.raises(DuplicateRegistrationError) as excinfo:
|
||||||
|
@stix2.v21.CustomObject(
|
||||||
|
'x-new-type-2', [
|
||||||
|
('property1', stix2.properties.StringProperty()),
|
||||||
|
('property2', stix2.properties.IntegerProperty()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewType2(object):
|
||||||
|
pass
|
||||||
|
assert "cannot be registered again" in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
@stix2.v21.CustomObservable(
|
||||||
|
'x-new-observable-3', [
|
||||||
|
('property1', stix2.properties.StringProperty()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewObservable3(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_observable():
|
||||||
|
custom_obs = NewObservable3(property1="Test Observable")
|
||||||
|
v = 'v21'
|
||||||
|
|
||||||
|
assert custom_obs.type in stix2.parsing.STIX2_OBJ_MAPS[v]['observables']
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_duplicate_observable():
|
||||||
|
with pytest.raises(DuplicateRegistrationError) as excinfo:
|
||||||
|
@stix2.v21.CustomObservable(
|
||||||
|
'x-new-observable-2', [
|
||||||
|
('property1', stix2.properties.StringProperty()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewObservable2(object):
|
||||||
|
pass
|
||||||
|
assert "cannot be registered again" in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_observable_custom_extension():
|
||||||
|
@stix2.v21.CustomExtension(
|
||||||
|
stix2.v21.DomainName, 'x-new-2-ext', [
|
||||||
|
('property1', stix2.properties.StringProperty(required=True)),
|
||||||
|
('property2', stix2.properties.IntegerProperty()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewExtension2():
|
||||||
|
pass
|
||||||
|
|
||||||
|
example = NewExtension2(property1="Hi there")
|
||||||
|
v = 'v21'
|
||||||
|
|
||||||
|
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():
|
||||||
|
with pytest.raises(DuplicateRegistrationError) as excinfo:
|
||||||
|
@stix2.v21.CustomExtension(
|
||||||
|
stix2.v21.DomainName, 'x-new-2-ext', [
|
||||||
|
('property1', stix2.properties.StringProperty(required=True)),
|
||||||
|
('property2', stix2.properties.IntegerProperty()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewExtension2():
|
||||||
|
pass
|
||||||
|
assert "cannot be registered again" in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_duplicate_marking():
|
||||||
|
with pytest.raises(DuplicateRegistrationError) as excinfo:
|
||||||
|
@stix2.v21.CustomMarking(
|
||||||
|
'x-new-obj', [
|
||||||
|
('property1', stix2.properties.StringProperty(required=True)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewObj2():
|
||||||
|
pass
|
||||||
|
assert "cannot be registered again" in str(excinfo.value)
|
||||||
|
|
|
@ -656,7 +656,7 @@ def test_filesystem_object_with_custom_property_in_bundle(fs_store):
|
||||||
|
|
||||||
def test_filesystem_custom_object(fs_store):
|
def test_filesystem_custom_object(fs_store):
|
||||||
@stix2.v21.CustomObject(
|
@stix2.v21.CustomObject(
|
||||||
'x-new-obj', [
|
'x-new-obj-2', [
|
||||||
('property1', stix2.properties.StringProperty(required=True)),
|
('property1', stix2.properties.StringProperty(required=True)),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -671,7 +671,7 @@ def test_filesystem_custom_object(fs_store):
|
||||||
assert newobj_r["property1"] == 'something'
|
assert newobj_r["property1"] == 'something'
|
||||||
|
|
||||||
# remove dir
|
# remove dir
|
||||||
shutil.rmtree(os.path.join(FS_PATH, "x-new-obj"), True)
|
shutil.rmtree(os.path.join(FS_PATH, "x-new-obj-2"), True)
|
||||||
|
|
||||||
|
|
||||||
def test_relationships(rel_fs_store):
|
def test_relationships(rel_fs_store):
|
||||||
|
|
|
@ -344,7 +344,7 @@ def test_memory_store_object_with_custom_property_in_bundle(mem_store):
|
||||||
|
|
||||||
def test_memory_store_custom_object(mem_store):
|
def test_memory_store_custom_object(mem_store):
|
||||||
@CustomObject(
|
@CustomObject(
|
||||||
'x-new-obj', [
|
'x-new-obj-3', [
|
||||||
('property1', properties.StringProperty(required=True)),
|
('property1', properties.StringProperty(required=True)),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,11 +4,13 @@ from medallion.filters.basic_filter import BasicFilter
|
||||||
import pytest
|
import pytest
|
||||||
from requests.models import Response
|
from requests.models import Response
|
||||||
import six
|
import six
|
||||||
from taxii2client import Collection, _filter_kwargs_to_query_params
|
from taxii2client.common import _filter_kwargs_to_query_params
|
||||||
|
from taxii2client.v21 import Collection
|
||||||
|
|
||||||
import stix2
|
import stix2
|
||||||
from stix2.datastore import DataSourceError
|
from stix2.datastore import DataSourceError
|
||||||
from stix2.datastore.filters import Filter
|
from stix2.datastore.filters import Filter
|
||||||
|
from stix2.utils import get_timestamp
|
||||||
|
|
||||||
COLLECTION_URL = 'https://example.com/api1/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/'
|
COLLECTION_URL = 'https://example.com/api1/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/'
|
||||||
|
|
||||||
|
@ -21,6 +23,7 @@ class MockTAXIICollectionEndpoint(Collection):
|
||||||
url, collection_info=collection_info,
|
url, collection_info=collection_info,
|
||||||
)
|
)
|
||||||
self.objects = []
|
self.objects = []
|
||||||
|
self.manifests = []
|
||||||
|
|
||||||
def add_objects(self, bundle):
|
def add_objects(self, bundle):
|
||||||
self._verify_can_write()
|
self._verify_can_write()
|
||||||
|
@ -28,6 +31,14 @@ class MockTAXIICollectionEndpoint(Collection):
|
||||||
bundle = json.loads(bundle, encoding='utf-8')
|
bundle = json.loads(bundle, encoding='utf-8')
|
||||||
for object in bundle.get("objects", []):
|
for object in bundle.get("objects", []):
|
||||||
self.objects.append(object)
|
self.objects.append(object)
|
||||||
|
self.manifests.append(
|
||||||
|
{
|
||||||
|
"date_added": get_timestamp(),
|
||||||
|
"id": object["id"],
|
||||||
|
"media_type": "application/stix+json;version=2.1",
|
||||||
|
"version": object.get("modified", object.get("created", get_timestamp())),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
def get_objects(self, **filter_kwargs):
|
def get_objects(self, **filter_kwargs):
|
||||||
self._verify_can_read()
|
self._verify_can_read()
|
||||||
|
@ -37,8 +48,9 @@ class MockTAXIICollectionEndpoint(Collection):
|
||||||
objs = full_filter.process_filter(
|
objs = full_filter.process_filter(
|
||||||
self.objects,
|
self.objects,
|
||||||
("id", "type", "version"),
|
("id", "type", "version"),
|
||||||
[],
|
self.manifests,
|
||||||
)
|
100,
|
||||||
|
)[0]
|
||||||
if objs:
|
if objs:
|
||||||
return stix2.v21.Bundle(objects=objs)
|
return stix2.v21.Bundle(objects=objs)
|
||||||
else:
|
else:
|
||||||
|
@ -58,8 +70,9 @@ class MockTAXIICollectionEndpoint(Collection):
|
||||||
filtered_objects = full_filter.process_filter(
|
filtered_objects = full_filter.process_filter(
|
||||||
objects,
|
objects,
|
||||||
("version",),
|
("version",),
|
||||||
[],
|
self.manifests,
|
||||||
)
|
100,
|
||||||
|
)[0]
|
||||||
else:
|
else:
|
||||||
filtered_objects = []
|
filtered_objects = []
|
||||||
if filtered_objects:
|
if filtered_objects:
|
||||||
|
@ -71,7 +84,7 @@ class MockTAXIICollectionEndpoint(Collection):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def collection(stix_objs1):
|
def collection(stix_objs1, stix_objs1_manifests):
|
||||||
mock = MockTAXIICollectionEndpoint(
|
mock = MockTAXIICollectionEndpoint(
|
||||||
COLLECTION_URL, {
|
COLLECTION_URL, {
|
||||||
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
||||||
|
@ -86,11 +99,12 @@ def collection(stix_objs1):
|
||||||
)
|
)
|
||||||
|
|
||||||
mock.objects.extend(stix_objs1)
|
mock.objects.extend(stix_objs1)
|
||||||
|
mock.manifests.extend(stix_objs1_manifests)
|
||||||
return mock
|
return mock
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def collection_no_rw_access(stix_objs1):
|
def collection_no_rw_access(stix_objs1, stix_objs1_manifests):
|
||||||
mock = MockTAXIICollectionEndpoint(
|
mock = MockTAXIICollectionEndpoint(
|
||||||
COLLECTION_URL, {
|
COLLECTION_URL, {
|
||||||
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
||||||
|
@ -105,6 +119,7 @@ def collection_no_rw_access(stix_objs1):
|
||||||
)
|
)
|
||||||
|
|
||||||
mock.objects.extend(stix_objs1)
|
mock.objects.extend(stix_objs1)
|
||||||
|
mock.manifests.extend(stix_objs1_manifests)
|
||||||
return mock
|
return mock
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -277,14 +277,12 @@ def test_not_registered_marking_raises_exception():
|
||||||
|
|
||||||
|
|
||||||
def test_marking_wrong_type_construction():
|
def test_marking_wrong_type_construction():
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError):
|
||||||
# Test passing wrong type for properties.
|
# Test passing wrong type for properties.
|
||||||
@stix2.v21.CustomMarking('x-new-marking-type2', ("a", "b"))
|
@stix2.v21.CustomMarking('x-new-marking-type2', ("a", "b"))
|
||||||
class NewObject3(object):
|
class NewObject3(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
assert str(excinfo.value) == "Must supply a list, containing tuples. For example, [('property1', IntegerProperty())]"
|
|
||||||
|
|
||||||
|
|
||||||
def test_campaign_add_markings():
|
def test_campaign_add_markings():
|
||||||
campaign = stix2.v21.Campaign(
|
campaign = stix2.v21.Campaign(
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import stix2
|
||||||
|
from stix2 import exceptions, parsing
|
||||||
|
|
||||||
|
BUNDLE = {
|
||||||
|
"type": "bundle",
|
||||||
|
"id": "bundle--00000000-0000-4000-8000-000000000007",
|
||||||
|
"objects": [
|
||||||
|
{
|
||||||
|
"type": "indicator",
|
||||||
|
"spec_version": "2.1",
|
||||||
|
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||||
|
"created": "2017-01-01T12:34:56.000Z",
|
||||||
|
"modified": "2017-01-01T12:34:56.000Z",
|
||||||
|
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||||
|
"pattern_type": "stix",
|
||||||
|
"valid_from": "2017-01-01T12:34:56Z",
|
||||||
|
"indicator_types": [
|
||||||
|
"malicious-activity",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "malware",
|
||||||
|
"spec_version": "2.1",
|
||||||
|
"id": "malware--00000000-0000-4000-8000-000000000003",
|
||||||
|
"created": "2017-01-01T12:34:56.000Z",
|
||||||
|
"modified": "2017-01-01T12:34:56.000Z",
|
||||||
|
"name": "Cryptolocker",
|
||||||
|
"malware_types": [
|
||||||
|
"ransomware",
|
||||||
|
],
|
||||||
|
"is_family": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "relationship",
|
||||||
|
"spec_version": "2.1",
|
||||||
|
"id": "relationship--00000000-0000-4000-8000-000000000005",
|
||||||
|
"created": "2017-01-01T12:34:56.000Z",
|
||||||
|
"modified": "2017-01-01T12:34:56.000Z",
|
||||||
|
"relationship_type": "indicates",
|
||||||
|
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||||
|
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_dict_to_stix2_bundle_with_version():
|
||||||
|
with pytest.raises(exceptions.InvalidValueError) as excinfo:
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_observable_with_version():
|
||||||
|
observable = {"type": "file", "name": "foo.exe"}
|
||||||
|
obs_obj = parsing.parse_observable(observable, version='2.1')
|
||||||
|
v = 'v21'
|
||||||
|
|
||||||
|
assert v in str(obs_obj.__class__)
|
||||||
|
|
||||||
|
|
||||||
|
@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 = parsing.parse_observable(observable)
|
||||||
|
v = 'v21'
|
||||||
|
|
||||||
|
assert v in str(obs_obj.__class__)
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_marking_with_version():
|
||||||
|
parsing._register_marking(stix2.v21.TLP_WHITE.__class__, version='2.1')
|
||||||
|
v = 'v21'
|
||||||
|
|
||||||
|
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)
|
||||||
|
parsing._register_marking(stix2.v21.TLP_WHITE.__class__)
|
||||||
|
v = 'v21'
|
||||||
|
|
||||||
|
assert stix2.v21.TLP_WHITE.definition._type in parsing.STIX2_OBJ_MAPS[v]['markings']
|
||||||
|
assert v in str(stix2.v21.TLP_WHITE.__class__)
|
|
@ -175,20 +175,34 @@ def test_greater_than():
|
||||||
assert str(exp) == "[file:extensions.'windows-pebinary-ext'.sections[*].entropy > 7.0]"
|
assert str(exp) == "[file:extensions.'windows-pebinary-ext'.sections[*].entropy > 7.0]"
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_greater_than():
|
||||||
|
patt_obj = create_pattern_object("[file:extensions.'windows-pebinary-ext'.sections[*].entropy > 7.478901]", version="2.1")
|
||||||
|
assert str(patt_obj) == "[file:extensions.'windows-pebinary-ext'.sections[*].entropy > 7.478901]"
|
||||||
|
|
||||||
|
|
||||||
def test_less_than():
|
def test_less_than():
|
||||||
exp = stix2.LessThanComparisonExpression("file:size", 1024)
|
exp = stix2.LessThanComparisonExpression("file:size", 1024)
|
||||||
assert str(exp) == "file:size < 1024"
|
assert str(exp) == "file:size < 1024"
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_less_than():
|
||||||
|
patt_obj = create_pattern_object("[file:size < 1024]", version="2.1")
|
||||||
|
assert str(patt_obj) == "[file:size < 1024]"
|
||||||
|
|
||||||
|
|
||||||
def test_greater_than_or_equal():
|
def test_greater_than_or_equal():
|
||||||
exp = stix2.GreaterThanEqualComparisonExpression(
|
exp = stix2.GreaterThanEqualComparisonExpression(
|
||||||
"file:size",
|
"file:size",
|
||||||
1024,
|
1024,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert str(exp) == "file:size >= 1024"
|
assert str(exp) == "file:size >= 1024"
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_greater_than_or_equal():
|
||||||
|
patt_obj = create_pattern_object("[file:size >= 1024]", version="2.1")
|
||||||
|
assert str(patt_obj) == "[file:size >= 1024]"
|
||||||
|
|
||||||
|
|
||||||
def test_less_than_or_equal():
|
def test_less_than_or_equal():
|
||||||
exp = stix2.LessThanEqualComparisonExpression(
|
exp = stix2.LessThanEqualComparisonExpression(
|
||||||
"file:size",
|
"file:size",
|
||||||
|
@ -197,6 +211,36 @@ def test_less_than_or_equal():
|
||||||
assert str(exp) == "file:size <= 1024"
|
assert str(exp) == "file:size <= 1024"
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_less_than_or_equal():
|
||||||
|
patt_obj = create_pattern_object("[file:size <= 1024]", version="2.1")
|
||||||
|
assert str(patt_obj) == "[file:size <= 1024]"
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_issubset():
|
||||||
|
patt_obj = create_pattern_object("[network-traffic:dst_ref.value ISSUBSET '2001:0db8:dead:beef:0000:0000:0000:0000/64']", version="2.1")
|
||||||
|
assert str(patt_obj) == "[network-traffic:dst_ref.value ISSUBSET '2001:0db8:dead:beef:0000:0000:0000:0000/64']"
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_issuperset():
|
||||||
|
patt_obj = create_pattern_object("[network-traffic:dst_ref.value ISSUPERSET '2001:0db8:dead:beef:0000:0000:0000:0000/64']", version="2.1")
|
||||||
|
assert str(patt_obj) == "[network-traffic:dst_ref.value ISSUPERSET '2001:0db8:dead:beef:0000:0000:0000:0000/64']"
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_like():
|
||||||
|
patt_obj = create_pattern_object("[directory:path LIKE 'C:\\\\Windows\\\\%\\\\foo']", version="2.1")
|
||||||
|
assert str(patt_obj) == "[directory:path LIKE 'C:\\\\Windows\\\\%\\\\foo']"
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_match():
|
||||||
|
patt_obj = create_pattern_object("[process:command_line MATCHES '^.+>-add GlobalSign.cer -c -s -r localMachine Root$'] FOLLOWEDBY [process:command_line MATCHES '^.+>-add GlobalSign.cer -c -s -r localMachineTrustedPublisher$'] WITHIN 300 SECONDS", version="2.1") # noqa
|
||||||
|
assert str(patt_obj) == "[process:command_line MATCHES '^.+>-add GlobalSign.cer -c -s -r localMachine Root$'] FOLLOWEDBY [process:command_line MATCHES '^.+>-add GlobalSign.cer -c -s -r localMachineTrustedPublisher$'] WITHIN 300 SECONDS" # noqa
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_followed_by():
|
||||||
|
patt_obj = create_pattern_object("([file:hashes.MD5 = '79054025255fb1a26e4bc422aef54eb4'] FOLLOWEDBY [windows-registry-key:key = 'HKEY_LOCAL_MACHINE\\\\foo\\\\bar']) WITHIN 300 SECONDS", version="2.1") # noqa
|
||||||
|
assert str(patt_obj) == "([file:hashes.MD5 = '79054025255fb1a26e4bc422aef54eb4'] FOLLOWEDBY [windows-registry-key:key = 'HKEY_LOCAL_MACHINE\\\\foo\\\\bar']) WITHIN 300 SECONDS" # noqa
|
||||||
|
|
||||||
|
|
||||||
def test_not():
|
def test_not():
|
||||||
exp = stix2.LessThanComparisonExpression(
|
exp = stix2.LessThanComparisonExpression(
|
||||||
"file:size",
|
"file:size",
|
||||||
|
@ -257,6 +301,67 @@ def test_and_observable_expression():
|
||||||
assert str(exp) == "[user-account:account_type = 'unix' AND user-account:user_id = '1007' AND user-account:account_login = 'Peter'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1008' AND user-account:account_login = 'Paul'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1009' AND user-account:account_login = 'Mary']" # noqa
|
assert str(exp) == "[user-account:account_type = 'unix' AND user-account:user_id = '1007' AND user-account:account_login = 'Peter'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1008' AND user-account:account_login = 'Paul'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1009' AND user-account:account_login = 'Mary']" # noqa
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_and_observable_expression():
|
||||||
|
exp = create_pattern_object("[user-account:account_type = 'unix' AND user-account:user_id = '1007' AND user-account:account_login = 'Peter'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1008' AND user-account:account_login = 'Paul']", version="2.1") # noqa
|
||||||
|
assert str(exp) == "[user-account:account_type = 'unix' AND user-account:user_id = '1007' AND user-account:account_login = 'Peter'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1008' AND user-account:account_login = 'Paul']" # noqa
|
||||||
|
|
||||||
|
|
||||||
|
def test_or_observable_expression():
|
||||||
|
exp1 = stix2.AndBooleanExpression([
|
||||||
|
stix2.EqualityComparisonExpression(
|
||||||
|
"user-account:account_type",
|
||||||
|
"unix",
|
||||||
|
),
|
||||||
|
stix2.EqualityComparisonExpression(
|
||||||
|
"user-account:user_id",
|
||||||
|
stix2.StringConstant("1007"),
|
||||||
|
),
|
||||||
|
stix2.EqualityComparisonExpression(
|
||||||
|
"user-account:account_login",
|
||||||
|
"Peter",
|
||||||
|
),
|
||||||
|
])
|
||||||
|
exp2 = stix2.AndBooleanExpression([
|
||||||
|
stix2.EqualityComparisonExpression(
|
||||||
|
"user-account:account_type",
|
||||||
|
"unix",
|
||||||
|
),
|
||||||
|
stix2.EqualityComparisonExpression(
|
||||||
|
"user-account:user_id",
|
||||||
|
stix2.StringConstant("1008"),
|
||||||
|
),
|
||||||
|
stix2.EqualityComparisonExpression(
|
||||||
|
"user-account:account_login",
|
||||||
|
"Paul",
|
||||||
|
),
|
||||||
|
])
|
||||||
|
exp3 = stix2.AndBooleanExpression([
|
||||||
|
stix2.EqualityComparisonExpression(
|
||||||
|
"user-account:account_type",
|
||||||
|
"unix",
|
||||||
|
),
|
||||||
|
stix2.EqualityComparisonExpression(
|
||||||
|
"user-account:user_id",
|
||||||
|
stix2.StringConstant("1009"),
|
||||||
|
),
|
||||||
|
stix2.EqualityComparisonExpression(
|
||||||
|
"user-account:account_login",
|
||||||
|
"Mary",
|
||||||
|
),
|
||||||
|
])
|
||||||
|
exp = stix2.OrObservationExpression([
|
||||||
|
stix2.ObservationExpression(exp1),
|
||||||
|
stix2.ObservationExpression(exp2),
|
||||||
|
stix2.ObservationExpression(exp3),
|
||||||
|
])
|
||||||
|
assert str(exp) == "[user-account:account_type = 'unix' AND user-account:user_id = '1007' AND user-account:account_login = 'Peter'] OR [user-account:account_type = 'unix' AND user-account:user_id = '1008' AND user-account:account_login = 'Paul'] OR [user-account:account_type = 'unix' AND user-account:user_id = '1009' AND user-account:account_login = 'Mary']" # noqa
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_or_observable_expression():
|
||||||
|
exp = create_pattern_object("[user-account:account_type = 'unix' AND user-account:user_id = '1007' AND user-account:account_login = 'Peter'] OR [user-account:account_type = 'unix' AND user-account:user_id = '1008' AND user-account:account_login = 'Paul']", version="2.1") # noqa
|
||||||
|
assert str(exp) == "[user-account:account_type = 'unix' AND user-account:user_id = '1007' AND user-account:account_login = 'Peter'] OR [user-account:account_type = 'unix' AND user-account:user_id = '1008' AND user-account:account_login = 'Paul']" # noqa
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_and_observable_expression():
|
def test_invalid_and_observable_expression():
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
stix2.AndBooleanExpression([
|
stix2.AndBooleanExpression([
|
||||||
|
@ -286,6 +391,11 @@ def test_hex():
|
||||||
assert str(exp) == "[file:mime_type = 'image/bmp' AND file:magic_number_hex = h'ffd8']"
|
assert str(exp) == "[file:mime_type = 'image/bmp' AND file:magic_number_hex = h'ffd8']"
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_hex():
|
||||||
|
patt_obj = create_pattern_object("[file:magic_number_hex = h'ffd8']", version="2.1")
|
||||||
|
assert str(patt_obj) == "[file:magic_number_hex = h'ffd8']"
|
||||||
|
|
||||||
|
|
||||||
def test_multiple_qualifiers():
|
def test_multiple_qualifiers():
|
||||||
exp_and = stix2.AndBooleanExpression([
|
exp_and = stix2.AndBooleanExpression([
|
||||||
stix2.EqualityComparisonExpression(
|
stix2.EqualityComparisonExpression(
|
||||||
|
@ -334,6 +444,11 @@ def test_binary():
|
||||||
assert str(exp) == "artifact:payload_bin = b'dGhpcyBpcyBhIHRlc3Q='"
|
assert str(exp) == "artifact:payload_bin = b'dGhpcyBpcyBhIHRlc3Q='"
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_binary():
|
||||||
|
patt_obj = create_pattern_object("[artifact:payload_bin = b'dGhpcyBpcyBhIHRlc3Q=']", version="2.1")
|
||||||
|
assert str(patt_obj) == "[artifact:payload_bin = b'dGhpcyBpcyBhIHRlc3Q=']"
|
||||||
|
|
||||||
|
|
||||||
def test_list():
|
def test_list():
|
||||||
exp = stix2.InComparisonExpression(
|
exp = stix2.InComparisonExpression(
|
||||||
"process:name",
|
"process:name",
|
||||||
|
@ -495,29 +610,45 @@ def test_make_constant_already_a_constant():
|
||||||
|
|
||||||
|
|
||||||
def test_parsing_comparison_expression():
|
def test_parsing_comparison_expression():
|
||||||
patt_obj = create_pattern_object("[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f']")
|
patt_obj = create_pattern_object("[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f']", version="2.1")
|
||||||
assert str(patt_obj) == "[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f']"
|
assert str(patt_obj) == "[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f']"
|
||||||
|
|
||||||
|
|
||||||
def test_parsing_qualified_expression():
|
def test_parsing_repeat_and_within_qualified_expression():
|
||||||
patt_obj = create_pattern_object(
|
patt_obj = create_pattern_object(
|
||||||
"[network-traffic:dst_ref.type = 'domain-name' AND network-traffic:dst_ref.value = 'example.com'] REPEATS 5 TIMES WITHIN 1800 SECONDS",
|
"[network-traffic:dst_ref.type = 'domain-name' AND network-traffic:dst_ref.value = 'example.com'] REPEATS 5 TIMES WITHIN 1800 SECONDS",
|
||||||
|
version="2.1",
|
||||||
)
|
)
|
||||||
assert str(
|
assert str(
|
||||||
patt_obj,
|
patt_obj,
|
||||||
) == "[network-traffic:dst_ref.type = 'domain-name' AND network-traffic:dst_ref.value = 'example.com'] REPEATS 5 TIMES WITHIN 1800 SECONDS"
|
) == "[network-traffic:dst_ref.type = 'domain-name' AND network-traffic:dst_ref.value = 'example.com'] REPEATS 5 TIMES WITHIN 1800 SECONDS"
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_start_stop_qualified_expression():
|
||||||
|
patt_obj = create_pattern_object(
|
||||||
|
"[network-traffic:dst_ref.type = 'domain-name' AND network-traffic:dst_ref.value = 'example.com'] START t'2016-06-01T00:00:00Z' STOP t'2017-03-12T08:30:00Z'", # noqa
|
||||||
|
version="2.1",
|
||||||
|
)
|
||||||
|
assert str(
|
||||||
|
patt_obj,
|
||||||
|
) == "[network-traffic:dst_ref.type = 'domain-name' AND network-traffic:dst_ref.value = 'example.com'] START t'2016-06-01T00:00:00Z' STOP t'2017-03-12T08:30:00Z'" # noqa
|
||||||
|
|
||||||
|
|
||||||
def test_list_constant():
|
def test_list_constant():
|
||||||
patt_obj = create_pattern_object("[network-traffic:src_ref.value IN ('10.0.0.0', '10.0.0.1', '10.0.0.2')]")
|
patt_obj = create_pattern_object("[network-traffic:src_ref.value IN ('10.0.0.0', '10.0.0.1', '10.0.0.2')]", version="2.1")
|
||||||
assert str(patt_obj) == "[network-traffic:src_ref.value IN ('10.0.0.0', '10.0.0.1', '10.0.0.2')]"
|
assert str(patt_obj) == "[network-traffic:src_ref.value IN ('10.0.0.0', '10.0.0.1', '10.0.0.2')]"
|
||||||
|
|
||||||
|
|
||||||
|
def test_parsing_boolean():
|
||||||
|
patt_obj = create_pattern_object("[network-traffic:is_active = true]", version="2.1")
|
||||||
|
assert str(patt_obj) == "[network-traffic:is_active = true]"
|
||||||
|
|
||||||
|
|
||||||
def test_parsing_multiple_slashes_quotes():
|
def test_parsing_multiple_slashes_quotes():
|
||||||
patt_obj = create_pattern_object("[ file:name = 'weird_name\\'' ]")
|
patt_obj = create_pattern_object("[ file:name = 'weird_name\\'' ]", version="2.1")
|
||||||
assert str(patt_obj) == "[file:name = 'weird_name\\'']"
|
assert str(patt_obj) == "[file:name = 'weird_name\\'']"
|
||||||
|
|
||||||
|
|
||||||
def test_parse_error():
|
def test_parse_error():
|
||||||
with pytest.raises(ParseException):
|
with pytest.raises(ParseException):
|
||||||
create_pattern_object("[ file: name = 'weirdname]")
|
create_pattern_object("[ file: name = 'weirdname]", version="2.1")
|
||||||
|
|
|
@ -404,7 +404,7 @@ def test_dictionary_property_invalid(d):
|
||||||
|
|
||||||
def test_property_list_of_dictionary():
|
def test_property_list_of_dictionary():
|
||||||
@stix2.v21.CustomObject(
|
@stix2.v21.CustomObject(
|
||||||
'x-new-obj', [
|
'x-new-obj-4', [
|
||||||
('property1', ListProperty(DictionaryProperty(spec_version='2.1'), required=True)),
|
('property1', ListProperty(DictionaryProperty(spec_version='2.1'), required=True)),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
import datetime
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import stix2
|
||||||
|
from stix2.utils import (
|
||||||
|
Precision, PrecisionConstraint, STIXdatetime, _to_enum, format_datetime,
|
||||||
|
parse_into_datetime,
|
||||||
|
)
|
||||||
|
|
||||||
|
_DT = datetime.datetime.utcnow()
|
||||||
|
# intentionally omit microseconds from the following. We add it in as
|
||||||
|
# needed for each test.
|
||||||
|
_DT_STR = _DT.strftime("%Y-%m-%dT%H:%M:%S")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"value, enum_type, enum_default, enum_expected", [
|
||||||
|
("second", Precision, None, Precision.SECOND),
|
||||||
|
(
|
||||||
|
"eXaCt", PrecisionConstraint, PrecisionConstraint.MIN,
|
||||||
|
PrecisionConstraint.EXACT,
|
||||||
|
),
|
||||||
|
(None, Precision, Precision.MILLISECOND, Precision.MILLISECOND),
|
||||||
|
(Precision.ANY, Precision, None, Precision.ANY),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_to_enum(value, enum_type, enum_default, enum_expected):
|
||||||
|
result = _to_enum(value, enum_type, enum_default)
|
||||||
|
assert result == enum_expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"value, err_type", [
|
||||||
|
("foo", KeyError),
|
||||||
|
(1, TypeError),
|
||||||
|
(PrecisionConstraint.EXACT, TypeError),
|
||||||
|
(None, TypeError),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_to_enum_errors(value, err_type):
|
||||||
|
with pytest.raises(err_type):
|
||||||
|
_to_enum(value, Precision)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xfail(
|
||||||
|
sys.version_info[:2] == (3, 6), strict=True,
|
||||||
|
reason="https://bugs.python.org/issue32404",
|
||||||
|
)
|
||||||
|
def test_stix_datetime_now():
|
||||||
|
dt = STIXdatetime.utcnow()
|
||||||
|
assert dt.precision is Precision.ANY
|
||||||
|
assert dt.precision_constraint is PrecisionConstraint.EXACT
|
||||||
|
|
||||||
|
|
||||||
|
def test_stix_datetime():
|
||||||
|
dt = datetime.datetime.utcnow()
|
||||||
|
|
||||||
|
sdt = STIXdatetime(dt, precision=Precision.SECOND)
|
||||||
|
assert sdt.precision is Precision.SECOND
|
||||||
|
assert sdt == dt
|
||||||
|
|
||||||
|
sdt = STIXdatetime(
|
||||||
|
dt,
|
||||||
|
precision_constraint=PrecisionConstraint.EXACT,
|
||||||
|
)
|
||||||
|
assert sdt.precision_constraint is PrecisionConstraint.EXACT
|
||||||
|
assert sdt == dt
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"us, precision, precision_constraint, expected_truncated_us", [
|
||||||
|
(123456, Precision.ANY, PrecisionConstraint.EXACT, 123456),
|
||||||
|
(123456, Precision.SECOND, PrecisionConstraint.EXACT, 0),
|
||||||
|
(123456, Precision.SECOND, PrecisionConstraint.MIN, 123456),
|
||||||
|
(123456, Precision.MILLISECOND, PrecisionConstraint.EXACT, 123000),
|
||||||
|
(123456, Precision.MILLISECOND, PrecisionConstraint.MIN, 123456),
|
||||||
|
(1234, Precision.MILLISECOND, PrecisionConstraint.EXACT, 1000),
|
||||||
|
(123, Precision.MILLISECOND, PrecisionConstraint.EXACT, 0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_parse_datetime(
|
||||||
|
us, precision, precision_constraint, expected_truncated_us,
|
||||||
|
):
|
||||||
|
|
||||||
|
# complete the datetime string with microseconds
|
||||||
|
dt_us_str = "{}.{:06d}Z".format(_DT_STR, us)
|
||||||
|
|
||||||
|
sdt = parse_into_datetime(
|
||||||
|
dt_us_str,
|
||||||
|
precision=precision,
|
||||||
|
precision_constraint=precision_constraint,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert sdt.precision is precision
|
||||||
|
assert sdt.precision_constraint is precision_constraint
|
||||||
|
assert sdt.microsecond == expected_truncated_us
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"us, precision, precision_constraint, expected_us_str", [
|
||||||
|
(123456, Precision.ANY, PrecisionConstraint.EXACT, ".123456"),
|
||||||
|
(123456, Precision.SECOND, PrecisionConstraint.EXACT, ""),
|
||||||
|
(123456, Precision.SECOND, PrecisionConstraint.MIN, ".123456"),
|
||||||
|
(123456, Precision.MILLISECOND, PrecisionConstraint.EXACT, ".123"),
|
||||||
|
(123456, Precision.MILLISECOND, PrecisionConstraint.MIN, ".123456"),
|
||||||
|
(0, Precision.SECOND, PrecisionConstraint.MIN, ""),
|
||||||
|
(0, Precision.MILLISECOND, PrecisionConstraint.MIN, ".000"),
|
||||||
|
(0, Precision.MILLISECOND, PrecisionConstraint.EXACT, ".000"),
|
||||||
|
(1000, Precision.MILLISECOND, PrecisionConstraint.EXACT, ".001"),
|
||||||
|
(10000, Precision.MILLISECOND, PrecisionConstraint.EXACT, ".010"),
|
||||||
|
(100000, Precision.MILLISECOND, PrecisionConstraint.EXACT, ".100"),
|
||||||
|
(1000, Precision.ANY, PrecisionConstraint.EXACT, ".001"),
|
||||||
|
(10000, Precision.ANY, PrecisionConstraint.EXACT, ".01"),
|
||||||
|
(100000, Precision.ANY, PrecisionConstraint.EXACT, ".1"),
|
||||||
|
(1001, Precision.MILLISECOND, PrecisionConstraint.MIN, ".001001"),
|
||||||
|
(10010, Precision.MILLISECOND, PrecisionConstraint.MIN, ".01001"),
|
||||||
|
(100100, Precision.MILLISECOND, PrecisionConstraint.MIN, ".1001"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_format_datetime(us, precision, precision_constraint, expected_us_str):
|
||||||
|
|
||||||
|
dt = _DT.replace(microsecond=us)
|
||||||
|
expected_dt_str = "{}{}Z".format(_DT_STR, expected_us_str)
|
||||||
|
|
||||||
|
sdt = STIXdatetime(
|
||||||
|
dt,
|
||||||
|
precision=precision,
|
||||||
|
precision_constraint=precision_constraint,
|
||||||
|
)
|
||||||
|
s = format_datetime(sdt)
|
||||||
|
assert s == expected_dt_str
|
||||||
|
|
||||||
|
|
||||||
|
def test_sdo_extra_precision():
|
||||||
|
# add extra precision for "modified", ensure it's not lost
|
||||||
|
identity_dict = {
|
||||||
|
"type": "identity",
|
||||||
|
"id": "identity--4a457eeb-6639-4aa3-be81-5930a3000c39",
|
||||||
|
"created": "2015-12-21T19:59:11.000Z",
|
||||||
|
"modified": "2015-12-21T19:59:11.0001Z",
|
||||||
|
"name": "John Smith",
|
||||||
|
"identity_class": "individual",
|
||||||
|
"spec_version": "2.1",
|
||||||
|
}
|
||||||
|
|
||||||
|
identity_obj = stix2.parse(identity_dict)
|
||||||
|
assert identity_obj.modified.microsecond == 100
|
||||||
|
assert identity_obj.modified.precision is Precision.MILLISECOND
|
||||||
|
assert identity_obj.modified.precision_constraint is PrecisionConstraint.MIN
|
||||||
|
|
||||||
|
identity_str = identity_obj.serialize(pretty=True)
|
||||||
|
|
||||||
|
# ensure precision is retained in JSON
|
||||||
|
assert identity_str == """{
|
||||||
|
"type": "identity",
|
||||||
|
"spec_version": "2.1",
|
||||||
|
"id": "identity--4a457eeb-6639-4aa3-be81-5930a3000c39",
|
||||||
|
"created": "2015-12-21T19:59:11.000Z",
|
||||||
|
"modified": "2015-12-21T19:59:11.0001Z",
|
||||||
|
"name": "John Smith",
|
||||||
|
"identity_class": "individual"
|
||||||
|
}"""
|
|
@ -1,6 +1,9 @@
|
||||||
|
import datetime
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import stix2
|
import stix2
|
||||||
|
import stix2.utils
|
||||||
|
|
||||||
from .constants import CAMPAIGN_MORE_KWARGS
|
from .constants import CAMPAIGN_MORE_KWARGS
|
||||||
|
|
||||||
|
@ -236,8 +239,7 @@ def test_remove_custom_stix_property():
|
||||||
mal_nc = stix2.utils.remove_custom_stix(mal)
|
mal_nc = stix2.utils.remove_custom_stix(mal)
|
||||||
|
|
||||||
assert "x_custom" not in mal_nc
|
assert "x_custom" not in mal_nc
|
||||||
assert (stix2.utils.parse_into_datetime(mal["modified"], precision="millisecond") <
|
assert mal["modified"] < mal_nc["modified"]
|
||||||
stix2.utils.parse_into_datetime(mal_nc["modified"], precision="millisecond"))
|
|
||||||
|
|
||||||
|
|
||||||
def test_remove_custom_stix_object():
|
def test_remove_custom_stix_object():
|
||||||
|
@ -264,3 +266,33 @@ def test_remove_custom_stix_no_custom():
|
||||||
assert len(campaign_v1.keys()) == len(campaign_v2.keys())
|
assert len(campaign_v1.keys()) == len(campaign_v2.keys())
|
||||||
assert campaign_v1.id == campaign_v2.id
|
assert campaign_v1.id == campaign_v2.id
|
||||||
assert campaign_v1.description == campaign_v2.description
|
assert campaign_v1.description == campaign_v2.description
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"old, candidate_new, expected_new, use_stix21", [
|
||||||
|
("1999-08-15T00:19:07.000Z", "1999-08-15T00:19:07.001Z", "1999-08-15T00:19:07.001Z", False),
|
||||||
|
("1999-08-15T00:19:07.000Z", "1999-08-15T00:19:07.000Z", "1999-08-15T00:19:07.001Z", False),
|
||||||
|
("1999-08-15T00:19:07.000Z", "1999-08-15T00:19:06.000Z", "1999-08-15T00:19:07.001Z", False),
|
||||||
|
("1999-08-15T00:19:07.000Z", "1999-08-15T00:19:06.999Z", "1999-08-15T00:19:07.001Z", False),
|
||||||
|
("1999-08-15T00:19:07.000Z", "1999-08-15T00:19:07.0001Z", "1999-08-15T00:19:07.001Z", False),
|
||||||
|
("1999-08-15T00:19:07.999Z", "1999-08-15T00:19:07.9999Z", "1999-08-15T00:19:08.000Z", False),
|
||||||
|
|
||||||
|
("1999-08-15T00:19:07.000Z", "1999-08-15T00:19:07.001Z", "1999-08-15T00:19:07.001Z", True),
|
||||||
|
("1999-08-15T00:19:07.000Z", "1999-08-15T00:19:07.000Z", "1999-08-15T00:19:07.000001Z", True),
|
||||||
|
("1999-08-15T00:19:07.000Z", "1999-08-15T00:19:06.000Z", "1999-08-15T00:19:07.000001Z", True),
|
||||||
|
("1999-08-15T00:19:07.000Z", "1999-08-15T00:19:06.999999Z", "1999-08-15T00:19:07.000001Z", True),
|
||||||
|
("1999-08-15T00:19:07.000Z", "1999-08-15T00:19:07.000001Z", "1999-08-15T00:19:07.000001Z", True),
|
||||||
|
("1999-08-15T00:19:07.999Z", "1999-08-15T00:19:07.999999Z", "1999-08-15T00:19:07.999999Z", True),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_fudge_modified(old, candidate_new, expected_new, use_stix21):
|
||||||
|
old_dt = datetime.datetime.strptime(old, "%Y-%m-%dT%H:%M:%S.%fZ")
|
||||||
|
candidate_new_dt = datetime.datetime.strptime(
|
||||||
|
candidate_new, "%Y-%m-%dT%H:%M:%S.%fZ",
|
||||||
|
)
|
||||||
|
expected_new_dt = datetime.datetime.strptime(
|
||||||
|
expected_new, "%Y-%m-%dT%H:%M:%S.%fZ",
|
||||||
|
)
|
||||||
|
|
||||||
|
fudged = stix2.utils._fudge_modified(old_dt, candidate_new_dt, use_stix21)
|
||||||
|
assert fudged == expected_new_dt
|
||||||
|
|
258
stix2/utils.py
258
stix2/utils.py
|
@ -6,12 +6,15 @@ except ImportError:
|
||||||
from collections import Mapping
|
from collections import Mapping
|
||||||
import copy
|
import copy
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
|
import enum
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
from dateutil import parser
|
from dateutil import parser
|
||||||
import pytz
|
import pytz
|
||||||
|
import six
|
||||||
|
|
||||||
import stix2.base
|
import stix2
|
||||||
|
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
InvalidValueError, RevokeError, UnmodifiablePropertyError,
|
InvalidValueError, RevokeError, UnmodifiablePropertyError,
|
||||||
|
@ -25,13 +28,84 @@ NOW = object()
|
||||||
# STIX object properties that cannot be modified
|
# STIX object properties that cannot be modified
|
||||||
STIX_UNMOD_PROPERTIES = ['created', 'created_by_ref', 'id', 'type']
|
STIX_UNMOD_PROPERTIES = ['created', 'created_by_ref', 'id', 'type']
|
||||||
|
|
||||||
TYPE_REGEX = r'^\-?[a-z0-9]+(-[a-z0-9]+)*\-?$'
|
TYPE_REGEX = re.compile(r'^\-?[a-z0-9]+(-[a-z0-9]+)*\-?$')
|
||||||
SCO21_EXT_REGEX = r'^\-?[a-z0-9]+(-[a-z0-9]+)*\-ext$'
|
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):
|
||||||
|
"""
|
||||||
|
Timestamp format precisions.
|
||||||
|
"""
|
||||||
|
# auto() wasn't introduced until Python 3.6.
|
||||||
|
ANY = 1
|
||||||
|
SECOND = 2
|
||||||
|
MILLISECOND = 3
|
||||||
|
|
||||||
|
|
||||||
|
class PrecisionConstraint(enum.Enum):
|
||||||
|
"""
|
||||||
|
Timestamp precision constraints. These affect how the Precision
|
||||||
|
values are applied when formatting a timestamp.
|
||||||
|
|
||||||
|
These constraints don't really make sense with the ANY precision, so they
|
||||||
|
have no effect in that case.
|
||||||
|
"""
|
||||||
|
EXACT = 1 # format must have exactly the given precision
|
||||||
|
MIN = 2 # format must have at least the given precision
|
||||||
|
# no need for a MAX constraint yet
|
||||||
|
|
||||||
|
|
||||||
|
def _to_enum(value, enum_type, enum_default=None):
|
||||||
|
"""
|
||||||
|
Detect and convert strings to enums and None to a default enum. This
|
||||||
|
allows use of strings and None in APIs, while enforcing the enum type: if
|
||||||
|
you use a string, it must name a valid enum value. This implementation is
|
||||||
|
case-insensitive.
|
||||||
|
|
||||||
|
:param value: A value to be interpreted as an enum (string, Enum instance,
|
||||||
|
or None). If an Enum instance, it must be an instance of enum_type.
|
||||||
|
:param enum_type: The enum type which strings will be interpreted against
|
||||||
|
:param enum_default: The default enum to use if value is None. Must be
|
||||||
|
an instance of enum_type, or None. If None, you are disallowing a
|
||||||
|
default and requiring that value be non-None.
|
||||||
|
:return: An instance of enum_type
|
||||||
|
:raises TypeError: If value was neither an instance of enum_type, None, nor
|
||||||
|
a string
|
||||||
|
:raises KeyError: If value was a string which couldn't be interpreted as an
|
||||||
|
enum value from enum_type
|
||||||
|
"""
|
||||||
|
assert enum_default is None or isinstance(enum_default, enum_type)
|
||||||
|
|
||||||
|
if not isinstance(value, enum_type):
|
||||||
|
if value is None and enum_default is not None:
|
||||||
|
value = enum_default
|
||||||
|
elif isinstance(value, six.string_types):
|
||||||
|
value = enum_type[value.upper()]
|
||||||
|
else:
|
||||||
|
raise TypeError("Not a valid {}: {}".format(
|
||||||
|
enum_type.__name__, value,
|
||||||
|
))
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
class STIXdatetime(dt.datetime):
|
class STIXdatetime(dt.datetime):
|
||||||
|
"""
|
||||||
|
Bundle a datetime with some format-related metadata, so that JSON
|
||||||
|
serialization has the info it needs to produce compliant timestamps.
|
||||||
|
"""
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
def __new__(cls, *args, **kwargs):
|
||||||
precision = kwargs.pop('precision', None)
|
precision = _to_enum(
|
||||||
|
kwargs.pop("precision", Precision.ANY),
|
||||||
|
Precision,
|
||||||
|
)
|
||||||
|
precision_constraint = _to_enum(
|
||||||
|
kwargs.pop("precision_constraint", PrecisionConstraint.EXACT),
|
||||||
|
PrecisionConstraint,
|
||||||
|
)
|
||||||
|
|
||||||
if isinstance(args[0], dt.datetime): # Allow passing in a datetime object
|
if isinstance(args[0], dt.datetime): # Allow passing in a datetime object
|
||||||
dttm = args[0]
|
dttm = args[0]
|
||||||
args = (
|
args = (
|
||||||
|
@ -41,6 +115,7 @@ class STIXdatetime(dt.datetime):
|
||||||
# self will be an instance of STIXdatetime, not dt.datetime
|
# self will be an instance of STIXdatetime, not dt.datetime
|
||||||
self = dt.datetime.__new__(cls, *args, **kwargs)
|
self = dt.datetime.__new__(cls, *args, **kwargs)
|
||||||
self.precision = precision
|
self.precision = precision
|
||||||
|
self.precision_constraint = precision_constraint
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -90,7 +165,7 @@ def format_datetime(dttm):
|
||||||
2. Convert to UTC
|
2. Convert to UTC
|
||||||
3. Format in ISO format
|
3. Format in ISO format
|
||||||
4. Ensure correct precision
|
4. Ensure correct precision
|
||||||
a. Add subsecond value if non-zero and precision not defined
|
a. Add subsecond value if warranted, according to precision settings
|
||||||
5. Add "Z"
|
5. Add "Z"
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -101,20 +176,74 @@ def format_datetime(dttm):
|
||||||
else:
|
else:
|
||||||
zoned = dttm.astimezone(pytz.utc)
|
zoned = dttm.astimezone(pytz.utc)
|
||||||
ts = zoned.strftime('%Y-%m-%dT%H:%M:%S')
|
ts = zoned.strftime('%Y-%m-%dT%H:%M:%S')
|
||||||
ms = zoned.strftime('%f')
|
precision = getattr(dttm, 'precision', Precision.ANY)
|
||||||
precision = getattr(dttm, 'precision', None)
|
precision_constraint = getattr(
|
||||||
if precision == 'second':
|
dttm, 'precision_constraint', PrecisionConstraint.EXACT,
|
||||||
pass # Already precise to the second
|
)
|
||||||
elif precision == 'millisecond':
|
|
||||||
ts = ts + '.' + ms[:3]
|
frac_seconds_str = ""
|
||||||
elif zoned.microsecond > 0:
|
if precision == Precision.ANY:
|
||||||
ts = ts + '.' + ms.rstrip('0')
|
# No need to truncate; ignore constraint
|
||||||
return ts + 'Z'
|
if zoned.microsecond:
|
||||||
|
frac_seconds_str = "{:06d}".format(zoned.microsecond).rstrip("0")
|
||||||
|
|
||||||
|
elif precision == Precision.SECOND:
|
||||||
|
if precision_constraint == PrecisionConstraint.MIN:
|
||||||
|
# second precision, or better. Winds up being the same as ANY:
|
||||||
|
# just use all our digits
|
||||||
|
if zoned.microsecond:
|
||||||
|
frac_seconds_str = "{:06d}".format(zoned.microsecond)\
|
||||||
|
.rstrip("0")
|
||||||
|
# exact: ignore microseconds entirely
|
||||||
|
|
||||||
|
else:
|
||||||
|
# precision == millisecond
|
||||||
|
if precision_constraint == PrecisionConstraint.EXACT:
|
||||||
|
# can't rstrip() here or we may lose precision
|
||||||
|
frac_seconds_str = "{:06d}".format(zoned.microsecond)[:3]
|
||||||
|
|
||||||
|
else:
|
||||||
|
# millisecond precision, or better. So we can rstrip() zeros, but
|
||||||
|
# only to a length of at least 3 digits (ljust() adds zeros back,
|
||||||
|
# if it stripped too far.)
|
||||||
|
frac_seconds_str = "{:06d}"\
|
||||||
|
.format(zoned.microsecond)\
|
||||||
|
.rstrip("0")\
|
||||||
|
.ljust(3, "0")
|
||||||
|
|
||||||
|
ts = "{}{}{}Z".format(
|
||||||
|
ts,
|
||||||
|
"." if frac_seconds_str else "",
|
||||||
|
frac_seconds_str,
|
||||||
|
)
|
||||||
|
|
||||||
|
return ts
|
||||||
|
|
||||||
|
|
||||||
def parse_into_datetime(value, precision=None):
|
def parse_into_datetime(
|
||||||
"""Parse a value into a valid STIX timestamp object.
|
value, precision=Precision.ANY,
|
||||||
|
precision_constraint=PrecisionConstraint.EXACT,
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
|
Parse a value into a valid STIX timestamp object. Also, optionally adjust
|
||||||
|
precision of fractional seconds. This allows alignment with JSON
|
||||||
|
serialization requirements, and helps ensure we're not using extra
|
||||||
|
precision which would be lost upon JSON serialization. The precision
|
||||||
|
info will be embedded in the returned object, so that JSON serialization
|
||||||
|
will format it correctly.
|
||||||
|
|
||||||
|
:param value: A datetime.datetime or datetime.date instance, or a string
|
||||||
|
:param precision: A precision value: either an instance of the Precision
|
||||||
|
enum, or a string naming one of the enum values (case-insensitive)
|
||||||
|
:param precision_constraint: A precision constraint value: either an
|
||||||
|
instance of the PrecisionConstraint enum, or a string naming one of
|
||||||
|
the enum values (case-insensitive)
|
||||||
|
:return: A STIXdatetime instance, which is a datetime but also carries the
|
||||||
|
precision info necessary to properly JSON-serialize it.
|
||||||
|
"""
|
||||||
|
precision = _to_enum(precision, Precision)
|
||||||
|
precision_constraint = _to_enum(precision_constraint, PrecisionConstraint)
|
||||||
|
|
||||||
if isinstance(value, dt.date):
|
if isinstance(value, dt.date):
|
||||||
if hasattr(value, 'hour'):
|
if hasattr(value, 'hour'):
|
||||||
ts = value
|
ts = value
|
||||||
|
@ -138,20 +267,23 @@ def parse_into_datetime(value, precision=None):
|
||||||
ts = pytz.utc.localize(parsed)
|
ts = pytz.utc.localize(parsed)
|
||||||
|
|
||||||
# Ensure correct precision
|
# Ensure correct precision
|
||||||
if not precision:
|
if precision == Precision.SECOND:
|
||||||
return STIXdatetime(ts, precision=precision)
|
if precision_constraint == PrecisionConstraint.EXACT:
|
||||||
ms = ts.microsecond
|
|
||||||
if precision == 'second':
|
|
||||||
ts = ts.replace(microsecond=0)
|
|
||||||
elif precision == 'millisecond':
|
|
||||||
ms_len = len(str(ms))
|
|
||||||
if ms_len > 3:
|
|
||||||
# Truncate to millisecond precision
|
|
||||||
factor = 10 ** (ms_len - 3)
|
|
||||||
ts = ts.replace(microsecond=(ts.microsecond // factor) * factor)
|
|
||||||
else:
|
|
||||||
ts = ts.replace(microsecond=0)
|
ts = ts.replace(microsecond=0)
|
||||||
return STIXdatetime(ts, precision=precision)
|
# else, no need to modify fractional seconds
|
||||||
|
|
||||||
|
elif precision == Precision.MILLISECOND:
|
||||||
|
if precision_constraint == PrecisionConstraint.EXACT:
|
||||||
|
us = (ts.microsecond // 1000) * 1000
|
||||||
|
ts = ts.replace(microsecond=us)
|
||||||
|
# else: at least millisecond precision: the constraint will affect JSON
|
||||||
|
# formatting, but there's nothing we need to do here.
|
||||||
|
|
||||||
|
# else, precision == Precision.ANY: nothing for us to do.
|
||||||
|
|
||||||
|
return STIXdatetime(
|
||||||
|
ts, precision=precision, precision_constraint=precision_constraint,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _get_dict(data):
|
def _get_dict(data):
|
||||||
|
@ -230,14 +362,12 @@ def find_property_index(obj, search_key, search_value):
|
||||||
Returns:
|
Returns:
|
||||||
int: An index; -1 if the key and value aren't found
|
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
|
# Special-case keys which are numbers-as-strings, e.g. for cyber-observable
|
||||||
# mappings. Use the int value of the key as the index.
|
# mappings. Use the int value of the key as the index.
|
||||||
if search_key.isdigit():
|
if search_key.isdigit():
|
||||||
return int(search_key)
|
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:
|
if search_key in obj and obj[search_key] == search_value:
|
||||||
idx = _find(obj.object_properties(), search_key)
|
idx = _find(obj.object_properties(), search_key)
|
||||||
else:
|
else:
|
||||||
|
@ -256,6 +386,39 @@ def find_property_index(obj, search_key, search_value):
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
|
|
||||||
|
def _fudge_modified(old_modified, new_modified, use_stix21):
|
||||||
|
"""
|
||||||
|
Ensures a new modified timestamp is newer than the old. When they are
|
||||||
|
too close together, new_modified must be pushed further ahead to ensure
|
||||||
|
it is distinct and later, after JSON serialization (which may mean it's
|
||||||
|
actually being pushed a little ways into the future). JSON serialization
|
||||||
|
can remove precision, which can cause distinct timestamps to accidentally
|
||||||
|
become equal, if we're not careful.
|
||||||
|
|
||||||
|
:param old_modified: A previous "modified" timestamp, as a datetime object
|
||||||
|
:param new_modified: A candidate new "modified" timestamp, as a datetime
|
||||||
|
object
|
||||||
|
:param use_stix21: Whether to use STIX 2.1+ versioning timestamp precision
|
||||||
|
rules (boolean). This is important so that we are aware of how
|
||||||
|
timestamp precision will be truncated, so we know how close together
|
||||||
|
the timestamps can be, and how far ahead to potentially push the new
|
||||||
|
one.
|
||||||
|
:return: A suitable new "modified" timestamp. This may be different from
|
||||||
|
what was passed in, if it had to be pushed ahead.
|
||||||
|
"""
|
||||||
|
if use_stix21:
|
||||||
|
# 2.1+: we can use full precision
|
||||||
|
if new_modified <= old_modified:
|
||||||
|
new_modified = old_modified + dt.timedelta(microseconds=1)
|
||||||
|
else:
|
||||||
|
# 2.0: we must use millisecond precision
|
||||||
|
one_ms = dt.timedelta(milliseconds=1)
|
||||||
|
if new_modified - old_modified < one_ms:
|
||||||
|
new_modified = old_modified + one_ms
|
||||||
|
|
||||||
|
return new_modified
|
||||||
|
|
||||||
|
|
||||||
def new_version(data, **kwargs):
|
def new_version(data, **kwargs):
|
||||||
"""Create a new version of a STIX object, by modifying properties and
|
"""Create a new version of a STIX object, by modifying properties and
|
||||||
updating the ``modified`` property.
|
updating the ``modified`` property.
|
||||||
|
@ -283,12 +446,32 @@ def new_version(data, **kwargs):
|
||||||
if unchangable_properties:
|
if unchangable_properties:
|
||||||
raise UnmodifiablePropertyError(unchangable_properties)
|
raise UnmodifiablePropertyError(unchangable_properties)
|
||||||
|
|
||||||
|
# Different versioning precision rules in STIX 2.0 vs 2.1, so we need
|
||||||
|
# to know which rules to apply.
|
||||||
|
is_21 = "spec_version" in data
|
||||||
|
precision_constraint = "min" if is_21 else "exact"
|
||||||
|
|
||||||
cls = type(data)
|
cls = type(data)
|
||||||
if 'modified' not in kwargs:
|
if 'modified' not in kwargs:
|
||||||
kwargs['modified'] = get_timestamp()
|
old_modified = parse_into_datetime(
|
||||||
|
data["modified"], precision="millisecond",
|
||||||
|
precision_constraint=precision_constraint,
|
||||||
|
)
|
||||||
|
|
||||||
|
new_modified = get_timestamp()
|
||||||
|
new_modified = _fudge_modified(old_modified, new_modified, is_21)
|
||||||
|
|
||||||
|
kwargs['modified'] = new_modified
|
||||||
|
|
||||||
elif 'modified' in data:
|
elif 'modified' in data:
|
||||||
old_modified_property = parse_into_datetime(data.get('modified'), precision='millisecond')
|
old_modified_property = parse_into_datetime(
|
||||||
new_modified_property = parse_into_datetime(kwargs['modified'], precision='millisecond')
|
data.get('modified'), precision='millisecond',
|
||||||
|
precision_constraint=precision_constraint,
|
||||||
|
)
|
||||||
|
new_modified_property = parse_into_datetime(
|
||||||
|
kwargs['modified'], precision='millisecond',
|
||||||
|
precision_constraint=precision_constraint,
|
||||||
|
)
|
||||||
if new_modified_property <= old_modified_property:
|
if new_modified_property <= old_modified_property:
|
||||||
raise InvalidValueError(
|
raise InvalidValueError(
|
||||||
cls, 'modified',
|
cls, 'modified',
|
||||||
|
@ -378,11 +561,6 @@ def remove_custom_stix(stix_obj):
|
||||||
|
|
||||||
new_obj = new_version(stix_obj, **(dict(props)))
|
new_obj = new_version(stix_obj, **(dict(props)))
|
||||||
|
|
||||||
while parse_into_datetime(new_obj['modified']) == parse_into_datetime(stix_obj['modified']):
|
|
||||||
# Prevents bug when fast computation allows multiple STIX object
|
|
||||||
# versions to be created in single unit of time
|
|
||||||
new_obj = new_version(stix_obj, **(dict(props)))
|
|
||||||
|
|
||||||
return new_obj
|
return new_obj
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
|
|
||||||
# flake8: noqa
|
# flake8: noqa
|
||||||
|
|
||||||
|
from .base import (
|
||||||
|
_DomainObject, _Extension, _Observable, _RelationshipObject, _STIXBase20,
|
||||||
|
)
|
||||||
from .bundle import Bundle
|
from .bundle import Bundle
|
||||||
from .common import (
|
from .common import (
|
||||||
TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference,
|
TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference,
|
||||||
|
|
|
@ -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
|
|
@ -2,20 +2,20 @@
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from ..base import _STIXBase
|
|
||||||
from ..properties import (
|
from ..properties import (
|
||||||
IDProperty, ListProperty, STIXObjectProperty, StringProperty, TypeProperty,
|
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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709293>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709293>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'bundle'
|
_type = 'bundle'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_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
|
# Not technically correct: STIX 2.0 spec doesn't say spec_version must
|
||||||
# have this value, but it's all we support for now.
|
# have this value, but it's all we support for now.
|
||||||
|
|
|
@ -5,7 +5,6 @@ import copy
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from ..base import _STIXBase
|
|
||||||
from ..custom import _custom_marking_builder
|
from ..custom import _custom_marking_builder
|
||||||
from ..markings import _MarkingsMixin
|
from ..markings import _MarkingsMixin
|
||||||
from ..markings.utils import check_tlp_marking
|
from ..markings.utils import check_tlp_marking
|
||||||
|
@ -14,6 +13,7 @@ from ..properties import (
|
||||||
SelectorProperty, StringProperty, TimestampProperty, TypeProperty,
|
SelectorProperty, StringProperty, TimestampProperty, TypeProperty,
|
||||||
)
|
)
|
||||||
from ..utils import NOW, _get_dict
|
from ..utils import NOW, _get_dict
|
||||||
|
from .base import _STIXBase20
|
||||||
|
|
||||||
|
|
||||||
def _should_set_millisecond(cr, marking_type):
|
def _should_set_millisecond(cr, marking_type):
|
||||||
|
@ -31,7 +31,7 @@ def _should_set_millisecond(cr, marking_type):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class ExternalReference(_STIXBase):
|
class ExternalReference(_STIXBase20):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709261>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709261>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -49,7 +49,7 @@ class ExternalReference(_STIXBase):
|
||||||
self._check_at_least_one_property(['description', 'external_id', 'url'])
|
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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709267>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709267>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -60,7 +60,7 @@ class KillChainPhase(_STIXBase):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class GranularMarking(_STIXBase):
|
class GranularMarking(_STIXBase20):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709290>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709290>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -71,7 +71,7 @@ class GranularMarking(_STIXBase):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class TLPMarking(_STIXBase):
|
class TLPMarking(_STIXBase20):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709287>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709287>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -83,7 +83,7 @@ class TLPMarking(_STIXBase):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class StatementMarking(_STIXBase):
|
class StatementMarking(_STIXBase20):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709286>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709286>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -113,14 +113,14 @@ class MarkingProperty(Property):
|
||||||
raise ValueError("must be a Statement, TLP Marking or a registered marking.")
|
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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709284>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709284>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'marking-definition'
|
_type = 'marking-definition'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW)),
|
('created', TimestampProperty(default=lambda: NOW)),
|
||||||
|
@ -188,7 +188,7 @@ def CustomMarking(type='x-custom-marking', properties=None):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def wrapper(cls):
|
def wrapper(cls):
|
||||||
return _custom_marking_builder(cls, type, properties, '2.0')
|
return _custom_marking_builder(cls, type, properties, '2.0', _STIXBase20)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
"""STIX 2.0 Cyber Observable Objects.
|
"""STIX 2.0 Cyber Observable Objects.
|
||||||
|
|
||||||
Embedded observable object types, such as Email MIME Component, which is
|
Embedded observable object types, such as Email MIME Component, which is
|
||||||
embedded in Email Message objects, inherit from ``_STIXBase`` instead of
|
embedded in Email Message objects, inherit from ``_STIXBase20`` instead of
|
||||||
Observable and do not have a ``_type`` attribute.
|
_Observable and do not have a ``_type`` attribute.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
from ..base import _Extension, _Observable, _STIXBase
|
|
||||||
from ..custom import _custom_extension_builder, _custom_observable_builder
|
from ..custom import _custom_extension_builder, _custom_observable_builder
|
||||||
from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError
|
from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError
|
||||||
from ..properties import (
|
from ..properties import (
|
||||||
|
@ -17,6 +16,7 @@ from ..properties import (
|
||||||
HashesProperty, HexProperty, IntegerProperty, ListProperty,
|
HashesProperty, HexProperty, IntegerProperty, ListProperty,
|
||||||
ObjectReferenceProperty, StringProperty, TimestampProperty, TypeProperty,
|
ObjectReferenceProperty, StringProperty, TimestampProperty, TypeProperty,
|
||||||
)
|
)
|
||||||
|
from .base import _Extension, _Observable, _STIXBase20
|
||||||
|
|
||||||
|
|
||||||
class Artifact(_Observable):
|
class Artifact(_Observable):
|
||||||
|
@ -26,7 +26,7 @@ class Artifact(_Observable):
|
||||||
|
|
||||||
_type = 'artifact'
|
_type = 'artifact'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('mime_type', StringProperty()),
|
('mime_type', StringProperty()),
|
||||||
('payload_bin', BinaryProperty()),
|
('payload_bin', BinaryProperty()),
|
||||||
('url', StringProperty()),
|
('url', StringProperty()),
|
||||||
|
@ -47,7 +47,7 @@ class AutonomousSystem(_Observable):
|
||||||
|
|
||||||
_type = 'autonomous-system'
|
_type = 'autonomous-system'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('number', IntegerProperty(required=True)),
|
('number', IntegerProperty(required=True)),
|
||||||
('name', StringProperty()),
|
('name', StringProperty()),
|
||||||
('rir', StringProperty()),
|
('rir', StringProperty()),
|
||||||
|
@ -62,7 +62,7 @@ class Directory(_Observable):
|
||||||
|
|
||||||
_type = 'directory'
|
_type = 'directory'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('path', StringProperty(required=True)),
|
('path', StringProperty(required=True)),
|
||||||
('path_enc', StringProperty()),
|
('path_enc', StringProperty()),
|
||||||
# these are not the created/modified timestamps of the object itself
|
# these are not the created/modified timestamps of the object itself
|
||||||
|
@ -81,7 +81,7 @@ class DomainName(_Observable):
|
||||||
|
|
||||||
_type = 'domain-name'
|
_type = 'domain-name'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('value', StringProperty(required=True)),
|
('value', StringProperty(required=True)),
|
||||||
('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types=['ipv4-addr', 'ipv6-addr', 'domain-name']))),
|
('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types=['ipv4-addr', 'ipv6-addr', 'domain-name']))),
|
||||||
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)),
|
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)),
|
||||||
|
@ -95,7 +95,7 @@ class EmailAddress(_Observable):
|
||||||
|
|
||||||
_type = 'email-addr'
|
_type = 'email-addr'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('value', StringProperty(required=True)),
|
('value', StringProperty(required=True)),
|
||||||
('display_name', StringProperty()),
|
('display_name', StringProperty()),
|
||||||
('belongs_to_ref', ObjectReferenceProperty(valid_types='user-account')),
|
('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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part4-cyber-observable-objects/stix-v2.0-cs01-part4-cyber-observable-objects.html#_Toc496716231>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part4-cyber-observable-objects/stix-v2.0-cs01-part4-cyber-observable-objects.html#_Toc496716231>`__.
|
||||||
""" # noqa
|
""" # noqa
|
||||||
|
@ -127,7 +127,7 @@ class EmailMessage(_Observable):
|
||||||
|
|
||||||
_type = 'email-message'
|
_type = 'email-message'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('is_multipart', BooleanProperty(required=True)),
|
('is_multipart', BooleanProperty(required=True)),
|
||||||
('date', TimestampProperty()),
|
('date', TimestampProperty()),
|
||||||
('content_type', StringProperty()),
|
('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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part4-cyber-observable-objects/stix-v2.0-cs01-part4-cyber-observable-objects.html#_Toc496716239>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part4-cyber-observable-objects/stix-v2.0-cs01-part4-cyber-observable-objects.html#_Toc496716239>`__.
|
||||||
""" # noqa
|
""" # noqa
|
||||||
|
@ -220,7 +220,7 @@ class RasterImageExt(_Extension):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class WindowsPEOptionalHeaderType(_STIXBase):
|
class WindowsPEOptionalHeaderType(_STIXBase20):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part4-cyber-observable-objects/stix-v2.0-cs01-part4-cyber-observable-objects.html#_Toc496716248>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part4-cyber-observable-objects/stix-v2.0-cs01-part4-cyber-observable-objects.html#_Toc496716248>`__.
|
||||||
""" # noqa
|
""" # noqa
|
||||||
|
@ -264,7 +264,7 @@ class WindowsPEOptionalHeaderType(_STIXBase):
|
||||||
self._check_at_least_one_property()
|
self._check_at_least_one_property()
|
||||||
|
|
||||||
|
|
||||||
class WindowsPESection(_STIXBase):
|
class WindowsPESection(_STIXBase20):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part4-cyber-observable-objects/stix-v2.0-cs01-part4-cyber-observable-objects.html#_Toc496716250>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part4-cyber-observable-objects/stix-v2.0-cs01-part4-cyber-observable-objects.html#_Toc496716250>`__.
|
||||||
""" # noqa
|
""" # noqa
|
||||||
|
@ -306,7 +306,7 @@ class File(_Observable):
|
||||||
|
|
||||||
_type = 'file'
|
_type = 'file'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('hashes', HashesProperty()),
|
('hashes', HashesProperty()),
|
||||||
('size', IntegerProperty()),
|
('size', IntegerProperty()),
|
||||||
('name', StringProperty()),
|
('name', StringProperty()),
|
||||||
|
@ -339,7 +339,7 @@ class IPv4Address(_Observable):
|
||||||
|
|
||||||
_type = 'ipv4-addr'
|
_type = 'ipv4-addr'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('value', StringProperty(required=True)),
|
('value', StringProperty(required=True)),
|
||||||
('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types='mac-addr'))),
|
('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types='mac-addr'))),
|
||||||
('belongs_to_refs', ListProperty(ObjectReferenceProperty(valid_types='autonomous-system'))),
|
('belongs_to_refs', ListProperty(ObjectReferenceProperty(valid_types='autonomous-system'))),
|
||||||
|
@ -354,7 +354,7 @@ class IPv6Address(_Observable):
|
||||||
|
|
||||||
_type = 'ipv6-addr'
|
_type = 'ipv6-addr'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('value', StringProperty(required=True)),
|
('value', StringProperty(required=True)),
|
||||||
('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types='mac-addr'))),
|
('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types='mac-addr'))),
|
||||||
('belongs_to_refs', ListProperty(ObjectReferenceProperty(valid_types='autonomous-system'))),
|
('belongs_to_refs', ListProperty(ObjectReferenceProperty(valid_types='autonomous-system'))),
|
||||||
|
@ -369,7 +369,7 @@ class MACAddress(_Observable):
|
||||||
|
|
||||||
_type = 'mac-addr'
|
_type = 'mac-addr'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('value', StringProperty(required=True)),
|
('value', StringProperty(required=True)),
|
||||||
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)),
|
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)),
|
||||||
])
|
])
|
||||||
|
@ -382,7 +382,7 @@ class Mutex(_Observable):
|
||||||
|
|
||||||
_type = 'mutex'
|
_type = 'mutex'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)),
|
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)),
|
||||||
])
|
])
|
||||||
|
@ -483,7 +483,7 @@ class NetworkTraffic(_Observable):
|
||||||
|
|
||||||
_type = 'network-traffic'
|
_type = 'network-traffic'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('start', TimestampProperty()),
|
('start', TimestampProperty()),
|
||||||
('end', TimestampProperty()),
|
('end', TimestampProperty()),
|
||||||
('is_active', BooleanProperty()),
|
('is_active', BooleanProperty()),
|
||||||
|
@ -575,7 +575,7 @@ class Process(_Observable):
|
||||||
|
|
||||||
_type = 'process'
|
_type = 'process'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('is_hidden', BooleanProperty()),
|
('is_hidden', BooleanProperty()),
|
||||||
('pid', IntegerProperty()),
|
('pid', IntegerProperty()),
|
||||||
('name', StringProperty()),
|
('name', StringProperty()),
|
||||||
|
@ -615,7 +615,7 @@ class Software(_Observable):
|
||||||
|
|
||||||
_type = 'software'
|
_type = 'software'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('cpe', StringProperty()),
|
('cpe', StringProperty()),
|
||||||
('languages', ListProperty(StringProperty)),
|
('languages', ListProperty(StringProperty)),
|
||||||
|
@ -632,7 +632,7 @@ class URL(_Observable):
|
||||||
|
|
||||||
_type = 'url'
|
_type = 'url'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('value', StringProperty(required=True)),
|
('value', StringProperty(required=True)),
|
||||||
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)),
|
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)),
|
||||||
])
|
])
|
||||||
|
@ -659,7 +659,7 @@ class UserAccount(_Observable):
|
||||||
|
|
||||||
_type = 'user-account'
|
_type = 'user-account'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('user_id', StringProperty(required=True)),
|
('user_id', StringProperty(required=True)),
|
||||||
('account_login', StringProperty()),
|
('account_login', StringProperty()),
|
||||||
('account_type', StringProperty()), # open vocab
|
('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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part4-cyber-observable-objects/stix-v2.0-cs01-part4-cyber-observable-objects.html#_Toc496716293>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part4-cyber-observable-objects/stix-v2.0-cs01-part4-cyber-observable-objects.html#_Toc496716293>`__.
|
||||||
""" # noqa
|
""" # noqa
|
||||||
|
@ -713,7 +713,7 @@ class WindowsRegistryKey(_Observable):
|
||||||
|
|
||||||
_type = 'windows-registry-key'
|
_type = 'windows-registry-key'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('key', StringProperty(required=True)),
|
('key', StringProperty(required=True)),
|
||||||
('values', ListProperty(EmbeddedObjectProperty(type=WindowsRegistryValueType))),
|
('values', ListProperty(EmbeddedObjectProperty(type=WindowsRegistryValueType))),
|
||||||
# this is not the modified timestamps of the object itself
|
# 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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part4-cyber-observable-objects/stix-v2.0-cs01-part4-cyber-observable-objects.html#_Toc496716298>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part4-cyber-observable-objects/stix-v2.0-cs01-part4-cyber-observable-objects.html#_Toc496716298>`__.
|
||||||
""" # noqa
|
""" # noqa
|
||||||
|
@ -757,7 +757,7 @@ class X509Certificate(_Observable):
|
||||||
|
|
||||||
_type = 'x509-certificate'
|
_type = 'x509-certificate'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('is_self_signed', BooleanProperty()),
|
('is_self_signed', BooleanProperty()),
|
||||||
('hashes', HashesProperty()),
|
('hashes', HashesProperty()),
|
||||||
('version', StringProperty()),
|
('version', StringProperty()),
|
||||||
|
@ -791,11 +791,11 @@ def CustomObservable(type='x-custom-observable', properties=None):
|
||||||
"""
|
"""
|
||||||
def wrapper(cls):
|
def wrapper(cls):
|
||||||
_properties = list(itertools.chain.from_iterable([
|
_properties = list(itertools.chain.from_iterable([
|
||||||
[('type', TypeProperty(type))],
|
[('type', TypeProperty(type, spec_version='2.0'))],
|
||||||
properties,
|
properties,
|
||||||
[('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=type))],
|
[('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
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@ -803,5 +803,5 @@ def CustomExtension(observable=None, type='x-custom-observable-ext', properties=
|
||||||
"""Decorator for custom extensions to STIX Cyber Observables.
|
"""Decorator for custom extensions to STIX Cyber Observables.
|
||||||
"""
|
"""
|
||||||
def wrapper(cls):
|
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
|
return wrapper
|
||||||
|
|
|
@ -5,7 +5,6 @@ import itertools
|
||||||
|
|
||||||
from stix2patterns.validator import run_validator
|
from stix2patterns.validator import run_validator
|
||||||
|
|
||||||
from ..core import STIXDomainObject
|
|
||||||
from ..custom import _custom_object_builder
|
from ..custom import _custom_object_builder
|
||||||
from ..exceptions import InvalidValueError
|
from ..exceptions import InvalidValueError
|
||||||
from ..properties import (
|
from ..properties import (
|
||||||
|
@ -14,17 +13,18 @@ from ..properties import (
|
||||||
TimestampProperty, TypeProperty,
|
TimestampProperty, TypeProperty,
|
||||||
)
|
)
|
||||||
from ..utils import NOW
|
from ..utils import NOW
|
||||||
|
from .base import _DomainObject
|
||||||
from .common import ExternalReference, GranularMarking, KillChainPhase
|
from .common import ExternalReference, GranularMarking, KillChainPhase
|
||||||
|
|
||||||
|
|
||||||
class AttackPattern(STIXDomainObject):
|
class AttackPattern(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714302>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714302>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'attack-pattern'
|
_type = 'attack-pattern'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714305>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714305>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'campaign'
|
_type = 'campaign'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714308>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714308>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'course-of-action'
|
_type = 'course-of-action'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714311>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714311>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'identity'
|
_type = 'identity'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714314>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714314>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'indicator'
|
_type = 'indicator'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
|
@ -144,14 +144,14 @@ class Indicator(STIXDomainObject):
|
||||||
raise InvalidValueError(self.__class__, 'pattern', str(errors[0]))
|
raise InvalidValueError(self.__class__, 'pattern', str(errors[0]))
|
||||||
|
|
||||||
|
|
||||||
class IntrusionSet(STIXDomainObject):
|
class IntrusionSet(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714317>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714317>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'intrusion-set'
|
_type = 'intrusion-set'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714320>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714320>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'malware'
|
_type = 'malware'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714323>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714323>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'observed-data'
|
_type = 'observed-data'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
|
@ -226,14 +226,14 @@ class ObservedData(STIXDomainObject):
|
||||||
super(ObservedData, self).__init__(*args, **kwargs)
|
super(ObservedData, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Report(STIXDomainObject):
|
class Report(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714326>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714326>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'report'
|
_type = 'report'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
|
@ -256,14 +256,14 @@ class Report(STIXDomainObject):
|
||||||
super(Report, self).__init__(*args, **kwargs)
|
super(Report, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ThreatActor(STIXDomainObject):
|
class ThreatActor(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714329>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714329>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'threat-actor'
|
_type = 'threat-actor'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
|
@ -286,14 +286,14 @@ class ThreatActor(STIXDomainObject):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class Tool(STIXDomainObject):
|
class Tool(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714332>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714332>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'tool'
|
_type = 'tool'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
|
@ -310,14 +310,14 @@ class Tool(STIXDomainObject):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class Vulnerability(STIXDomainObject):
|
class Vulnerability(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714335>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714335>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'vulnerability'
|
_type = 'vulnerability'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
|
@ -364,7 +364,7 @@ def CustomObject(type='x-custom-type', properties=None):
|
||||||
def wrapper(cls):
|
def wrapper(cls):
|
||||||
_properties = list(itertools.chain.from_iterable([
|
_properties = list(itertools.chain.from_iterable([
|
||||||
[
|
[
|
||||||
('type', TypeProperty(type)),
|
('type', TypeProperty(type, spec_version='2.0')),
|
||||||
('id', IDProperty(type, spec_version='2.0')),
|
('id', IDProperty(type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
|
@ -380,5 +380,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]),
|
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
|
return wrapper
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from ..core import STIXRelationshipObject
|
|
||||||
from ..properties import (
|
from ..properties import (
|
||||||
BooleanProperty, IDProperty, IntegerProperty, ListProperty,
|
BooleanProperty, IDProperty, IntegerProperty, ListProperty,
|
||||||
ReferenceProperty, StringProperty, TimestampProperty, TypeProperty,
|
ReferenceProperty, StringProperty, TimestampProperty, TypeProperty,
|
||||||
)
|
)
|
||||||
from ..utils import NOW
|
from ..utils import NOW
|
||||||
|
from .base import _RelationshipObject
|
||||||
from .common import ExternalReference, GranularMarking
|
from .common import ExternalReference, GranularMarking
|
||||||
|
|
||||||
|
|
||||||
class Relationship(STIXRelationshipObject):
|
class Relationship(_RelationshipObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714340>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714340>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -20,7 +20,7 @@ class Relationship(STIXRelationshipObject):
|
||||||
|
|
||||||
_type = 'relationship'
|
_type = 'relationship'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
|
@ -55,14 +55,14 @@ class Relationship(STIXRelationshipObject):
|
||||||
super(Relationship, self).__init__(**kwargs)
|
super(Relationship, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Sighting(STIXRelationshipObject):
|
class Sighting(_RelationshipObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714343>`__.
|
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part2-stix-objects/stix-v2.0-cs01-part2-stix-objects.html#_Toc496714343>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'sighting'
|
_type = 'sighting'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.0')),
|
||||||
('id', IDProperty(_type, spec_version='2.0')),
|
('id', IDProperty(_type, spec_version='2.0')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.0')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
|
|
||||||
# flake8: noqa
|
# flake8: noqa
|
||||||
|
|
||||||
|
from .base import (
|
||||||
|
_DomainObject, _Extension, _Observable, _RelationshipObject, _STIXBase21,
|
||||||
|
)
|
||||||
from .bundle import Bundle
|
from .bundle import Bundle
|
||||||
from .common import (
|
from .common import (
|
||||||
TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference,
|
TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference,
|
||||||
|
|
|
@ -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
|
|
@ -2,20 +2,20 @@
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from ..base import _STIXBase
|
|
||||||
from ..properties import (
|
from ..properties import (
|
||||||
IDProperty, ListProperty, STIXObjectProperty, TypeProperty,
|
IDProperty, ListProperty, STIXObjectProperty, TypeProperty,
|
||||||
)
|
)
|
||||||
|
from .base import _STIXBase21
|
||||||
|
|
||||||
|
|
||||||
class Bundle(_STIXBase):
|
class Bundle(_STIXBase21):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_nuwp4rox8c7r>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_nuwp4rox8c7r>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'bundle'
|
_type = 'bundle'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('objects', ListProperty(STIXObjectProperty(spec_version='2.1'))),
|
('objects', ListProperty(STIXObjectProperty(spec_version='2.1'))),
|
||||||
])
|
])
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from ..base import _STIXBase
|
|
||||||
from ..custom import _custom_marking_builder
|
from ..custom import _custom_marking_builder
|
||||||
from ..exceptions import InvalidValueError
|
from ..exceptions import InvalidValueError
|
||||||
from ..markings import _MarkingsMixin
|
from ..markings import _MarkingsMixin
|
||||||
|
@ -13,9 +12,10 @@ from ..properties import (
|
||||||
SelectorProperty, StringProperty, TimestampProperty, TypeProperty,
|
SelectorProperty, StringProperty, TimestampProperty, TypeProperty,
|
||||||
)
|
)
|
||||||
from ..utils import NOW, _get_dict
|
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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_bajcvqteiard>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_bajcvqteiard>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -49,7 +49,7 @@ class ExternalReference(_STIXBase):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class KillChainPhase(_STIXBase):
|
class KillChainPhase(_STIXBase21):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_i4tjv75ce50h>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_i4tjv75ce50h>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -60,7 +60,7 @@ class KillChainPhase(_STIXBase):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class GranularMarking(_STIXBase):
|
class GranularMarking(_STIXBase21):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_robezi5egfdr>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_robezi5egfdr>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -76,19 +76,19 @@ class GranularMarking(_STIXBase):
|
||||||
self._check_at_least_one_property(['lang', 'marking_ref'])
|
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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_nfwr8z9ax2bi>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_nfwr8z9ax2bi>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'language-content'
|
_type = 'language-content'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('object_ref', ReferenceProperty(valid_types=["SCO", "SDO", "SRO"], spec_version='2.1', required=True)),
|
('object_ref', ReferenceProperty(valid_types=["SCO", "SDO", "SRO"], spec_version='2.1', required=True)),
|
||||||
# TODO: 'object_modified' it MUST be an exact match for the modified time of the STIX Object (SRO or SDO) being referenced.
|
# TODO: 'object_modified' it MUST be an exact match for the modified time of the STIX Object (SRO or SDO) being referenced.
|
||||||
('object_modified', TimestampProperty(precision='millisecond')),
|
('object_modified', TimestampProperty(precision='millisecond')),
|
||||||
|
@ -103,7 +103,7 @@ class LanguageContent(_STIXBase):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class TLPMarking(_STIXBase):
|
class TLPMarking(_STIXBase21):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_yd3ar14ekwrs>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_yd3ar14ekwrs>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -114,7 +114,7 @@ class TLPMarking(_STIXBase):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class StatementMarking(_STIXBase):
|
class StatementMarking(_STIXBase21):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_3ru8r05saera>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_3ru8r05saera>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -144,18 +144,18 @@ class MarkingProperty(Property):
|
||||||
raise ValueError("must be a Statement, TLP Marking or a registered marking.")
|
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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_hr5vgqxjk7ns>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_hr5vgqxjk7ns>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'marking-definition'
|
_type = 'marking-definition'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type)),
|
('id', IDProperty(_type)),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('external_references', ListProperty(ExternalReference)),
|
('external_references', ListProperty(ExternalReference)),
|
||||||
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
|
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
|
||||||
('granular_markings', ListProperty(GranularMarking)),
|
('granular_markings', ListProperty(GranularMarking)),
|
||||||
|
@ -214,7 +214,7 @@ def CustomMarking(type='x-custom-marking', properties=None):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def wrapper(cls):
|
def wrapper(cls):
|
||||||
return _custom_marking_builder(cls, type, properties, '2.1')
|
return _custom_marking_builder(cls, type, properties, '2.1', _STIXBase21)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
"""STIX 2.1 Cyber Observable Objects.
|
"""STIX 2.1 Cyber Observable Objects.
|
||||||
|
|
||||||
Embedded observable object types, such as Email MIME Component, which is
|
Embedded observable object types, such as Email MIME Component, which is
|
||||||
embedded in Email Message objects, inherit from ``_STIXBase`` instead of
|
embedded in Email Message objects, inherit from ``_STIXBase21`` instead of
|
||||||
Observable and do not have a ``_type`` attribute.
|
_Observable and do not have a ``_type`` attribute.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
from ..base import _Extension, _Observable, _STIXBase
|
|
||||||
from ..custom import _custom_extension_builder, _custom_observable_builder
|
from ..custom import _custom_extension_builder, _custom_observable_builder
|
||||||
from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError
|
from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError
|
||||||
from ..properties import (
|
from ..properties import (
|
||||||
|
@ -18,6 +17,7 @@ from ..properties import (
|
||||||
ObjectReferenceProperty, ReferenceProperty, StringProperty,
|
ObjectReferenceProperty, ReferenceProperty, StringProperty,
|
||||||
TimestampProperty, TypeProperty,
|
TimestampProperty, TypeProperty,
|
||||||
)
|
)
|
||||||
|
from .base import _Extension, _Observable, _STIXBase21
|
||||||
from .common import GranularMarking
|
from .common import GranularMarking
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ class Artifact(_Observable):
|
||||||
|
|
||||||
_type = 'artifact'
|
_type = 'artifact'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('mime_type', StringProperty()),
|
('mime_type', StringProperty()),
|
||||||
('payload_bin', BinaryProperty()),
|
('payload_bin', BinaryProperty()),
|
||||||
|
@ -57,7 +57,7 @@ class AutonomousSystem(_Observable):
|
||||||
|
|
||||||
_type = 'autonomous-system'
|
_type = 'autonomous-system'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('number', IntegerProperty(required=True)),
|
('number', IntegerProperty(required=True)),
|
||||||
('name', StringProperty()),
|
('name', StringProperty()),
|
||||||
|
@ -78,7 +78,7 @@ class Directory(_Observable):
|
||||||
|
|
||||||
_type = 'directory'
|
_type = 'directory'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('path', StringProperty(required=True)),
|
('path', StringProperty(required=True)),
|
||||||
('path_enc', StringProperty()),
|
('path_enc', StringProperty()),
|
||||||
|
@ -103,7 +103,7 @@ class DomainName(_Observable):
|
||||||
|
|
||||||
_type = 'domain-name'
|
_type = 'domain-name'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('value', StringProperty(required=True)),
|
('value', StringProperty(required=True)),
|
||||||
('resolves_to_refs', ListProperty(ReferenceProperty(valid_types=['ipv4-addr', 'ipv6-addr', 'domain-name'], spec_version='2.1'))),
|
('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'
|
_type = 'email-addr'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('value', StringProperty(required=True)),
|
('value', StringProperty(required=True)),
|
||||||
('display_name', StringProperty()),
|
('display_name', StringProperty()),
|
||||||
|
@ -137,7 +137,7 @@ class EmailAddress(_Observable):
|
||||||
_id_contributing_properties = ["value"]
|
_id_contributing_properties = ["value"]
|
||||||
|
|
||||||
|
|
||||||
class EmailMIMEComponent(_STIXBase):
|
class EmailMIMEComponent(_STIXBase21):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_kzv52qqc0xw1>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_kzv52qqc0xw1>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -161,7 +161,7 @@ class EmailMessage(_Observable):
|
||||||
|
|
||||||
_type = 'email-message'
|
_type = 'email-message'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('is_multipart', BooleanProperty(required=True)),
|
('is_multipart', BooleanProperty(required=True)),
|
||||||
('date', TimestampProperty()),
|
('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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_nbqgazg6fsma>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_nbqgazg6fsma>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -259,7 +259,7 @@ class RasterImageExt(_Extension):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class WindowsPEOptionalHeaderType(_STIXBase):
|
class WindowsPEOptionalHeaderType(_STIXBase21):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_wyp5qdc2wugy>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_wyp5qdc2wugy>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -303,7 +303,7 @@ class WindowsPEOptionalHeaderType(_STIXBase):
|
||||||
self._check_at_least_one_property()
|
self._check_at_least_one_property()
|
||||||
|
|
||||||
|
|
||||||
class WindowsPESection(_STIXBase):
|
class WindowsPESection(_STIXBase21):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_wiqw87xsov3t>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_wiqw87xsov3t>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -345,7 +345,7 @@ class File(_Observable):
|
||||||
|
|
||||||
_type = 'file'
|
_type = 'file'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('hashes', HashesProperty(spec_version='2.1')),
|
('hashes', HashesProperty(spec_version='2.1')),
|
||||||
('size', IntegerProperty(min=0)),
|
('size', IntegerProperty(min=0)),
|
||||||
|
@ -380,7 +380,7 @@ class IPv4Address(_Observable):
|
||||||
|
|
||||||
_type = 'ipv4-addr'
|
_type = 'ipv4-addr'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('value', StringProperty(required=True)),
|
('value', StringProperty(required=True)),
|
||||||
('resolves_to_refs', ListProperty(ReferenceProperty(valid_types='mac-addr', spec_version='2.1'))),
|
('resolves_to_refs', ListProperty(ReferenceProperty(valid_types='mac-addr', spec_version='2.1'))),
|
||||||
|
@ -401,7 +401,7 @@ class IPv6Address(_Observable):
|
||||||
|
|
||||||
_type = 'ipv6-addr'
|
_type = 'ipv6-addr'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('value', StringProperty(required=True)),
|
('value', StringProperty(required=True)),
|
||||||
('resolves_to_refs', ListProperty(ReferenceProperty(valid_types='mac-addr', spec_version='2.1'))),
|
('resolves_to_refs', ListProperty(ReferenceProperty(valid_types='mac-addr', spec_version='2.1'))),
|
||||||
|
@ -422,7 +422,7 @@ class MACAddress(_Observable):
|
||||||
|
|
||||||
_type = 'mac-addr'
|
_type = 'mac-addr'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('value', StringProperty(required=True)),
|
('value', StringProperty(required=True)),
|
||||||
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
|
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
|
||||||
|
@ -441,7 +441,7 @@ class Mutex(_Observable):
|
||||||
|
|
||||||
_type = 'mutex'
|
_type = 'mutex'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
|
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
|
||||||
|
@ -562,7 +562,7 @@ class NetworkTraffic(_Observable):
|
||||||
|
|
||||||
_type = 'network-traffic'
|
_type = 'network-traffic'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('start', TimestampProperty()),
|
('start', TimestampProperty()),
|
||||||
('end', TimestampProperty()),
|
('end', TimestampProperty()),
|
||||||
|
@ -684,7 +684,7 @@ class Process(_Observable):
|
||||||
|
|
||||||
_type = 'process'
|
_type = 'process'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('is_hidden', BooleanProperty()),
|
('is_hidden', BooleanProperty()),
|
||||||
('pid', IntegerProperty()),
|
('pid', IntegerProperty()),
|
||||||
|
@ -728,7 +728,7 @@ class Software(_Observable):
|
||||||
|
|
||||||
_type = 'software'
|
_type = 'software'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('cpe', StringProperty()),
|
('cpe', StringProperty()),
|
||||||
|
@ -752,7 +752,7 @@ class URL(_Observable):
|
||||||
|
|
||||||
_type = 'url'
|
_type = 'url'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('value', StringProperty(required=True)),
|
('value', StringProperty(required=True)),
|
||||||
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
|
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
|
||||||
|
@ -785,7 +785,7 @@ class UserAccount(_Observable):
|
||||||
|
|
||||||
_type = 'user-account'
|
_type = 'user-account'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('user_id', StringProperty()),
|
('user_id', StringProperty()),
|
||||||
('credential', StringProperty()),
|
('credential', StringProperty()),
|
||||||
|
@ -810,7 +810,7 @@ class UserAccount(_Observable):
|
||||||
_id_contributing_properties = ["account_type", "user_id", "account_login"]
|
_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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_6jiqabgqp2hp>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_6jiqabgqp2hp>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -846,7 +846,7 @@ class WindowsRegistryKey(_Observable):
|
||||||
|
|
||||||
_type = 'windows-registry-key'
|
_type = 'windows-registry-key'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('key', StringProperty()),
|
('key', StringProperty()),
|
||||||
('values', ListProperty(EmbeddedObjectProperty(type=WindowsRegistryValueType))),
|
('values', ListProperty(EmbeddedObjectProperty(type=WindowsRegistryValueType))),
|
||||||
|
@ -863,7 +863,7 @@ class WindowsRegistryKey(_Observable):
|
||||||
_id_contributing_properties = ["key", "values"]
|
_id_contributing_properties = ["key", "values"]
|
||||||
|
|
||||||
|
|
||||||
class X509V3ExtenstionsType(_STIXBase):
|
class X509V3ExtenstionsType(_STIXBase21):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_c1kt4dheb6vz>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_c1kt4dheb6vz>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -896,7 +896,7 @@ class X509Certificate(_Observable):
|
||||||
|
|
||||||
_type = 'x509-certificate'
|
_type = 'x509-certificate'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('is_self_signed', BooleanProperty()),
|
('is_self_signed', BooleanProperty()),
|
||||||
('hashes', HashesProperty(spec_version='2.1')),
|
('hashes', HashesProperty(spec_version='2.1')),
|
||||||
|
@ -948,12 +948,12 @@ def CustomObservable(type='x-custom-observable', properties=None, id_contrib_pro
|
||||||
"""
|
"""
|
||||||
def wrapper(cls):
|
def wrapper(cls):
|
||||||
_properties = list(itertools.chain.from_iterable([
|
_properties = list(itertools.chain.from_iterable([
|
||||||
[('type', TypeProperty(type))],
|
[('type', TypeProperty(type, spec_version='2.1'))],
|
||||||
[('id', IDProperty(type, spec_version='2.1'))],
|
[('id', IDProperty(type, spec_version='2.1'))],
|
||||||
properties,
|
properties,
|
||||||
[('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=type))],
|
[('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
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@ -961,5 +961,5 @@ def CustomExtension(observable=None, type='x-custom-observable-ext', properties=
|
||||||
"""Decorator for custom extensions to STIX Cyber Observables.
|
"""Decorator for custom extensions to STIX Cyber Observables.
|
||||||
"""
|
"""
|
||||||
def wrapper(cls):
|
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
|
return wrapper
|
||||||
|
|
156
stix2/v21/sdo.py
156
stix2/v21/sdo.py
|
@ -7,7 +7,6 @@ import warnings
|
||||||
from six.moves.urllib.parse import quote_plus
|
from six.moves.urllib.parse import quote_plus
|
||||||
from stix2patterns.validator import run_validator
|
from stix2patterns.validator import run_validator
|
||||||
|
|
||||||
from ..core import STIXDomainObject
|
|
||||||
from ..custom import _custom_object_builder
|
from ..custom import _custom_object_builder
|
||||||
from ..exceptions import (
|
from ..exceptions import (
|
||||||
InvalidValueError, PropertyPresenceError, STIXDeprecationWarning,
|
InvalidValueError, PropertyPresenceError, STIXDeprecationWarning,
|
||||||
|
@ -18,22 +17,23 @@ from ..properties import (
|
||||||
StringProperty, TimestampProperty, TypeProperty,
|
StringProperty, TimestampProperty, TypeProperty,
|
||||||
)
|
)
|
||||||
from ..utils import NOW
|
from ..utils import NOW
|
||||||
|
from .base import _DomainObject
|
||||||
from .common import ExternalReference, GranularMarking, KillChainPhase
|
from .common import ExternalReference, GranularMarking, KillChainPhase
|
||||||
|
|
||||||
|
|
||||||
class AttackPattern(STIXDomainObject):
|
class AttackPattern(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_4ohsa4pay4h4>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_4ohsa4pay4h4>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'attack-pattern'
|
_type = 'attack-pattern'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('aliases', ListProperty(StringProperty)),
|
('aliases', ListProperty(StringProperty)),
|
||||||
|
@ -48,19 +48,19 @@ class AttackPattern(STIXDomainObject):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class Campaign(STIXDomainObject):
|
class Campaign(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_vvysvm8mt434>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_vvysvm8mt434>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'campaign'
|
_type = 'campaign'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('aliases', ListProperty(StringProperty)),
|
('aliases', ListProperty(StringProperty)),
|
||||||
|
@ -87,19 +87,19 @@ class Campaign(STIXDomainObject):
|
||||||
raise ValueError(msg.format(self))
|
raise ValueError(msg.format(self))
|
||||||
|
|
||||||
|
|
||||||
class CourseOfAction(STIXDomainObject):
|
class CourseOfAction(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_d5yf99f0a230>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_d5yf99f0a230>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'course-of-action'
|
_type = 'course-of-action'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('revoked', BooleanProperty(default=lambda: False)),
|
('revoked', BooleanProperty(default=lambda: False)),
|
||||||
|
@ -112,18 +112,18 @@ class CourseOfAction(STIXDomainObject):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class Grouping(STIXDomainObject):
|
class Grouping(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_9e3uldaqqha2>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_9e3uldaqqha2>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'grouping'
|
_type = 'grouping'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('revoked', BooleanProperty(default=lambda: False)),
|
('revoked', BooleanProperty(default=lambda: False)),
|
||||||
('labels', ListProperty(StringProperty)),
|
('labels', ListProperty(StringProperty)),
|
||||||
|
@ -139,19 +139,19 @@ class Grouping(STIXDomainObject):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class Identity(STIXDomainObject):
|
class Identity(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_ru8fmldl2p6w>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_ru8fmldl2p6w>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'identity'
|
_type = 'identity'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('roles', ListProperty(StringProperty)),
|
('roles', ListProperty(StringProperty)),
|
||||||
|
@ -168,19 +168,19 @@ class Identity(STIXDomainObject):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class Indicator(STIXDomainObject):
|
class Indicator(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_wfiae74706sw>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_wfiae74706sw>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'indicator'
|
_type = 'indicator'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('name', StringProperty()),
|
('name', StringProperty()),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('indicator_types', ListProperty(StringProperty)),
|
('indicator_types', ListProperty(StringProperty)),
|
||||||
|
@ -204,7 +204,7 @@ class Indicator(STIXDomainObject):
|
||||||
if kwargs.get('pattern') and kwargs.get('pattern_type') == 'stix' and not kwargs.get('pattern_version'):
|
if kwargs.get('pattern') and kwargs.get('pattern_type') == 'stix' and not kwargs.get('pattern_version'):
|
||||||
kwargs['pattern_version'] = '2.1'
|
kwargs['pattern_version'] = '2.1'
|
||||||
|
|
||||||
super(STIXDomainObject, self).__init__(*args, **kwargs)
|
super(_DomainObject, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def _check_object_constraints(self):
|
def _check_object_constraints(self):
|
||||||
super(Indicator, self)._check_object_constraints()
|
super(Indicator, self)._check_object_constraints()
|
||||||
|
@ -227,19 +227,19 @@ class Indicator(STIXDomainObject):
|
||||||
raise InvalidValueError(self.__class__, 'pattern', str(errors[0]))
|
raise InvalidValueError(self.__class__, 'pattern', str(errors[0]))
|
||||||
|
|
||||||
|
|
||||||
class Infrastructure(STIXDomainObject):
|
class Infrastructure(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_l2alfbbcmfep>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_l2alfbbcmfep>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'infrastructure'
|
_type = 'infrastructure'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('revoked', BooleanProperty(default=lambda: False)),
|
('revoked', BooleanProperty(default=lambda: False)),
|
||||||
('labels', ListProperty(StringProperty)),
|
('labels', ListProperty(StringProperty)),
|
||||||
('confidence', IntegerProperty()),
|
('confidence', IntegerProperty()),
|
||||||
|
@ -267,19 +267,19 @@ class Infrastructure(STIXDomainObject):
|
||||||
raise ValueError(msg.format(self))
|
raise ValueError(msg.format(self))
|
||||||
|
|
||||||
|
|
||||||
class IntrusionSet(STIXDomainObject):
|
class IntrusionSet(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_ticprjb32bc4>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_ticprjb32bc4>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'intrusion-set'
|
_type = 'intrusion-set'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('aliases', ListProperty(StringProperty)),
|
('aliases', ListProperty(StringProperty)),
|
||||||
|
@ -309,19 +309,19 @@ class IntrusionSet(STIXDomainObject):
|
||||||
raise ValueError(msg.format(self))
|
raise ValueError(msg.format(self))
|
||||||
|
|
||||||
|
|
||||||
class Location(STIXDomainObject):
|
class Location(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_sqez6sri9vtz>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_sqez6sri9vtz>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'location'
|
_type = 'location'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('name', StringProperty()),
|
('name', StringProperty()),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('latitude', FloatProperty(min=-90.0, max=90.0)),
|
('latitude', FloatProperty(min=-90.0, max=90.0)),
|
||||||
|
@ -416,19 +416,19 @@ class Location(STIXDomainObject):
|
||||||
return final_url
|
return final_url
|
||||||
|
|
||||||
|
|
||||||
class Malware(STIXDomainObject):
|
class Malware(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_gc4ooz6oaz7y>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_gc4ooz6oaz7y>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'malware'
|
_type = 'malware'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('name', StringProperty()),
|
('name', StringProperty()),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('malware_types', ListProperty(StringProperty)),
|
('malware_types', ListProperty(StringProperty)),
|
||||||
|
@ -468,18 +468,18 @@ class Malware(STIXDomainObject):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class MalwareAnalysis(STIXDomainObject):
|
class MalwareAnalysis(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_dw67pa20zss5>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_dw67pa20zss5>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'malware-analysis'
|
_type = 'malware-analysis'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('revoked', BooleanProperty(default=lambda: False)),
|
('revoked', BooleanProperty(default=lambda: False)),
|
||||||
('labels', ListProperty(StringProperty)),
|
('labels', ListProperty(StringProperty)),
|
||||||
|
@ -512,19 +512,19 @@ class MalwareAnalysis(STIXDomainObject):
|
||||||
self._check_at_least_one_property(["result", "analysis_sco_refs"])
|
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
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_hr77jvcbs9jk>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_hr77jvcbs9jk>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'note'
|
_type = 'note'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('abstract', StringProperty()),
|
('abstract', StringProperty()),
|
||||||
('content', StringProperty(required=True)),
|
('content', StringProperty(required=True)),
|
||||||
('authors', ListProperty(StringProperty)),
|
('authors', ListProperty(StringProperty)),
|
||||||
|
@ -539,19 +539,19 @@ class Note(STIXDomainObject):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class ObservedData(STIXDomainObject):
|
class ObservedData(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_h1590esrzg5f>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_h1590esrzg5f>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'observed-data'
|
_type = 'observed-data'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('first_observed', TimestampProperty(required=True)),
|
('first_observed', TimestampProperty(required=True)),
|
||||||
('last_observed', TimestampProperty(required=True)),
|
('last_observed', TimestampProperty(required=True)),
|
||||||
('number_observed', IntegerProperty(min=1, max=999999999, required=True)),
|
('number_observed', IntegerProperty(min=1, max=999999999, required=True)),
|
||||||
|
@ -594,19 +594,19 @@ class ObservedData(STIXDomainObject):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Opinion(STIXDomainObject):
|
class Opinion(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_sr2hswmu5t1>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_sr2hswmu5t1>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'opinion'
|
_type = 'opinion'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('explanation', StringProperty()),
|
('explanation', StringProperty()),
|
||||||
('authors', ListProperty(StringProperty)),
|
('authors', ListProperty(StringProperty)),
|
||||||
(
|
(
|
||||||
|
@ -631,19 +631,19 @@ class Opinion(STIXDomainObject):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class Report(STIXDomainObject):
|
class Report(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_ha4fpad0r9pf>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_ha4fpad0r9pf>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'report'
|
_type = 'report'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('report_types', ListProperty(StringProperty)),
|
('report_types', ListProperty(StringProperty)),
|
||||||
|
@ -664,19 +664,19 @@ class Report(STIXDomainObject):
|
||||||
super(Report, self).__init__(*args, **kwargs)
|
super(Report, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ThreatActor(STIXDomainObject):
|
class ThreatActor(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_2wowmlcbkqst>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_2wowmlcbkqst>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'threat-actor'
|
_type = 'threat-actor'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('threat_actor_types', ListProperty(StringProperty)),
|
('threat_actor_types', ListProperty(StringProperty)),
|
||||||
|
@ -710,19 +710,19 @@ class ThreatActor(STIXDomainObject):
|
||||||
raise ValueError(msg.format(self))
|
raise ValueError(msg.format(self))
|
||||||
|
|
||||||
|
|
||||||
class Tool(STIXDomainObject):
|
class Tool(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_m21z3a1f3lou>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_m21z3a1f3lou>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'tool'
|
_type = 'tool'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('tool_types', ListProperty(StringProperty)),
|
('tool_types', ListProperty(StringProperty)),
|
||||||
|
@ -739,19 +739,19 @@ class Tool(STIXDomainObject):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class Vulnerability(STIXDomainObject):
|
class Vulnerability(_DomainObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_d9f0iay06wtx>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_d9f0iay06wtx>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'vulnerability'
|
_type = 'vulnerability'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('revoked', BooleanProperty(default=lambda: False)),
|
('revoked', BooleanProperty(default=lambda: False)),
|
||||||
|
@ -796,12 +796,12 @@ def CustomObject(type='x-custom-type', properties=None):
|
||||||
def wrapper(cls):
|
def wrapper(cls):
|
||||||
_properties = list(itertools.chain.from_iterable([
|
_properties = list(itertools.chain.from_iterable([
|
||||||
[
|
[
|
||||||
('type', TypeProperty(type)),
|
('type', TypeProperty(type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(type, spec_version='2.1')),
|
('id', IDProperty(type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
],
|
],
|
||||||
[x for x in properties if not x[0].startswith('x_')],
|
[x for x in properties if not x[0].startswith('x_')],
|
||||||
[
|
[
|
||||||
|
@ -815,6 +815,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]),
|
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
|
return wrapper
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from ..core import STIXRelationshipObject
|
|
||||||
from ..properties import (
|
from ..properties import (
|
||||||
BooleanProperty, IDProperty, IntegerProperty, ListProperty,
|
BooleanProperty, IDProperty, IntegerProperty, ListProperty,
|
||||||
ReferenceProperty, StringProperty, TimestampProperty, TypeProperty,
|
ReferenceProperty, StringProperty, TimestampProperty, TypeProperty,
|
||||||
)
|
)
|
||||||
from ..utils import NOW
|
from ..utils import NOW
|
||||||
|
from .base import _RelationshipObject
|
||||||
from .common import ExternalReference, GranularMarking
|
from .common import ExternalReference, GranularMarking
|
||||||
|
|
||||||
|
|
||||||
class Relationship(STIXRelationshipObject):
|
class Relationship(_RelationshipObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_al0fb8fcd9e7>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_al0fb8fcd9e7>`__.
|
||||||
"""
|
"""
|
||||||
|
@ -20,12 +20,12 @@ class Relationship(STIXRelationshipObject):
|
||||||
|
|
||||||
_type = 'relationship'
|
_type = 'relationship'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('relationship_type', StringProperty(required=True)),
|
('relationship_type', StringProperty(required=True)),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('source_ref', ReferenceProperty(invalid_types=_invalid_source_target_types, spec_version='2.1', required=True)),
|
('source_ref', ReferenceProperty(invalid_types=_invalid_source_target_types, spec_version='2.1', required=True)),
|
||||||
|
@ -70,19 +70,19 @@ class Relationship(STIXRelationshipObject):
|
||||||
raise ValueError(msg.format(self))
|
raise ValueError(msg.format(self))
|
||||||
|
|
||||||
|
|
||||||
class Sighting(STIXRelationshipObject):
|
class Sighting(_RelationshipObject):
|
||||||
"""For more detailed information on this object's properties, see
|
"""For more detailed information on this object's properties, see
|
||||||
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_7p0n81ikux8f>`__.
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_7p0n81ikux8f>`__.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_type = 'sighting'
|
_type = 'sighting'
|
||||||
_properties = OrderedDict([
|
_properties = OrderedDict([
|
||||||
('type', TypeProperty(_type)),
|
('type', TypeProperty(_type, spec_version='2.1')),
|
||||||
('spec_version', StringProperty(fixed='2.1')),
|
('spec_version', StringProperty(fixed='2.1')),
|
||||||
('id', IDProperty(_type, spec_version='2.1')),
|
('id', IDProperty(_type, spec_version='2.1')),
|
||||||
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('first_seen', TimestampProperty()),
|
('first_seen', TimestampProperty()),
|
||||||
('last_seen', TimestampProperty()),
|
('last_seen', TimestampProperty()),
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
__version__ = "1.3.1"
|
__version__ = "1.4.0"
|
||||||
|
|
Loading…
Reference in New Issue