Skip to content

Commit

Permalink
Update v21 properties to latest spec changes
Browse files Browse the repository at this point in the history
  • Loading branch information
emmanvg committed Jul 12, 2018
1 parent 281dbfb commit bdfc221
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 64 deletions.
69 changes: 36 additions & 33 deletions stix2/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@

# This uses the regular expression for a RFC 4122, Version 4 UUID. In the
# 8-4-4-4-12 hexadecimal representation, the first hex digit of the third
# component must be a 4, and the first hex digit of the fourth component must be
# 8, 9, a, or b (10xx bit pattern).
# component must be a 4, and the first hex digit of the fourth component
# must be 8, 9, a, or b (10xx bit pattern).
ID_REGEX = re.compile("^[a-z0-9][a-z0-9-]+[a-z0-9]--" # object type
"[0-9a-fA-F]{8}-"
"[0-9a-fA-F]{4}-"
Expand All @@ -39,14 +39,15 @@ class Property(object):
``__init__()``.
Args:
required (bool): If ``True``, the property must be provided when creating an
object with that property. No default value exists for these properties.
(Default: ``False``)
required (bool): If ``True``, the property must be provided when
creating an object with that property. No default value exists for
these properties. (Default: ``False``)
fixed: This provides a constant default value. Users are free to
provide this value explicity when constructing an object (which allows
you to copy **all** values from an existing object to a new object), but
if the user provides a value other than the ``fixed`` value, it will raise
an error. This is semantically equivalent to defining both:
provide this value explicity when constructing an object (which
allows you to copy **all** values from an existing object to a new
object), but if the user provides a value other than the ``fixed``
value, it will raise an error. This is semantically equivalent to
defining both:
- a ``clean()`` function that checks if the value matches the fixed
value, and
Expand All @@ -57,29 +58,31 @@ class Property(object):
- ``def clean(self, value) -> any:``
- Return a value that is valid for this property. If ``value`` is not
valid for this property, this will attempt to transform it first. If
``value`` is not valid and no such transformation is possible, it should
raise a ValueError.
``value`` is not valid and no such transformation is possible, it
should raise a ValueError.
- ``def default(self):``
- provide a default value for this property.
- ``default()`` can return the special value ``NOW`` to use the current
time. This is useful when several timestamps in the same object need
to use the same default value, so calling now() for each property--
likely several microseconds apart-- does not work.
Subclasses can instead provide a lambda function for ``default`` as a keyword
argument. ``clean`` should not be provided as a lambda since lambdas cannot
raise their own exceptions.
When instantiating Properties, ``required`` and ``default`` should not be used
together. ``default`` implies that the property is required in the specification
so this function will be used to supply a value if none is provided.
``required`` means that the user must provide this; it is required in the
specification and we can't or don't want to create a default value.
time. This is useful when several timestamps in the same object
need to use the same default value, so calling now() for each
property-- likely several microseconds apart-- does not work.
Subclasses can instead provide a lambda function for ``default`` as a
keyword argument. ``clean`` should not be provided as a lambda since
lambdas cannot raise their own exceptions.
When instantiating Properties, ``required`` and ``default`` should not be
used together. ``default`` implies that the property is required in the
specification so this function will be used to supply a value if none is
provided. ``required`` means that the user must provide this; it is
required in the specification and we can't or don't want to create a
default value.
"""

def _default_clean(self, value):
if value != self._fixed_value:
raise ValueError("must equal '{0}'.".format(self._fixed_value))
raise ValueError("must equal '{}'.".format(self._fixed_value))
return value

def __init__(self, required=False, fixed=None, default=None):
Expand Down Expand Up @@ -186,7 +189,7 @@ def __init__(self, type):

def clean(self, value):
if not value.startswith(self.required_prefix):
raise ValueError("must start with '{0}'.".format(self.required_prefix))
raise ValueError("must start with '{}'.".format(self.required_prefix))
if not ID_REGEX.match(value):
raise ValueError(ERROR_INVALID_ID)
return value
Expand Down Expand Up @@ -219,8 +222,8 @@ def clean(self, value):
if isinstance(value, bool):
return value

trues = ['true', 't']
falses = ['false', 'f']
trues = ['true', 't', '1']
falses = ['false', 'f', '0']
try:
if value.lower() in trues:
return True
Expand Down Expand Up @@ -302,7 +305,7 @@ def clean(self, value):
if key in HASHES_REGEX:
vocab_key = HASHES_REGEX[key][1]
if not re.match(HASHES_REGEX[key][0], v):
raise ValueError("'%s' is not a valid %s hash" % (v, vocab_key))
raise ValueError("'{0}' is not a valid {1} hash".format(v, vocab_key))
if k != vocab_key:
clean_dict[vocab_key] = clean_dict[k]
del clean_dict[k]
Expand Down Expand Up @@ -342,7 +345,7 @@ def clean(self, value):
value = str(value)
if self.type:
if not value.startswith(self.type):
raise ValueError("must start with '{0}'.".format(self.type))
raise ValueError("must start with '{}'.".format(self.type))
if not ID_REGEX.match(value):
raise ValueError(ERROR_INVALID_ID)
return value
Expand Down Expand Up @@ -378,7 +381,7 @@ def clean(self, value):
if type(value) is dict:
value = self.type(**value)
elif not isinstance(value, self.type):
raise ValueError("must be of type %s." % self.type.__name__)
raise ValueError("must be of type {}.".format(self.type.__name__))
return value


Expand All @@ -393,7 +396,7 @@ def __init__(self, allowed, **kwargs):
def clean(self, value):
value = super(EnumProperty, self).clean(value)
if value not in self.allowed:
raise ValueError("value '%s' is not valid for this enumeration." % value)
raise ValueError("value '{}' is not valid for this enumeration.".format(value))
return self.string_type(value)


Expand Down Expand Up @@ -483,7 +486,7 @@ def clean(self, value):
else:
raise CustomContentError("Can't parse unknown extension type: {}".format(key))
else:
raise ValueError("The enclosing type '%s' has no extensions defined" % self.enclosing_type)
raise ValueError("The enclosing type '{}' has no extensions defined".format(self.enclosing_type))
return dictified


Expand Down
2 changes: 1 addition & 1 deletion stix2/v21/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class ExternalReference(_STIXBase):
('source_name', StringProperty(required=True)),
('description', StringProperty()),
('url', StringProperty()),
('hashes', HashesProperty()),
('hashes', HashesProperty(spec_version='2.1')),
('external_id', StringProperty()),
])

Expand Down
33 changes: 16 additions & 17 deletions stix2/v21/observables.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ class Artifact(_Observable):
('mime_type', StringProperty()),
('payload_bin', BinaryProperty()),
('url', StringProperty()),
('hashes', HashesProperty()),
('hashes', HashesProperty(spec_version='2.1')),
('encryption_algorithm', StringProperty()),
('decryption_key', StringProperty()),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
])

Expand Down Expand Up @@ -182,7 +184,7 @@ class AlternateDataStream(_STIXBase):

_properties = OrderedDict([
('name', StringProperty(required=True)),
('hashes', HashesProperty()),
('hashes', HashesProperty(spec_version='2.1')),
('size', IntegerProperty()),
])

Expand Down Expand Up @@ -269,7 +271,7 @@ class WindowsPEOptionalHeaderType(_STIXBase):
('size_of_heap_commit', IntegerProperty()),
('loader_flags_hex', HexProperty()),
('number_of_rva_and_sizes', IntegerProperty()),
('hashes', HashesProperty()),
('hashes', HashesProperty(spec_version='2.1')),
])

def _check_object_constraints(self):
Expand All @@ -287,7 +289,7 @@ class WindowsPESection(_STIXBase):
('name', StringProperty(required=True)),
('size', IntegerProperty()),
('entropy', FloatProperty()),
('hashes', HashesProperty()),
('hashes', HashesProperty(spec_version='2.1')),
])


Expand All @@ -308,7 +310,7 @@ class WindowsPEBinaryExt(_Extension):
('number_of_symbols', IntegerProperty()),
('size_of_optional_header', IntegerProperty()),
('characteristics_hex', HexProperty()),
('file_header_hashes', HashesProperty()),
('file_header_hashes', HashesProperty(spec_version='2.1')),
('optional_header', EmbeddedObjectProperty(type=WindowsPEOptionalHeaderType)),
('sections', ListProperty(EmbeddedObjectProperty(type=WindowsPESection))),
])
Expand All @@ -323,7 +325,7 @@ class File(_Observable):
_type = 'file'
_properties = OrderedDict([
('type', TypeProperty(_type)),
('hashes', HashesProperty()),
('hashes', HashesProperty(spec_version='2.1')),
('size', IntegerProperty()),
('name', StringProperty()),
('name_enc', StringProperty()),
Expand All @@ -334,17 +336,13 @@ class File(_Observable):
('modified', TimestampProperty()),
('accessed', TimestampProperty()),
('parent_directory_ref', ObjectReferenceProperty(valid_types='directory')),
('is_encrypted', BooleanProperty()),
('encryption_algorithm', StringProperty()),
('decryption_key', StringProperty()),
('contains_refs', ListProperty(ObjectReferenceProperty)),
('content_ref', ObjectReferenceProperty(valid_types='artifact')),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
])

def _check_object_constraints(self):
super(File, self)._check_object_constraints()
self._check_properties_dependency(['is_encrypted'], ['encryption_algorithm', 'decryption_key'])
self._check_at_least_one_property(['hashes', 'name'])


Expand Down Expand Up @@ -551,7 +549,7 @@ class WindowsServiceExt(_Extension):

_type = 'windows-service-ext'
_properties = OrderedDict([
('service_name', StringProperty(required=True)),
('service_name', StringProperty()),
('descriptions', ListProperty(StringProperty)),
('display_name', StringProperty()),
('group_name', StringProperty()),
Expand Down Expand Up @@ -601,7 +599,7 @@ class Process(_Observable):
('environment_variables', DictionaryProperty(spec_version='2.1')),
('opened_connection_refs', ListProperty(ObjectReferenceProperty(valid_types='network-traffic'))),
('creator_user_ref', ObjectReferenceProperty(valid_types='user-account')),
('binary_ref', ObjectReferenceProperty(valid_types='file')),
('image_ref', ObjectReferenceProperty(valid_types='file')),
('parent_ref', ObjectReferenceProperty(valid_types='process')),
('child_refs', ListProperty(ObjectReferenceProperty('process'))),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
Expand Down Expand Up @@ -678,7 +676,8 @@ class UserAccount(_Observable):
_type = 'user-account'
_properties = OrderedDict([
('type', TypeProperty(_type)),
('user_id', StringProperty(required=True)),
('user_id', StringProperty()),
('credential', StringProperty()),
('account_login', StringProperty()),
('account_type', StringProperty()), # open vocab
('display_name', StringProperty()),
Expand All @@ -688,7 +687,7 @@ class UserAccount(_Observable):
('is_disabled', BooleanProperty()),
('account_created', TimestampProperty()),
('account_expires', TimestampProperty()),
('password_last_changed', TimestampProperty()),
('credential_last_changed', TimestampProperty()),
('account_first_login', TimestampProperty()),
('account_last_login', TimestampProperty()),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
Expand All @@ -703,7 +702,7 @@ class WindowsRegistryValueType(_STIXBase):

_type = 'windows-registry-value-type'
_properties = OrderedDict([
('name', StringProperty(required=True)),
('name', StringProperty()),
('data', StringProperty()),
('data_type', EnumProperty(allowed=[
"REG_NONE",
Expand Down Expand Up @@ -732,7 +731,7 @@ class WindowsRegistryKey(_Observable):
_type = 'windows-registry-key'
_properties = OrderedDict([
('type', TypeProperty(_type)),
('key', StringProperty(required=True)),
('key', StringProperty()),
('values', ListProperty(EmbeddedObjectProperty(type=WindowsRegistryValueType))),
# this is not the modified timestamps of the object itself
('modified', TimestampProperty()),
Expand Down Expand Up @@ -784,7 +783,7 @@ class X509Certificate(_Observable):
_properties = OrderedDict([
('type', TypeProperty(_type)),
('is_self_signed', BooleanProperty()),
('hashes', HashesProperty()),
('hashes', HashesProperty(spec_version='2.1')),
('version', StringProperty()),
('serial_number', StringProperty()),
('signature_algorithm', StringProperty()),
Expand Down
31 changes: 18 additions & 13 deletions stix2/v21/sdo.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,14 @@ class Indicator(STIXDomainObject):
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
('name', StringProperty()),
('indicator_types', ListProperty(StringProperty, required=True)),
('description', StringProperty()),
('pattern', PatternProperty(required=True)),
('valid_from', TimestampProperty(default=lambda: NOW)),
('valid_until', TimestampProperty()),
('kill_chain_phases', ListProperty(KillChainPhase)),
('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty, required=True)),
('labels', ListProperty(StringProperty)),
('confidence', IntegerProperty()),
('lang', StringProperty()),
('external_references', ListProperty(ExternalReference)),
Expand Down Expand Up @@ -263,17 +264,11 @@ class Malware(STIXDomainObject):
('created_by_ref', ReferenceProperty(type='identity')),
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
('is_family', BooleanProperty(required=True)),
('name', StringProperty(required=True)),
('malware_types', ListProperty(StringProperty, required=True)),
('description', StringProperty()),
('kill_chain_phases', ListProperty(KillChainPhase)),
('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty, required=True)),
('confidence', IntegerProperty()),
('lang', StringProperty()),
('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))),
('granular_markings', ListProperty(GranularMarking)),
('is_family', BooleanProperty(required=True)),
('first_seen', TimestampProperty()),
('last_seen', TimestampProperty()),
('os_execution_envs', ListProperty(StringProperty)),
Expand All @@ -283,7 +278,14 @@ class Malware(STIXDomainObject):
('static_analysis_results', ListProperty(EmbeddedObjectProperty(AnalysisType))),
('dynamic_analysis_results', ListProperty(EmbeddedObjectProperty(AnalysisType))),
('av_results', ListProperty(EmbeddedObjectProperty(AVResultsType))),
('capabilities', ListProperty(StringProperty))
('capabilities', ListProperty(StringProperty)),
('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty)),
('confidence', IntegerProperty()),
('lang', StringProperty()),
('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))),
('granular_markings', ListProperty(GranularMarking))
])


Expand Down Expand Up @@ -398,11 +400,12 @@ class Report(STIXDomainObject):
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
('name', StringProperty(required=True)),
('report_types', ListProperty(StringProperty, required=True)),
('description', StringProperty()),
('published', TimestampProperty(required=True)),
('object_refs', ListProperty(ReferenceProperty, required=True)),
('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty, required=True)),
('labels', ListProperty(StringProperty)),
('confidence', IntegerProperty()),
('lang', StringProperty()),
('external_references', ListProperty(ExternalReference)),
Expand All @@ -426,6 +429,7 @@ class ThreatActor(STIXDomainObject):
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
('name', StringProperty(required=True)),
('threat_actor_types', ListProperty(StringProperty, required=True)),
('description', StringProperty()),
('aliases', ListProperty(StringProperty)),
('roles', ListProperty(StringProperty)),
Expand All @@ -436,7 +440,7 @@ class ThreatActor(STIXDomainObject):
('secondary_motivations', ListProperty(StringProperty)),
('personal_motivations', ListProperty(StringProperty)),
('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty, required=True)),
('labels', ListProperty(StringProperty)),
('confidence', IntegerProperty()),
('lang', StringProperty()),
('external_references', ListProperty(ExternalReference)),
Expand All @@ -460,11 +464,12 @@ class Tool(STIXDomainObject):
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
('name', StringProperty(required=True)),
('tool_types', ListProperty(StringProperty, required=True)),
('description', StringProperty()),
('kill_chain_phases', ListProperty(KillChainPhase)),
('tool_version', StringProperty()),
('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty, required=True)),
('labels', ListProperty(StringProperty)),
('confidence', IntegerProperty()),
('lang', StringProperty()),
('external_references', ListProperty(ExternalReference)),
Expand Down

0 comments on commit bdfc221

Please sign in to comment.