WIP: updating objects to be compliant with stix2.1 WD05. This
includes SDO/SRO class updates, but no unit test updates. The class updates broke unit tests, so that still needs to be addressed.master
parent
b1fa177f07
commit
1b7abaf228
|
@ -19,37 +19,87 @@ class InvalidValueError(STIXError, ValueError):
|
||||||
return msg.format(self)
|
return msg.format(self)
|
||||||
|
|
||||||
|
|
||||||
class MissingPropertiesError(STIXError, ValueError):
|
class InvalidPropertyConfigurationError(STIXError, ValueError):
|
||||||
|
"""
|
||||||
|
Represents an invalid combination of properties on a STIX object. This
|
||||||
|
class can be used directly when the object requirements are more
|
||||||
|
complicated and none of the more specific exception subclasses apply.
|
||||||
|
"""
|
||||||
|
def __init__(self, message, cls):
|
||||||
|
super(InvalidPropertyConfigurationError, self).__init__(message)
|
||||||
|
self.cls = cls
|
||||||
|
|
||||||
|
|
||||||
|
class MissingPropertiesError(InvalidPropertyConfigurationError):
|
||||||
"""Missing one or more required properties when constructing STIX object."""
|
"""Missing one or more required properties when constructing STIX object."""
|
||||||
|
|
||||||
def __init__(self, cls, properties):
|
def __init__(self, cls, properties):
|
||||||
super(MissingPropertiesError, self).__init__()
|
self.properties = sorted(properties)
|
||||||
self.cls = cls
|
|
||||||
self.properties = sorted(list(properties))
|
|
||||||
|
|
||||||
def __str__(self):
|
msg = "No values for required properties for {0}: ({1}).".format(
|
||||||
msg = "No values for required properties for {0}: ({1})."
|
cls.__name__,
|
||||||
return msg.format(
|
|
||||||
self.cls.__name__,
|
|
||||||
", ".join(x for x in self.properties),
|
", ".join(x for x in self.properties),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
super(MissingPropertiesError, self).__init__(msg, cls)
|
||||||
|
|
||||||
class ExtraPropertiesError(STIXError, TypeError):
|
|
||||||
|
class ExtraPropertiesError(InvalidPropertyConfigurationError):
|
||||||
"""One or more extra properties were provided when constructing STIX object."""
|
"""One or more extra properties were provided when constructing STIX object."""
|
||||||
|
|
||||||
def __init__(self, cls, properties):
|
def __init__(self, cls, properties):
|
||||||
super(ExtraPropertiesError, self).__init__()
|
self.properties = sorted(properties)
|
||||||
self.cls = cls
|
|
||||||
self.properties = sorted(list(properties))
|
|
||||||
|
|
||||||
def __str__(self):
|
msg = "Unexpected properties for {0}: ({1}).".format(
|
||||||
msg = "Unexpected properties for {0}: ({1})."
|
cls.__name__,
|
||||||
return msg.format(
|
|
||||||
self.cls.__name__,
|
|
||||||
", ".join(x for x in self.properties),
|
", ".join(x for x in self.properties),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
super(ExtraPropertiesError, self).__init__(msg, cls)
|
||||||
|
|
||||||
|
|
||||||
|
class MutuallyExclusivePropertiesError(InvalidPropertyConfigurationError):
|
||||||
|
"""Violating interproperty mutually exclusive constraint of a STIX object type."""
|
||||||
|
|
||||||
|
def __init__(self, cls, properties):
|
||||||
|
self.properties = sorted(properties)
|
||||||
|
|
||||||
|
msg = "The ({1}) properties for {0} are mutually exclusive.".format(
|
||||||
|
cls.__name__,
|
||||||
|
", ".join(x for x in self.properties),
|
||||||
|
)
|
||||||
|
|
||||||
|
super(MutuallyExclusivePropertiesError, self).__init__(msg, cls)
|
||||||
|
|
||||||
|
|
||||||
|
class DependentPropertiesError(InvalidPropertyConfigurationError):
|
||||||
|
"""Violating interproperty dependency constraint of a STIX object type."""
|
||||||
|
|
||||||
|
def __init__(self, cls, dependencies):
|
||||||
|
self.dependencies = dependencies
|
||||||
|
|
||||||
|
msg = "The property dependencies for {0}: ({1}) are not met.".format(
|
||||||
|
cls.__name__,
|
||||||
|
", ".join(name for x in self.dependencies for name in x),
|
||||||
|
)
|
||||||
|
|
||||||
|
super(DependentPropertiesError, self).__init__(msg, cls)
|
||||||
|
|
||||||
|
|
||||||
|
class AtLeastOnePropertyError(InvalidPropertyConfigurationError):
|
||||||
|
"""Violating a constraint of a STIX object type that at least one of the given properties must be populated."""
|
||||||
|
|
||||||
|
def __init__(self, cls, properties):
|
||||||
|
self.properties = sorted(properties)
|
||||||
|
|
||||||
|
msg = "At least one of the ({1}) properties for {0} must be " \
|
||||||
|
"populated.".format(
|
||||||
|
cls.__name__,
|
||||||
|
", ".join(x for x in self.properties),
|
||||||
|
)
|
||||||
|
|
||||||
|
super(AtLeastOnePropertyError, self).__init__(msg, cls)
|
||||||
|
|
||||||
|
|
||||||
class ImmutableError(STIXError, ValueError):
|
class ImmutableError(STIXError, ValueError):
|
||||||
"""Attempted to modify an object after creation."""
|
"""Attempted to modify an object after creation."""
|
||||||
|
@ -103,54 +153,6 @@ class UnmodifiablePropertyError(STIXError, ValueError):
|
||||||
return msg.format(", ".join(self.unchangable_properties))
|
return msg.format(", ".join(self.unchangable_properties))
|
||||||
|
|
||||||
|
|
||||||
class MutuallyExclusivePropertiesError(STIXError, TypeError):
|
|
||||||
"""Violating interproperty mutually exclusive constraint of a STIX object type."""
|
|
||||||
|
|
||||||
def __init__(self, cls, properties):
|
|
||||||
super(MutuallyExclusivePropertiesError, self).__init__()
|
|
||||||
self.cls = cls
|
|
||||||
self.properties = sorted(list(properties))
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
msg = "The ({1}) properties for {0} are mutually exclusive."
|
|
||||||
return msg.format(
|
|
||||||
self.cls.__name__,
|
|
||||||
", ".join(x for x in self.properties),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class DependentPropertiesError(STIXError, TypeError):
|
|
||||||
"""Violating interproperty dependency constraint of a STIX object type."""
|
|
||||||
|
|
||||||
def __init__(self, cls, dependencies):
|
|
||||||
super(DependentPropertiesError, self).__init__()
|
|
||||||
self.cls = cls
|
|
||||||
self.dependencies = dependencies
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
msg = "The property dependencies for {0}: ({1}) are not met."
|
|
||||||
return msg.format(
|
|
||||||
self.cls.__name__,
|
|
||||||
", ".join(name for x in self.dependencies for name in x),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class AtLeastOnePropertyError(STIXError, TypeError):
|
|
||||||
"""Violating a constraint of a STIX object type that at least one of the given properties must be populated."""
|
|
||||||
|
|
||||||
def __init__(self, cls, properties):
|
|
||||||
super(AtLeastOnePropertyError, self).__init__()
|
|
||||||
self.cls = cls
|
|
||||||
self.properties = sorted(list(properties))
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
msg = "At least one of the ({1}) properties for {0} must be populated."
|
|
||||||
return msg.format(
|
|
||||||
self.cls.__name__,
|
|
||||||
", ".join(x for x in self.properties),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class RevokeError(STIXError, ValueError):
|
class RevokeError(STIXError, ValueError):
|
||||||
"""Attempted to an operation on a revoked object."""
|
"""Attempted to an operation on a revoked object."""
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ from six.moves.urllib.parse import quote_plus
|
||||||
|
|
||||||
from ..core import STIXDomainObject
|
from ..core import STIXDomainObject
|
||||||
from ..custom import _custom_object_builder
|
from ..custom import _custom_object_builder
|
||||||
|
from ..exceptions import InvalidPropertyConfigurationError
|
||||||
from ..properties import (
|
from ..properties import (
|
||||||
BinaryProperty, BooleanProperty, EmbeddedObjectProperty, EnumProperty,
|
BinaryProperty, BooleanProperty, EmbeddedObjectProperty, EnumProperty,
|
||||||
FloatProperty, IDProperty, IntegerProperty, ListProperty,
|
FloatProperty, IDProperty, IntegerProperty, ListProperty,
|
||||||
|
@ -33,6 +34,7 @@ class AttackPattern(STIXDomainObject):
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
|
('aliases', ListProperty(StringProperty)),
|
||||||
('kill_chain_phases', ListProperty(KillChainPhase)),
|
('kill_chain_phases', ListProperty(KillChainPhase)),
|
||||||
('revoked', BooleanProperty(default=lambda: False)),
|
('revoked', BooleanProperty(default=lambda: False)),
|
||||||
('labels', ListProperty(StringProperty)),
|
('labels', ListProperty(StringProperty)),
|
||||||
|
@ -146,7 +148,7 @@ class Grouping(STIXDomainObject):
|
||||||
('name', StringProperty()),
|
('name', StringProperty()),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('context', StringProperty(required=True)),
|
('context', StringProperty(required=True)),
|
||||||
('object_refs', ListProperty(ReferenceProperty)),
|
('object_refs', ListProperty(ReferenceProperty, required=True)),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
@ -198,6 +200,8 @@ class Indicator(STIXDomainObject):
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('indicator_types', ListProperty(StringProperty, required=True)),
|
('indicator_types', ListProperty(StringProperty, required=True)),
|
||||||
('pattern', PatternProperty(required=True)),
|
('pattern', PatternProperty(required=True)),
|
||||||
|
('pattern_type', StringProperty(required=True)),
|
||||||
|
('pattern_version', StringProperty()),
|
||||||
('valid_from', TimestampProperty(default=lambda: NOW, required=True)),
|
('valid_from', TimestampProperty(default=lambda: NOW, required=True)),
|
||||||
('valid_until', TimestampProperty()),
|
('valid_until', TimestampProperty()),
|
||||||
('kill_chain_phases', ListProperty(KillChainPhase)),
|
('kill_chain_phases', ListProperty(KillChainPhase)),
|
||||||
|
@ -245,6 +249,7 @@ class Infrastructure(STIXDomainObject):
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty(required=True)),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('infrastructure_types', ListProperty(StringProperty, required=True)),
|
('infrastructure_types', ListProperty(StringProperty, required=True)),
|
||||||
|
('aliases', ListProperty(StringProperty)),
|
||||||
('kill_chain_phases', ListProperty(KillChainPhase)),
|
('kill_chain_phases', ListProperty(KillChainPhase)),
|
||||||
('first_seen', TimestampProperty()),
|
('first_seen', TimestampProperty()),
|
||||||
('last_seen', TimestampProperty()),
|
('last_seen', TimestampProperty()),
|
||||||
|
@ -318,6 +323,7 @@ class Location(STIXDomainObject):
|
||||||
('created_by_ref', ReferenceProperty(type='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(type='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
|
('name', StringProperty()),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('latitude', FloatProperty(min=-90.0, max=90.0)),
|
('latitude', FloatProperty(min=-90.0, max=90.0)),
|
||||||
('longitude', FloatProperty(min=-180.0, max=180.0)),
|
('longitude', FloatProperty(min=-180.0, max=180.0)),
|
||||||
|
@ -346,6 +352,20 @@ class Location(STIXDomainObject):
|
||||||
self._check_properties_dependency(['latitude'], ['longitude'])
|
self._check_properties_dependency(['latitude'], ['longitude'])
|
||||||
self._check_properties_dependency(['longitude'], ['latitude'])
|
self._check_properties_dependency(['longitude'], ['latitude'])
|
||||||
|
|
||||||
|
if not (
|
||||||
|
'region' in self
|
||||||
|
or 'country' in self
|
||||||
|
or (
|
||||||
|
'latitude' in self
|
||||||
|
and 'longitude' in self
|
||||||
|
)
|
||||||
|
):
|
||||||
|
raise InvalidPropertyConfigurationError(
|
||||||
|
"Location objects must have the properties 'region', "
|
||||||
|
"'country', or 'latitude' and 'longitude'",
|
||||||
|
Location
|
||||||
|
)
|
||||||
|
|
||||||
def to_maps_url(self, map_engine="Google Maps"):
|
def to_maps_url(self, map_engine="Google Maps"):
|
||||||
"""Return URL to this location in an online map engine.
|
"""Return URL to this location in an online map engine.
|
||||||
|
|
||||||
|
@ -411,7 +431,7 @@ class Malware(STIXDomainObject):
|
||||||
('created_by_ref', ReferenceProperty(type='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(type='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
('name', StringProperty(required=True)),
|
('name', StringProperty()),
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('malware_types', ListProperty(StringProperty, required=True)),
|
('malware_types', ListProperty(StringProperty, required=True)),
|
||||||
('is_family', BooleanProperty(required=True)),
|
('is_family', BooleanProperty(required=True)),
|
||||||
|
@ -443,6 +463,12 @@ class Malware(STIXDomainObject):
|
||||||
msg = "{0.id} 'last_seen' must be greater than or equal to 'first_seen'"
|
msg = "{0.id} 'last_seen' must be greater than or equal to 'first_seen'"
|
||||||
raise ValueError(msg.format(self))
|
raise ValueError(msg.format(self))
|
||||||
|
|
||||||
|
if self.is_family and "name" not in self:
|
||||||
|
raise InvalidPropertyConfigurationError(
|
||||||
|
"'name' is a required property for malware families",
|
||||||
|
Malware
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MalwareAnalysis(STIXDomainObject):
|
class MalwareAnalysis(STIXDomainObject):
|
||||||
# TODO: Add link
|
# TODO: Add link
|
||||||
|
@ -471,7 +497,7 @@ class MalwareAnalysis(STIXDomainObject):
|
||||||
('operating_system_ref', ReferenceProperty(type='software', spec_version='2.1')),
|
('operating_system_ref', ReferenceProperty(type='software', spec_version='2.1')),
|
||||||
('installed_software_refs', ListProperty(ReferenceProperty(type='software', spec_version='2.1'))),
|
('installed_software_refs', ListProperty(ReferenceProperty(type='software', spec_version='2.1'))),
|
||||||
('configuration_version', StringProperty()),
|
('configuration_version', StringProperty()),
|
||||||
('module', StringProperty()),
|
('modules', ListProperty(StringProperty)),
|
||||||
('analysis_engine_version', StringProperty()),
|
('analysis_engine_version', StringProperty()),
|
||||||
('analysis_definition_version', StringProperty()),
|
('analysis_definition_version', StringProperty()),
|
||||||
('submitted', TimestampProperty()),
|
('submitted', TimestampProperty()),
|
||||||
|
@ -580,7 +606,6 @@ class Opinion(STIXDomainObject):
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
('explanation', StringProperty()),
|
('explanation', StringProperty()),
|
||||||
('authors', ListProperty(StringProperty)),
|
('authors', ListProperty(StringProperty)),
|
||||||
('object_refs', ListProperty(ReferenceProperty, required=True)),
|
|
||||||
(
|
(
|
||||||
'opinion', EnumProperty(
|
'opinion', EnumProperty(
|
||||||
allowed=[
|
allowed=[
|
||||||
|
@ -592,6 +617,7 @@ class Opinion(STIXDomainObject):
|
||||||
], required=True,
|
], required=True,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
('object_refs', ListProperty(ReferenceProperty, required=True)),
|
||||||
('revoked', BooleanProperty(default=lambda: False)),
|
('revoked', BooleanProperty(default=lambda: False)),
|
||||||
('labels', ListProperty(StringProperty)),
|
('labels', ListProperty(StringProperty)),
|
||||||
('confidence', IntegerProperty()),
|
('confidence', IntegerProperty()),
|
||||||
|
@ -649,6 +675,8 @@ class ThreatActor(STIXDomainObject):
|
||||||
('description', StringProperty()),
|
('description', StringProperty()),
|
||||||
('threat_actor_types', ListProperty(StringProperty, required=True)),
|
('threat_actor_types', ListProperty(StringProperty, required=True)),
|
||||||
('aliases', ListProperty(StringProperty)),
|
('aliases', ListProperty(StringProperty)),
|
||||||
|
('first_seen', TimestampProperty()),
|
||||||
|
('last_seen', TimestampProperty()),
|
||||||
('roles', ListProperty(StringProperty)),
|
('roles', ListProperty(StringProperty)),
|
||||||
('goals', ListProperty(StringProperty)),
|
('goals', ListProperty(StringProperty)),
|
||||||
('sophistication', StringProperty()),
|
('sophistication', StringProperty()),
|
||||||
|
@ -665,6 +693,16 @@ class ThreatActor(STIXDomainObject):
|
||||||
('granular_markings', ListProperty(GranularMarking)),
|
('granular_markings', ListProperty(GranularMarking)),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def _check_object_constraints(self):
|
||||||
|
super(self.__class__, self)._check_object_constraints()
|
||||||
|
|
||||||
|
first_observed = self.get('first_seen')
|
||||||
|
last_observed = self.get('last_seen')
|
||||||
|
|
||||||
|
if first_observed and last_observed and last_observed < first_observed:
|
||||||
|
msg = "{0.id} 'last_seen' must be greater than or equal to 'first_seen'"
|
||||||
|
raise ValueError(msg.format(self))
|
||||||
|
|
||||||
|
|
||||||
class Tool(STIXDomainObject):
|
class Tool(STIXDomainObject):
|
||||||
# TODO: Add link
|
# TODO: Add link
|
||||||
|
|
|
@ -80,6 +80,7 @@ class Sighting(STIXRelationshipObject):
|
||||||
('created_by_ref', ReferenceProperty(type='identity', spec_version='2.1')),
|
('created_by_ref', ReferenceProperty(type='identity', spec_version='2.1')),
|
||||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||||
|
('description', StringProperty()),
|
||||||
('first_seen', TimestampProperty()),
|
('first_seen', TimestampProperty()),
|
||||||
('last_seen', TimestampProperty()),
|
('last_seen', TimestampProperty()),
|
||||||
('count', IntegerProperty(min=0, max=999999999)),
|
('count', IntegerProperty(min=0, max=999999999)),
|
||||||
|
|
Loading…
Reference in New Issue