2017-11-02 12:21:24 +01:00
|
|
|
"""STIX 2.1 Relationship Objects."""
|
2017-02-10 22:35:02 +01:00
|
|
|
|
2017-09-01 22:37:49 +02:00
|
|
|
from collections import OrderedDict
|
2017-08-14 14:27:49 +02:00
|
|
|
|
2018-07-13 17:10:05 +02:00
|
|
|
from ..properties import (
|
|
|
|
BooleanProperty, IDProperty, IntegerProperty, ListProperty,
|
|
|
|
ReferenceProperty, StringProperty, TimestampProperty, TypeProperty,
|
|
|
|
)
|
2018-06-26 18:23:53 +02:00
|
|
|
from ..utils import NOW
|
2020-03-27 07:40:42 +01:00
|
|
|
from .base import _RelationshipObject
|
2018-06-26 18:23:53 +02:00
|
|
|
from .common import ExternalReference, GranularMarking
|
2017-10-03 21:01:55 +02:00
|
|
|
|
|
|
|
|
2020-03-27 07:40:42 +01:00
|
|
|
class Relationship(_RelationshipObject):
|
2018-06-11 20:37:45 +02:00
|
|
|
"""For more detailed information on this object's properties, see
|
2020-03-25 16:36:29 +01:00
|
|
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_al0fb8fcd9e7>`__.
|
2018-06-11 20:37:45 +02:00
|
|
|
"""
|
2017-02-10 22:35:02 +01:00
|
|
|
|
2019-08-29 23:15:51 +02:00
|
|
|
_invalid_source_target_types = ['bundle', 'language-content', 'marking-definition', 'relationship', 'sighting']
|
|
|
|
|
2017-02-10 22:35:02 +01:00
|
|
|
_type = 'relationship'
|
2018-06-30 00:38:04 +02:00
|
|
|
_properties = OrderedDict([
|
2020-04-02 03:52:04 +02:00
|
|
|
('type', TypeProperty(_type, spec_version='2.1')),
|
2018-06-30 00:38:04 +02:00
|
|
|
('spec_version', StringProperty(fixed='2.1')),
|
2019-06-14 23:58:51 +02:00
|
|
|
('id', IDProperty(_type, spec_version='2.1')),
|
2019-08-27 23:36:45 +02:00
|
|
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
2020-03-17 01:25:38 +01:00
|
|
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
|
|
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
2017-08-14 14:27:49 +02:00
|
|
|
('relationship_type', StringProperty(required=True)),
|
|
|
|
('description', StringProperty()),
|
2019-08-30 09:47:47 +02:00
|
|
|
('source_ref', ReferenceProperty(invalid_types=_invalid_source_target_types, spec_version='2.1', required=True)),
|
|
|
|
('target_ref', ReferenceProperty(invalid_types=_invalid_source_target_types, spec_version='2.1', required=True)),
|
2018-07-25 18:44:46 +02:00
|
|
|
('start_time', TimestampProperty()),
|
|
|
|
('stop_time', TimestampProperty()),
|
2018-06-11 20:37:45 +02:00
|
|
|
('revoked', BooleanProperty(default=lambda: False)),
|
2017-08-14 14:27:49 +02:00
|
|
|
('labels', ListProperty(StringProperty)),
|
2017-10-06 21:09:14 +02:00
|
|
|
('confidence', IntegerProperty()),
|
|
|
|
('lang', StringProperty()),
|
2017-08-14 14:27:49 +02:00
|
|
|
('external_references', ListProperty(ExternalReference)),
|
2019-08-27 23:36:45 +02:00
|
|
|
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
|
2017-08-14 14:27:49 +02:00
|
|
|
('granular_markings', ListProperty(GranularMarking)),
|
|
|
|
])
|
2017-02-10 22:35:02 +01:00
|
|
|
|
|
|
|
# Explicitly define the first three kwargs to make readable Relationship declarations.
|
2018-07-13 17:10:05 +02:00
|
|
|
def __init__(
|
|
|
|
self, source_ref=None, relationship_type=None,
|
|
|
|
target_ref=None, **kwargs
|
|
|
|
):
|
2017-02-10 22:35:02 +01:00
|
|
|
# Allow (source_ref, relationship_type, target_ref) as positional args.
|
|
|
|
if source_ref and not kwargs.get('source_ref'):
|
|
|
|
kwargs['source_ref'] = source_ref
|
|
|
|
if relationship_type and not kwargs.get('relationship_type'):
|
|
|
|
kwargs['relationship_type'] = relationship_type
|
|
|
|
if target_ref and not kwargs.get('target_ref'):
|
|
|
|
kwargs['target_ref'] = target_ref
|
2018-12-14 10:12:30 +01:00
|
|
|
interoperability = kwargs.get('interoperability', False)
|
|
|
|
self._properties['source_ref'].interoperability = interoperability
|
|
|
|
self._properties['target_ref'].interoperability = interoperability
|
2017-02-10 22:35:02 +01:00
|
|
|
|
2017-03-31 21:52:27 +02:00
|
|
|
super(Relationship, self).__init__(**kwargs)
|
2017-02-10 22:35:02 +01:00
|
|
|
|
2018-07-25 18:44:46 +02:00
|
|
|
def _check_object_constraints(self):
|
2018-10-15 21:02:59 +02:00
|
|
|
super(self.__class__, self)._check_object_constraints()
|
|
|
|
|
|
|
|
start_time = self.get('start_time')
|
|
|
|
stop_time = self.get('stop_time')
|
|
|
|
|
|
|
|
if start_time and stop_time and stop_time <= start_time:
|
2018-07-25 18:44:46 +02:00
|
|
|
msg = "{0.id} 'stop_time' must be later than 'start_time'"
|
|
|
|
raise ValueError(msg.format(self))
|
|
|
|
|
2017-02-10 22:35:02 +01:00
|
|
|
|
2020-03-27 07:40:42 +01:00
|
|
|
class Sighting(_RelationshipObject):
|
2018-06-11 20:37:45 +02:00
|
|
|
"""For more detailed information on this object's properties, see
|
2020-03-25 16:36:29 +01:00
|
|
|
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_7p0n81ikux8f>`__.
|
2018-06-11 20:37:45 +02:00
|
|
|
"""
|
2017-10-06 21:09:14 +02:00
|
|
|
|
2017-03-31 21:52:27 +02:00
|
|
|
_type = 'sighting'
|
2018-06-30 00:38:04 +02:00
|
|
|
_properties = OrderedDict([
|
2020-04-02 03:52:04 +02:00
|
|
|
('type', TypeProperty(_type, spec_version='2.1')),
|
2018-06-30 00:48:41 +02:00
|
|
|
('spec_version', StringProperty(fixed='2.1')),
|
2019-06-14 23:58:51 +02:00
|
|
|
('id', IDProperty(_type, spec_version='2.1')),
|
2019-08-27 23:36:45 +02:00
|
|
|
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
|
2020-03-17 01:25:38 +01:00
|
|
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
|
|
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
|
2019-07-14 21:34:31 +02:00
|
|
|
('description', StringProperty()),
|
2017-08-14 14:27:49 +02:00
|
|
|
('first_seen', TimestampProperty()),
|
|
|
|
('last_seen', TimestampProperty()),
|
2018-10-15 21:02:59 +02:00
|
|
|
('count', IntegerProperty(min=0, max=999999999)),
|
2019-11-06 16:11:12 +01:00
|
|
|
('sighting_of_ref', ReferenceProperty(valid_types="SDO", spec_version='2.1', required=True)),
|
2019-08-27 23:36:45 +02:00
|
|
|
('observed_data_refs', ListProperty(ReferenceProperty(valid_types='observed-data', spec_version='2.1'))),
|
|
|
|
('where_sighted_refs', ListProperty(ReferenceProperty(valid_types='identity', spec_version='2.1'))),
|
2017-08-14 14:27:49 +02:00
|
|
|
('summary', BooleanProperty()),
|
2018-06-11 20:37:45 +02:00
|
|
|
('revoked', BooleanProperty(default=lambda: False)),
|
2017-08-14 14:27:49 +02:00
|
|
|
('labels', ListProperty(StringProperty)),
|
2017-10-06 21:09:14 +02:00
|
|
|
('confidence', IntegerProperty()),
|
|
|
|
('lang', StringProperty()),
|
2017-08-14 14:27:49 +02:00
|
|
|
('external_references', ListProperty(ExternalReference)),
|
2019-08-27 23:36:45 +02:00
|
|
|
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
|
2017-08-14 14:27:49 +02:00
|
|
|
('granular_markings', ListProperty(GranularMarking)),
|
|
|
|
])
|
2017-03-31 21:52:27 +02:00
|
|
|
|
|
|
|
# Explicitly define the first kwargs to make readable Sighting declarations.
|
|
|
|
def __init__(self, sighting_of_ref=None, **kwargs):
|
|
|
|
# Allow sighting_of_ref as a positional arg.
|
|
|
|
if sighting_of_ref and not kwargs.get('sighting_of_ref'):
|
|
|
|
kwargs['sighting_of_ref'] = sighting_of_ref
|
2018-12-14 10:12:30 +01:00
|
|
|
interoperability = kwargs.get('interoperability', False)
|
|
|
|
self._properties['sighting_of_ref'].interoperability = interoperability
|
|
|
|
if kwargs.get('observed_data_refs'):
|
|
|
|
self._properties['observed_data_refs'].contained.interoperability = interoperability
|
|
|
|
if kwargs.get('where_sighted_refs'):
|
|
|
|
self._properties['where_sighted_refs'].contained.interoperability = interoperability
|
2017-03-31 21:52:27 +02:00
|
|
|
|
|
|
|
super(Sighting, self).__init__(**kwargs)
|
2018-10-15 21:02:59 +02:00
|
|
|
|
|
|
|
def _check_object_constraints(self):
|
|
|
|
super(self.__class__, self)._check_object_constraints()
|
|
|
|
|
|
|
|
first_seen = self.get('first_seen')
|
|
|
|
last_seen = self.get('last_seen')
|
|
|
|
|
|
|
|
if first_seen and last_seen and last_seen <= first_seen:
|
|
|
|
msg = "{0.id} 'last_seen' must be later than 'first_seen'"
|
|
|
|
raise ValueError(msg.format(self))
|