2018-06-14 02:09:07 +02:00
|
|
|
from collections import OrderedDict
|
|
|
|
|
2018-06-26 18:23:53 +02:00
|
|
|
from ..base import _STIXBase
|
|
|
|
from ..core import parse
|
|
|
|
from ..utils import _get_dict, get_class_hierarchy_names
|
2018-06-26 11:32:24 +02:00
|
|
|
from .properties import IDProperty, ListProperty, Property, TypeProperty
|
2018-06-14 02:09:07 +02:00
|
|
|
|
|
|
|
|
|
|
|
class STIXObjectProperty(Property):
|
|
|
|
|
|
|
|
def __init__(self, allow_custom=False, *args, **kwargs):
|
|
|
|
self.allow_custom = allow_custom
|
|
|
|
super(STIXObjectProperty, self).__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
def clean(self, value):
|
|
|
|
# Any STIX Object (SDO, SRO, or Marking Definition) can be added to
|
|
|
|
# a bundle with no further checks.
|
|
|
|
if any(x in ('STIXDomainObject', 'STIXRelationshipObject', 'MarkingDefinition')
|
|
|
|
for x in get_class_hierarchy_names(value)):
|
|
|
|
return value
|
|
|
|
try:
|
|
|
|
dictified = _get_dict(value)
|
|
|
|
except ValueError:
|
|
|
|
raise ValueError("This property may only contain a dictionary or object")
|
|
|
|
if dictified == {}:
|
|
|
|
raise ValueError("This property may only contain a non-empty dictionary or object")
|
|
|
|
if 'type' in dictified and dictified['type'] == 'bundle':
|
|
|
|
raise ValueError('This property may not contain a Bundle object')
|
|
|
|
|
|
|
|
parsed_obj = parse(dictified, allow_custom=self.allow_custom)
|
|
|
|
|
|
|
|
return parsed_obj
|
|
|
|
|
|
|
|
|
|
|
|
class Bundle(_STIXBase):
|
|
|
|
"""For more detailed information on this object's properties, see
|
|
|
|
TODO: Update this to a STIX 2.1 link.
|
|
|
|
`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'
|
|
|
|
_properties = OrderedDict()
|
|
|
|
_properties.update([
|
|
|
|
('type', TypeProperty(_type)),
|
|
|
|
('id', IDProperty(_type)),
|
|
|
|
('objects', ListProperty(STIXObjectProperty)),
|
|
|
|
])
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
# Add any positional arguments to the 'objects' kwarg.
|
|
|
|
if args:
|
|
|
|
if isinstance(args[0], list):
|
|
|
|
kwargs['objects'] = args[0] + list(args[1:]) + kwargs.get('objects', [])
|
|
|
|
else:
|
|
|
|
kwargs['objects'] = list(args) + kwargs.get('objects', [])
|
|
|
|
|
|
|
|
self.__allow_custom = kwargs.get('allow_custom', False)
|
|
|
|
self._properties['objects'].contained.allow_custom = kwargs.get('allow_custom', False)
|
|
|
|
|
|
|
|
super(Bundle, self).__init__(**kwargs)
|