# Copyright (c) 2017, The MITRE Corporation. All rights reserved.
# See LICENSE.txt for complete terms.
from mixbox import entities, fields, idgen
import cybox
import cybox.utils
import cybox.bindings.cybox_core as core_binding
from cybox.common import MeasureSource, StructuredText
from cybox.common.location import Location, LocationFactory
from cybox.common.object_properties import ObjectPropertiesFactory, ObjectProperties
from cybox.common.vocabs import VocabField
from cybox.common.vocabs import ObjectRelationship as Relationship
from cybox.core.effect import DefinedEffectFactory
_EXTERNAL_CLASSES = {} # Maps xsi:type values to binding
[docs]def add_external_class(klass, xsi_type):
"""Adds a class implementation to this binding's globals() dict.
These classes can be used to implement Properties,
Domain_Specific_Object_Properties, or Defined_Effect fields on an Object.
Args:
klass (class): Python class that implements the new type
xsi_type (str): An xsi:type value corresponding to the `klass`.
"""
_EXTERNAL_CLASSES[xsi_type] = klass
class ExternalTypeFactory(entities.EntityFactory):
def entity_class(cls, key):
return _EXTERNAL_CLASSES[key]
def _modify_properties_parent(instance, value=None):
if isinstance(instance, RelatedObject) and not instance._inline:
return
if instance.properties:
instance.properties.parent = instance
def _cache_object(instance, value=None):
if instance.id_:
cybox.utils.cache_put(instance)
[docs]class Object(entities.Entity):
"""
The CybOX Object construct identifies and specifies the characteristics of
a specific cyber-relevant object (e.g. a file, a registry key or a
process).
Currently only supports the following data members:
- id
- idref
- has_changed
- description
- properties
- related_objects
- domain_specific_object_properties
Notes:
By default ``cybox.core.object.Object`` will cache objects when
instantiated. If your are experiencing memory issues in your
environment, we encourage the use of ``cybox.utils.caches.cache_clear()``
in your script to prevent an Out of Memory error. Depending on your
use case, it can be after serialization or if a certain threshold is
met (e.g. %30 of memory consumed by cache mechanism).
"""
_binding = core_binding
_binding_class = _binding.ObjectType
_namespace = 'http://cybox.mitre.org/cybox-2'
id_ = fields.IdField("id", postset_hook=_cache_object)
idref = fields.IdrefField("idref")
has_changed = fields.TypedField("has_changed")
state = VocabField("State")
description = fields.TypedField("Description", StructuredText)
properties = fields.TypedField("Properties", ObjectProperties, factory=ObjectPropertiesFactory, postset_hook=_modify_properties_parent)
domain_specific_object_properties = fields.TypedField("Domain_Specific_Object_Properties", type_="cybox.core.object.DomainSpecificObjectProperties", factory=ExternalTypeFactory)
location = fields.TypedField("Location", Location, factory=LocationFactory)
related_objects = fields.TypedField("Related_Objects", type_="cybox.core.object.RelatedObjects")
defined_effect = fields.TypedField("Defined_Effect", "cybox.core.effect.DefinedEffect", factory=DefinedEffectFactory)
discovery_method = fields.TypedField("Discovery_Method", MeasureSource)
def __init__(self, properties=None, id_=None, idref=None):
super(Object, self).__init__()
if properties:
prefix = str(properties.__class__.__name__)
else:
prefix = "Object"
self.id_ = id_ or idgen.create_id(prefix=prefix)
self.idref = idref
self.properties = properties
self.related_objects = RelatedObjects()
def __str__(self):
if self.id_ is not None:
return self.id_
elif self.idref is not None:
return self.idref
else:
return super(Object, self).__repr__()
[docs]class DomainSpecificObjectProperties(entities.Entity):
"""The Cybox DomainSpecificObjectProperties base class."""
_binding = core_binding
_binding_class = _binding.DomainSpecificObjectPropertiesType
# Override in subclass
_XSI_TYPE = None
_XSI_NS = None
[docs] def to_obj(self, ns_info=None):
obj = super(DomainSpecificObjectProperties, self).to_obj(ns_info=ns_info)
obj.xsi_type = "%s:%s" % (self._XSI_NS, self._XSI_TYPE)
[docs] def to_dict(self):
d = super(DomainSpecificObjectProperties, self).to_dict()
if self._XSI_TYPE:
d['xsi:type'] = self._XSI_TYPE
return d