From 6779e1a82fdd37a64d90e44c097535a9867c865e Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 17 Apr 2015 16:12:10 -0400 Subject: [PATCH 001/438] Began work on multi-description support. --- stix/common/structured_text.py | 44 +++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index f9b07d89..c21414aa 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -7,28 +7,43 @@ class StructuredText(stix.Entity): _binding = stix_common_binding + _binding_class = _binding.StructuredTextType _namespace = 'http://stix.mitre.org/common-1' def __init__(self, value=None): + self.id_ = None self.value = value self.structuring_format = None + self.ordinality = None def to_obj(self, return_obj=None, ns_info=None): + if not return_obj: + return_obj = self._binding_class() + super(StructuredText, self).to_obj( return_obj=return_obj, ns_info=ns_info ) - text_obj = self._binding.StructuredTextType() + return_obj.id = self.id_ + return_obj.valueOf_ = self.value + return_obj.ordinality = self.ordinality + return_obj.structuring_format = self.structuring_format + + return return_obj + + def is_plain(self): + plain = ( + (not self.id_) and + (not self.structuring_format) and + (self.ordinality in (1, None)) + ) - text_obj.valueOf_ = self.value - if self.structuring_format is not None: - text_obj.structuring_format = self.structuring_format - return text_obj + return plain def to_dict(self): # Return a plain string if there is no format specified. - if self.structuring_format is None: + if self.is_plain(): return self.value else: return super(StructuredText, self).to_dict() @@ -41,7 +56,9 @@ def from_obj(cls, obj, return_obj=None): if not return_obj: return_obj = cls() + return_obj.id_ = obj.id return_obj.value = obj.valueOf_ + return_obj.ordinality = obj.ordinality return_obj.structuring_format = obj.structuring_format return return_obj @@ -57,7 +74,9 @@ def from_dict(cls, d, return_obj=None): if not isinstance(d, dict): return_obj.value = d else: + return_obj.id_ = d.get('id') return_obj.value = d.get('value') + return_obj.ordinality = d.get('ordinality') return_obj.structuring_format = d.get('structuring_format') return return_obj @@ -67,3 +86,16 @@ def __str__(self): def __unicode__(self): return unicode(self.value) + + +class StructuredTextList(stix.TypedList): + _contained_type = StructuredText + + def __iter__(self): + return sorted(self._inner, key=lambda x: x.ordinality) + + def __getitem__(self, item): + pass + + def __setitem__(self, key, value): + pass From dff548106723f981362be95e93414a4728c1beca Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 20 Apr 2015 21:11:08 -0400 Subject: [PATCH 002/438] First pass at 1.2.0.0 support of multiple descriptions. --- stix/base.py | 85 ++++++++++++---- stix/bindings/campaign.py | 30 ++++-- stix/bindings/course_of_action.py | 30 ++++-- stix/bindings/exploit_target.py | 30 ++++-- stix/bindings/incident.py | 30 ++++-- stix/bindings/indicator.py | 30 ++++-- stix/bindings/stix_common.py | 25 ++++- stix/bindings/threat_actor.py | 26 +++-- stix/bindings/ttp.py | 30 ++++-- stix/common/__init__.py | 2 +- stix/common/structured_text.py | 160 ++++++++++++++++++++++++++++-- stix/indicator/indicator.py | 18 +++- stix/utils/__init__.py | 5 + 13 files changed, 397 insertions(+), 104 deletions(-) diff --git a/stix/base.py b/stix/base.py index f01dd60a..8daf9c78 100644 --- a/stix/base.py +++ b/stix/base.py @@ -518,9 +518,12 @@ def from_obj(cls, obj_list, contained_type=None): @classmethod def from_list(cls, list_repr, contained_type=None): - if not utils.is_sequence(list_repr): + if not list_repr: return None + if not utils.is_sequence(list_repr): + list_repr = [list_repr] + return_obj = cls() if not contained_type: @@ -692,12 +695,23 @@ def description(self): :class:`.StructuredText` """ - return self._description + if self.descriptions: + return self.descriptions.sorted[0] + else: + return None @description.setter def description(self, value): - from stix.common import StructuredText - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + return self._descriptions + + @descriptions.setter + def descriptions(self, value): + from stix.common import StructuredTextList + self._descriptions = StructuredTextList(value) @property def short_description(self): @@ -715,12 +729,23 @@ def short_description(self): :class:`.StructuredText` """ - return self._short_description + if self.short_descriptions: + return self.short_descriptions.sorted[0] + else: + return None @short_description.setter def short_description(self, value): - from stix.common import StructuredText - self._set_var(StructuredText, short_description=value) + self.short_descriptions = value + + @property + def short_descriptions(self): + return self._short_descriptions + + @short_descriptions.setter + def short_descriptions(self, value): + from stix.common import StructuredTextList + self._short_descriptions = StructuredTextList(value) @property def information_source(self): @@ -747,7 +772,7 @@ def information_source(self, value): @classmethod def from_obj(cls, obj, return_obj=None): - from stix.common import StructuredText, InformationSource + from stix.common import StructuredTextList, InformationSource if not return_obj: raise ValueError("Must provide a return_obj argument") @@ -763,10 +788,10 @@ def from_obj(cls, obj, return_obj=None): # type definition (e.g., used as a reference) return_obj.version = getattr(obj, 'version', None) return_obj.title = getattr(obj, 'Title', None) - return_obj.description = \ - StructuredText.from_obj(getattr(obj, 'Description', None)) - return_obj.short_description = \ - StructuredText.from_obj(getattr(obj, 'Short_Description', None)) + return_obj.descriptions = \ + StructuredTextList.from_obj(getattr(obj, 'Description', None)) + return_obj.short_descriptions = \ + StructuredTextList.from_obj(getattr(obj, 'Short_Description', None)) return_obj.information_source = \ InformationSource.from_obj(getattr(obj, 'Information_Source', None)) @@ -788,10 +813,10 @@ def to_obj(self, return_obj=None, ns_info=None): if self.timestamp: return_obj.timestamp = utils.dates.serialize_value(self.timestamp) - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) - if self.short_description: - return_obj.Short_Description = self.short_description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) + if self.short_descriptions: + return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) if self.information_source: return_obj.Information_Source = self.information_source.to_obj(ns_info=ns_info) @@ -799,7 +824,7 @@ def to_obj(self, return_obj=None, ns_info=None): @classmethod def from_dict(cls, d, return_obj=None): - from stix.common import StructuredText, InformationSource + from stix.common import StructuredTextList, InformationSource if not return_obj: raise ValueError("Must provide a return_obj argument") @@ -810,14 +835,30 @@ def from_dict(cls, d, return_obj=None): return_obj.timestamp = get('timestamp') return_obj.version = get('version') return_obj.title = get('title') - return_obj.description = \ - StructuredText.from_dict(get('description')) - return_obj.short_description = \ - StructuredText.from_dict(get('short_description')) + return_obj.descriptions = \ + StructuredTextList.from_dict(get('description')) + return_obj.short_descriptions = \ + StructuredTextList.from_dict(get('short_description')) return_obj.information_source = \ InformationSource.from_dict(get('information_source')) return return_obj def to_dict(self): - return super(BaseCoreComponent, self).to_dict() + skip = ( + 'description', + 'descriptions', + 'short_description', + 'short_descriptions' + ) + + d = utils.to_dict(self, skip=skip) + + if self.descriptions: + d['description'] = self.descriptions.to_dict() + if self.short_descriptions: + d['short_description'] = self.short_descriptions.to_dict() + + return d + + diff --git a/stix/bindings/campaign.py b/stix/bindings/campaign.py index bb16e77e..95acd1e0 100644 --- a/stix/bindings/campaign.py +++ b/stix/bindings/campaign.py @@ -445,8 +445,14 @@ def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None self.xml_type = "CampaignType" self.version = _cast(None, version) self.Title = Title - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description self.Names = Names if Intended_Effect is None: self.Intended_Effect = [] @@ -477,8 +483,12 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Title(self): return self.Title def set_Title(self, Title): self.Title = Title + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Names(self): return self.Names @@ -518,8 +528,8 @@ def set_version(self, version): self.version = version def hasContent_(self): if ( self.Title is not None or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.Names is not None or self.Intended_Effect or self.Status is not None or @@ -576,10 +586,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Campaig if self.Title is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:Title>%s%s' % (nsmap[namespace_], quote_xml(self.Title), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) if self.Names is not None: self.Names.export(lwrite, level, nsmap, namespace_, name_='Names', pretty_print=pretty_print) for Intended_Effect_ in self.Intended_Effect: @@ -626,11 +636,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Names': obj_ = NamesType.factory() obj_.build(child_) diff --git a/stix/bindings/course_of_action.py b/stix/bindings/course_of_action.py index cfc6770c..6dc139ad 100644 --- a/stix/bindings/course_of_action.py +++ b/stix/bindings/course_of_action.py @@ -215,8 +215,14 @@ def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None self.Title = Title self.Stage = Stage self.Type = Type - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description self.Objective = Objective self.Parameter_Observables = Parameter_Observables self.Structured_COA = Structured_COA @@ -239,8 +245,12 @@ def get_Stage(self): return self.Stage def set_Stage(self, Stage): self.Stage = Stage def get_Type(self): return self.Type def set_Type(self, Type): self.Type = Type + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Objective(self): return self.Objective @@ -270,8 +280,8 @@ def hasContent_(self): self.Title is not None or self.Stage is not None or self.Type is not None or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.Objective is not None or self.Parameter_Observables is not None or self.Structured_COA is not None or @@ -329,10 +339,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CourseO self.Stage.export(lwrite, level, nsmap, namespace_, name_='Stage', pretty_print=pretty_print) if self.Type is not None: self.Type.export(lwrite, level, nsmap, namespace_, name_='Type', pretty_print=pretty_print) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) if self.Objective is not None: self.Objective.export(lwrite, level, nsmap, namespace_, name_='Objective', pretty_print=pretty_print) if self.Parameter_Observables is not None: @@ -381,11 +391,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Objective': obj_ = ObjectiveType.factory() obj_.build(child_) diff --git a/stix/bindings/exploit_target.py b/stix/bindings/exploit_target.py index 146d49dc..ed766841 100644 --- a/stix/bindings/exploit_target.py +++ b/stix/bindings/exploit_target.py @@ -737,8 +737,14 @@ def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None self.xml_type = "ExploitTargetType" self.version = _cast(None, version) self.Title = Title - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description if Vulnerability is None: self.Vulnerability = [] else: @@ -764,8 +770,12 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Title(self): return self.Title def set_Title(self, Title): self.Title = Title + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Vulnerability(self): return self.Vulnerability @@ -795,8 +805,8 @@ def set_version(self, version): self.version = version def hasContent_(self): if ( self.Title is not None or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.Vulnerability or self.Weakness or self.Configuration or @@ -848,10 +858,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Exploit if self.Title is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:Title>%s%s' % (nsmap[namespace_],quote_xml(self.Title), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) for Vulnerability_ in self.Vulnerability: Vulnerability_.export(lwrite, level, nsmap, namespace_, name_='Vulnerability', pretty_print=pretty_print) for Weakness_ in self.Weakness: @@ -888,11 +898,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Vulnerability': type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') if type_name_ is None: diff --git a/stix/bindings/incident.py b/stix/bindings/incident.py index 156067ff..3ea99554 100644 --- a/stix/bindings/incident.py +++ b/stix/bindings/incident.py @@ -2169,8 +2169,14 @@ def __init__(self, idref=None, id=None, timestamp=None, URL=None, version=None, else: self.External_ID = External_ID self.Time = Time - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description self.Categories = Categories self.Reporter = Reporter if Responder is None: @@ -2233,8 +2239,12 @@ def add_External_ID(self, value): self.External_ID.append(value) def insert_External_ID(self, index, value): self.External_ID[index] = value def get_Time(self): return self.Time def set_Time(self, Time): self.Time = Time + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Categories(self): return self.Categories @@ -2310,8 +2320,8 @@ def hasContent_(self): self.Title is not None or self.External_ID or self.Time is not None or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.Categories is not None or self.Reporter is not None or self.Responder or @@ -2386,10 +2396,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Inciden External_ID_.export(lwrite, level, nsmap, namespace_, name_='External_ID', pretty_print=pretty_print) if self.Time is not None: self.Time.export(lwrite, level, nsmap, namespace_, name_='Time', pretty_print=pretty_print) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) if self.Categories is not None: self.Categories.export(lwrite, level, nsmap, namespace_, name_='Categories', pretty_print=pretty_print) if self.Reporter is not None: @@ -2470,11 +2480,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Categories': obj_ = CategoriesType.factory() obj_.build(child_) diff --git a/stix/bindings/indicator.py b/stix/bindings/indicator.py index 4bbedf65..9d16c0c3 100644 --- a/stix/bindings/indicator.py +++ b/stix/bindings/indicator.py @@ -859,8 +859,14 @@ def __init__(self, idref=None, id=None, timestamp=None, negate=False, version=No self.Alternative_ID = [] else: self.Alternative_ID = Alternative_ID - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description if Valid_Time_Position is None: self.Valid_Time_Position = [] else: @@ -898,8 +904,12 @@ def get_Alternative_ID(self): return self.Alternative_ID def set_Alternative_ID(self, Alternative_ID): self.Alternative_ID = Alternative_ID def add_Alternative_ID(self, value): self.Alternative_ID.append(value) def insert_Alternative_ID(self, index, value): self.Alternative_ID[index] = value + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Valid_Time_Position(self): return self.Valid_Time_Position @@ -945,8 +955,8 @@ def hasContent_(self): self.Title is not None or self.Type or self.Alternative_ID or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.Valid_Time_Position or self.Observable is not None or self.Composite_Indicator_Expression is not None or @@ -1013,10 +1023,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Indicat for Alternative_ID_ in self.Alternative_ID: showIndent(lwrite, level, pretty_print) lwrite('<%s:Alternative_ID>%s%s' % (nsmap[namespace_], quote_xml(Alternative_ID_), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) for Valid_Time_Position_ in self.Valid_Time_Position: Valid_Time_Position_.export(lwrite, level, nsmap, namespace_, name_='Valid_Time_Position', pretty_print=pretty_print) if self.Observable is not None: @@ -1083,11 +1093,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Valid_Time_Position': obj_ = ValidTimeType.factory() obj_.build(child_) diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index b0c813ec..82b86d00 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -3589,9 +3589,14 @@ class StructuredTextType(GeneratedsSuper): attribute is absent, the implication is that no markup is being used.""" subclass = None superclass = None - def __init__(self, structuring_format=None, valueOf_=None): + def __init__(self, structuring_format=None, valueOf_=None, id=None, + idref=None, ordinality=None): self.structuring_format = _cast(None, structuring_format) self.valueOf_ = valueOf_ + self.id = id, + self.idref = idref, + self.ordinality = ordinality + def factory(*args_, **kwargs_): if StructuredTextType.subclass: return StructuredTextType.subclass(*args_, **kwargs_) @@ -3602,6 +3607,10 @@ def get_structuring_format(self): return self.structuring_format def set_structuring_format(self, structuring_format): self.structuring_format = structuring_format def get_valueOf_(self): return self.valueOf_ def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def get_id(self): return self.id + def set_id(self, id): self.id = id + def get_ordinality(self): return self.ordinality + def set_ordinality(self, ordinality): self.ordinality = ordinality def hasContent_(self): if ( self.valueOf_ @@ -3629,6 +3638,12 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom if self.structuring_format is not None and 'structuring_format' not in already_processed: already_processed.add('structuring_format') lwrite(' structuring_format=%s' % (quote_attrib(self.structuring_format), )) + if self.id is not None and 'id' not in already_processed: + already_processed.add('id') + lwrite(' id=%s' % (quote_attrib(self.id), )) + if self.ordinality is not None and 'ordinality' not in already_processed: + already_processed.add('ordinality') + lwrite(' ordinality=%s' % (quote_attrib(self.ordinality), )) def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='StructuredTextType', fromsubclass_=False, pretty_print=True): pass def build(self, node): @@ -3643,6 +3658,14 @@ def buildAttributes(self, node, attrs, already_processed): if value is not None and 'structuring_format' not in already_processed: already_processed.add('structuring_format') self.structuring_format = value + value = find_attr_value_('id', node) + if value is not None and 'id' not in already_processed: + already_processed.add('id') + self.id = value + value = find_attr_value_('ordinality', node) + if value is not None and 'ordinality' not in already_processed: + already_processed.add('ordinality') + self.ordinality = value def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass # end class StructuredTextType diff --git a/stix/bindings/threat_actor.py b/stix/bindings/threat_actor.py index 9e84d689..2b8d0119 100644 --- a/stix/bindings/threat_actor.py +++ b/stix/bindings/threat_actor.py @@ -239,8 +239,14 @@ def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None self.xml_type = "ThreatActorType" self.version = _cast(None, version) self.Title = Title - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description self.Identity = Identity if Type is None: self.Type = [] @@ -277,8 +283,12 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Title(self): return self.Title def set_Title(self, Title): self.Title = Title + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Identity(self): return self.Identity @@ -380,10 +390,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ThreatA if self.Title is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:Title>%s%s' % (nsmap[namespace_], quote_xml(self.Title), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) if self.Identity is not None: self.Identity.export(lwrite, level, nsmap, namespace_, name_='Identity', pretty_print=pretty_print) for Type_ in self.Type: @@ -430,11 +440,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Identity': type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') if type_name_ is None: diff --git a/stix/bindings/ttp.py b/stix/bindings/ttp.py index 8ba5882a..0ea62d95 100644 --- a/stix/bindings/ttp.py +++ b/stix/bindings/ttp.py @@ -1256,8 +1256,14 @@ def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None self.version = _cast(None, version) self.Title = Title - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description if Intended_Effect is None: self.Intended_Effect = [] else: @@ -1280,8 +1286,12 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Title(self): return self.Title def set_Title(self, Title): self.Title = Title + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Intended_Effect(self): return self.Intended_Effect @@ -1313,8 +1323,8 @@ def set_version(self, version): self.version = version def hasContent_(self): if ( self.Title is not None or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.Intended_Effect or self.Behavior is not None or self.Resources is not None or @@ -1369,10 +1379,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TTPType if self.Title is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:Title>%s%s' % (nsmap[namespace_], quote_xml(self.Title), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) for Intended_Effect_ in self.Intended_Effect: Intended_Effect_.export(lwrite, level, nsmap, namespace_, name_='Intended_Effect', pretty_print=pretty_print) if self.Behavior is not None: @@ -1415,11 +1425,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Intended_Effect': obj_ = stix_common_binding.StatementType.factory() obj_.build(child_) diff --git a/stix/common/__init__.py b/stix/common/__init__.py index 32a55393..28eab16f 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -3,7 +3,7 @@ from __future__ import absolute_import -from .structured_text import StructuredText # noqa +from .structured_text import StructuredText, StructuredTextList # noqa from .vocabs import VocabString # noqa from .datetimewithprecision import DateTimeWithPrecision # noqa from .activity import Activity # noqa diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index c21414aa..f4f6fbf1 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -1,7 +1,12 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# stdlib +import itertools + +# internal import stix +import stix.utils as utils import stix.bindings.stix_common as stix_common_binding @@ -10,11 +15,30 @@ class StructuredText(stix.Entity): _binding_class = _binding.StructuredTextType _namespace = 'http://stix.mitre.org/common-1' - def __init__(self, value=None): + def __init__(self, value=None, ordinality=None): self.id_ = None self.value = value self.structuring_format = None - self.ordinality = None + self.ordinality = ordinality + + @property + def ordinality(self): + return self._ordinality + + @ordinality.setter + def ordinality(self, value): + if value is None: + self._ordinality = None + return + + value = int(value) + + if value > 0: + self._ordinality = value + return + + error = "Value must be an integer > 0. Received {0}".format(value) + raise ValueError(error) def to_obj(self, return_obj=None, ns_info=None): if not return_obj: @@ -36,7 +60,7 @@ def is_plain(self): plain = ( (not self.id_) and (not self.structuring_format) and - (self.ordinality in (1, None)) + (self.ordinality is None) ) return plain @@ -88,14 +112,136 @@ def __unicode__(self): return unicode(self.value) +def _ordkey(text): + o = text.ordinality + o = int(o) if o is not None else None + return (o is None, o) + + class StructuredTextList(stix.TypedList): _contained_type = StructuredText + def with_ordinality(self, ordinality): + if not isinstance(ordinality, int): + error = "ordinality must be an integer. Received {}" + error = error.format(type(ordinality)) + raise ValueError(error) + + for item in self._inner: + if item.ordinality == ordinality: + return item + + return None + + def with_id(self, id): + for text in self._inner: + if text.id_ == id: + return text + + return None + + def reset(self): + for idx, item in enumerate(self.sorted, 1): + item.ordinality = idx + + @property + def sorted(self): + return sorted(self._inner, key=_ordkey) + + @property + def ordinalities(self): + return tuple(x.ordinality for x in self.sorted) + def __iter__(self): - return sorted(self._inner, key=lambda x: x.ordinality) + return iter(self.sorted) - def __getitem__(self, item): - pass + def __getitem__(self, key): + o = int(key) + text = self.with_ordinality(o) + + if text: + return text + + error = "No item found with an ordinality of {0}".format(o) + raise IndexError(error) def __setitem__(self, key, value): - pass + o = int(key) + + if o < 1: + raise IndexError("ordinality must be > 0") + + if not self._is_valid(value): + value = self._fix_value(value) + + if value.ordinality is None: + value.ordinality = o + elif value.ordinality != o: + error = ( + "Ordinality mismatch. {0} found on input object but index " + "was {1}" + ).format(value.ordinality, o) + raise ValueError(error) + + existing = self.with_ordinality(o) + + if existing is not None: + self._inner.remove(existing) + + self._inner.append(value) + + def __delitem__(self, key): + o = int(key) + text = self.with_ordinality(o) + + if text: + self._inner.remove(text) + return + + error = "No item found with an ordinality of {0}".format(o) + raise IndexError(error) + + def insert(self, idx, value): + if value is None: + return + + if not self._is_valid(value): + value = self._fix_value(value) + + if value.ordinality is None: + if self._inner: + new_ord = self.ordinalities[-1] + 1 + value.ordinality = new_ord + else: + value.ordinality = 1 + + exists = self.with_ordinality(value.ordinality) + if not exists: + self._inner.append(value) + return + + error = "Value with ordinality {0} exists: '{1}'." + error = error.format(value.ordinality, exists.value) + raise ValueError(error) + + def to_list(self): + l = super(StructuredTextList, self).to_list() + + if len(l) > 1: + return l + + d = l[0] + ordinality = int(d.get('ordinality', 1)) + + if ordinality != 1: + return l + + del d['ordinality'] + + if len(d.keys()) == 1 and 'value' in d: + return d['value'] + + return d + + to_dict = to_list + diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 3b202e47..ab6238ec 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -906,9 +906,9 @@ def from_obj(cls, obj, return_obj=None): if isinstance(obj, cls._binding_class): return_obj.negate = obj.negate - return_obj.producer = InformationSource.from_obj(obj.Producer) - return_obj.confidence = Confidence.from_obj(obj.Confidence) - return_obj.sightings = Sightings.from_obj(obj.Sightings) + return_obj.producer = InformationSource.from_obj(obj.Producer) + return_obj.confidence = Confidence.from_obj(obj.Confidence) + return_obj.sightings = Sightings.from_obj(obj.Sightings) return_obj.composite_indicator_expression = CompositeIndicatorExpression.from_obj(obj.Composite_Indicator_Expression) return_obj.handling = Marking.from_obj(obj.Handling) return_obj.kill_chain_phases = KillChainPhasesReference.from_obj(obj.Kill_Chain_Phases) @@ -927,8 +927,16 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - skip = ('observables', 'observable_composition_operator', 'negate') - d = utils.to_dict(self, skip=skip) + skip = ( + 'observables', + 'observable_composition_operator', + 'negate', + 'descriptions', + 'short_descriptions', + ) + + d = super(Indicator, self).to_dict() + utils.remove_entries(d, skip) if self.negate: d['negate'] = True diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index ae0fd6db..1c9f9bd5 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -337,6 +337,11 @@ def cast_var(item, klass, arg=None): return klass(**kwarg) # klass(value='foobar') +def remove_entries(map, keys): + for key in keys: + map.pop(key, None) + + # Namespace flattening from .nsparser import * # noqa from .dates import * # noqa From 6b43ee29c74934f57bfb4b9aee0f138f3290cf18 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 20 Apr 2015 21:14:25 -0400 Subject: [PATCH 003/438] Bumped version to 1.2.0.0-dev --- stix/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/version.py b/stix/version.py index b7b1ff7f..69c52d59 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.1.1.5.dev0" +__version__ = "1.2.0.0.dev0" From ac9169888304319fd6569f09f579f0d73d2a0e93 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 17 Apr 2015 16:12:10 -0400 Subject: [PATCH 004/438] Began work on multi-description support. --- stix/common/structured_text.py | 44 +++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index f9b07d89..c21414aa 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -7,28 +7,43 @@ class StructuredText(stix.Entity): _binding = stix_common_binding + _binding_class = _binding.StructuredTextType _namespace = 'http://stix.mitre.org/common-1' def __init__(self, value=None): + self.id_ = None self.value = value self.structuring_format = None + self.ordinality = None def to_obj(self, return_obj=None, ns_info=None): + if not return_obj: + return_obj = self._binding_class() + super(StructuredText, self).to_obj( return_obj=return_obj, ns_info=ns_info ) - text_obj = self._binding.StructuredTextType() + return_obj.id = self.id_ + return_obj.valueOf_ = self.value + return_obj.ordinality = self.ordinality + return_obj.structuring_format = self.structuring_format + + return return_obj + + def is_plain(self): + plain = ( + (not self.id_) and + (not self.structuring_format) and + (self.ordinality in (1, None)) + ) - text_obj.valueOf_ = self.value - if self.structuring_format is not None: - text_obj.structuring_format = self.structuring_format - return text_obj + return plain def to_dict(self): # Return a plain string if there is no format specified. - if self.structuring_format is None: + if self.is_plain(): return self.value else: return super(StructuredText, self).to_dict() @@ -41,7 +56,9 @@ def from_obj(cls, obj, return_obj=None): if not return_obj: return_obj = cls() + return_obj.id_ = obj.id return_obj.value = obj.valueOf_ + return_obj.ordinality = obj.ordinality return_obj.structuring_format = obj.structuring_format return return_obj @@ -57,7 +74,9 @@ def from_dict(cls, d, return_obj=None): if not isinstance(d, dict): return_obj.value = d else: + return_obj.id_ = d.get('id') return_obj.value = d.get('value') + return_obj.ordinality = d.get('ordinality') return_obj.structuring_format = d.get('structuring_format') return return_obj @@ -67,3 +86,16 @@ def __str__(self): def __unicode__(self): return unicode(self.value) + + +class StructuredTextList(stix.TypedList): + _contained_type = StructuredText + + def __iter__(self): + return sorted(self._inner, key=lambda x: x.ordinality) + + def __getitem__(self, item): + pass + + def __setitem__(self, key, value): + pass From 82b03edaf9576392b49debf69f1489b03023d9f5 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 20 Apr 2015 21:11:08 -0400 Subject: [PATCH 005/438] First pass at 1.2.0.0 support of multiple descriptions. --- stix/base.py | 85 ++++++++++++---- stix/bindings/campaign.py | 30 ++++-- stix/bindings/course_of_action.py | 30 ++++-- stix/bindings/exploit_target.py | 30 ++++-- stix/bindings/incident.py | 30 ++++-- stix/bindings/indicator.py | 30 ++++-- stix/bindings/stix_common.py | 25 ++++- stix/bindings/threat_actor.py | 26 +++-- stix/bindings/ttp.py | 30 ++++-- stix/common/__init__.py | 2 +- stix/common/structured_text.py | 160 ++++++++++++++++++++++++++++-- stix/indicator/indicator.py | 18 +++- stix/utils/__init__.py | 5 + 13 files changed, 397 insertions(+), 104 deletions(-) diff --git a/stix/base.py b/stix/base.py index f01dd60a..8daf9c78 100644 --- a/stix/base.py +++ b/stix/base.py @@ -518,9 +518,12 @@ def from_obj(cls, obj_list, contained_type=None): @classmethod def from_list(cls, list_repr, contained_type=None): - if not utils.is_sequence(list_repr): + if not list_repr: return None + if not utils.is_sequence(list_repr): + list_repr = [list_repr] + return_obj = cls() if not contained_type: @@ -692,12 +695,23 @@ def description(self): :class:`.StructuredText` """ - return self._description + if self.descriptions: + return self.descriptions.sorted[0] + else: + return None @description.setter def description(self, value): - from stix.common import StructuredText - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + return self._descriptions + + @descriptions.setter + def descriptions(self, value): + from stix.common import StructuredTextList + self._descriptions = StructuredTextList(value) @property def short_description(self): @@ -715,12 +729,23 @@ def short_description(self): :class:`.StructuredText` """ - return self._short_description + if self.short_descriptions: + return self.short_descriptions.sorted[0] + else: + return None @short_description.setter def short_description(self, value): - from stix.common import StructuredText - self._set_var(StructuredText, short_description=value) + self.short_descriptions = value + + @property + def short_descriptions(self): + return self._short_descriptions + + @short_descriptions.setter + def short_descriptions(self, value): + from stix.common import StructuredTextList + self._short_descriptions = StructuredTextList(value) @property def information_source(self): @@ -747,7 +772,7 @@ def information_source(self, value): @classmethod def from_obj(cls, obj, return_obj=None): - from stix.common import StructuredText, InformationSource + from stix.common import StructuredTextList, InformationSource if not return_obj: raise ValueError("Must provide a return_obj argument") @@ -763,10 +788,10 @@ def from_obj(cls, obj, return_obj=None): # type definition (e.g., used as a reference) return_obj.version = getattr(obj, 'version', None) return_obj.title = getattr(obj, 'Title', None) - return_obj.description = \ - StructuredText.from_obj(getattr(obj, 'Description', None)) - return_obj.short_description = \ - StructuredText.from_obj(getattr(obj, 'Short_Description', None)) + return_obj.descriptions = \ + StructuredTextList.from_obj(getattr(obj, 'Description', None)) + return_obj.short_descriptions = \ + StructuredTextList.from_obj(getattr(obj, 'Short_Description', None)) return_obj.information_source = \ InformationSource.from_obj(getattr(obj, 'Information_Source', None)) @@ -788,10 +813,10 @@ def to_obj(self, return_obj=None, ns_info=None): if self.timestamp: return_obj.timestamp = utils.dates.serialize_value(self.timestamp) - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) - if self.short_description: - return_obj.Short_Description = self.short_description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) + if self.short_descriptions: + return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) if self.information_source: return_obj.Information_Source = self.information_source.to_obj(ns_info=ns_info) @@ -799,7 +824,7 @@ def to_obj(self, return_obj=None, ns_info=None): @classmethod def from_dict(cls, d, return_obj=None): - from stix.common import StructuredText, InformationSource + from stix.common import StructuredTextList, InformationSource if not return_obj: raise ValueError("Must provide a return_obj argument") @@ -810,14 +835,30 @@ def from_dict(cls, d, return_obj=None): return_obj.timestamp = get('timestamp') return_obj.version = get('version') return_obj.title = get('title') - return_obj.description = \ - StructuredText.from_dict(get('description')) - return_obj.short_description = \ - StructuredText.from_dict(get('short_description')) + return_obj.descriptions = \ + StructuredTextList.from_dict(get('description')) + return_obj.short_descriptions = \ + StructuredTextList.from_dict(get('short_description')) return_obj.information_source = \ InformationSource.from_dict(get('information_source')) return return_obj def to_dict(self): - return super(BaseCoreComponent, self).to_dict() + skip = ( + 'description', + 'descriptions', + 'short_description', + 'short_descriptions' + ) + + d = utils.to_dict(self, skip=skip) + + if self.descriptions: + d['description'] = self.descriptions.to_dict() + if self.short_descriptions: + d['short_description'] = self.short_descriptions.to_dict() + + return d + + diff --git a/stix/bindings/campaign.py b/stix/bindings/campaign.py index bb16e77e..95acd1e0 100644 --- a/stix/bindings/campaign.py +++ b/stix/bindings/campaign.py @@ -445,8 +445,14 @@ def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None self.xml_type = "CampaignType" self.version = _cast(None, version) self.Title = Title - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description self.Names = Names if Intended_Effect is None: self.Intended_Effect = [] @@ -477,8 +483,12 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Title(self): return self.Title def set_Title(self, Title): self.Title = Title + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Names(self): return self.Names @@ -518,8 +528,8 @@ def set_version(self, version): self.version = version def hasContent_(self): if ( self.Title is not None or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.Names is not None or self.Intended_Effect or self.Status is not None or @@ -576,10 +586,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Campaig if self.Title is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:Title>%s%s' % (nsmap[namespace_], quote_xml(self.Title), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) if self.Names is not None: self.Names.export(lwrite, level, nsmap, namespace_, name_='Names', pretty_print=pretty_print) for Intended_Effect_ in self.Intended_Effect: @@ -626,11 +636,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Names': obj_ = NamesType.factory() obj_.build(child_) diff --git a/stix/bindings/course_of_action.py b/stix/bindings/course_of_action.py index cfc6770c..6dc139ad 100644 --- a/stix/bindings/course_of_action.py +++ b/stix/bindings/course_of_action.py @@ -215,8 +215,14 @@ def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None self.Title = Title self.Stage = Stage self.Type = Type - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description self.Objective = Objective self.Parameter_Observables = Parameter_Observables self.Structured_COA = Structured_COA @@ -239,8 +245,12 @@ def get_Stage(self): return self.Stage def set_Stage(self, Stage): self.Stage = Stage def get_Type(self): return self.Type def set_Type(self, Type): self.Type = Type + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Objective(self): return self.Objective @@ -270,8 +280,8 @@ def hasContent_(self): self.Title is not None or self.Stage is not None or self.Type is not None or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.Objective is not None or self.Parameter_Observables is not None or self.Structured_COA is not None or @@ -329,10 +339,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CourseO self.Stage.export(lwrite, level, nsmap, namespace_, name_='Stage', pretty_print=pretty_print) if self.Type is not None: self.Type.export(lwrite, level, nsmap, namespace_, name_='Type', pretty_print=pretty_print) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) if self.Objective is not None: self.Objective.export(lwrite, level, nsmap, namespace_, name_='Objective', pretty_print=pretty_print) if self.Parameter_Observables is not None: @@ -381,11 +391,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Objective': obj_ = ObjectiveType.factory() obj_.build(child_) diff --git a/stix/bindings/exploit_target.py b/stix/bindings/exploit_target.py index 146d49dc..ed766841 100644 --- a/stix/bindings/exploit_target.py +++ b/stix/bindings/exploit_target.py @@ -737,8 +737,14 @@ def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None self.xml_type = "ExploitTargetType" self.version = _cast(None, version) self.Title = Title - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description if Vulnerability is None: self.Vulnerability = [] else: @@ -764,8 +770,12 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Title(self): return self.Title def set_Title(self, Title): self.Title = Title + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Vulnerability(self): return self.Vulnerability @@ -795,8 +805,8 @@ def set_version(self, version): self.version = version def hasContent_(self): if ( self.Title is not None or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.Vulnerability or self.Weakness or self.Configuration or @@ -848,10 +858,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Exploit if self.Title is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:Title>%s%s' % (nsmap[namespace_],quote_xml(self.Title), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) for Vulnerability_ in self.Vulnerability: Vulnerability_.export(lwrite, level, nsmap, namespace_, name_='Vulnerability', pretty_print=pretty_print) for Weakness_ in self.Weakness: @@ -888,11 +898,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Vulnerability': type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') if type_name_ is None: diff --git a/stix/bindings/incident.py b/stix/bindings/incident.py index 156067ff..3ea99554 100644 --- a/stix/bindings/incident.py +++ b/stix/bindings/incident.py @@ -2169,8 +2169,14 @@ def __init__(self, idref=None, id=None, timestamp=None, URL=None, version=None, else: self.External_ID = External_ID self.Time = Time - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description self.Categories = Categories self.Reporter = Reporter if Responder is None: @@ -2233,8 +2239,12 @@ def add_External_ID(self, value): self.External_ID.append(value) def insert_External_ID(self, index, value): self.External_ID[index] = value def get_Time(self): return self.Time def set_Time(self, Time): self.Time = Time + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Categories(self): return self.Categories @@ -2310,8 +2320,8 @@ def hasContent_(self): self.Title is not None or self.External_ID or self.Time is not None or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.Categories is not None or self.Reporter is not None or self.Responder or @@ -2386,10 +2396,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Inciden External_ID_.export(lwrite, level, nsmap, namespace_, name_='External_ID', pretty_print=pretty_print) if self.Time is not None: self.Time.export(lwrite, level, nsmap, namespace_, name_='Time', pretty_print=pretty_print) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) if self.Categories is not None: self.Categories.export(lwrite, level, nsmap, namespace_, name_='Categories', pretty_print=pretty_print) if self.Reporter is not None: @@ -2470,11 +2480,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Categories': obj_ = CategoriesType.factory() obj_.build(child_) diff --git a/stix/bindings/indicator.py b/stix/bindings/indicator.py index 4bbedf65..9d16c0c3 100644 --- a/stix/bindings/indicator.py +++ b/stix/bindings/indicator.py @@ -859,8 +859,14 @@ def __init__(self, idref=None, id=None, timestamp=None, negate=False, version=No self.Alternative_ID = [] else: self.Alternative_ID = Alternative_ID - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description if Valid_Time_Position is None: self.Valid_Time_Position = [] else: @@ -898,8 +904,12 @@ def get_Alternative_ID(self): return self.Alternative_ID def set_Alternative_ID(self, Alternative_ID): self.Alternative_ID = Alternative_ID def add_Alternative_ID(self, value): self.Alternative_ID.append(value) def insert_Alternative_ID(self, index, value): self.Alternative_ID[index] = value + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Valid_Time_Position(self): return self.Valid_Time_Position @@ -945,8 +955,8 @@ def hasContent_(self): self.Title is not None or self.Type or self.Alternative_ID or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.Valid_Time_Position or self.Observable is not None or self.Composite_Indicator_Expression is not None or @@ -1013,10 +1023,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Indicat for Alternative_ID_ in self.Alternative_ID: showIndent(lwrite, level, pretty_print) lwrite('<%s:Alternative_ID>%s%s' % (nsmap[namespace_], quote_xml(Alternative_ID_), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) for Valid_Time_Position_ in self.Valid_Time_Position: Valid_Time_Position_.export(lwrite, level, nsmap, namespace_, name_='Valid_Time_Position', pretty_print=pretty_print) if self.Observable is not None: @@ -1083,11 +1093,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Valid_Time_Position': obj_ = ValidTimeType.factory() obj_.build(child_) diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index b0c813ec..82b86d00 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -3589,9 +3589,14 @@ class StructuredTextType(GeneratedsSuper): attribute is absent, the implication is that no markup is being used.""" subclass = None superclass = None - def __init__(self, structuring_format=None, valueOf_=None): + def __init__(self, structuring_format=None, valueOf_=None, id=None, + idref=None, ordinality=None): self.structuring_format = _cast(None, structuring_format) self.valueOf_ = valueOf_ + self.id = id, + self.idref = idref, + self.ordinality = ordinality + def factory(*args_, **kwargs_): if StructuredTextType.subclass: return StructuredTextType.subclass(*args_, **kwargs_) @@ -3602,6 +3607,10 @@ def get_structuring_format(self): return self.structuring_format def set_structuring_format(self, structuring_format): self.structuring_format = structuring_format def get_valueOf_(self): return self.valueOf_ def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def get_id(self): return self.id + def set_id(self, id): self.id = id + def get_ordinality(self): return self.ordinality + def set_ordinality(self, ordinality): self.ordinality = ordinality def hasContent_(self): if ( self.valueOf_ @@ -3629,6 +3638,12 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom if self.structuring_format is not None and 'structuring_format' not in already_processed: already_processed.add('structuring_format') lwrite(' structuring_format=%s' % (quote_attrib(self.structuring_format), )) + if self.id is not None and 'id' not in already_processed: + already_processed.add('id') + lwrite(' id=%s' % (quote_attrib(self.id), )) + if self.ordinality is not None and 'ordinality' not in already_processed: + already_processed.add('ordinality') + lwrite(' ordinality=%s' % (quote_attrib(self.ordinality), )) def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='StructuredTextType', fromsubclass_=False, pretty_print=True): pass def build(self, node): @@ -3643,6 +3658,14 @@ def buildAttributes(self, node, attrs, already_processed): if value is not None and 'structuring_format' not in already_processed: already_processed.add('structuring_format') self.structuring_format = value + value = find_attr_value_('id', node) + if value is not None and 'id' not in already_processed: + already_processed.add('id') + self.id = value + value = find_attr_value_('ordinality', node) + if value is not None and 'ordinality' not in already_processed: + already_processed.add('ordinality') + self.ordinality = value def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass # end class StructuredTextType diff --git a/stix/bindings/threat_actor.py b/stix/bindings/threat_actor.py index 9e84d689..2b8d0119 100644 --- a/stix/bindings/threat_actor.py +++ b/stix/bindings/threat_actor.py @@ -239,8 +239,14 @@ def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None self.xml_type = "ThreatActorType" self.version = _cast(None, version) self.Title = Title - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description self.Identity = Identity if Type is None: self.Type = [] @@ -277,8 +283,12 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Title(self): return self.Title def set_Title(self, Title): self.Title = Title + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Identity(self): return self.Identity @@ -380,10 +390,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ThreatA if self.Title is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:Title>%s%s' % (nsmap[namespace_], quote_xml(self.Title), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) if self.Identity is not None: self.Identity.export(lwrite, level, nsmap, namespace_, name_='Identity', pretty_print=pretty_print) for Type_ in self.Type: @@ -430,11 +440,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Identity': type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') if type_name_ is None: diff --git a/stix/bindings/ttp.py b/stix/bindings/ttp.py index 8ba5882a..0ea62d95 100644 --- a/stix/bindings/ttp.py +++ b/stix/bindings/ttp.py @@ -1256,8 +1256,14 @@ def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None self.version = _cast(None, version) self.Title = Title - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description if Intended_Effect is None: self.Intended_Effect = [] else: @@ -1280,8 +1286,12 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Title(self): return self.Title def set_Title(self, Title): self.Title = Title + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Intended_Effect(self): return self.Intended_Effect @@ -1313,8 +1323,8 @@ def set_version(self, version): self.version = version def hasContent_(self): if ( self.Title is not None or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.Intended_Effect or self.Behavior is not None or self.Resources is not None or @@ -1369,10 +1379,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TTPType if self.Title is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:Title>%s%s' % (nsmap[namespace_], quote_xml(self.Title), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) for Intended_Effect_ in self.Intended_Effect: Intended_Effect_.export(lwrite, level, nsmap, namespace_, name_='Intended_Effect', pretty_print=pretty_print) if self.Behavior is not None: @@ -1415,11 +1425,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Intended_Effect': obj_ = stix_common_binding.StatementType.factory() obj_.build(child_) diff --git a/stix/common/__init__.py b/stix/common/__init__.py index 32a55393..28eab16f 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -3,7 +3,7 @@ from __future__ import absolute_import -from .structured_text import StructuredText # noqa +from .structured_text import StructuredText, StructuredTextList # noqa from .vocabs import VocabString # noqa from .datetimewithprecision import DateTimeWithPrecision # noqa from .activity import Activity # noqa diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index c21414aa..f4f6fbf1 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -1,7 +1,12 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# stdlib +import itertools + +# internal import stix +import stix.utils as utils import stix.bindings.stix_common as stix_common_binding @@ -10,11 +15,30 @@ class StructuredText(stix.Entity): _binding_class = _binding.StructuredTextType _namespace = 'http://stix.mitre.org/common-1' - def __init__(self, value=None): + def __init__(self, value=None, ordinality=None): self.id_ = None self.value = value self.structuring_format = None - self.ordinality = None + self.ordinality = ordinality + + @property + def ordinality(self): + return self._ordinality + + @ordinality.setter + def ordinality(self, value): + if value is None: + self._ordinality = None + return + + value = int(value) + + if value > 0: + self._ordinality = value + return + + error = "Value must be an integer > 0. Received {0}".format(value) + raise ValueError(error) def to_obj(self, return_obj=None, ns_info=None): if not return_obj: @@ -36,7 +60,7 @@ def is_plain(self): plain = ( (not self.id_) and (not self.structuring_format) and - (self.ordinality in (1, None)) + (self.ordinality is None) ) return plain @@ -88,14 +112,136 @@ def __unicode__(self): return unicode(self.value) +def _ordkey(text): + o = text.ordinality + o = int(o) if o is not None else None + return (o is None, o) + + class StructuredTextList(stix.TypedList): _contained_type = StructuredText + def with_ordinality(self, ordinality): + if not isinstance(ordinality, int): + error = "ordinality must be an integer. Received {}" + error = error.format(type(ordinality)) + raise ValueError(error) + + for item in self._inner: + if item.ordinality == ordinality: + return item + + return None + + def with_id(self, id): + for text in self._inner: + if text.id_ == id: + return text + + return None + + def reset(self): + for idx, item in enumerate(self.sorted, 1): + item.ordinality = idx + + @property + def sorted(self): + return sorted(self._inner, key=_ordkey) + + @property + def ordinalities(self): + return tuple(x.ordinality for x in self.sorted) + def __iter__(self): - return sorted(self._inner, key=lambda x: x.ordinality) + return iter(self.sorted) - def __getitem__(self, item): - pass + def __getitem__(self, key): + o = int(key) + text = self.with_ordinality(o) + + if text: + return text + + error = "No item found with an ordinality of {0}".format(o) + raise IndexError(error) def __setitem__(self, key, value): - pass + o = int(key) + + if o < 1: + raise IndexError("ordinality must be > 0") + + if not self._is_valid(value): + value = self._fix_value(value) + + if value.ordinality is None: + value.ordinality = o + elif value.ordinality != o: + error = ( + "Ordinality mismatch. {0} found on input object but index " + "was {1}" + ).format(value.ordinality, o) + raise ValueError(error) + + existing = self.with_ordinality(o) + + if existing is not None: + self._inner.remove(existing) + + self._inner.append(value) + + def __delitem__(self, key): + o = int(key) + text = self.with_ordinality(o) + + if text: + self._inner.remove(text) + return + + error = "No item found with an ordinality of {0}".format(o) + raise IndexError(error) + + def insert(self, idx, value): + if value is None: + return + + if not self._is_valid(value): + value = self._fix_value(value) + + if value.ordinality is None: + if self._inner: + new_ord = self.ordinalities[-1] + 1 + value.ordinality = new_ord + else: + value.ordinality = 1 + + exists = self.with_ordinality(value.ordinality) + if not exists: + self._inner.append(value) + return + + error = "Value with ordinality {0} exists: '{1}'." + error = error.format(value.ordinality, exists.value) + raise ValueError(error) + + def to_list(self): + l = super(StructuredTextList, self).to_list() + + if len(l) > 1: + return l + + d = l[0] + ordinality = int(d.get('ordinality', 1)) + + if ordinality != 1: + return l + + del d['ordinality'] + + if len(d.keys()) == 1 and 'value' in d: + return d['value'] + + return d + + to_dict = to_list + diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 3b202e47..ab6238ec 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -906,9 +906,9 @@ def from_obj(cls, obj, return_obj=None): if isinstance(obj, cls._binding_class): return_obj.negate = obj.negate - return_obj.producer = InformationSource.from_obj(obj.Producer) - return_obj.confidence = Confidence.from_obj(obj.Confidence) - return_obj.sightings = Sightings.from_obj(obj.Sightings) + return_obj.producer = InformationSource.from_obj(obj.Producer) + return_obj.confidence = Confidence.from_obj(obj.Confidence) + return_obj.sightings = Sightings.from_obj(obj.Sightings) return_obj.composite_indicator_expression = CompositeIndicatorExpression.from_obj(obj.Composite_Indicator_Expression) return_obj.handling = Marking.from_obj(obj.Handling) return_obj.kill_chain_phases = KillChainPhasesReference.from_obj(obj.Kill_Chain_Phases) @@ -927,8 +927,16 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - skip = ('observables', 'observable_composition_operator', 'negate') - d = utils.to_dict(self, skip=skip) + skip = ( + 'observables', + 'observable_composition_operator', + 'negate', + 'descriptions', + 'short_descriptions', + ) + + d = super(Indicator, self).to_dict() + utils.remove_entries(d, skip) if self.negate: d['negate'] = True diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index ae0fd6db..1c9f9bd5 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -337,6 +337,11 @@ def cast_var(item, klass, arg=None): return klass(**kwarg) # klass(value='foobar') +def remove_entries(map, keys): + for key in keys: + map.pop(key, None) + + # Namespace flattening from .nsparser import * # noqa from .dates import * # noqa From 0035becc1d4b20fe4d10e91ae6deceb377e2b45f Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 20 Apr 2015 21:14:25 -0400 Subject: [PATCH 006/438] Bumped version to 1.2.0.0-dev --- stix/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/version.py b/stix/version.py index b7b1ff7f..69c52d59 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.1.1.5.dev0" +__version__ = "1.2.0.0.dev0" From aeaf99bfb130fd867f2f282de2f8e8c8684d62d5 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 21 Apr 2015 08:24:48 -0400 Subject: [PATCH 007/438] Updated version strings for 1.2. --- stix/core/stix_package.py | 2 +- stix/test/core/stix_package_test.py | 2 +- stix/test/encoding_test.py | 2 +- stix/test/utils/nsparser_test.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 64c1842e..93ad2c00 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -31,7 +31,7 @@ class STIXPackage(stix.Entity): _binding = stix_core_binding _binding_class = _binding.STIXType _namespace = 'http://stix.mitre.org/stix-1' - _version = "1.1.1" + _version = "1.2" def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, courses_of_action=None, exploit_targets=None, indicators=None, diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index f63edf21..d952a84d 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -90,7 +90,7 @@ class STIXPackageTests(EntityTestCase, unittest.TestCase): }, 'threat_actors': ThreatActorsTests._full_dict, 'ttps': TTPsTests._full_dict, - 'version': "1.1.1" + 'version': "1.2" } diff --git a/stix/test/encoding_test.py b/stix/test/encoding_test.py index 9797c262..787bc77d 100644 --- a/stix/test/encoding_test.py +++ b/stix/test/encoding_test.py @@ -28,7 +28,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:stix="http://stix.mitre.org/stix-1" xmlns:example="http://example.com/" - id="example:Indicator-ba1d406e-937c-414f-9231-6e1dbe64fe8b" version="1.1.1" timestamp="2014-05-08T09:00:00.000000Z"> + id="example:Indicator-ba1d406e-937c-414f-9231-6e1dbe64fe8b" version="1.2.0" timestamp="2014-05-08T09:00:00.000000Z"> {0} diff --git a/stix/test/utils/nsparser_test.py b/stix/test/utils/nsparser_test.py index d3f7452d..9b3ee82d 100644 --- a/stix/test/utils/nsparser_test.py +++ b/stix/test/utils/nsparser_test.py @@ -131,7 +131,7 @@ def test_duplicate_ns_prefix(self): """""" ) @@ -163,7 +163,7 @@ def test_parsed_namespaces(self): xmlns:stixVocabs="http://stix.mitre.org/default_vocabularies-1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="example:Package-e2454ee8-e59c-43ac-a085-46ae4516fd6e" - version="1.1.1" + version="1.2" timestamp="2015-04-09T14:22:25.620831+00:00"/>""" ) From 2b68ac1d32e7a77bca5185d435a85f2d6fc8b607 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 21 Apr 2015 12:26:42 -0400 Subject: [PATCH 008/438] Refactored StructuredTextList to not be a MutableSequence type. * Made StructuredTextList a Sequence type. * Added TypedCollection layer and refactored TypedList to extend from it. * Added TypedSeqeunce base class. * Added StructuredTextList.to_obj() which strips ordinality from the output if the len(collection) == 1 and its ordinality is 1. * Need to push my unit tests! --- stix/__init__.py | 6 +- stix/base.py | 90 +++++++------ stix/common/structured_text.py | 237 ++++++++++++++++++++++++++------- 3 files changed, 241 insertions(+), 92 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index 95df5e34..a6c9e679 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -2,7 +2,11 @@ # See LICENSE.txt for complete terms. # Make sure base gets imported before common. -from .base import Entity, EntityList, TypedList, BaseCoreComponent # noqa +from .base import ( # noqa + Entity, EntityList, TypedCollection, TypedList, TypedSequence, + BaseCoreComponent +) + from . import common # noqa from .version import __version__ # noqa diff --git a/stix/base.py b/stix/base.py index 8daf9c78..f6d3dd45 100644 --- a/stix/base.py +++ b/stix/base.py @@ -425,47 +425,18 @@ def from_dict(cls, dict_repr, return_obj=None, contained_type=None, return return_obj - -class TypedList(collections.MutableSequence): +class TypedCollection(object): _contained_type = _override - def __init__(self, *args): + def __init__(self): self._inner = [] - # Check if it was initialized with args=None - if not any(args): - return - - for arg in args: - if utils.is_sequence(arg): - self.extend(arg) - else: - self.append(arg) + def __len__(self): + return bool(self._inner) def __nonzero__(self): return bool(self._inner) - def __getitem__(self, key): - return self._inner.__getitem__(key) - - def __setitem__(self, key, value): - if not self._is_valid(value): - value = self._fix_value(value) - self._inner.__setitem__(key, value) - - def __delitem__(self, key): - self._inner.__delitem__(key) - - def __len__(self): - return len(self._inner) - - def insert(self, idx, value): - if not value: - return - if not self._is_valid(value): - value = self._fix_value(value) - self._inner.insert(idx, value) - def _is_valid(self, value): """Check if this is a valid object to add to the list.""" # Subclasses can override this function, but if it becomes common, @@ -497,8 +468,6 @@ def to_obj(self, ns_info=None): def to_list(self): return [h.to_dict() for h in self] - to_dict = to_list - @classmethod def from_obj(cls, obj_list, contained_type=None): if not obj_list: @@ -512,8 +481,8 @@ def from_obj(cls, obj_list, contained_type=None): if not utils.is_sequence(obj_list): obj_list = [obj_list] - return_obj.extend(contained_type.from_obj(x) for x in obj_list) - return return_obj + items = (contained_type.from_obj(x) for x in obj_list) + return cls(items) @classmethod def from_list(cls, list_repr, contained_type=None): @@ -524,15 +493,14 @@ def from_list(cls, list_repr, contained_type=None): if not utils.is_sequence(list_repr): list_repr = [list_repr] - return_obj = cls() - if not contained_type: contained_type = cls._contained_type - return_obj.extend(contained_type.from_dict(x) for x in list_repr) - return return_obj + items = (contained_type.from_dict(x) for x in list_repr) + return cls(items) from_dict = from_list + to_dict = to_list @classmethod def object_from_dict(cls, entity_dict): @@ -545,6 +513,46 @@ def dict_from_object(cls, entity_obj): return cls.from_obj(entity_obj).to_dict() +class TypedSequence(TypedCollection, collections.Sequence): + pass + + +class TypedList(TypedCollection, collections.MutableSequence): + def __init__(self, *args): + TypedCollection.__init__(self) + + # Check if it was initialized with args=None + if not any(args): + return + + for arg in args: + if utils.is_sequence(arg): + self.extend(arg) + else: + self.append(arg) + + def __getitem__(self, key): + return self._inner.__getitem__(key) + + def __setitem__(self, key, value): + if not self._is_valid(value): + value = self._fix_value(value) + self._inner.__setitem__(key, value) + + def __delitem__(self, key): + self._inner.__delitem__(key) + + def __len__(self): + return len(self._inner) + + def insert(self, idx, value): + if not value: + return + if not self._is_valid(value): + value = self._fix_value(value) + self._inner.insert(idx, value) + + class BaseCoreComponent(Entity): _ALL_VERSIONS = () _ID_PREFIX = None diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index f4f6fbf1..28916862 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -1,10 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# stdlib import itertools -# internal import stix import stix.utils as utils import stix.bindings.stix_common as stix_common_binding @@ -112,50 +110,116 @@ def __unicode__(self): return unicode(self.value) -def _ordkey(text): - o = text.ordinality - o = int(o) if o is not None else None - return (o is None, o) +class StructuredTextList(stix.TypedSequence): + """A sequence type used to store StructureText objects. + Args: + *args: A variable-length argument list which can contain single + :class:`StructuredText` objects or sequences of objects. -class StructuredTextList(stix.TypedList): + Attributes: + sorted: + ordinalities: + next_ordinality: + + + """ _contained_type = StructuredText + def __init__(self, *args): + super(StructuredTextList, self).__init__() + + # Check if it was initialized with args=None + if not any(args): + return + + for arg in args: + if utils.is_sequence(arg): + self.update(arg) + else: + self.add(arg) + def with_ordinality(self, ordinality): - if not isinstance(ordinality, int): - error = "ordinality must be an integer. Received {}" - error = error.format(type(ordinality)) - raise ValueError(error) + """Returns a :class:`StructuredText` object with a matching `ordinality` + or ``None`` if not found. + + """ + o = int(ordinality) for item in self._inner: - if item.ordinality == ordinality: + if item.ordinality == o: return item + # Not found. Return None. return None def with_id(self, id): + """Returns a :class:`StructuredText` object with a matching `id` or + ``None`` if not found. + + """ for text in self._inner: if text.id_ == id: return text + # Not found. Return None. return None def reset(self): + """Assigns sequential ordinality values to each of the sorted + :class:`StructuredText` objects, starting with ``1`` and ending + at ``len(self)``. + + """ for idx, item in enumerate(self.sorted, 1): item.ordinality = idx + def __reversed__(self): + """The collections.Sequence class defines this in an incompatible way. + + """ + raise NotImplementedError() + @property def sorted(self): - return sorted(self._inner, key=_ordkey) + """Returns a copy of the collection of internal + :class:`StructuredText` objects, sorted by their ``ordinality``. + + """ + return sorted(self._inner, key=lambda x: int(x.ordinality)) @property def ordinalities(self): + """Returns a sorted list of all the ``ordinality`` attribute + values of the internal :class:`StructuredTex` objects. + + """ return tuple(x.ordinality for x in self.sorted) + @property + def next_ordinality(self): + """Returns the "+1" of the highest ordinality in the collection. + + """ + if self.ordinalities: + return self.ordinalities[-1] + 1 + else: + return 1 + def __iter__(self): + """Returns an iterator for the collection sorted by ordinality. + + """ return iter(self.sorted) def __getitem__(self, key): + """Returns the :class:`StructuredText` object with a matching + ordinality. + + Args: + key: An ordinality value. + + """ o = int(key) text = self.with_ordinality(o) @@ -163,34 +227,78 @@ def __getitem__(self, key): return text error = "No item found with an ordinality of {0}".format(o) - raise IndexError(error) + raise KeyError(error) - def __setitem__(self, key, value): - o = int(key) + def add(self, value): + """Adds the :class:`StructuredText` `value` to the collection. - if o < 1: - raise IndexError("ordinality must be > 0") + If `value` does not have an ``ordinality`` set, one will be assigned. + If `value` has an ordinality which matches one already in the + collection, `value` will replace the existing item. + """ if not self._is_valid(value): value = self._fix_value(value) if value.ordinality is None: - value.ordinality = o - elif value.ordinality != o: - error = ( - "Ordinality mismatch. {0} found on input object but index " - "was {1}" - ).format(value.ordinality, o) - raise ValueError(error) + value.ordinality = self.next_ordinality - existing = self.with_ordinality(o) + # Find an item with a matching ordinality. Remove it if one exists. + existing = self.with_ordinality(value.ordinality) if existing is not None: self._inner.remove(existing) self._inner.append(value) + def update(self, iterable): + """Adds each item of `iterable` to the collection. + + """ + for item in iterable: + self.add(item) + + def _shift(self, ordinality): + to_shift = [] + + for o in itertools.count(ordinality): + text = self.with_ordinality(o) + + if not text: + break + + to_shift.append(text) + + for text in to_shift: + text.ordinality += 1 + + def insert(self, value): + """Inserts `value` into the collection. + + If `value` has an ordinality which conflicts with an existing value, + the existing value (and any contiguous items) will have their + ordinality values incremented by one. + + """ + if value.ordinality is None: + self.add(value) + + o = value.ordinality + self._shift(o) + self._inner.append(value) + + def __delitem__(self, key): + """Removes the item with a given ordinality. + + Args: + key: An ordinality value. + + Raises: + KeyError: If the `key` does not match the ordinality for any object + in the collection. + + """ o = int(key) text = self.with_ordinality(o) @@ -199,48 +307,77 @@ def __delitem__(self, key): return error = "No item found with an ordinality of {0}".format(o) - raise IndexError(error) + raise KeyError(error) - def insert(self, idx, value): - if value is None: - return + def remove(self, value): + """Removes the value from the collection. - if not self._is_valid(value): - value = self._fix_value(value) + """ + self._inner.remove(value) - if value.ordinality is None: - if self._inner: - new_ord = self.ordinalities[-1] + 1 - value.ordinality = new_ord - else: - value.ordinality = 1 + def to_obj(self, ns_info=None): + """Returns a binding object list for the StructuredTextList. - exists = self.with_ordinality(value.ordinality) - if not exists: - self._inner.append(value) - return + If the list has a length of 1, and its member has an ordinality of 1, + the ordinality will be unset. - error = "Value with ordinality {0} exists: '{1}'." - error = error.format(value.ordinality, exists.value) - raise ValueError(error) + """ + objlist = super(StructuredTextList, self).to_obj(ns_info=ns_info) + + if len(objlist) > 1: + return objlist + + # List has a size of 1. Get the only member + obj = objlist[0] + + # If the ordinality is 1, unset it. + if obj.ordinality == 1: + obj.ordinality = None + + return objlist def to_list(self): + """Attempts to flatten out the returned list when there is only one + item in the list. This is to support backwards compatibility with + previous versions of python-stix. + + * If the list repr has more than one item, return the list. + * If there is only one item, inspect it. + * If the item is not a dictionary, return it. + * If its ``ordinality`` key has a corresponding value of ``1``, remove + it from the dictionary since it's assumed if there is only one item. + * After removing ``ordinality``, if the only key left is ``value``, + just return the value of ``value`` (a string). + + """ + # Build the list representation l = super(StructuredTextList, self).to_list() + # If we have more than one StructuredText list item, return the list. if len(l) > 1: return l + # Only one item. d = l[0] - ordinality = int(d.get('ordinality', 1)) - if ordinality != 1: - return l + # If the item is not a dictionary (e.g., a string), return it. + if not isinstance(d, dict): + return d + + # Item was a dictionary. Check for `ordinality` and remove it if its + # value is ``1``. + if 'ordinality' in d: + ordinality = int(d['ordinality']) - del d['ordinality'] + if ordinality == 1: + del d['ordinality'] - if len(d.keys()) == 1 and 'value' in d: + # If the only key we have left is ``value``, just return the + # corresponding string. + if len(d) == 1 and 'value' in d: return d['value'] + # The dictionary has more than one key, so we can't flatten it. return d to_dict = to_list From 253222e392c4f2c2fae9c6c45b2dfa248a4aca0a Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 21 Apr 2015 12:30:13 -0400 Subject: [PATCH 009/438] Removed empty docstrings. --- stix/common/structured_text.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 28916862..684b6239 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -117,12 +117,6 @@ class StructuredTextList(stix.TypedSequence): *args: A variable-length argument list which can contain single :class:`StructuredText` objects or sequences of objects. - Attributes: - sorted: - ordinalities: - next_ordinality: - - """ _contained_type = StructuredText From 534d9ebf81cd891b54b9e843eb00aa5ea60e9fe8 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 21 Apr 2015 18:04:44 -0400 Subject: [PATCH 010/438] Added StructureText and StructuredTextList unit tests. --- stix/test/common/structured_text_tests.py | 163 ++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 stix/test/common/structured_text_tests.py diff --git a/stix/test/common/structured_text_tests.py b/stix/test/common/structured_text_tests.py new file mode 100644 index 00000000..6c7c6262 --- /dev/null +++ b/stix/test/common/structured_text_tests.py @@ -0,0 +1,163 @@ +import unittest +import random + +from stix.test import EntityTestCase, TypedListTestCase + +from stix import common + + +class StructuredTextTests(unittest.TestCase, EntityTestCase): + klass = common.StructuredText + _full_dict = { + 'ordinality': 1, + 'value': 'TEST', + 'id': 'example:test-1', + 'structuring_format': 'text/plain' + } + + +class StructuredTextListTests(unittest.TestCase, TypedListTestCase): + klass = common.StructuredTextList + + _full_dict = [ + StructuredTextTests._full_dict, + { + 'ordinality': 2, + 'value': 'TEST 2', + 'id': 'example:test-2', + 'structuring_format': 'text/plain' + } + ] + + def test_with_ordinality(self): + for idx in xrange(1, len(self.slist)): + text = self.slist.with_ordinality(idx) + self.assertEqual(text.ordinality, idx) + + @classmethod + def _get_text_list(cls): + slist = [] + + for ordinality in xrange(1, 10): + text = common.StructuredText("Ordinality %s" % ordinality) + text.ordinality = ordinality + slist.append(text) + + random.shuffle(slist) + return slist + + @classmethod + def setUpClass(cls): + slist = cls._get_text_list() + cls.slist = common.StructuredTextList(slist) + + def test_iter(self): + for idx, text in enumerate(self.slist, 1): + self.assertEqual(text.ordinality, idx) + + def test_reset(self): + ords = (5,33,167) + slist = common.StructuredTextList() + + for o in ords: + text = common.StructuredText("orig: %s" % o, o) + slist.add(text) + + # test that original assignment worked correctly + for o in ords: + self.assertEqual(o, slist[o].ordinality) + + # reset ordinalities + slist.reset() + + for o in xrange(1, len(ords) + 1): + self.assertEqual(o, slist[o].ordinality) + + def test_ordinalities(self): + all_ords = range(1,10) + self.assertTrue(all(x in self.slist.ordinalities for x in all_ords)) + + def test_add(self): + slist = common.StructuredTextList() + st1 = common.StructuredText("foo", ordinality=1) + st2 = common.StructuredText("bar", ordinality=2) + + slist.add(st1) + slist.add(st2) + + self.assertTrue(st1 in slist) + self.assertTrue(st2 in slist) + + def test_insert(self): + slist = common.StructuredTextList() + st1 = common.StructuredText("foo", ordinality=1) + st2 = common.StructuredText("bar", ordinality=2) + + slist.add(st1) + slist.add(st2) + + new_st1 = common.StructuredText("foobar", ordinality=1) + slist.insert(new_st1) + + # test that the ordinality shift worked + self.assertEqual(new_st1.ordinality, 1) + self.assertEqual(st1.ordinality, 2) + self.assertEqual(st2.ordinality, 3) + + def test_delitem(self): + slist = common.StructuredTextList() + st1 = common.StructuredText("foo", ordinality=1) + st2 = common.StructuredText("bar", ordinality=2) + + slist.add(st1) + slist.add(st2) + + del slist[1] + + self.assertTrue(st1 not in slist) + self.assertTrue(st2 in slist) + self.assertRaises( + KeyError, + slist.__getitem__, + 1 + ) + + def test_remove(self): + slist = common.StructuredTextList() + st1 = common.StructuredText("foo", ordinality=1) + st2 = common.StructuredText("bar", ordinality=2) + + slist.add(st1) + slist.add(st2) + slist.remove(st1) + + self.assertTrue(st1 not in slist) + self.assertTrue(st2 in slist) + self.assertRaises( + KeyError, + slist.__getitem__, + 1 + ) + + def test_update(self): + slist = common.StructuredTextList() + st1 = common.StructuredText("foo", ordinality=1) + st2 = common.StructuredText("bar", ordinality=2) + + slist.add(st1) + slist.add(st2) + + new_st1 = common.StructuredText("FOO", ordinality=1) + new_st2 = common.StructuredText("BAR", ordinality=2) + + newlist = [new_st1, new_st2] + slist.update(newlist) + + self.assertEqual(slist[1], new_st1) + self.assertEqual(slist[2], new_st2) + self.assertTrue(st1 not in slist) + self.assertTrue(st2 not in slist) + + +if __name__ == "__main__": + unittest.main() From 3b7231da3faf1b4abf98648534598294edfa2c08 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 08:29:30 -0400 Subject: [PATCH 011/438] Updated DiscoveryMethodVocab to use 2.0 terms. --- stix/common/vocabs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index 88d90dee..19b6b470 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -244,10 +244,11 @@ class AttackerInfrastructureType(VocabString): @add_allowed_values class DiscoveryMethod(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' - _XSI_TYPE = 'stixVocabs:DiscoveryMethodVocab-1.0' + _XSI_TYPE = 'stixVocabs:DiscoveryMethodVocab-2.0' TERM_AGENT_DISCLOSURE = "Agent Disclosure" - TERM_FRAUD_DETECTION = "Fraud Detection" + TERM_EXTERNAL_FRAUD_DETECTION = "External - Fraud Detection" + TERM_INTERNAL_FRAUD_DETECTION = "Internal - Fraud Detection" TERM_MONITORING_SERVICE = "Monitoring Service" TERM_LAW_ENFORCEMENT = "Law Enforcement" TERM_CUSTOMER = "Customer" From 53d27eed77ec419d8e8f7160892b2355bb0583aa Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 09:00:06 -0400 Subject: [PATCH 012/438] Updated InformationSource to support multiple descriptions. --- stix/bindings/stix_common.py | 13 +++++--- stix/common/information_source.py | 50 +++++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index 82b86d00..a0eba34f 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -501,7 +501,10 @@ class InformationSourceType(GeneratedsSuper): subclass = None superclass = None def __init__(self, Description=None, Identity=None, Role=None, Contributing_Sources=None, Time=None, Tools=None, References=None): - self.Description = Description + if Description is None: + self.Description = [] + else: + self.Description = Description self.Identity = Identity if Role is None: self.Role = [] @@ -517,6 +520,8 @@ def factory(*args_, **kwargs_): else: return InformationSourceType(*args_, **kwargs_) factory = staticmethod(factory) + def add_Description(self, Description): self.Description.append(Description) + def insert_Description(self, index, Description): self.Description[index] = Description def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description def get_Identity(self): return self.Identity @@ -535,7 +540,7 @@ def get_References(self): return self.References def set_References(self, References): self.References = References def hasContent_(self): if ( - self.Description is not None or + self.Description or self.Identity is not None or self.Role or self.Contributing_Sources is not None or @@ -569,8 +574,8 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Informa eol_ = '\n' else: eol_ = '' - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) if self.Identity is not None: self.Identity.export(lwrite, level, nsmap, namespace_, name_='Identity', pretty_print=pretty_print) for Role_ in self.Role: diff --git a/stix/common/information_source.py b/stix/common/information_source.py index d4fac2f0..a0ef288d 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -14,7 +14,7 @@ # relative from . import vocabs, VocabString from .identity import Identity -from .structured_text import StructuredText +from .structured_text import StructuredText, StructuredTextList class InformationSource(stix.Entity): @@ -66,18 +66,37 @@ def add_reference(self, value): @property def description(self): - return self._description + """A description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If set to a value that is not an instance of + :class:`.StructuredText`, an attempt to will be made to convert + the value into an instance of :class:`.StructuredText`. + + Returns: + An instance of + :class:`.StructuredText` + + """ + if self.descriptions: + return self.descriptions.sorted[0] + else: + return None @description.setter def description(self, value): - """Sets the value of the description property. + self.descriptions = value - If the value is an instance of basestring, it will be coerced into an - instance of StructuredText, with its 'text' property set to the input - value. + @property + def descriptions(self): + return self._descriptions - """ - self._set_var(StructuredText, description=value) + @descriptions.setter + def descriptions(self, value): + from stix.common import StructuredTextList + self._descriptions = StructuredTextList(value) @property def identity(self): @@ -123,8 +142,8 @@ def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() - if self.description is not None: - return_obj.Description = self.description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) if self.references: return_obj.References = stix_common_binding.ReferencesType(Reference=self.references) if self.contributing_sources: @@ -147,7 +166,7 @@ def from_obj(cls, obj, return_obj=None): if not return_obj: return_obj = cls() - return_obj.description = StructuredText.from_obj(obj.Description) + return_obj.description = StructuredTextList.from_obj(obj.Description) return_obj.identity = Identity.from_obj(obj.Identity) return_obj.contributing_sources = ContributingSources.from_obj(obj.Contributing_Sources) return_obj.roles = _Roles.from_obj(obj.Role) @@ -172,7 +191,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj = cls() get = dict_repr.get - return_obj.description = StructuredText.from_dict(get('description')) + return_obj.description = StructuredTextList.from_dict(get('description')) return_obj.references = get('references') return_obj.contributing_sources = ContributingSources.from_dict(get('contributing_sources')) return_obj.identity = Identity.from_dict(get('identity')) @@ -183,8 +202,13 @@ def from_dict(cls, dict_repr, return_obj=None): return return_obj def to_dict(self): - return super(InformationSource, self).to_dict() + skip = ('description', 'descriptions') + d = utils.to_dict(self, skip=skip) + + if self.descriptions: + d['description'] = self.descriptions.to_dict() + return d class ContributingSources(stix.EntityList): _namespace = "http://stix.mitre.org/common-1" From 77d06d967178323447cb558f458a75d2c864374c Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 09:01:00 -0400 Subject: [PATCH 013/438] Removed unnecessary import. Copy/paste error. --- stix/common/information_source.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stix/common/information_source.py b/stix/common/information_source.py index a0ef288d..3ca5953e 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -14,7 +14,7 @@ # relative from . import vocabs, VocabString from .identity import Identity -from .structured_text import StructuredText, StructuredTextList +from .structured_text import StructuredTextList class InformationSource(stix.Entity): @@ -95,7 +95,6 @@ def descriptions(self): @descriptions.setter def descriptions(self, value): - from stix.common import StructuredTextList self._descriptions = StructuredTextList(value) @property From 4f809940d8227cfb53ac481b05714cb0b6ad27ac Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 09:07:20 -0400 Subject: [PATCH 014/438] Changed if/else in description/short_description getter to use next(iter(...)). --- stix/base.py | 10 ++-------- stix/common/information_source.py | 5 +---- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/stix/base.py b/stix/base.py index f6d3dd45..a74539f2 100644 --- a/stix/base.py +++ b/stix/base.py @@ -703,10 +703,7 @@ def description(self): :class:`.StructuredText` """ - if self.descriptions: - return self.descriptions.sorted[0] - else: - return None + return next(iter(self.descriptions), None) @description.setter def description(self, value): @@ -737,10 +734,7 @@ def short_description(self): :class:`.StructuredText` """ - if self.short_descriptions: - return self.short_descriptions.sorted[0] - else: - return None + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 3ca5953e..af6da510 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -80,10 +80,7 @@ def description(self): :class:`.StructuredText` """ - if self.descriptions: - return self.descriptions.sorted[0] - else: - return None + return next(iter(self.descriptions), None) @description.setter def description(self, value): From 8e338dce99cc83f7d0b8d31782e298b6c2b472fd Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 09:46:36 -0400 Subject: [PATCH 015/438] Added multiple description and short_description support across common types. Added unit tests. --- stix/bindings/stix_common.py | 62 +++++++++++++------- stix/common/activity.py | 63 ++++++++++++++++++--- stix/common/confidence.py | 60 +++++++++++++++++--- stix/common/information_source.py | 26 +++++++-- stix/common/statement.py | 62 +++++++++++++++++--- stix/common/tools.py | 59 ++++++++++++++++--- stix/test/common/activity_test.py | 9 +++ stix/test/common/confidence_test.py | 8 +++ stix/test/common/information_source_test.py | 8 +++ stix/test/common/statement_test.py | 8 +++ stix/test/common/structured_text_tests.py | 3 + stix/test/common/tools_tests.py | 13 ++++- 12 files changed, 321 insertions(+), 60 deletions(-) diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index a0eba34f..dd12c2b0 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -417,7 +417,10 @@ class ToolInformationType(cybox_common_binding.ToolInformationType): def __init__(self, idref=None, id=None, Name=None, Type=None, Description=None, References=None, Vendor=None, Version=None, Service_Pack=None, Tool_Specific_Data=None, Tool_Hashes=None, Tool_Configuration=None, Execution_Environment=None, Errors=None, Metadata=None, Compensation_Model=None, Title=None, Short_Description=None, extensiontype_=None): super(ToolInformationType, self).__init__(idref=idref, id=id, Name=Name, Type=Type, Description=Description, References=References, Vendor=Vendor, Version=Version, Service_Pack=Service_Pack, Tool_Specific_Data=Tool_Specific_Data, Execution_Environment=Execution_Environment, Errors=Errors, Metadata=Metadata, Compensation_Model=Compensation_Model) self.Title = Title - self.Short_Description = Short_Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description self.extensiontype_ = extensiontype_ def factory(*args_, **kwargs_): if ToolInformationType.subclass: @@ -428,13 +431,15 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Title(self): return self.Title def set_Title(self, Title): self.Title = Title + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) + def insert_Short_Description(self, index, Short_Description): self.Short_Description[index] = Short_Description def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def hasContent_(self): if ( super(ToolInformationType, self).hasContent_() or self.Title is not None or - self.Short_Description is not None + self.Short_Description ): return True else: @@ -470,8 +475,8 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ToolInf if self.Title: showIndent(lwrite, level, pretty_print) lwrite('<%s:Title>%s%s' % (nsmap[namespace_],quote_xml(self.Title), nsmap[namespace_], eol_)) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) def build(self, node): already_processed = set() self.buildAttributes(node, node.attrib, already_processed) @@ -493,7 +498,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Short_Description': obj_ = StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) # end class ToolInformationType class InformationSourceType(GeneratedsSuper): @@ -600,7 +605,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Description': obj_ = StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Identity': type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') if type_name_ is None: @@ -651,7 +656,10 @@ def __init__(self, timestamp=None, timestamp_precision='second', Value=None, Des self.timestamp = _cast(None, timestamp) self.timestamp_precision = _cast(None, timestamp_precision) self.Value = Value - self.Description = Description + if Description is None: + self.Description = [] + else: + self.Description = Description self.Source = Source self.Confidence_Assertion_Chain = Confidence_Assertion_Chain def factory(*args_, **kwargs_): @@ -662,6 +670,8 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Value(self): return self.Value def set_Value(self, Value): self.Value = Value + def add_Description(self, Description): self.Description.append(Description) + def insert_Description(self, index, Description): self.Description[index] = Description def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description def get_Source(self): return self.Source @@ -675,7 +685,7 @@ def set_timestamp_precision(self, timestamp_precision): self.timestamp_precision def hasContent_(self): if ( self.Value is not None or - self.Description is not None or + self.Description or self.Source is not None or self.Confidence_Assertion_Chain is not None ): @@ -712,8 +722,8 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Confide eol_ = '' if self.Value is not None: self.Value.export(lwrite, level, nsmap, namespace_, name_='Value', pretty_print=pretty_print) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) if self.Source is not None: self.Source.export(lwrite, level, nsmap, namespace_, name_='Source', pretty_print=pretty_print) if self.Confidence_Assertion_Chain is not None: @@ -745,7 +755,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Source': obj_ = InformationSourceType.factory() obj_.build(child_) @@ -761,7 +771,10 @@ class ActivityType(GeneratedsSuper): superclass = None def __init__(self, Date_Time=None, Description=None): self.Date_Time = Date_Time - self.Description = Description + if Description is None: + self.Description = [] + else: + self.Description = Description def factory(*args_, **kwargs_): if ActivityType.subclass: return ActivityType.subclass(*args_, **kwargs_) @@ -770,12 +783,14 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Date_Time(self): return self.Date_Time def set_Date_Time(self, Date_Time): self.Date_Time = Date_Time + def add_Description(self, Description): self.Description.append(Description) + def insert_Description(self, index, Description): self.Description[index] = Description def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description def hasContent_(self): if ( self.Date_Time is not None or - self.Description is not None + self.Description ): return True else: @@ -805,8 +820,8 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Activit eol_ = '' if self.Date_Time is not None: self.Date_Time.export(lwrite, level, nsmap, namespace_, name_='Date_Time', pretty_print=pretty_print) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) def build(self, node): already_processed = set() self.buildAttributes(node, node.attrib, already_processed) @@ -823,7 +838,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) # end class ActivityType class KillChainsType(GeneratedsSuper): @@ -3477,7 +3492,10 @@ def __init__(self, timestamp=None, timestamp_precision='second', Value=None, Des self.timestamp = _cast(None, timestamp) self.timestamp_precision = _cast(None, timestamp_precision) self.Value = Value - self.Description = Description + if Description is None: + self.Description = [] + else: + self.Description = Description self.Source = Source self.Confidence = Confidence def factory(*args_, **kwargs_): @@ -3488,6 +3506,8 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Value(self): return self.Value def set_Value(self, Value): self.Value = Value + def add_Description(self, Description): self.Description.append(Description) + def insert_Description(self, index, Description): self.Description[index] = Description def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description def get_Source(self): return self.Source @@ -3501,7 +3521,7 @@ def set_timestamp_precision(self, timestamp_precision): self.timestamp_precision def hasContent_(self): if ( self.Value is not None or - self.Description is not None or + self.Description or self.Source is not None or self.Confidence is not None ): @@ -3538,8 +3558,8 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Stateme eol_ = '' if self.Value is not None: self.Value.export(lwrite, level, nsmap, namespace_, name_='Value', pretty_print=pretty_print) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) if self.Source is not None: self.Source.export(lwrite, level, nsmap, namespace_, name_='Source', pretty_print=pretty_print) if self.Confidence is not None: @@ -3570,7 +3590,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Source': obj_ = InformationSourceType.factory() obj_.build(child_) diff --git a/stix/common/activity.py b/stix/common/activity.py index 76f1d175..688843c7 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -2,10 +2,11 @@ # See LICENSE.txt for complete terms. import stix +import stix.utils as utils import stix.bindings.stix_common as common_binding from .datetimewithprecision import DateTimeWithPrecision -from .structured_text import StructuredText +from .structured_text import StructuredTextList class Activity(stix.Entity): @@ -27,11 +28,51 @@ def date_time(self, value): @property def description(self): - return self._description + """A single description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If this object has more than one description set, this will return + the description with the lowest ordinality value. + + Returns: + An instance of + :class:`.StructuredText` + + """ + return next(iter(self.descriptions), None) @description.setter def description(self, value): - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return self._descriptions + + @descriptions.setter + def descriptions(self, value): + self._descriptions = StructuredTextList(value) def to_obj(self, return_obj=None, ns_info=None): super(Activity, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -41,8 +82,8 @@ def to_obj(self, return_obj=None, ns_info=None): if self.date_time: return_obj.Date_Time = self.date_time.to_obj(ns_info=ns_info) - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) return return_obj @@ -55,12 +96,18 @@ def from_obj(cls, obj, return_obj=None): return_obj = cls() return_obj.date_time = DateTimeWithPrecision.from_obj(obj.Date_Time) - return_obj.description = StructuredText.from_obj(obj.Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) return return_obj def to_dict(self): - return super(Activity, self).to_dict() + skip = ('description', 'descriptions') + d = utils.to_dict(self, skip=skip) + + if self.descriptions: + d['description'] = self.descriptions.to_dict() + + return d @classmethod def from_dict(cls, dict_repr, return_obj=None): @@ -72,6 +119,6 @@ def from_dict(cls, dict_repr, return_obj=None): get = dict_repr.get return_obj.date_time = DateTimeWithPrecision.from_dict(get('date_time')) - return_obj.description = StructuredText.from_dict(get('description')) + return_obj.descriptions = StructuredTextList.from_dict(get('description')) return return_obj diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 4751c166..8cb50388 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -8,7 +8,7 @@ import stix.bindings.stix_common as common_binding from . import vocabs, VocabString -from .structured_text import StructuredText +from .structured_text import StructuredTextList class Confidence(stix.Entity): @@ -52,11 +52,51 @@ def source(self, value): @property def description(self): - return self._description + """A single description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If this object has more than one description set, this will return + the description with the lowest ordinality value. + + Returns: + An instance of + :class:`.StructuredText` + + """ + return next(iter(self.descriptions), None) @description.setter def description(self, value): - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return self._descriptions + + @descriptions.setter + def descriptions(self, value): + self._descriptions = StructuredTextList(value) # @property # def confidence_assertion_chain(self): @@ -76,19 +116,23 @@ def to_obj(self, return_obj=None, ns_info=None): if self.value: obj.Value = self.value.to_obj(ns_info=ns_info) - if self.description: - obj.Description = self.description.to_obj(ns_info=ns_info) + if self.descriptions: + obj.Description = self.descriptions.to_obj(ns_info=ns_info) if self.source: obj.Source = self.source.to_obj(ns_info=ns_info) return obj def to_dict(self): - d = utils.to_dict(self, skip=('timestamp_precision',)) + skip = ('timestamp_precision', 'description', 'descriptions') + d = utils.to_dict(self, skip=skip) if self.timestamp_precision != 'second': d['timestamp_precision'] = self.timestamp_precision + if self.descriptions: + d['description'] = self.descriptions.to_dict() + return d @classmethod @@ -104,7 +148,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.timestamp = obj.timestamp return_obj.timestamp_precision = obj.timestamp_precision return_obj.value = VocabString.from_obj(obj.Value) - return_obj.description = StructuredText.from_obj(obj.Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) return_obj.source = InformationSource.from_obj(obj.Source) return return_obj @@ -122,7 +166,7 @@ def from_dict(cls, d, return_obj=None): return_obj.timestamp = d.get('timestamp') return_obj.timestamp_precision = d.get('timestamp_precision', 'second') return_obj.value = VocabString.from_dict(d.get('value')) - return_obj.description = StructuredText.from_dict(d.get('description')) + return_obj.descriptions = StructuredTextList.from_dict(d.get('description')) return_obj.source = InformationSource.from_dict(d.get('source')) return return_obj diff --git a/stix/common/information_source.py b/stix/common/information_source.py index af6da510..96d6c2ec 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -66,14 +66,13 @@ def add_reference(self, value): @property def description(self): - """A description about the contents or purpose of this object. + """A single description about the contents or purpose of this object. Default Value: ``None`` Note: - If set to a value that is not an instance of - :class:`.StructuredText`, an attempt to will be made to convert - the value into an instance of :class:`.StructuredText`. + If this object has more than one description set, this will return + the description with the lowest ordinality value. Returns: An instance of @@ -88,6 +87,25 @@ def description(self, value): @property def descriptions(self): + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ return self._descriptions @descriptions.setter diff --git a/stix/common/statement.py b/stix/common/statement.py index 69294d18..6880dccc 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -8,7 +8,7 @@ import stix.bindings.stix_common as common_binding from .confidence import Confidence -from .structured_text import StructuredText +from .structured_text import StructuredTextList from .vocabs import VocabString, HighMediumLow @@ -53,24 +53,64 @@ def source(self, value): @property def description(self): - return self._description + """A single description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If this object has more than one description set, this will return + the description with the lowest ordinality value. + + Returns: + An instance of + :class:`.StructuredText` + + """ + return next(iter(self.descriptions), None) @description.setter def description(self, value): - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return self._descriptions + + @descriptions.setter + def descriptions(self, value): + self._descriptions = StructuredTextList(value) def to_obj(self, return_obj=None, ns_info=None): super(Statement, self).to_obj(return_obj=return_obj, ns_info=ns_info) obj = self._binding_class() + obj.timestamp_precision = self.timestamp_precision if self.timestamp: obj.timestamp = self.timestamp.isoformat() - obj.timestamp_precision = self.timestamp_precision if self.value: obj.Value = self.value.to_obj(ns_info=ns_info) - if self.description: - obj.Description = self.description.to_obj(ns_info=ns_info) + if self.descriptions: + obj.Description = self.descriptions.to_obj(ns_info=ns_info) if self.source: obj.Source = self.source.to_obj(ns_info=ns_info) if self.confidence: @@ -79,11 +119,15 @@ def to_obj(self, return_obj=None, ns_info=None): return obj def to_dict(self): - d = utils.to_dict(self, skip=('timestamp_precision',)) + skip = ('timestamp_precision', 'description', 'descriptions') + d = utils.to_dict(self, skip=skip) if self.timestamp_precision != 'second': d['timestamp_precision'] = self.timestamp_precision + if self.descriptions: + d['description'] = self.descriptions.to_dict() + return d @classmethod @@ -99,7 +143,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.timestamp = obj.timestamp return_obj.timestamp_precision = obj.timestamp_precision return_obj.value = VocabString.from_obj(obj.Value) - return_obj.description = StructuredText.from_obj(obj.Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) return_obj.source = InformationSource.from_obj(obj.Source) return_obj.confidence = Confidence.from_obj(obj.Confidence) @@ -118,7 +162,7 @@ def from_dict(cls, d, return_obj=None): return_obj.timestamp = d.get('timestamp') return_obj.timestamp_precision = d.get('timestamp_precision', 'second') return_obj.value = VocabString.from_dict(d.get('value')) - return_obj.description = StructuredText.from_dict(d.get('description')) + return_obj.descriptions = StructuredTextList.from_dict(d.get('description')) return_obj.source = InformationSource.from_dict(d.get('source')) return_obj.confidence = Confidence.from_dict(d.get('confidence')) diff --git a/stix/common/tools.py b/stix/common/tools.py index 046b4332..9a9e2399 100644 --- a/stix/common/tools.py +++ b/stix/common/tools.py @@ -9,7 +9,7 @@ import stix.bindings.stix_common as common_binding # relative -from .structured_text import StructuredText +from .structured_text import StructuredTextList class ToolInformation(stix.Entity, cybox.common.ToolInformation): _namespace = 'http://stix.mitre.org/common-1' @@ -31,11 +31,52 @@ def title(self, value): @property def short_description(self): - return self._short_description + """A single short description about the contents or purpose of this + object. + + Default Value: ``None`` + + Note: + If this object has more than one short description set, this will + return the short_description with the lowest ordinality value. + + Returns: + An instance of + :class:`.StructuredText` + + """ + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): - self._set_var(StructuredText, short_description=value) + self.short_descriptions = value + + @property + def short_descriptions(self): + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return self._short_descriptions + + @short_descriptions.setter + def short_descriptions(self, value): + self._short_descriptions = StructuredTextList(value) def to_obj(self, return_obj=None, ns_info=None): if not return_obj: @@ -49,8 +90,8 @@ def to_obj(self, return_obj=None, ns_info=None): ) return_obj.Title = self.title - if self.short_description: - return_obj.Short_Description = self.short_description.to_obj(ns_info=ns_info) + if self.short_descriptions: + return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) return return_obj @@ -64,7 +105,7 @@ def from_obj(cls, obj, return_obj=None): cybox.common.ToolInformation.from_obj(obj, return_obj) return_obj.title = obj.Title - return_obj.short_description = StructuredText.from_obj(obj.Short_Description) + return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) return return_obj @@ -73,8 +114,8 @@ def to_dict(self): if self.title: d['title'] = self.title - if self.short_description: - d['short_description'] = self.short_description.to_dict() + if self.short_descriptions: + d['short_description'] = self.short_descriptions.to_dict() return d @@ -87,6 +128,6 @@ def from_dict(cls, dict_repr, return_obj=None): cybox.common.ToolInformation.from_dict(dict_repr, return_obj) return_obj.title = dict_repr.get('title') - return_obj.short_description = StructuredText.from_dict(dict_repr.get('short_description')) + return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) return return_obj diff --git a/stix/test/common/activity_test.py b/stix/test/common/activity_test.py index 690eb06a..00b7027c 100644 --- a/stix/test/common/activity_test.py +++ b/stix/test/common/activity_test.py @@ -4,6 +4,7 @@ import unittest from stix.test import EntityTestCase +from stix.test.common import structured_text_tests from stix.common import Activity @@ -16,5 +17,13 @@ class ActivityTests(EntityTestCase, unittest.TestCase): } +class ActivityMultiDescTests(EntityTestCase, unittest.TestCase): + klass = Activity + _full_dict = { + 'date_time': "2014-01-31T06:14:46", + 'description': structured_text_tests.StructuredTextListTests._full_dict + } + + if __name__ == "__main__": unittest.main() diff --git a/stix/test/common/confidence_test.py b/stix/test/common/confidence_test.py index bc704409..9e69fd05 100644 --- a/stix/test/common/confidence_test.py +++ b/stix/test/common/confidence_test.py @@ -4,6 +4,7 @@ import unittest from stix.test import EntityTestCase +from stix.test.common import structured_text_tests from stix.common import Confidence @@ -21,6 +22,13 @@ class ConfidenceTests(EntityTestCase, unittest.TestCase): } } +class ConfidenceMultiDescTests(EntityTestCase, unittest.TestCase): + klass = Confidence + _full_dict = { + 'description': structured_text_tests.StructuredTextListTests._full_dict + } + + if __name__ == "__main__": unittest.main() diff --git a/stix/test/common/information_source_test.py b/stix/test/common/information_source_test.py index 2543aca1..cace5256 100644 --- a/stix/test/common/information_source_test.py +++ b/stix/test/common/information_source_test.py @@ -4,6 +4,7 @@ import unittest from stix.test import EntityTestCase +from stix.test.common import structured_text_tests from stix.common import InformationSource @@ -64,6 +65,13 @@ class InformationSourceTests(EntityTestCase, unittest.TestCase): ] } +class InformationSourceMultiDescTests(EntityTestCase, unittest.TestCase): + klass = InformationSource + _full_dict = { + 'description': structured_text_tests.StructuredTextListTests._full_dict + } + + if __name__ == "__main__": unittest.main() diff --git a/stix/test/common/statement_test.py b/stix/test/common/statement_test.py index 9c13619c..a266a866 100644 --- a/stix/test/common/statement_test.py +++ b/stix/test/common/statement_test.py @@ -4,6 +4,7 @@ import unittest from stix.test import EntityTestCase +from stix.test.common import structured_text_tests from stix.common import Statement @@ -24,5 +25,12 @@ class StatementTests(EntityTestCase, unittest.TestCase): } +class StatementMultiDescTests(EntityTestCase, unittest.TestCase): + klass = Statement + _full_dict = { + 'description': structured_text_tests.StructuredTextListTests._full_dict + } + + if __name__ == "__main__": unittest.main() diff --git a/stix/test/common/structured_text_tests.py b/stix/test/common/structured_text_tests.py index 6c7c6262..77abf9eb 100644 --- a/stix/test/common/structured_text_tests.py +++ b/stix/test/common/structured_text_tests.py @@ -1,3 +1,6 @@ +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + import unittest import random diff --git a/stix/test/common/tools_tests.py b/stix/test/common/tools_tests.py index 40fe4c9f..9348f6d8 100644 --- a/stix/test/common/tools_tests.py +++ b/stix/test/common/tools_tests.py @@ -1,7 +1,11 @@ -__author__ = 'bworrell' +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. import unittest + from stix.test import EntityTestCase +from stix.test.common import structured_text_tests + from stix import common @@ -16,5 +20,12 @@ class ToolInformationTests(EntityTestCase, unittest.TestCase): } +class ToolInformationMultiDescTests(EntityTestCase, unittest.TestCase): + klass = common.ToolInformation + + _full_dict = { + 'short_description': structured_text_tests.StructuredTextListTests._full_dict + } + if __name__ == "__main__": unittest.main() From 02f114a29433076c5c78f5b95e158fdfa45f83d1 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 10:10:40 -0400 Subject: [PATCH 016/438] Removed with_ordinality() method on StructuredTextList. Leverage __getitem__ iternally now. --- stix/common/structured_text.py | 97 +++++++++++++--------------------- 1 file changed, 37 insertions(+), 60 deletions(-) diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 684b6239..85a87929 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -133,20 +133,6 @@ def __init__(self, *args): else: self.add(arg) - def with_ordinality(self, ordinality): - """Returns a :class:`StructuredText` object with a matching `ordinality` - or ``None`` if not found. - - """ - o = int(ordinality) - - for item in self._inner: - if item.ordinality == o: - return item - - # Not found. Return None. - return None - def with_id(self, id): """Returns a :class:`StructuredText` object with a matching `id` or ``None`` if not found. @@ -168,12 +154,6 @@ def reset(self): for idx, item in enumerate(self.sorted, 1): item.ordinality = idx - def __reversed__(self): - """The collections.Sequence class defines this in an incompatible way. - - """ - raise NotImplementedError() - @property def sorted(self): """Returns a copy of the collection of internal @@ -215,14 +195,33 @@ def __getitem__(self, key): """ o = int(key) - text = self.with_ordinality(o) - if text: - return text + for item in self._inner: + if item.ordinality == o: + return item error = "No item found with an ordinality of {0}".format(o) raise KeyError(error) + def __delitem__(self, key): + """Removes the item with a given ordinality. + + Args: + key: An ordinality value. + + Raises: + KeyError: If the `key` does not match the ordinality for any object + in the collection. + + """ + self._inner.remove(self[key]) + + def __reversed__(self): + """The collections.Sequence class defines this in an incompatible way. + + """ + raise NotImplementedError() + def add(self, value): """Adds the :class:`StructuredText` `value` to the collection. @@ -237,11 +236,9 @@ def add(self, value): if value.ordinality is None: value.ordinality = self.next_ordinality - # Find an item with a matching ordinality. Remove it if one exists. - existing = self.with_ordinality(value.ordinality) - - if existing is not None: - self._inner.remove(existing) + # Remove the existing item if there is one. + with utils.ignored(KeyError): + del self[value.ordinality] self._inner.append(value) @@ -256,13 +253,11 @@ def _shift(self, ordinality): to_shift = [] for o in itertools.count(ordinality): - text = self.with_ordinality(o) - - if not text: + try: + to_shift.append(self[o]) + except KeyError: break - to_shift.append(text) - for text in to_shift: text.ordinality += 1 @@ -282,27 +277,6 @@ def insert(self, value): self._inner.append(value) - def __delitem__(self, key): - """Removes the item with a given ordinality. - - Args: - key: An ordinality value. - - Raises: - KeyError: If the `key` does not match the ordinality for any object - in the collection. - - """ - o = int(key) - text = self.with_ordinality(o) - - if text: - self._inner.remove(text) - return - - error = "No item found with an ordinality of {0}".format(o) - raise KeyError(error) - def remove(self, value): """Removes the value from the collection. @@ -347,6 +321,10 @@ def to_list(self): # Build the list representation l = super(StructuredTextList, self).to_list() + # No items. Just return the empty list. + if not l: + return l + # If we have more than one StructuredText list item, return the list. if len(l) > 1: return l @@ -358,13 +336,12 @@ def to_list(self): if not isinstance(d, dict): return d - # Item was a dictionary. Check for `ordinality` and remove it if its - # value is ``1``. - if 'ordinality' in d: - ordinality = int(d['ordinality']) + # Item was a dictionary. Check if there is an 'ordinality' value. + ordinality = int(d.pop('ordinality', 1)) - if ordinality == 1: - del d['ordinality'] + # Reinsert it if the value is different than the default + if ordinality != 1: + d['ordinality'] = ordinality # If the only key we have left is ``value``, just return the # corresponding string. From a31b2fdaae0bb47cd0f3f5e955b97c11dace0de3 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 10:22:50 -0400 Subject: [PATCH 017/438] Added docstrings to StructuredTextList --- stix/common/structured_text.py | 37 ++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 85a87929..fc9356dc 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -193,6 +193,10 @@ def __getitem__(self, key): Args: key: An ordinality value. + Raises: + KeyError: If `key` does not match the ordinality of any + :class:`.StructuredText` object. + """ o = int(key) @@ -225,9 +229,16 @@ def __reversed__(self): def add(self, value): """Adds the :class:`StructuredText` `value` to the collection. - If `value` does not have an ``ordinality`` set, one will be assigned. - If `value` has an ordinality which matches one already in the - collection, `value` will replace the existing item. + If `value` is not a :class:`StructuredText` object, an attempt will + be made to convert it to one. + + Note: + If `value` does not have an ``ordinality`` set, one will be + assigned. If `value` has an ordinality which matches one already + in the collection, `value` will replace the existing item. + + Args: + value: A :class:`StructuredText` object. """ if not self._is_valid(value): @@ -245,11 +256,30 @@ def add(self, value): def update(self, iterable): """Adds each item of `iterable` to the collection. + Note: + Any existing objects with conflicting ordinality values will be + overwritten. + + Args: + iterable: An iterable collection of :class:`StructuredText` objects + to add to this collection. + """ for item in iterable: self.add(item) def _shift(self, ordinality): + """Increments the ordinality values on all objects in the collection + that have an ordinality greater than or equal to `ordinality`. + + This is used in ``insert()`` operations. + + Note: + This will only shift contiguous ordinalities, so if the collection + contains the ordinaliities [1,2,6], then _shift(1) would result in + [2,3,6] since 6 is not contiguous with [1,2]. + + """ to_shift = [] for o in itertools.count(ordinality): @@ -276,7 +306,6 @@ def insert(self, value): self._shift(o) self._inner.append(value) - def remove(self, value): """Removes the value from the collection. From 49a03d50d4516149f3ad0da4d81c52df9fb4cbae Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 11:03:09 -0400 Subject: [PATCH 018/438] Added type checking and casting to StructuredTextList.insert() --- stix/common/structured_text.py | 14 ++++++++------ stix/test/common/structured_text_tests.py | 12 ++++++++---- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index fc9356dc..c9c270e3 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -295,16 +295,18 @@ def insert(self, value): """Inserts `value` into the collection. If `value` has an ordinality which conflicts with an existing value, - the existing value (and any contiguous items) will have their + the existing value (and any contiguous values) will have their ordinality values incremented by one. """ + if not self._is_valid(value): + value = self._fix_value(value) + if value.ordinality is None: self.add(value) - - o = value.ordinality - self._shift(o) - self._inner.append(value) + else: + self._shift(value.ordinality) + self._inner.append(value) def remove(self, value): """Removes the value from the collection. @@ -368,7 +370,7 @@ def to_list(self): # Item was a dictionary. Check if there is an 'ordinality' value. ordinality = int(d.pop('ordinality', 1)) - # Reinsert it if the value is different than the default + # Reinsert it if the value is different than the default. if ordinality != 1: d['ordinality'] = ordinality diff --git a/stix/test/common/structured_text_tests.py b/stix/test/common/structured_text_tests.py index 77abf9eb..77a17c6a 100644 --- a/stix/test/common/structured_text_tests.py +++ b/stix/test/common/structured_text_tests.py @@ -92,12 +92,9 @@ def test_add(self): self.assertTrue(st2 in slist) def test_insert(self): - slist = common.StructuredTextList() st1 = common.StructuredText("foo", ordinality=1) st2 = common.StructuredText("bar", ordinality=2) - - slist.add(st1) - slist.add(st2) + slist = common.StructuredTextList(st1, st2) new_st1 = common.StructuredText("foobar", ordinality=1) slist.insert(new_st1) @@ -107,6 +104,13 @@ def test_insert(self): self.assertEqual(st1.ordinality, 2) self.assertEqual(st2.ordinality, 3) + + def test_insert_str(self): + slist = common.StructuredTextList("foo", "bar") + slist.insert("test") + + self.assertEqual(str(slist[3]), "test") + def test_delitem(self): slist = common.StructuredTextList() st1 = common.StructuredText("foo", ordinality=1) From 803104787491ce557a5eb549e02301caa91ae569 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 11:21:06 -0400 Subject: [PATCH 019/438] Added multiple description and short description support to STIXHeader --- stix/base.py | 35 +++++--- stix/bindings/stix_core.py | 30 ++++--- stix/core/stix_header.py | 102 ++++++++++++++++------ stix/test/common/structured_text_tests.py | 2 - stix/test/core/stix_header_test.py | 10 ++- 5 files changed, 127 insertions(+), 52 deletions(-) diff --git a/stix/base.py b/stix/base.py index a74539f2..2368b13a 100644 --- a/stix/base.py +++ b/stix/base.py @@ -689,18 +689,23 @@ def title(self, value): @property def description(self): - """A description about the contents or purpose of this object. + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. - Default Value: ``None`` + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. Note: - If set to a value that is not an instance of - :class:`.StructuredText`, an attempt to will be made to convert - the value into an instance of :class:`.StructuredText`. + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. Returns: An instance of - :class:`.StructuredText` + :class:`.StructuredTextList` """ return next(iter(self.descriptions), None) @@ -720,18 +725,23 @@ def descriptions(self, value): @property def short_description(self): - """A short description about the contents or purpose of this object. + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. - Default Value: ``None`` + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. Note: - If set to a value that is not an instance of - :class:`.StructuredText`, an attempt to will be made to convert - the value into an instance of :class:`.StructuredText`. + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. Returns: An instance of - :class:`.StructuredText` + :class:`.StructuredTextList` """ return next(iter(self.short_descriptions), None) @@ -858,6 +868,7 @@ def to_dict(self): if self.descriptions: d['description'] = self.descriptions.to_dict() + if self.short_descriptions: d['short_description'] = self.short_descriptions.to_dict() diff --git a/stix/bindings/stix_core.py b/stix/bindings/stix_core.py index 9ee8927b..6e2c31a8 100644 --- a/stix/bindings/stix_core.py +++ b/stix/bindings/stix_core.py @@ -373,9 +373,15 @@ def __init__(self, Title=None, Package_Intent=None, Description=None, Short_Desc self.Package_Intent = [] else: self.Package_Intent = Package_Intent - self.Description = Description + if Description is None: + self.Description = [] + else: + self.Description = Description self.Handling = Handling - self.Short_Description = Short_Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description self.Profiles = Profiles self.Information_Source = Information_Source def factory(*args_, **kwargs_): @@ -390,8 +396,12 @@ def get_Package_Intent(self): return self.Package_Intent def set_Package_Intent(self, Package_Intent): self.Package_Intent = Package_Intent def add_Package_Intent(self, value): self.Package_Intent.append(value) def insert_Package_Intent(self, index, value): self.Package_Intent[index] = value + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Profiles(self): return self.Profiles @@ -404,8 +414,8 @@ def hasContent_(self): if ( self.Title is not None or self.Package_Intent or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.Profiles is not None or self.Handling is not None or self.Information_Source is not None @@ -441,10 +451,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='STIXHea lwrite('<%s:Title>%s%s' % (nsmap[namespace_], quote_xml(self.Title), nsmap[namespace_], eol_)) for Package_Intent_ in self.Package_Intent: Package_Intent_.export(lwrite, level, nsmap, namespace_, name_='Package_Intent', pretty_print=pretty_print) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) if self.Profiles is not None: self.Profiles.export(lwrite, level, nsmap, namespace_, name_='Profiles', pretty_print=pretty_print) if self.Handling is not None: @@ -471,11 +481,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Profiles': obj_ = stix_common_binding.ProfilesType.factory() obj_.build(child_) diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index 37afdd5e..f72b4f12 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -2,9 +2,11 @@ # See LICENSE.txt for complete terms. import stix +import stix.utils as utils import stix.bindings.stix_common as stix_common_binding import stix.bindings.stix_core as stix_core_binding -from stix.common import vocabs, InformationSource, StructuredText, VocabString +from stix.common import InformationSource, StructuredTextList, VocabString +from stix.common.vocabs import PackageIntent from stix.data_marking import Marking @@ -25,41 +27,73 @@ def __init__(self, package_intents=None, description=None, handling=None, @property def description(self): - return self._description + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.descriptions), None) @description.setter def description(self, value): - """Sets the value of the description property. + self.descriptions = value - If the value is an instance of basestring, it will be coerced into an - instance of StructuredText, with its 'text' property set to the input - value. + @property + def descriptions(self): + return self._descriptions - """ - self._set_var(StructuredText, description=value) + @descriptions.setter + def descriptions(self, value): + self._descriptions = StructuredTextList(value) @property def short_description(self): - """The ``short_description`` property for this entity. + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. - Default Value: ``None`` + Default Value: Empty :class:`StructuredTextList` object. Note: - If set to a value that is not an instance of - :class:`stix.common.structured_text.StructuredText`, an attempt to - will be made to convert the value into an instance of - :class:`stix.common.structured_text.StructuredText`. + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. Returns: An instance of - :class:`stix.common.structured_text.StructuredText` + :class:`.StructuredTextList` """ - return self._short_description + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): - self._set_var(StructuredText, short_description=value) + self.short_descriptions = value + + @property + def short_descriptions(self): + return self._short_descriptions + + @short_descriptions.setter + def short_descriptions(self, value): + self._short_descriptions = StructuredTextList(value) @property def handling(self): @@ -104,8 +138,8 @@ def from_obj(cls, obj, return_obj=None): return_obj = cls() return_obj.title = obj.Title - return_obj.description = StructuredText.from_obj(obj.Description) - return_obj.short_description = StructuredText.from_obj(obj.Short_Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) + return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) return_obj.handling = Marking.from_obj(obj.Handling) return_obj.information_source = InformationSource.from_obj(obj.Information_Source) return_obj.package_intents = _PackageIntents.from_obj(obj.Package_Intent) @@ -123,10 +157,10 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Title = self.title if self.package_intents: return_obj.Package_Intent = self.package_intents.to_obj(ns_info=ns_info) - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) - if self.short_description: - return_obj.Short_Description = self.short_description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) + if self.short_descriptions: + return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) if self.handling: return_obj.Handling = self.handling.to_obj(ns_info=ns_info) if self.information_source: @@ -148,8 +182,8 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.title = get('title') return_obj.package_intents = _PackageIntents.from_list(get('package_intents')) - return_obj.description = StructuredText.from_dict(get('description')) - return_obj.short_description = StructuredText.from_dict(get('short_description')) + return_obj.descriptions = StructuredTextList.from_dict(get('description')) + return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) return_obj.handling = Marking.from_dict(get('handling')) return_obj.information_source = InformationSource.from_dict(get('information_source')) return_obj.profiles = get('profiles') @@ -157,7 +191,21 @@ def from_dict(cls, dict_repr, return_obj=None): return return_obj def to_dict(self): - return super(STIXHeader, self).to_dict() + skip = ( + 'description', + 'descriptions', + 'short_description', + 'short_descriptions' + ) + + d = utils.to_dict(self, skip=skip) + + if self.descriptions: + d['description'] = self.descriptions.to_dict() + if self.short_descriptions: + d['short_description'] = self.short_descriptions.to_dict() + + return d # NOT AN ACTUAL STIX TYPE! @@ -165,4 +213,4 @@ class _PackageIntents(stix.TypedList): _contained_type = VocabString def _fix_value(self, value): - return vocabs.PackageIntent(value) + return PackageIntent(value) diff --git a/stix/test/common/structured_text_tests.py b/stix/test/common/structured_text_tests.py index 77a17c6a..2c23b5d0 100644 --- a/stix/test/common/structured_text_tests.py +++ b/stix/test/common/structured_text_tests.py @@ -104,11 +104,9 @@ def test_insert(self): self.assertEqual(st1.ordinality, 2) self.assertEqual(st2.ordinality, 3) - def test_insert_str(self): slist = common.StructuredTextList("foo", "bar") slist.insert("test") - self.assertEqual(str(slist[3]), "test") def test_delitem(self): diff --git a/stix/test/core/stix_header_test.py b/stix/test/core/stix_header_test.py index 8001a7af..1dde21aa 100644 --- a/stix/test/core/stix_header_test.py +++ b/stix/test/core/stix_header_test.py @@ -4,7 +4,7 @@ import unittest from stix.test import EntityTestCase, data_marking_test -from stix.test.common import information_source_test +from stix.test.common import information_source_test, structured_text_tests from stix import core @@ -26,5 +26,13 @@ def test_duplicate_package_intent(self): self.assertEqual(1, len(hdr.package_intents)) +class STIXHeaderMultiDescTests(EntityTestCase, unittest.TestCase): + klass = core.STIXHeader + _full_dict = { + 'description': structured_text_tests.StructuredTextListTests._full_dict, + 'short_description': structured_text_tests.StructuredTextListTests._full_dict + } + + if __name__ == "__main__": unittest.main() From 140a957453d325bd98fbbb0627824a2151e627e6 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 13:12:11 -0400 Subject: [PATCH 020/438] Added dict check to TypedCollection.from_list() --- stix/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/base.py b/stix/base.py index 2368b13a..46589dfd 100644 --- a/stix/base.py +++ b/stix/base.py @@ -490,7 +490,7 @@ def from_list(cls, list_repr, contained_type=None): if not list_repr: return None - if not utils.is_sequence(list_repr): + if isinstance(list_repr, dict) or not utils.is_sequence(list_repr): list_repr = [list_repr] if not contained_type: From 656709798165b0e044fcc1c87dd3f87c2a79c829 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 13:12:33 -0400 Subject: [PATCH 021/438] Added multiple description support to Generic COA extension. --- .../extensions/structured_coa/generic.py | 15 ++-- .../structured_coa/generic_structured_coa.py | 87 +++++++++++++++++-- 2 files changed, 89 insertions(+), 13 deletions(-) diff --git a/stix/bindings/extensions/structured_coa/generic.py b/stix/bindings/extensions/structured_coa/generic.py index a7cd6b87..52c47949 100644 --- a/stix/bindings/extensions/structured_coa/generic.py +++ b/stix/bindings/extensions/structured_coa/generic.py @@ -32,7 +32,10 @@ def __init__(self, idref=None, id=None, reference_location=None, Description=Non self.xmlns_prefix = "genericStructuredCOA" self.xml_type = "GenericStructuredCOAType" self.reference_location = _cast(None, reference_location) - self.Description = Description + if Description is None: + self.Description = [] + else: + self.Description = Description self.Type = Type self.Specification = Specification def factory(*args_, **kwargs_): @@ -41,6 +44,8 @@ def factory(*args_, **kwargs_): else: return GenericStructuredCOAType(*args_, **kwargs_) factory = staticmethod(factory) + def add_Description(self, Description): self.Description.append(Description) + def insert_Description(self, index, Description): self.Description[index] = Description def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description def get_Type(self): return self.Type @@ -51,7 +56,7 @@ def get_reference_location(self): return self.reference_location def set_reference_location(self, reference_location): self.reference_location = reference_location def hasContent_(self): if ( - self.Description is not None or + self.Description or self.Type is not None or self.Specification is not None or super(GenericStructuredCOAType, self).hasContent_() @@ -94,8 +99,8 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Generic eol_ = '\n' else: eol_ = '' - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) if self.Type is not None: self.Type.export(lwrite, level, nsmap, namespace_, name_='Type', pretty_print=pretty_print) if self.Specification is not None: @@ -116,7 +121,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Type': obj_ = stix_common_binding.ControlledVocabularyStringType.factory() obj_.build(child_) diff --git a/stix/extensions/structured_coa/generic_structured_coa.py b/stix/extensions/structured_coa/generic_structured_coa.py index c83ee5c2..af476ba5 100644 --- a/stix/extensions/structured_coa/generic_structured_coa.py +++ b/stix/extensions/structured_coa/generic_structured_coa.py @@ -4,7 +4,7 @@ import stix import stix.utils import stix.coa.structured_coa -from stix.common import EncodedCDATA, StructuredText, VocabString +from stix.common import EncodedCDATA, StructuredTextList, VocabString from stix.coa.structured_coa import _BaseStructuredCOA import stix.bindings.extensions.structured_coa.generic as generic_structured_coa_binding @@ -32,11 +32,78 @@ def specification(self, value): @property def description(self): - return self._description + """A single description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If this object has more than one description set, this will return + the description with the lowest ordinality value. + + Returns: + An instance of + :class:`.StructuredText` + + """ + return next(iter(self.descriptions), None) @description.setter def description(self, value): - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return self._descriptions + + @descriptions.setter + def descriptions(self, value): + self._descriptions = StructuredTextList(value) + + @property + def descriptions(self): + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return self._descriptions + + @descriptions.setter + def descriptions(self, value): + self._descriptions = StructuredTextList(value) @property def type_(self): @@ -56,7 +123,7 @@ def from_obj(cls, obj, return_obj=None): super(GenericStructuredCOA, cls).from_obj(obj, return_obj) return_obj.reference_location = obj.reference_location - return_obj.description = StructuredText.from_obj(obj.Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) return_obj.type_ = VocabString.from_obj(obj.Type) return_obj.specification = EncodedCDATA.from_obj(obj.Specification) @@ -69,8 +136,8 @@ def to_obj(self, return_obj=None, ns_info=None): super(GenericStructuredCOA, self).to_obj(return_obj=return_obj, ns_info=ns_info) if self.reference_location: return_obj.reference_location = self.reference_location - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) if self.type_: return_obj.Type = self.type_.to_obj(ns_info=ns_info) if self.specification: @@ -87,15 +154,19 @@ def from_dict(cls, d, return_obj=None): super(GenericStructuredCOA, cls).from_dict(d, return_obj) return_obj.reference_location = d.get('reference_location') - return_obj.description = StructuredText.from_dict(d.get('description')) + return_obj.descriptions = StructuredTextList.from_dict(d.get('description')) return_obj.type_ = VocabString.from_dict(d.get('type')) return_obj.specification = EncodedCDATA.from_dict(d.get('specification')) return return_obj def to_dict(self): - return super(GenericStructuredCOA, self).to_dict() + d = super(GenericStructuredCOA, self).to_dict() + + if 'descriptions' in d: + d['description'] = d.pop('descriptions') + return d # Register the extension stix.coa.structured_coa.add_extension(GenericStructuredCOA) From ec94962e5dda60a966314f0b6c2e0576b3d638b5 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 15:41:59 -0400 Subject: [PATCH 022/438] More support for multiple descriptions and short_descriptions. * Added fix_descriptions() utility method. --- stix/base.py | 16 +--- stix/bindings/course_of_action.py | 31 +++++-- stix/bindings/exploit_target.py | 77 +++++++++++------ .../extensions/test_mechanism/generic.py | 15 ++-- stix/coa/objective.py | 80 ++++++++++++++---- stix/common/activity.py | 7 +- stix/common/confidence.py | 2 +- stix/common/information_source.py | 7 +- stix/common/statement.py | 2 +- stix/exploit_target/configuration.py | 83 +++++++++++------- stix/exploit_target/vulnerability.py | 84 ++++++++++++------- stix/exploit_target/weakness.py | 47 +++++++---- .../structured_coa/generic_structured_coa.py | 6 +- .../test_mechanism/generic_test_mechanism.py | 73 +++++++++++----- stix/incident/affected_asset.py | 75 +++++++++++++---- stix/utils/__init__.py | 24 ++++++ 16 files changed, 438 insertions(+), 191 deletions(-) diff --git a/stix/base.py b/stix/base.py index 46589dfd..a547a42f 100644 --- a/stix/base.py +++ b/stix/base.py @@ -857,20 +857,10 @@ def from_dict(cls, d, return_obj=None): return return_obj def to_dict(self): - skip = ( - 'description', - 'descriptions', - 'short_description', - 'short_descriptions' - ) - - d = utils.to_dict(self, skip=skip) + d = utils.to_dict(self) - if self.descriptions: - d['description'] = self.descriptions.to_dict() - - if self.short_descriptions: - d['short_description'] = self.short_descriptions.to_dict() + # Rename 'descriptions' and 'short_descriptions' keys. + utils.fix_descriptions(d) return d diff --git a/stix/bindings/course_of_action.py b/stix/bindings/course_of_action.py index 6dc139ad..13e8e584 100644 --- a/stix/bindings/course_of_action.py +++ b/stix/bindings/course_of_action.py @@ -123,8 +123,16 @@ class ObjectiveType(GeneratedsSuper): subclass = None superclass = None def __init__(self, Description=None, Short_Description=None, Applicability_Confidence=None): - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description + self.Applicability_Confidence = Applicability_Confidence def factory(*args_, **kwargs_): if ObjectiveType.subclass: @@ -132,15 +140,20 @@ def factory(*args_, **kwargs_): else: return ObjectiveType(*args_, **kwargs_) factory = staticmethod(factory) + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Applicability_Confidence(self): return self.Applicability_Confidence def set_Applicability_Confidence(self, Applicability_Confidence): self.Applicability_Confidence = Applicability_Confidence def hasContent_(self): if ( - self.Description is not None or + self.Description or + self.Short_Description or self.Applicability_Confidence is not None ): return True @@ -169,10 +182,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Objecti eol_ = '\n' else: eol_ = '' - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) if self.Applicability_Confidence is not None: self.Applicability_Confidence.export(lwrite, level, nsmap, namespace_, name_='Applicability_Confidence', pretty_print=pretty_print) def build(self, node): @@ -187,11 +200,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Applicability_Confidence': obj_ = stix_common_binding.ConfidenceType.factory() obj_.build(child_) diff --git a/stix/bindings/exploit_target.py b/stix/bindings/exploit_target.py index ed766841..86b05da9 100644 --- a/stix/bindings/exploit_target.py +++ b/stix/bindings/exploit_target.py @@ -43,8 +43,15 @@ def __init__(self, is_publicly_acknowledged=None, is_known=None, Title=None, Des self.is_publicly_acknowledged = _cast(bool, is_publicly_acknowledged) self.is_known = _cast(bool, is_known) self.Title = Title - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description self.CVE_ID = CVE_ID self.OSVDB_ID = OSVDB_ID self.Source = Source @@ -61,8 +68,12 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Title(self): return self.Title def set_Title(self, Title): self.Title = Title + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_CVE_ID(self): return self.CVE_ID @@ -88,8 +99,8 @@ def set_is_known(self, is_known): self.is_known = is_known def hasContent_(self): if ( self.Title is not None or - self.Description is not None or - self.Short_Description is not None or + self.Description or + self.Short_Description or self.CVE_ID is not None or self.OSVDB_ID is not None or self.Source is not None or @@ -133,10 +144,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Vulnera if self.Title is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:Title>%s%s' % (nsmap[namespace_], quote_xml(self.Title), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) if self.CVE_ID is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:CVE_ID>%s%s' % (nsmap[namespace_],quote_xml(self.CVE_ID), nsmap[namespace_], eol_)) @@ -189,11 +200,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'CVE_ID': CVE_ID_ = child_.text CVE_ID_ = self.gds_validate_string(CVE_ID_, node, 'CVE_ID') @@ -238,8 +249,16 @@ class ConfigurationType(GeneratedsSuper): subclass = None superclass = None def __init__(self, Description=None, Short_Description=None, CCE_ID=None): - self.Short_Description = Short_Description - self.Description = Description + if Description is None: + self.Description = [] + else: + self.Description = Description + + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description + self.CCE_ID = CCE_ID def factory(*args_, **kwargs_): if ConfigurationType.subclass: @@ -247,15 +266,20 @@ def factory(*args_, **kwargs_): else: return ConfigurationType(*args_, **kwargs_) factory = staticmethod(factory) + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_CCE_ID(self): return self.CCE_ID def set_CCE_ID(self, CCE_ID): self.CCE_ID = CCE_ID def hasContent_(self): if ( - self.Description is not None or + self.Description or + self.Short_Description or self.CCE_ID is not None ): return True @@ -284,10 +308,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Configu eol_ = '\n' else: eol_ = '' - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) if self.CCE_ID is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:CCE_ID>%s%s' % (nsmap[namespace_], quote_xml(self.CCE_ID), nsmap[namespace_], eol_)) @@ -303,11 +327,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) if nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'CCE_ID': CCE_ID_ = child_.text CCE_ID_ = self.gds_validate_string(CCE_ID_, node, 'CCE_ID') @@ -457,7 +481,10 @@ class WeaknessType(GeneratedsSuper): subclass = None superclass = None def __init__(self, Description=None, CWE_ID=None): - self.Description = Description + if Description is None: + self.Description = [] + else: + self.Description = Description self.CWE_ID = CWE_ID def factory(*args_, **kwargs_): if WeaknessType.subclass: @@ -465,13 +492,15 @@ def factory(*args_, **kwargs_): else: return WeaknessType(*args_, **kwargs_) factory = staticmethod(factory) + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description def get_CWE_ID(self): return self.CWE_ID def set_CWE_ID(self, CWE_ID): self.CWE_ID = CWE_ID def hasContent_(self): if ( - self.Description is not None or + self.Description or self.CWE_ID is not None ): return True @@ -500,8 +529,8 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Weaknes eol_ = '\n' else: eol_ = '' - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) if self.CWE_ID is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:CWE_ID>%s%s' % (nsmap[namespace_], quote_xml(self.CWE_ID), nsmap[namespace_], eol_)) @@ -517,7 +546,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'CWE_ID': CWE_ID_ = child_.text CWE_ID_ = self.gds_validate_string(CWE_ID_, node, 'CWE_ID') diff --git a/stix/bindings/extensions/test_mechanism/generic.py b/stix/bindings/extensions/test_mechanism/generic.py index 8afd5efd..e84b01aa 100644 --- a/stix/bindings/extensions/test_mechanism/generic.py +++ b/stix/bindings/extensions/test_mechanism/generic.py @@ -32,7 +32,10 @@ def __init__(self, idref=None, id=None, Efficacy=None, Producer=None, reference_ self.xmlns_prefix = "genericTM" self.xml_type = "GenericTestMechanismType" self.reference_location = _cast(None, reference_location) - self.Description = Description + if Description is None: + self.Description = [] + else: + self.Description = Description self.Type = Type self.Specification = Specification def factory(*args_, **kwargs_): @@ -41,6 +44,8 @@ def factory(*args_, **kwargs_): else: return GenericTestMechanismType(*args_, **kwargs_) factory = staticmethod(factory) + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description def get_Type(self): return self.Type @@ -51,7 +56,7 @@ def get_reference_location(self): return self.reference_location def set_reference_location(self, reference_location): self.reference_location = reference_location def hasContent_(self): if ( - self.Description is not None or + self.Description or self.Type is not None or self.Specification is not None or super(GenericTestMechanismType, self).hasContent_() @@ -94,8 +99,8 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Generic eol_ = '\n' else: eol_ = '' - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) if self.Type is not None: self.Type.export(lwrite, level, nsmap, namespace_, name_='Type', pretty_print=pretty_print) if self.Specification is not None: @@ -116,7 +121,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Type': obj_ = stix_common_binding.ControlledVocabularyStringType.factory() obj_.build(child_) diff --git a/stix/coa/objective.py b/stix/coa/objective.py index 1dc9d405..35886570 100644 --- a/stix/coa/objective.py +++ b/stix/coa/objective.py @@ -2,7 +2,8 @@ # See LICENSE.txt for complete terms. import stix -from stix.common import StructuredText, Confidence +import stix.utils as utils +from stix.common import StructuredTextList, Confidence import stix.bindings.course_of_action as coa_binding @@ -18,19 +19,66 @@ def __init__(self, description=None, short_description=None): @property def description(self): - return self._description + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.descriptions), None) @description.setter def description(self, value): - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + return self._descriptions + + @descriptions.setter + def descriptions(self, value): + from stix.common import StructuredTextList + self._descriptions = StructuredTextList(value) @property def short_description(self): - return self._short_description + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): - self._set_var(StructuredText, short_description=value) + self.short_descriptions = value @property def applicability_confidence(self): @@ -46,10 +94,10 @@ def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) - if self.short_description: - return_obj.Short_Description = self.short_description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) + if self.short_descriptions: + return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) if self.applicability_confidence: return_obj.Applicability_Confidence = self.applicability_confidence.to_obj(ns_info=ns_info) @@ -62,13 +110,17 @@ def from_obj(cls, obj, return_obj=None): if not return_obj: return_obj = cls() - return_obj.description = StructuredText.from_obj(obj.Description) - return_obj.short_description = StructuredText.from_obj(obj.Short_Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) + return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) return_obj.applicability_confidence = Confidence.from_obj(obj.Applicability_Confidence) return return_obj def to_dict(self): - return super(Objective, self).to_dict() + d = super(Objective, self).to_dict() + + utils.fix_descriptions(d) + + return d @classmethod def from_dict(cls, dict_repr, return_obj=None): @@ -78,8 +130,8 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj = cls() get = dict_repr.get - return_obj.description = StructuredText.from_dict(get('description')) - return_obj.short_description = StructuredText.from_dict(get('short_description')) + return_obj.description = StructuredTextList.from_dict(get('description')) + return_obj.short_description = StructuredTextList.from_dict(get('short_description')) return_obj.applicability_confidence = Confidence.from_dict(get('applicability_confidence')) return return_obj diff --git a/stix/common/activity.py b/stix/common/activity.py index 688843c7..8d343943 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -101,11 +101,10 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - skip = ('description', 'descriptions') - d = utils.to_dict(self, skip=skip) + d = utils.to_dict(self) - if self.descriptions: - d['description'] = self.descriptions.to_dict() + # Rename 'descriptions' key. + utils.fix_descriptions(d) return d diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 8cb50388..236c7cc9 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -124,7 +124,7 @@ def to_obj(self, return_obj=None, ns_info=None): return obj def to_dict(self): - skip = ('timestamp_precision', 'description', 'descriptions') + skip = ('timestamp_precision', 'descriptions') d = utils.to_dict(self, skip=skip) if self.timestamp_precision != 'second': diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 96d6c2ec..3d906d7b 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -216,11 +216,10 @@ def from_dict(cls, dict_repr, return_obj=None): return return_obj def to_dict(self): - skip = ('description', 'descriptions') - d = utils.to_dict(self, skip=skip) + d = utils.to_dict(self) - if self.descriptions: - d['description'] = self.descriptions.to_dict() + # Rename 'descriptions' key. + utils.fix_descriptions(d) return d diff --git a/stix/common/statement.py b/stix/common/statement.py index 6880dccc..474f8df0 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -119,7 +119,7 @@ def to_obj(self, return_obj=None, ns_info=None): return obj def to_dict(self): - skip = ('timestamp_precision', 'description', 'descriptions') + skip = ('timestamp_precision', 'descriptions') d = utils.to_dict(self, skip=skip) if self.timestamp_precision != 'second': diff --git a/stix/exploit_target/configuration.py b/stix/exploit_target/configuration.py index 45a624ed..6a8c5d13 100644 --- a/stix/exploit_target/configuration.py +++ b/stix/exploit_target/configuration.py @@ -2,8 +2,9 @@ # See LICENSE.txt for complete terms. import stix +import stix.utils as utils +from stix.common import StructuredTextList import stix.bindings.exploit_target as exploit_target_binding -from stix.common import StructuredText class Configuration(stix.Entity): @@ -26,49 +27,66 @@ def __init__(self, description=None, short_description=None, cce_id=None): @property def description(self): - """The ``description`` property for this :class:`Configuration`. + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. - Default Value: ``None`` + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. Note: - If set to a value that is not an instance of - :class:`stix.common.structured_text.StructuredText`, an attempt to - will be made to convert the value into an instance of - :class:`stix.common.structured_text.StructuredText`. + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. Returns: An instance of - :class:`stix.common.structured_text.StructuredText` + :class:`.StructuredTextList` """ - return self._description + return next(iter(self.descriptions), None) @description.setter def description(self, value): - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + return self._descriptions + + @descriptions.setter + def descriptions(self, value): + from stix.common import StructuredTextList + self._descriptions = StructuredTextList(value) @property def short_description(self): - return self._short_description + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. - @short_description.setter - def short_description(self, value): - """The ``short_description`` property for this :class:`Configuration`. + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. - Default Value: ``None`` + Default Value: Empty :class:`StructuredTextList` object. Note: - If set to a value that is not an instance of - :class:`stix.common.structured_text.StructuredText`, an attempt to - will be made to convert the value into an instance of - :class:`stix.common.structured_text.StructuredText`. + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. Returns: An instance of - :class:`stix.common.structured_text.StructuredText` + :class:`.StructuredTextList` """ - self._set_var(StructuredText, short_description=value) + return next(iter(self.short_descriptions), None) + + @short_description.setter + def short_description(self, value): + self.short_descriptions = value @property def cce_id(self): @@ -91,10 +109,10 @@ def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) - if self.short_description: - return_obj.Short_Description = self.short_description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) + if self.short_descriptions: + return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) return_obj.CCE_ID = self.cce_id return return_obj @@ -107,14 +125,19 @@ def from_obj(cls, obj, return_obj=None): if not return_obj: return_obj = cls() - return_obj.description = StructuredText.from_obj(obj.Description) - return_obj.short_description = StructuredText.from_obj(obj.Short_Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) + return_obj.short_description = StructuredTextList.from_obj(obj.Short_Description) return_obj.cce_id = obj.CCE_ID return return_obj def to_dict(self): - return super(Configuration, self).to_dict() + d = super(Configuration, self).to_dict() + + # Rename 'descriptions' and 'short_descriptions' keys. + utils.fix_descriptions(d) + + return d @classmethod def from_dict(cls, dict_repr, return_obj=None): @@ -125,8 +148,8 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj = cls() get = dict_repr.get - return_obj.description = StructuredText.from_dict(get('description')) - return_obj.short_description = StructuredText.from_dict(get('short_description')) + return_obj.descriptions = StructuredTextList.from_dict(get('description')) + return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) return_obj.cce_id = get('cce_id') return return_obj diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index 0d8702bf..27943a21 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -5,7 +5,7 @@ import stix.utils as utils import stix.bindings.exploit_target as exploit_target_binding import stix.bindings.stix_common as stix_common_binding -from stix.common import DateTimeWithPrecision, StructuredText +from stix.common import DateTimeWithPrecision, StructuredTextList from stix.common.related import GenericRelationshipList, RelatedObservable @@ -52,50 +52,74 @@ def title(self, value): @property def description(self): - """The ``description`` property for this :class:`Vulnerability`. + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. - Default Value: ``None`` + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. Note: - If set to a value that is not an instance of - :class:`stix.common.structured_text.StructuredText`, an attempt to - will be made to convert the value into an instance of - :class:`stix.common.structured_text.StructuredText`. + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. Returns: An instance of - :class:`stix.common.structured_text.StructuredText` + :class:`.StructuredTextList` """ - - return self._description + return next(iter(self.descriptions), None) @description.setter def description(self, value): - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + return self._descriptions + + @descriptions.setter + def descriptions(self, value): + self._descriptions = StructuredTextList(value) @property def short_description(self): - """The ``short_description`` property for this :class:`Vulnerability`. + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. - Default Value: ``None`` + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. Note: - If set to a value that is not an instance of - :class:`stix.common.structured_text.StructuredText`, an attempt to - will be made to convert the value into an instance of - :class:`stix.common.structured_text.StructuredText`. + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. Returns: An instance of - :class:`stix.common.structured_text.StructuredText` + :class:`.StructuredTextList` """ - return self._short_description + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): - self._set_var(StructuredText, short_description=value) + self.short_descriptions = value + + @property + def short_descriptions(self): + return self._short_descriptions + + @short_descriptions.setter + def short_descriptions(self, value): + from stix.common import StructuredTextList + self._short_descriptions = StructuredTextList(value) @property def discovered_datetime(self): @@ -154,10 +178,10 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.is_known = utils.xml_bool(self.is_known) return_obj.is_publicly_acknowledged = utils.xml_bool(self.is_publicly_acknowledged) - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) - if self.short_description: - return_obj.Short_Description = self.short_description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) + if self.short_descriptions: + return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) if self.cvss_score: return_obj.CVSS_Score = self.cvss_score.to_obj(ns_info=ns_info) if self.discovered_datetime: @@ -181,8 +205,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.is_known = utils.xml_bool(obj.is_known) return_obj.is_publicly_acknowledged = utils.xml_bool(obj.is_publicly_acknowledged) return_obj.title = obj.Title - return_obj.description = StructuredText.from_obj(obj.Description) - return_obj.short_description = StructuredText.from_obj(obj.Short_Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) + return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) return_obj.cve_id = obj.CVE_ID return_obj.osvdb_id = obj.OSVDB_ID return_obj.source = obj.Source @@ -197,7 +221,9 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - return super(Vulnerability, self).to_dict() + d = super(Vulnerability, self).to_dict() + utils.fix_descriptions(d) + return d @classmethod def from_dict(cls, dict_repr, return_obj=None): @@ -210,8 +236,8 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.is_known = utils.xml_bool(get('is_known')) return_obj.is_publicly_acknowledged = utils.xml_bool(get('is_publicly_acknowledged')) return_obj.title = get('title') - return_obj.description = StructuredText.from_dict(get('description')) - return_obj.short_description = StructuredText.from_dict(get('short_description')) + return_obj.descriptions = StructuredTextList.from_dict(get('description')) + return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) return_obj.cve_id = get('cve_id') return_obj.osvdb_id = get('osvdb_id') return_obj.source = get('source') diff --git a/stix/exploit_target/weakness.py b/stix/exploit_target/weakness.py index fce3607f..aa9d2c4c 100644 --- a/stix/exploit_target/weakness.py +++ b/stix/exploit_target/weakness.py @@ -2,8 +2,9 @@ # See LICENSE.txt for complete terms. import stix +import stix.utils as utils import stix.bindings.exploit_target as exploit_target_binding -from stix.common import StructuredText +from stix.common import StructuredTextList class Weakness(stix.Entity): @@ -35,26 +36,38 @@ def cwe_id(self, value): @property def description(self): - """The ``description`` property for this :class:`Weakness`. + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. - Default Value: ``None`` + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. Note: - If set to a value that is not an instance of - :class:`stix.common.structured_text.StructuredText`, an attempt to - will be made to convert the value into an instance of - :class:`stix.common.structured_text.StructuredText`. + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. Returns: An instance of - :class:`stix.common.structured_text.StructuredText` + :class:`.StructuredTextList` """ - return self._description + return next(iter(self.descriptions), None) @description.setter def description(self, value): - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + return self._descriptions + + @descriptions.setter + def descriptions(self, value): + self._descriptions = StructuredTextList(value) def to_obj(self, return_obj=None, ns_info=None): super(Weakness, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -62,8 +75,8 @@ def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) return_obj.CWE_ID = self.cwe_id return return_obj @@ -75,13 +88,17 @@ def from_obj(cls, obj, return_obj=None): if not return_obj: return_obj = cls() - return_obj.description = StructuredText.from_obj(obj.Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) return_obj.cwe_id = obj.CWE_ID return return_obj def to_dict(self): - return super(Weakness, self).to_dict() + d = super(Weakness, self).to_dict() + + utils.fix_descriptions(d) + + return d @classmethod def from_dict(cls, dict_repr, return_obj=None): @@ -90,7 +107,7 @@ def from_dict(cls, dict_repr, return_obj=None): if not return_obj: return_obj = cls() - return_obj.description = StructuredText.from_dict(dict_repr.get('description')) + return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) return_obj.cwe_id = dict_repr.get('cwe_id') return return_obj diff --git a/stix/extensions/structured_coa/generic_structured_coa.py b/stix/extensions/structured_coa/generic_structured_coa.py index af476ba5..2bef7a2e 100644 --- a/stix/extensions/structured_coa/generic_structured_coa.py +++ b/stix/extensions/structured_coa/generic_structured_coa.py @@ -2,7 +2,7 @@ # See LICENSE.txt for complete terms. import stix -import stix.utils +import stix.utils as utils import stix.coa.structured_coa from stix.common import EncodedCDATA, StructuredTextList, VocabString from stix.coa.structured_coa import _BaseStructuredCOA @@ -163,8 +163,8 @@ def from_dict(cls, d, return_obj=None): def to_dict(self): d = super(GenericStructuredCOA, self).to_dict() - if 'descriptions' in d: - d['description'] = d.pop('descriptions') + # Rename 'descriptions' key. + utils.fix_descriptions(d) return d diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index f0edba67..5a938a51 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -2,9 +2,9 @@ # See LICENSE.txt for complete terms. import stix -import stix.utils +import stix.utils as utils import stix.indicator.test_mechanism -from stix.common import EncodedCDATA, StructuredText, VocabString +from stix.common import EncodedCDATA, StructuredTextList, VocabString from stix.indicator.test_mechanism import _BaseTestMechanism import stix.bindings.extensions.test_mechanism.generic as generic_tm_binding @@ -37,16 +37,51 @@ def specification(self, value): @property def description(self): - return self._description - + """A single description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If this object has more than one description set, this will return + the description with the lowest ordinality value. + + Returns: + An instance of + :class:`.StructuredText` + + """ + return next(iter(self.descriptions), None) + @description.setter def description(self, value): - if not value: - self._description = None - elif isinstance(value, StructuredText): - self._description = value - else: - self._description = StructuredText(value) + self.descriptions = value + + @property + def descriptions(self): + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return self._descriptions + + @descriptions.setter + def descriptions(self, value): + self._descriptions = StructuredTextList(value) @property def type_(self): @@ -70,7 +105,7 @@ def from_obj(cls, obj, return_obj=None): super(GenericTestMechanism, cls).from_obj(obj, return_obj) return_obj.reference_location = obj.reference_location - return_obj.description = StructuredText.from_obj(obj.Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) return_obj.type_ = VocabString.from_obj(obj.Type) return_obj.specification = EncodedCDATA.from_obj(obj.Specification) @@ -84,7 +119,7 @@ def to_obj(self, return_obj=None, ns_info=None): if self.reference_location: return_obj.reference_location = self.reference_location if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) if self.type_: return_obj.Type = self.type_.to_obj(ns_info=ns_info) if self.specification: @@ -101,7 +136,7 @@ def from_dict(cls, d, return_obj=None): super(GenericTestMechanism, cls).from_dict(d, return_obj) return_obj.reference_location = d.get('reference_location') - return_obj.description = StructuredText.from_dict(d.get('description')) + return_obj.descriptions = StructuredTextList.from_dict(d.get('description')) return_obj.type_ = VocabString.from_dict(d.get('type')) return_obj.specification = EncodedCDATA.from_dict(d.get('specification')) @@ -109,15 +144,9 @@ def from_dict(cls, d, return_obj=None): def to_dict(self): d = super(GenericTestMechanism, self).to_dict() - - if self.reference_location: - d['reference_location'] = self.reference_location - if self.description: - d['description'] = self.description.to_dict() - if self.type_: - d['type'] = self.type_.to_dict() - if self.specification: - d['specification'] = self.specification.to_dict() + + # Rename 'descriptions' key. + utils.fix_descriptions(d) return d diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index 2a5dac02..78547067 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -6,7 +6,8 @@ # internal import stix -from stix.common import vocabs, VocabString, StructuredText +import stix.utils as utils +from stix.common import vocabs, VocabString, StructuredTextList import stix.bindings.incident as incident_binding # relative @@ -36,23 +37,58 @@ def type_(self): @type_.setter def type_(self, value): self._set_var(AssetType, type=value) - + @property def description(self): - return self._description - + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.descriptions), None) + @description.setter def description(self, value): - self._set_var(StructuredText, description=value) - + self.descriptions = value + + @property + def descriptions(self): + return self._descriptions + + @descriptions.setter + def descriptions(self, value): + self._descriptions = StructuredTextList(value) + @property def business_function_or_role(self): - return self._business_function_or_role - + return next(iter(self.business_functions_or_roles), None) + @business_function_or_role.setter def business_function_or_role(self, value): - self._set_var(StructuredText, business_function_or_role=value) - + self.business_functions_or_roles = value + + @property + def business_functions_or_roles(self): + return self._business_functions_or_roles + + @business_functions_or_roles.setter + def business_functions_or_roles(self, value): + self._business_functions_or_roles = StructuredTextList(value) + @property def ownership_class(self): return self._ownership_class @@ -104,8 +140,8 @@ def from_obj(cls, obj, return_obj=None): return_obj = cls() return_obj.type_ = AssetType.from_obj(obj.Type) - return_obj.description = StructuredText.from_obj(obj.Description) - return_obj.business_function_or_role = StructuredText.from_obj(obj.Business_Function_Or_Role) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) + return_obj.business_functions_or_roles = StructuredTextList.from_obj(obj.Business_Function_Or_Role) return_obj.ownership_class = VocabString.from_obj(obj.Ownership_Class) return_obj.management_class = VocabString.from_obj(obj.Management_Class) return_obj.location_class = VocabString.from_obj(obj.Location_Class) @@ -127,8 +163,8 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Type = self.type_.to_obj(ns_info=ns_info) if self.description: return_obj.Description = self.description.to_obj(ns_info=ns_info) - if self.business_function_or_role: - return_obj.Business_Function_Or_Role = self.business_function_or_role.to_obj(ns_info=ns_info) + if self.business_functions_or_roles: + return_obj.Business_Function_Or_Role = self.business_functions_or_roles.to_obj(ns_info=ns_info) if self.ownership_class: return_obj.Ownership_Class = self.ownership_class.to_obj(ns_info=ns_info) if self.management_class: @@ -155,8 +191,8 @@ def from_dict(cls, d, return_obj=None): get = d.get return_obj.type_ = AssetType.from_dict(get('type')) - return_obj.description = StructuredText.from_dict(get('description')) - return_obj.business_function_or_role = StructuredText.from_dict(get('business_function_or_role')) + return_obj.description = StructuredTextList.from_dict(get('description')) + return_obj.business_functions_or_roles = StructuredTextList.from_dict(get('business_function_or_role')) return_obj.ownership_class = VocabString.from_dict(get('ownership_class')) return_obj.management_class = VocabString.from_dict(get('management_class')) return_obj.location_class = VocabString.from_dict(get('location_class')) @@ -166,8 +202,13 @@ def from_dict(cls, d, return_obj=None): return return_obj def to_dict(self): - return super(AffectedAsset, self).to_dict() + d = super(AffectedAsset, self).to_dict() + utils.fix_descriptions(d) + if 'business_functions_or_roles' in d: + d['business_function_or_role'] = d.pop('business_functions_or_roles') + + return d class AssetType(VocabString): _namespace = "http://stix.mitre.org/Incident-1" diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index b1800539..7a52ebcd 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -339,6 +339,30 @@ def remove_entries(map, keys): map.pop(key, None) +def fix_descriptions(d): + """Renames 'descriptions` and 'short_descriptions` keys to 'description' + and 'short_description' on the input dictionary. + + Dictionaries returned by ``to_dict()`` which are created by inspecting the + entity instance variables will produce the plural key forms. + + For backwards compatibility, we need to convert these keys to their + singular forms. + + Note: + This modification is applied to the input dictionary. + + Args: + d: An Entity dictionary. + + """ + if 'descriptions' in d: + d['description'] = d.pop('descriptions') + + if 'short_descriptions' in d: + d['short_description'] = d.pop('short_descriptions') + + # Namespace flattening from .nsparser import * # noqa from .dates import * # noqa From 64d510462a5ec68a85c8b4470b332db034faf721 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 15:44:48 -0400 Subject: [PATCH 023/438] Added missing short_descriptions properties --- stix/coa/objective.py | 8 ++++++++ stix/exploit_target/configuration.py | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/stix/coa/objective.py b/stix/coa/objective.py index 35886570..a07ecb7f 100644 --- a/stix/coa/objective.py +++ b/stix/coa/objective.py @@ -80,6 +80,14 @@ def short_description(self): def short_description(self, value): self.short_descriptions = value + @property + def short_descriptions(self): + return self._short_descriptions + + @short_descriptions.setter + def short_descriptions(self, value): + self._short_descriptions = StructuredTextList(value) + @property def applicability_confidence(self): return self._applicability_confidence diff --git a/stix/exploit_target/configuration.py b/stix/exploit_target/configuration.py index 6a8c5d13..2eb38861 100644 --- a/stix/exploit_target/configuration.py +++ b/stix/exploit_target/configuration.py @@ -88,6 +88,14 @@ def short_description(self): def short_description(self, value): self.short_descriptions = value + @property + def short_descriptions(self): + return self._short_descriptions + + @short_descriptions.setter + def short_descriptions(self, value): + self._short_descriptions = StructuredTextList(value) + @property def cce_id(self): """Common Configuration Enumeration value for this :class:`Configuration`. From c94bdfbe003f2815cfb23934a5cbdeb19d19a52f Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 16:44:22 -0400 Subject: [PATCH 024/438] Added multi description of effect support to PropertyEffected. --- stix/bindings/incident.py | 15 +++++++---- stix/incident/property_affected.py | 43 ++++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/stix/bindings/incident.py b/stix/bindings/incident.py index 3ea99554..27e392bb 100644 --- a/stix/bindings/incident.py +++ b/stix/bindings/incident.py @@ -25,7 +25,10 @@ class PropertyAffectedType(GeneratedsSuper): superclass = None def __init__(self, Property=None, Description_Of_Effect=None, Type_Of_Availability_Loss=None, Duration_Of_Availability_Loss=None, Non_Public_Data_Compromised=None): self.Property = Property - self.Description_Of_Effect = Description_Of_Effect + if Description_Of_Effect is None: + self.Description_Of_Effect = [] + else: + self.Description_Of_Effect = Description_Of_Effect self.Type_Of_Availability_Loss = Type_Of_Availability_Loss self.Duration_Of_Availability_Loss = Duration_Of_Availability_Loss self.Non_Public_Data_Compromised = Non_Public_Data_Compromised @@ -37,6 +40,8 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Property(self): return self.Property def set_Property(self, Property): self.Property = Property + def insert_Description_Of_Effect(self, index, value): self.Description_Of_Effect[index] = value + def add_Description_Of_Effect(self, value): self.Description_Of_Effect.append(value) def get_Description_Of_Effect(self): return self.Description_Of_Effect def set_Description_Of_Effect(self, Description_Of_Effect): self.Description_Of_Effect = Description_Of_Effect def get_Type_Of_Availability_Loss(self): return self.Type_Of_Availability_Loss @@ -48,7 +53,7 @@ def set_Non_Public_Data_Compromised(self, Non_Public_Data_Compromised): self.Non def hasContent_(self): if ( self.Property is not None or - self.Description_Of_Effect is not None or + self.Description_Of_Effect or self.Type_Of_Availability_Loss is not None or self.Duration_Of_Availability_Loss is not None or self.Non_Public_Data_Compromised is not None @@ -81,8 +86,8 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Propert eol_ = '' if self.Property is not None: self.Property.export(lwrite, level, nsmap, namespace_, name_='Property', pretty_print=pretty_print) - if self.Description_Of_Effect is not None: - self.Description_Of_Effect.export(lwrite, level, nsmap, namespace_, name_='Description_Of_Effect', pretty_print=pretty_print) + for doe in self.Description_Of_Effect: + doe.export(lwrite, level, nsmap, namespace_, name_='Description_Of_Effect', pretty_print=pretty_print) if self.Type_Of_Availability_Loss is not None: self.Type_Of_Availability_Loss.export(lwrite, level, nsmap, namespace_, name_='Type_Of_Availability_Loss', pretty_print=pretty_print) if self.Duration_Of_Availability_Loss is not None: @@ -105,7 +110,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description_Of_Effect': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description_Of_Effect(obj_) + self.add_Description_Of_Effect(obj_) elif nodeName_ == 'Type_Of_Availability_Loss': obj_ = stix_common_binding.ControlledVocabularyStringType.factory() obj_.build(child_) diff --git a/stix/incident/property_affected.py b/stix/incident/property_affected.py index a699ef37..85096f5d 100644 --- a/stix/incident/property_affected.py +++ b/stix/incident/property_affected.py @@ -3,7 +3,7 @@ import stix -from stix.common import vocabs, VocabString, StructuredText +from stix.common import vocabs, VocabString, StructuredTextList import stix.bindings.incident as incident_binding @@ -82,11 +82,38 @@ def property_(self, value): @property def description_of_effect(self): - return self._description_of_effect - + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.descriptions_of_effect), None) + @description_of_effect.setter def description_of_effect(self, value): - self._set_var(StructuredText, description_of_effect=value) + self.descriptions_of_effect = value + + @property + def descriptions_of_effect(self): + return self._description_of_effect + + @descriptions_of_effect.setter + def descriptions_of_effect(self, value): + self._description_of_effect = StructuredTextList(value) @property def type_of_availability_loss(self): @@ -120,7 +147,7 @@ def from_obj(cls, obj, return_obj=None): return_obj = cls() return_obj.property_ = VocabString.from_obj(obj.Property) - return_obj.description_of_effect = StructuredText.from_obj(obj.Description_Of_Effect) + return_obj.descriptions_of_effect = StructuredTextList.from_obj(obj.Description_Of_Effect) return_obj.type_of_availability_loss = VocabString.from_obj(obj.Type_Of_Availability_Loss) return_obj.duration_of_availability_loss = VocabString.from_obj(obj.Duration_Of_Availability_Loss) return_obj.non_public_data_compromised = NonPublicDataCompromised.from_obj(obj.Non_Public_Data_Compromised) @@ -134,8 +161,8 @@ def to_obj(self, return_obj=None, ns_info=None): if self.property_: return_obj.Property = self.property_.to_obj(ns_info=ns_info) - if self.description_of_effect: - return_obj.Description_Of_Effect = self.description_of_effect.to_obj(ns_info=ns_info) + if self.descriptions_of_effect: + return_obj.Description_Of_Effect = self.descriptions_of_effect.to_obj(ns_info=ns_info) if self.type_of_availability_loss: return_obj.Type_Of_Availability_Loss = self.type_of_availability_loss.to_obj(ns_info=ns_info) if self.duration_of_availability_loss: @@ -153,7 +180,7 @@ def from_dict(cls, d, return_obj=None): return_obj = cls() return_obj.property_ = VocabString.from_dict(d.get('property')) - return_obj.description_of_effect = StructuredText.from_dict(d.get('description_of_effect')) + return_obj.descriptions_of_effect = StructuredTextList.from_dict(d.get('description_of_effect')) return_obj.type_of_availability_loss = VocabString.from_dict(d.get('type_of_availability_loss')) return_obj.duration_of_availability_loss = VocabString.from_dict(d.get('duration_of_availability_loss')) return_obj.non_public_data_compromised = NonPublicDataCompromised.from_dict(d.get('non_public_data_compromised')) From 3ec21c5a75801bf9b4f17ba40953db3556f15189 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 17:01:40 -0400 Subject: [PATCH 025/438] Removed unnecessary fix_descriptions() usage. --- stix/base.py | 15 +++----- stix/coa/objective.py | 14 +++---- stix/common/activity.py | 11 ++---- stix/common/confidence.py | 9 ++--- stix/common/information_source.py | 11 ++---- stix/common/statement.py | 9 ++--- stix/common/tools.py | 14 ++----- stix/core/stix_header.py | 24 +++--------- stix/exploit_target/configuration.py | 17 +++------ stix/exploit_target/vulnerability.py | 13 +++---- stix/exploit_target/weakness.py | 10 ++--- .../structured_coa/generic_structured_coa.py | 37 ++----------------- .../test_mechanism/generic_test_mechanism.py | 13 ++----- stix/incident/affected_asset.py | 16 +++----- stix/indicator/indicator.py | 4 +- stix/utils/__init__.py | 24 ------------ 16 files changed, 57 insertions(+), 184 deletions(-) diff --git a/stix/base.py b/stix/base.py index a547a42f..8b54b20d 100644 --- a/stix/base.py +++ b/stix/base.py @@ -716,12 +716,12 @@ def description(self, value): @property def descriptions(self): - return self._descriptions + return self._description @descriptions.setter def descriptions(self, value): from stix.common import StructuredTextList - self._descriptions = StructuredTextList(value) + self._description = StructuredTextList(value) @property def short_description(self): @@ -752,12 +752,12 @@ def short_description(self, value): @property def short_descriptions(self): - return self._short_descriptions + return self._short_description @short_descriptions.setter def short_descriptions(self, value): from stix.common import StructuredTextList - self._short_descriptions = StructuredTextList(value) + self._short_description = StructuredTextList(value) @property def information_source(self): @@ -857,11 +857,6 @@ def from_dict(cls, d, return_obj=None): return return_obj def to_dict(self): - d = utils.to_dict(self) - - # Rename 'descriptions' and 'short_descriptions' keys. - utils.fix_descriptions(d) - - return d + return super(BaseCoreComponent, self).to_dict() diff --git a/stix/coa/objective.py b/stix/coa/objective.py index a07ecb7f..d0f44b0c 100644 --- a/stix/coa/objective.py +++ b/stix/coa/objective.py @@ -46,12 +46,12 @@ def description(self, value): @property def descriptions(self): - return self._descriptions + return self._description @descriptions.setter def descriptions(self, value): from stix.common import StructuredTextList - self._descriptions = StructuredTextList(value) + self._description = StructuredTextList(value) @property def short_description(self): @@ -82,11 +82,11 @@ def short_description(self, value): @property def short_descriptions(self): - return self._short_descriptions + return self._short_description @short_descriptions.setter def short_descriptions(self, value): - self._short_descriptions = StructuredTextList(value) + self._short_description = StructuredTextList(value) @property def applicability_confidence(self): @@ -124,11 +124,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - d = super(Objective, self).to_dict() - - utils.fix_descriptions(d) - - return d + return super(Objective, self).to_dict() @classmethod def from_dict(cls, dict_repr, return_obj=None): diff --git a/stix/common/activity.py b/stix/common/activity.py index 8d343943..259875b4 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -68,11 +68,11 @@ def descriptions(self): :class:`.StructuredTextList` """ - return self._descriptions + return self._description @descriptions.setter def descriptions(self, value): - self._descriptions = StructuredTextList(value) + self._description = StructuredTextList(value) def to_obj(self, return_obj=None, ns_info=None): super(Activity, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -101,12 +101,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - d = utils.to_dict(self) - - # Rename 'descriptions' key. - utils.fix_descriptions(d) - - return d + return super(Activity, self).to_dict() @classmethod def from_dict(cls, dict_repr, return_obj=None): diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 236c7cc9..f3bf12d0 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -92,11 +92,11 @@ def descriptions(self): :class:`.StructuredTextList` """ - return self._descriptions + return self._description @descriptions.setter def descriptions(self, value): - self._descriptions = StructuredTextList(value) + self._description = StructuredTextList(value) # @property # def confidence_assertion_chain(self): @@ -124,15 +124,12 @@ def to_obj(self, return_obj=None, ns_info=None): return obj def to_dict(self): - skip = ('timestamp_precision', 'descriptions') + skip = ('timestamp_precision',) d = utils.to_dict(self, skip=skip) if self.timestamp_precision != 'second': d['timestamp_precision'] = self.timestamp_precision - if self.descriptions: - d['description'] = self.descriptions.to_dict() - return d @classmethod diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 3d906d7b..d9addbcb 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -106,11 +106,11 @@ def descriptions(self): :class:`.StructuredTextList` """ - return self._descriptions + return self._description @descriptions.setter def descriptions(self, value): - self._descriptions = StructuredTextList(value) + self._description = StructuredTextList(value) @property def identity(self): @@ -216,12 +216,7 @@ def from_dict(cls, dict_repr, return_obj=None): return return_obj def to_dict(self): - d = utils.to_dict(self) - - # Rename 'descriptions' key. - utils.fix_descriptions(d) - - return d + return super(InformationSource, self).to_dict() class ContributingSources(stix.EntityList): _namespace = "http://stix.mitre.org/common-1" diff --git a/stix/common/statement.py b/stix/common/statement.py index 474f8df0..753d4565 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -93,11 +93,11 @@ def descriptions(self): :class:`.StructuredTextList` """ - return self._descriptions + return self._description @descriptions.setter def descriptions(self, value): - self._descriptions = StructuredTextList(value) + self._description = StructuredTextList(value) def to_obj(self, return_obj=None, ns_info=None): super(Statement, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -119,15 +119,12 @@ def to_obj(self, return_obj=None, ns_info=None): return obj def to_dict(self): - skip = ('timestamp_precision', 'descriptions') + skip = ('timestamp_precision',) d = utils.to_dict(self, skip=skip) if self.timestamp_precision != 'second': d['timestamp_precision'] = self.timestamp_precision - if self.descriptions: - d['description'] = self.descriptions.to_dict() - return d @classmethod diff --git a/stix/common/tools.py b/stix/common/tools.py index 9a9e2399..58dd90ea 100644 --- a/stix/common/tools.py +++ b/stix/common/tools.py @@ -6,6 +6,7 @@ # internal import stix +import stix.utils as utils import stix.bindings.stix_common as common_binding # relative @@ -72,11 +73,11 @@ def short_descriptions(self): :class:`.StructuredTextList` """ - return self._short_descriptions + return self._short_description @short_descriptions.setter def short_descriptions(self, value): - self._short_descriptions = StructuredTextList(value) + self._short_description = StructuredTextList(value) def to_obj(self, return_obj=None, ns_info=None): if not return_obj: @@ -110,14 +111,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - d = cybox.common.ToolInformation.to_dict(self) - - if self.title: - d['title'] = self.title - if self.short_descriptions: - d['short_description'] = self.short_descriptions.to_dict() - - return d + return utils.to_dict(self) @classmethod def from_dict(cls, dict_repr, return_obj=None): diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index f72b4f12..138a2673 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -54,11 +54,11 @@ def description(self, value): @property def descriptions(self): - return self._descriptions + return self._description @descriptions.setter def descriptions(self, value): - self._descriptions = StructuredTextList(value) + self._description = StructuredTextList(value) @property def short_description(self): @@ -89,11 +89,11 @@ def short_description(self, value): @property def short_descriptions(self): - return self._short_descriptions + return self._short_description @short_descriptions.setter def short_descriptions(self, value): - self._short_descriptions = StructuredTextList(value) + self._short_description = StructuredTextList(value) @property def handling(self): @@ -191,21 +191,7 @@ def from_dict(cls, dict_repr, return_obj=None): return return_obj def to_dict(self): - skip = ( - 'description', - 'descriptions', - 'short_description', - 'short_descriptions' - ) - - d = utils.to_dict(self, skip=skip) - - if self.descriptions: - d['description'] = self.descriptions.to_dict() - if self.short_descriptions: - d['short_description'] = self.short_descriptions.to_dict() - - return d + return super(STIXHeader, self).to_dict() # NOT AN ACTUAL STIX TYPE! diff --git a/stix/exploit_target/configuration.py b/stix/exploit_target/configuration.py index 2eb38861..6ab6202e 100644 --- a/stix/exploit_target/configuration.py +++ b/stix/exploit_target/configuration.py @@ -2,7 +2,6 @@ # See LICENSE.txt for complete terms. import stix -import stix.utils as utils from stix.common import StructuredTextList import stix.bindings.exploit_target as exploit_target_binding @@ -54,12 +53,11 @@ def description(self, value): @property def descriptions(self): - return self._descriptions + return self._description @descriptions.setter def descriptions(self, value): - from stix.common import StructuredTextList - self._descriptions = StructuredTextList(value) + self._description = StructuredTextList(value) @property def short_description(self): @@ -90,11 +88,11 @@ def short_description(self, value): @property def short_descriptions(self): - return self._short_descriptions + return self._short_description @short_descriptions.setter def short_descriptions(self, value): - self._short_descriptions = StructuredTextList(value) + self._short_description = StructuredTextList(value) @property def cce_id(self): @@ -140,12 +138,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - d = super(Configuration, self).to_dict() - - # Rename 'descriptions' and 'short_descriptions' keys. - utils.fix_descriptions(d) - - return d + return super(Configuration, self).to_dict() @classmethod def from_dict(cls, dict_repr, return_obj=None): diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index 27943a21..b42171b8 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -79,11 +79,11 @@ def description(self, value): @property def descriptions(self): - return self._descriptions + return self._description @descriptions.setter def descriptions(self, value): - self._descriptions = StructuredTextList(value) + self._description = StructuredTextList(value) @property def short_description(self): @@ -114,12 +114,11 @@ def short_description(self, value): @property def short_descriptions(self): - return self._short_descriptions + return self._short_description @short_descriptions.setter def short_descriptions(self, value): - from stix.common import StructuredTextList - self._short_descriptions = StructuredTextList(value) + self._short_description = StructuredTextList(value) @property def discovered_datetime(self): @@ -221,9 +220,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - d = super(Vulnerability, self).to_dict() - utils.fix_descriptions(d) - return d + return super(Vulnerability, self).to_dict() @classmethod def from_dict(cls, dict_repr, return_obj=None): diff --git a/stix/exploit_target/weakness.py b/stix/exploit_target/weakness.py index aa9d2c4c..c9e3d22b 100644 --- a/stix/exploit_target/weakness.py +++ b/stix/exploit_target/weakness.py @@ -63,11 +63,11 @@ def description(self, value): @property def descriptions(self): - return self._descriptions + return self._description @descriptions.setter def descriptions(self, value): - self._descriptions = StructuredTextList(value) + self._description = StructuredTextList(value) def to_obj(self, return_obj=None, ns_info=None): super(Weakness, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -94,11 +94,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - d = super(Weakness, self).to_dict() - - utils.fix_descriptions(d) - - return d + return super(Weakness, self).to_dict() @classmethod def from_dict(cls, dict_repr, return_obj=None): diff --git a/stix/extensions/structured_coa/generic_structured_coa.py b/stix/extensions/structured_coa/generic_structured_coa.py index 2bef7a2e..7b568b77 100644 --- a/stix/extensions/structured_coa/generic_structured_coa.py +++ b/stix/extensions/structured_coa/generic_structured_coa.py @@ -72,38 +72,11 @@ def descriptions(self): :class:`.StructuredTextList` """ - return self._descriptions + return self._description @descriptions.setter def descriptions(self, value): - self._descriptions = StructuredTextList(value) - - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._descriptions - - @descriptions.setter - def descriptions(self, value): - self._descriptions = StructuredTextList(value) + self._description = StructuredTextList(value) @property def type_(self): @@ -161,12 +134,8 @@ def from_dict(cls, d, return_obj=None): return return_obj def to_dict(self): - d = super(GenericStructuredCOA, self).to_dict() - - # Rename 'descriptions' key. - utils.fix_descriptions(d) + return super(GenericStructuredCOA, self).to_dict() - return d # Register the extension stix.coa.structured_coa.add_extension(GenericStructuredCOA) diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index 5a938a51..e908fd9b 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -34,7 +34,7 @@ def specification(self, value): self._specification = value else: self._specification = EncodedCDATA(value=value) - + @property def description(self): """A single description about the contents or purpose of this object. @@ -77,11 +77,11 @@ def descriptions(self): :class:`.StructuredTextList` """ - return self._descriptions + return self._description @descriptions.setter def descriptions(self, value): - self._descriptions = StructuredTextList(value) + self._description = StructuredTextList(value) @property def type_(self): @@ -143,12 +143,7 @@ def from_dict(cls, d, return_obj=None): return return_obj def to_dict(self): - d = super(GenericTestMechanism, self).to_dict() - - # Rename 'descriptions' key. - utils.fix_descriptions(d) - - return d + return super(GenericTestMechanism, self).to_dict() stix.indicator.test_mechanism.add_extension(GenericTestMechanism) diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index 78547067..4d189b5e 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -67,11 +67,11 @@ def description(self, value): @property def descriptions(self): - return self._descriptions + return self._description @descriptions.setter def descriptions(self, value): - self._descriptions = StructuredTextList(value) + self._description = StructuredTextList(value) @property def business_function_or_role(self): @@ -83,11 +83,11 @@ def business_function_or_role(self, value): @property def business_functions_or_roles(self): - return self._business_functions_or_roles + return self._business_function_or_role @business_functions_or_roles.setter def business_functions_or_roles(self, value): - self._business_functions_or_roles = StructuredTextList(value) + self._business_function_or_role = StructuredTextList(value) @property def ownership_class(self): @@ -202,13 +202,7 @@ def from_dict(cls, d, return_obj=None): return return_obj def to_dict(self): - d = super(AffectedAsset, self).to_dict() - utils.fix_descriptions(d) - - if 'business_functions_or_roles' in d: - d['business_function_or_role'] = d.pop('business_functions_or_roles') - - return d + return super(AffectedAsset, self).to_dict() class AssetType(VocabString): _namespace = "http://stix.mitre.org/Incident-1" diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index ab6238ec..d86bb948 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -930,9 +930,7 @@ def to_dict(self): skip = ( 'observables', 'observable_composition_operator', - 'negate', - 'descriptions', - 'short_descriptions', + 'negate' ) d = super(Indicator, self).to_dict() diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index 7a52ebcd..b1800539 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -339,30 +339,6 @@ def remove_entries(map, keys): map.pop(key, None) -def fix_descriptions(d): - """Renames 'descriptions` and 'short_descriptions` keys to 'description' - and 'short_description' on the input dictionary. - - Dictionaries returned by ``to_dict()`` which are created by inspecting the - entity instance variables will produce the plural key forms. - - For backwards compatibility, we need to convert these keys to their - singular forms. - - Note: - This modification is applied to the input dictionary. - - Args: - d: An Entity dictionary. - - """ - if 'descriptions' in d: - d['description'] = d.pop('descriptions') - - if 'short_descriptions' in d: - d['short_description'] = d.pop('short_descriptions') - - # Namespace flattening from .nsparser import * # noqa from .dates import * # noqa From e26e19ac79e91ee169c62b8788722c59945ad140 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 17:48:40 -0400 Subject: [PATCH 026/438] Added more support for multiple structured text fields. --- stix/bindings/indicator.py | 15 +++-- stix/bindings/ttp.py | 125 ++++++++++++++++++++++++----------- stix/coa/objective.py | 1 - stix/indicator/sightings.py | 43 +++++++++--- stix/ttp/attack_pattern.py | 80 ++++++++++++++++++---- stix/ttp/exploit.py | 78 ++++++++++++++++++---- stix/ttp/infrastructure.py | 76 ++++++++++++++++++--- stix/ttp/malware_instance.py | 80 ++++++++++++++++++---- 8 files changed, 397 insertions(+), 101 deletions(-) diff --git a/stix/bindings/indicator.py b/stix/bindings/indicator.py index 9d16c0c3..75ce5176 100644 --- a/stix/bindings/indicator.py +++ b/stix/bindings/indicator.py @@ -413,7 +413,10 @@ def __init__(self, timestamp=None, timestamp_precision='second', Source=None, Re self.Source = Source self.Reference = Reference self.Confidence = Confidence - self.Description = Description + if Description is None: + self.Description = [] + else: + self.Description = Description self.Related_Observables = Related_Observables def factory(*args_, **kwargs_): if SightingType.subclass: @@ -427,6 +430,8 @@ def get_Reference(self): return self.Reference def set_Reference(self, Reference): self.Reference = Reference def get_Confidence(self): return self.Confidence def set_Confidence(self, Confidence): self.Confidence = Confidence + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description def get_Related_Observables(self): return self.Related_Observables @@ -440,7 +445,7 @@ def hasContent_(self): self.Source is not None or self.Reference is not None or self.Confidence is not None or - self.Description is not None or + self.Description or self.Related_Observables is not None ): return True @@ -481,8 +486,8 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Sightin lwrite('<%s:Reference>%s%s' % (nsmap[namespace_], quote_xml(self.Reference), nsmap[namespace_], eol_)) if self.Confidence is not None: self.Confidence.export(lwrite, level, nsmap, namespace_, name_='Confidence', pretty_print=pretty_print) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) if self.Related_Observables is not None: self.Related_Observables.export(lwrite, level, nsmap, namespace_, name_='Related_Observables', pretty_print=pretty_print) def build(self, node): @@ -519,7 +524,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Related_Observables': obj_ = RelatedObservablesType.factory() obj_.build(child_) diff --git a/stix/bindings/ttp.py b/stix/bindings/ttp.py index 0ea62d95..9601b9a4 100644 --- a/stix/bindings/ttp.py +++ b/stix/bindings/ttp.py @@ -44,8 +44,14 @@ def __init__(self, idref=None, capec_id=None, id=None, Title=None, Description=N self.capec_id = _cast(None, capec_id) self.id = _cast(None, id) self.Title = Title - self.Description = Description - self.Short_Description = Short_Description + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description def factory(*args_, **kwargs_): if AttackPatternType.subclass: return AttackPatternType.subclass(*args_, **kwargs_) @@ -54,8 +60,12 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Title(self): return self.Title def set_Title(self, Title): self.Title = Title + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_idref(self): return self.idref @@ -67,8 +77,8 @@ def set_id(self, id): self.id = id def hasContent_(self): if ( self.Title is not None or - self.Description is not None or - self.Short_Description is not None + self.Description or + self.Short_Description ): return True else: @@ -107,10 +117,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='AttackP if self.Title is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:Title>%s%s' % (nsmap[namespace_], quote_xml(self.Title), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) def build(self, node): already_processed = set() self.buildAttributes(node, node.attrib, already_processed) @@ -138,11 +148,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) # end class AttackPatternType @@ -175,8 +185,17 @@ def __init__(self, idref=None, id=None, Type=None, Name=None, Title=None, Descri else: self.Name = Name self.Title = Title - self.Description = Description - self.Short_Description = Short_Description + + if Description is None: + self.Description = [] + else: + self.Description = Description + + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description + def factory(*args_, **kwargs_): if MalwareInstanceType.subclass: return MalwareInstanceType.subclass(*args_, **kwargs_) @@ -193,8 +212,12 @@ def add_Name(self, value): self.Name.append(value) def insert_Name(self, index, value): self.Name[index] = value def get_Title(self): return self.Title def set_Title(self, Title): self.Title = Title + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_idref(self): return self.idref @@ -206,8 +229,8 @@ def hasContent_(self): self.Type or self.Name or self.Title is not None or - self.Description is not None or - self.Short_Description is not None + self.Description or + self.Short_Description ): return True else: @@ -247,10 +270,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Malware if self.Title is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:Title>%s%s' % (nsmap[namespace_], quote_xml(self.Title), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) def build(self, node): already_processed = set() self.buildAttributes(node, node.attrib, already_processed) @@ -282,11 +305,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) # end class MalwareInstanceType class ExploitType(GeneratedsSuper): @@ -305,8 +328,17 @@ def __init__(self, idref=None, id=None, Title=None, Description=None, Short_Desc self.idref = _cast(None, idref) self.id = _cast(None, id) self.Title = Title - self.Description = Description - self.Short_Description = Short_Description + + if Description is None: + self.Description = [] + else: + self.Description = Description + + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description + def factory(*args_, **kwargs_): if ExploitType.subclass: return ExploitType.subclass(*args_, **kwargs_) @@ -315,8 +347,12 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Title(self): return self.Title def set_Title(self, Title): self.Title = Title + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_idref(self): return self.idref @@ -326,8 +362,8 @@ def set_id(self, id): self.id = id def hasContent_(self): if ( self.Title is not None or - self.Description is not None or - self.Short_Description is not None + self.Description or + self.Short_Description ): return True else: @@ -363,10 +399,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Exploit if self.Title is not None: showIndent(lwrite, level, pretty_print) lwrite('<%s:Title>%s%s' % (nsmap[namespace_], quote_xml(self.Title), nsmap[namespace_], eol_)) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) def build(self, node): already_processed = set() self.buildAttributes(node, node.attrib, already_processed) @@ -390,11 +426,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) # end class ExploitType @@ -412,8 +448,17 @@ def __init__(self, idref=None, id=None, Title=None, Type=None, Description=None, self.Type = [] else: self.Type = Type - self.Description = Description - self.Short_Description = Short_Description + + if Description is None: + self.Description = [] + else: + self.Description = Description + + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description + self.Observable_Characterization = Observable_Characterization def factory(*args_, **kwargs_): if InfrastructureType.subclass: @@ -427,8 +472,12 @@ def get_Type(self): return self.Type def set_Type(self, Type): self.Type = Type def add_Type(self, value): self.Type.append(value) def insert_Type(self, index, value): self.Type[index] = value + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def add_Short_Description(self, Short_Description): self.Short_Description.append(Short_Description) def get_Short_Description(self): return self.Short_Description def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description def get_Observable_Characterization(self): return self.Observable_Characterization @@ -481,10 +530,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Infrast lwrite('<%s:Title>%s%s' % (nsmap[namespace_], quote_xml(self.Title), nsmap[namespace_], eol_)) for Type_ in self.Type: Type_.export(lwrite, level, nsmap, namespace_, name_='Type', pretty_print=pretty_print) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Short_Description is not None: - self.Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description in self.Short_Description: + Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) if self.Observable_Characterization is not None: self.Observable_Characterization.export(lwrite, level, "%s:" % (nsmap[namespace_]), name_='Observable_Characterization', pretty_print=pretty_print) def build(self, node): @@ -514,11 +563,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Short_Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Short_Description(obj_) + self.add_Short_Description(obj_) elif nodeName_ == 'Observable_Characterization': obj_ = cybox_core_binding.ObservablesType.factory() obj_.build(child_) diff --git a/stix/coa/objective.py b/stix/coa/objective.py index d0f44b0c..00c33a54 100644 --- a/stix/coa/objective.py +++ b/stix/coa/objective.py @@ -50,7 +50,6 @@ def descriptions(self): @descriptions.setter def descriptions(self, value): - from stix.common import StructuredTextList self._description = StructuredTextList(value) @property diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index 7af12240..494b05fa 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -4,7 +4,7 @@ import stix import stix.utils as utils from stix.common import ( - GenericRelationshipList, RelatedObservable, StructuredText, Confidence, + GenericRelationshipList, RelatedObservable, StructuredTextList, Confidence, InformationSource ) import stix.bindings.indicator as indicator_binding @@ -34,11 +34,38 @@ def timestamp(self, value): @property def description(self): - return self._description - + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.descriptions), None) + @description.setter def description(self, value): - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) @property def source(self): @@ -70,8 +97,8 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Source = self.source.to_obj(ns_info=ns_info) if self.confidence: return_obj.Confidence = self.confidence.to_obj(ns_info=ns_info) - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) if self.related_observables: return_obj.Related_Observables = self.related_observables.to_obj(ns_info=ns_info) @@ -93,7 +120,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.source = InformationSource.from_obj(obj.Source) return_obj.reference = obj.Reference return_obj.confidence = Confidence.from_obj(obj.Confidence) - return_obj.description = StructuredText.from_obj(obj.Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) return_obj.related_observables = RelatedObservables.from_obj(obj.Related_Observables) return return_obj @@ -109,7 +136,7 @@ def from_dict(cls, d, return_obj=None): return_obj.source = InformationSource.from_dict(d.get('source')) return_obj.reference = d.get('reference') return_obj.confidence = Confidence.from_dict(d.get('confidence')) - return_obj.description = StructuredText.from_dict(d.get('description')) + return_obj.descriptions = StructuredTextList.from_dict(d.get('description')) return_obj.related_observables = RelatedObservables.from_dict(d.get('related_observables')) return return_obj diff --git a/stix/ttp/attack_pattern.py b/stix/ttp/attack_pattern.py index eef1b585..c68c49d5 100644 --- a/stix/ttp/attack_pattern.py +++ b/stix/ttp/attack_pattern.py @@ -2,7 +2,7 @@ # See LICENSE.txt for complete terms. import stix -from stix.common import StructuredText +from stix.common import StructuredTextList import stix.bindings.ttp as ttp_binding @@ -28,19 +28,73 @@ def title(self, value): @property def description(self): - return self._description + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.descriptions), None) @description.setter def description(self, value): - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) @property def short_description(self): - return self._short_description + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): - self._set_var(StructuredText, short_description=value) + self.short_descriptions = value + + @property + def short_descriptions(self): + return self._short_description + + @short_descriptions.setter + def short_descriptions(self, value): + self._short_description = StructuredTextList(value) def to_obj(self, return_obj=None, ns_info=None): super(AttackPattern, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -52,10 +106,10 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.capec_id = self.capec_id return_obj.Title = self.title - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) - if self.short_description: - return_obj.Short_Description = self.short_description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) + if self.short_descriptions: + return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) return return_obj @@ -69,8 +123,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.id_ = obj.id return_obj.capec_id = obj.capec_id return_obj.title = obj.Title - return_obj.description = StructuredText.from_obj(obj.Description) - return_obj.short_description = StructuredText.from_obj(obj.Short_Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) + return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) return return_obj @@ -87,7 +141,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.id_ = dict_repr.get('id') return_obj.capec_id = dict_repr.get('capec_id') return_obj.title = dict_repr.get('title') - return_obj.description = StructuredText.from_dict(dict_repr.get('description')) - return_obj.short_description = StructuredText.from_dict(dict_repr.get('short_description')) + return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) + return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) return return_obj diff --git a/stix/ttp/exploit.py b/stix/ttp/exploit.py index 0d55aaf7..f7705f74 100644 --- a/stix/ttp/exploit.py +++ b/stix/ttp/exploit.py @@ -3,7 +3,7 @@ import stix import stix.utils -from stix.common import StructuredText +from stix.common import StructuredTextList import stix.bindings.ttp as ttp_binding @@ -28,19 +28,73 @@ def title(self, value): @property def description(self): - return self._description + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.descriptions), None) @description.setter def description(self, value): - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) @property def short_description(self): - return self._short_description + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): - self._set_var(StructuredText, short_description=value) + self.short_descriptions = value + + @property + def short_descriptions(self): + return self._short_description + + @short_descriptions.setter + def short_descriptions(self, value): + self._short_description = StructuredTextList(value) def to_obj(self, return_obj=None, ns_info=None): super(Exploit, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -51,10 +105,10 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.id = self.id_ return_obj.Title = self.title - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) if self.short_description: - return_obj.Short_Description = self.short_description.to_obj(ns_info=ns_info) + return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) return return_obj @@ -67,8 +121,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.id_ = obj.id return_obj.title = obj.Title - return_obj.description = StructuredText.from_obj(obj.Description) - return_obj.short_description = StructuredText.from_obj(obj.Short_Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) + return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) return return_obj @@ -84,7 +138,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.id_ = dict_repr.get('id') return_obj.title = dict_repr.get('title') - return_obj.description = StructuredText.from_dict(dict_repr.get('description')) - return_obj.short_description = StructuredText.from_dict(dict_repr.get('short_description')) + return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) + return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) return return_obj diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index d067ce01..2235a3ed 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -6,7 +6,7 @@ # internal import stix -from stix.common import StructuredText, VocabString +from stix.common import StructuredTextList, VocabString from stix.common.vocabs import AttackerInfrastructureType import stix.bindings.ttp as ttp_binding @@ -34,19 +34,73 @@ def title(self, value): @property def description(self): - return self._description + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.descriptions), None) @description.setter def description(self, value): - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) @property def short_description(self): - return self._short_description + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): - self._set_var(StructuredText, short_description=value) + self.short_descriptions = value + + @property + def short_descriptions(self): + return self._short_description + + @short_descriptions.setter + def short_descriptions(self, value): + self._short_description = StructuredTextList(value) @property def types(self): @@ -77,9 +131,9 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Title = self.title if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) if self.short_description: - return_obj.Short_Description = self.short_description.to_obj(ns_info=ns_info) + return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) if self.types: return_obj.Type = [x.to_obj(ns_info=ns_info) for x in self.types] if self.observable_characterization: @@ -96,8 +150,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.id_ = obj.id return_obj.title = obj.Title - return_obj.description = StructuredText.from_obj(obj.Description) - return_obj.short_description = StructuredText.from_obj(obj.Short_Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) + return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) return_obj.observable_characterization = Observables.from_obj(obj.Observable_Characterization) if obj.Type: @@ -117,8 +171,8 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.id_ = dict_repr.get('id') return_obj.title = dict_repr.get('title') - return_obj.description = StructuredText.from_dict(dict_repr.get('description')) - return_obj.short_description = StructuredText.from_dict(dict_repr.get('short_description')) + return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) + return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) return_obj.types = [VocabString.from_dict(x) for x in dict_repr.get('types', [])] return_obj.observable_characterization = Observables.from_dict(dict_repr.get('observable_characterization')) diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index fc921471..83538d5b 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -3,7 +3,7 @@ import stix import stix.utils as utils -from stix.common import vocabs, StructuredText, VocabString +from stix.common import vocabs, StructuredTextList, VocabString import stix.bindings.ttp as ttp_binding @@ -30,19 +30,73 @@ def title(self, value): @property def description(self): - return self._description + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.descriptions), None) @description.setter def description(self, value): - self._set_var(StructuredText, description=value) + self.descriptions = value + + @property + def descriptions(self): + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) @property def short_description(self): - return self._short_description + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): - self._set_var(StructuredText, short_description=value) + self.short_descriptions = value + + @property + def short_descriptions(self): + return self._short_description + + @short_descriptions.setter + def short_descriptions(self, value): + self._short_description = StructuredTextList(value) @property def names(self): @@ -87,10 +141,10 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.id = self.id_ return_obj.Title = self.title - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) - if self.short_description: - return_obj.Short_Description = self.short_description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) + if self.short_descriptions: + return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) if self.names: return_obj.Name = self.names.to_obj(ns_info=ns_info) if self.types: @@ -114,8 +168,8 @@ def from_obj(cls, obj, return_obj=None): else: return_obj.id_ = obj.id return_obj.title = obj.Title - return_obj.description = StructuredText.from_obj(obj.Description) - return_obj.short_description = StructuredText.from_obj(obj.Short_Description) + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) + return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) return_obj.names = MalwareNames.from_obj(obj.Name) return_obj.types = MalwareTypes.from_obj(obj.Type) @@ -148,8 +202,8 @@ def from_dict(cls, dict_repr, return_obj=None): else: return_obj.id_ = get('id') return_obj.title = get('title') - return_obj.description = StructuredText.from_dict(get('description')) - return_obj.short_description = StructuredText.from_dict(get('short_description')) + return_obj.descriptions = StructuredTextList.from_dict(get('description')) + return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) return_obj.names = MalwareNames.from_dict(get('names')) return_obj.types = MalwareTypes.from_dict(get('types')) From d0ec3a568d2b935852b42b7e6705c799fb55a9ad Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 20:00:31 -0400 Subject: [PATCH 027/438] Updated docstrings. --- stix/base.py | 74 +++++++++++++------ stix/coa/objective.py | 73 ++++++++++++------ stix/common/activity.py | 4 +- stix/common/confidence.py | 4 +- stix/common/information_source.py | 4 +- stix/common/statement.py | 4 +- stix/common/structured_text.py | 28 ++++--- stix/common/tools.py | 16 ++-- stix/core/stix_header.py | 73 ++++++++++++------ stix/exploit_target/configuration.py | 73 ++++++++++++------ stix/exploit_target/vulnerability.py | 73 ++++++++++++------ stix/exploit_target/weakness.py | 36 ++++++--- .../structured_coa/generic_structured_coa.py | 4 +- .../test_mechanism/generic_test_mechanism.py | 4 +- stix/incident/affected_asset.py | 36 ++++++--- stix/incident/property_affected.py | 4 +- stix/indicator/indicator.py | 10 +-- stix/indicator/sightings.py | 36 ++++++--- stix/ttp/attack_pattern.py | 73 ++++++++++++------ stix/ttp/exploit.py | 73 ++++++++++++------ stix/ttp/infrastructure.py | 73 ++++++++++++------ stix/ttp/malware_instance.py | 73 ++++++++++++------ 22 files changed, 587 insertions(+), 261 deletions(-) diff --git a/stix/base.py b/stix/base.py index 8b54b20d..1fc9c0b4 100644 --- a/stix/base.py +++ b/stix/base.py @@ -689,33 +689,48 @@ def title(self, value): @property def description(self): + """A single description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If this object has more than one description set, this will return + the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + + """ + return next(iter(self.descriptions), None) + + @description.setter + def description(self, value): + self.descriptions = value + + @property + def descriptions(self): """A :class:`.StructuredTextList` object, containing descriptions about the purpose or intent of this object. + This is typically used for the purpose of providing multiple + descriptions with different classificaton markings. + Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of :class:`.StructuredTextList` """ - return next(iter(self.descriptions), None) - - @description.setter - def description(self, value): - self.descriptions = value - - @property - def descriptions(self): return self._description @descriptions.setter @@ -725,23 +740,17 @@ def descriptions(self, value): @property def short_description(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. + """A single short description about the contents or purpose of this + object. - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`StructuredTextList` object. + Default Value: ``None`` Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + If this object has more than one short description set, this will + return the description with the lowest ordinality value. Returns: - An instance of - :class:`.StructuredTextList` + An instance of :class:`.StructuredText` """ return next(iter(self.short_descriptions), None) @@ -752,6 +761,27 @@ def short_description(self, value): @property def short_descriptions(self): + """A :class:`.StructuredTextList` object, containing short descriptions + about the purpose or intent of this object. + + This is typically used for the purpose of providing multiple + short descriptions with different classificaton markings. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`.StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`.StructuredText` will be be converted. + + Returns: + An instance of :class:`.StructuredTextList` + + """ return self._short_description @short_descriptions.setter diff --git a/stix/coa/objective.py b/stix/coa/objective.py index 00c33a54..f62df464 100644 --- a/stix/coa/objective.py +++ b/stix/coa/objective.py @@ -19,23 +19,17 @@ def __init__(self, description=None, short_description=None): @property def description(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. + """A single description about the contents or purpose of this object. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: ``None`` Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + If this object has more than one description set, this will return + the description with the lowest ordinality value. Returns: An instance of - :class:`.StructuredTextList` + :class:`.StructuredText` """ return next(iter(self.descriptions), None) @@ -46,32 +40,48 @@ def description(self, value): @property def descriptions(self): - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - - @property - def short_description(self): """A :class:`.StructuredTextList` object, containing descriptions about the purpose or intent of this object. + This is typically used for the purpose of providing multiple + descriptions with different classificaton markings. + Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of :class:`.StructuredTextList` + """ + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) + + @property + def short_description(self): + """A single short description about the contents or purpose of this + object. + + Default Value: ``None`` + + Note: + If this object has more than one short description set, this will + return the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + """ return next(iter(self.short_descriptions), None) @@ -81,6 +91,27 @@ def short_description(self, value): @property def short_descriptions(self): + """A :class:`.StructuredTextList` object, containing short descriptions + about the purpose or intent of this object. + + This is typically used for the purpose of providing multiple + short descriptions with different classificaton markings. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`.StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`.StructuredText` will be be converted. + + Returns: + An instance of :class:`.StructuredTextList` + + """ return self._short_description @short_descriptions.setter diff --git a/stix/common/activity.py b/stix/common/activity.py index 259875b4..e655b71b 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -55,13 +55,13 @@ def descriptions(self): Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of diff --git a/stix/common/confidence.py b/stix/common/confidence.py index f3bf12d0..c6975a2f 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -79,13 +79,13 @@ def descriptions(self): Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of diff --git a/stix/common/information_source.py b/stix/common/information_source.py index d9addbcb..32e0a0a1 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -93,13 +93,13 @@ def descriptions(self): Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of diff --git a/stix/common/statement.py b/stix/common/statement.py index 753d4565..48612945 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -80,13 +80,13 @@ def descriptions(self): Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index c9c270e3..dfd8e8be 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -115,7 +115,7 @@ class StructuredTextList(stix.TypedSequence): Args: *args: A variable-length argument list which can contain single - :class:`StructuredText` objects or sequences of objects. + :class:`.StructuredText` objects or sequences of objects. """ _contained_type = StructuredText @@ -134,7 +134,7 @@ def __init__(self, *args): self.add(arg) def with_id(self, id): - """Returns a :class:`StructuredText` object with a matching `id` or + """Returns a :class:`.StructuredText` object with a matching `id` or ``None`` if not found. """ @@ -147,7 +147,7 @@ def with_id(self, id): def reset(self): """Assigns sequential ordinality values to each of the sorted - :class:`StructuredText` objects, starting with ``1`` and ending + :class:`.StructuredText` objects, starting with ``1`` and ending at ``len(self)``. """ @@ -157,7 +157,7 @@ def reset(self): @property def sorted(self): """Returns a copy of the collection of internal - :class:`StructuredText` objects, sorted by their ``ordinality``. + :class:`.StructuredText` objects, sorted by their ``ordinality``. """ return sorted(self._inner, key=lambda x: int(x.ordinality)) @@ -187,7 +187,7 @@ def __iter__(self): return iter(self.sorted) def __getitem__(self, key): - """Returns the :class:`StructuredText` object with a matching + """Returns the :class:`.StructuredText` object with a matching ordinality. Args: @@ -227,9 +227,9 @@ def __reversed__(self): raise NotImplementedError() def add(self, value): - """Adds the :class:`StructuredText` `value` to the collection. + """Adds the :class:`.StructuredText` `value` to the collection. - If `value` is not a :class:`StructuredText` object, an attempt will + If `value` is not a :class:`.StructuredText` object, an attempt will be made to convert it to one. Note: @@ -238,7 +238,7 @@ def add(self, value): in the collection, `value` will replace the existing item. Args: - value: A :class:`StructuredText` object. + value: A :class:`.StructuredText` object. """ if not self._is_valid(value): @@ -261,7 +261,7 @@ def update(self, iterable): overwritten. Args: - iterable: An iterable collection of :class:`StructuredText` objects + iterable: An iterable collection of :class:`.StructuredText` objects to add to this collection. """ @@ -336,12 +336,16 @@ def to_obj(self, ns_info=None): return objlist def to_list(self): - """Attempts to flatten out the returned list when there is only one - item in the list. This is to support backwards compatibility with - previous versions of python-stix. + """Returns a list of dictionary representations of the contained + objects. + + An attempt is made to flatten out the returned list when there is only + one item in the collection. This is to support backwards + compatibility with previous versions of python-stix. * If the list repr has more than one item, return the list. * If there is only one item, inspect it. + * If the item is not a dictionary, return it. * If its ``ordinality`` key has a corresponding value of ``1``, remove it from the dictionary since it's assumed if there is only one item. diff --git a/stix/common/tools.py b/stix/common/tools.py index 58dd90ea..e947b685 100644 --- a/stix/common/tools.py +++ b/stix/common/tools.py @@ -39,7 +39,7 @@ def short_description(self): Note: If this object has more than one short description set, this will - return the short_description with the lowest ordinality value. + return the short description with the lowest ordinality value. Returns: An instance of @@ -54,23 +54,25 @@ def short_description(self, value): @property def short_descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. + """A :class:`.StructuredTextList` object, containing short descriptions + about the purpose or intent of this object. + + This is typically used for the purpose of providing multiple + short descriptions with different classificaton markings. Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: - An instance of - :class:`.StructuredTextList` + An instance of :class:`.StructuredTextList` """ return self._short_description diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index 138a2673..195388cb 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -27,23 +27,17 @@ def __init__(self, package_intents=None, description=None, handling=None, @property def description(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. + """A single description about the contents or purpose of this object. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: ``None`` Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + If this object has more than one description set, this will return + the description with the lowest ordinality value. Returns: An instance of - :class:`.StructuredTextList` + :class:`.StructuredText` """ return next(iter(self.descriptions), None) @@ -54,32 +48,48 @@ def description(self, value): @property def descriptions(self): - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - - @property - def short_description(self): """A :class:`.StructuredTextList` object, containing descriptions about the purpose or intent of this object. + This is typically used for the purpose of providing multiple + descriptions with different classificaton markings. + Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of :class:`.StructuredTextList` + """ + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) + + @property + def short_description(self): + """A single short description about the contents or purpose of this + object. + + Default Value: ``None`` + + Note: + If this object has more than one short description set, this will + return the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + """ return next(iter(self.short_descriptions), None) @@ -89,6 +99,27 @@ def short_description(self, value): @property def short_descriptions(self): + """A :class:`.StructuredTextList` object, containing short descriptions + about the purpose or intent of this object. + + This is typically used for the purpose of providing multiple + short descriptions with different classificaton markings. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`.StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`.StructuredText` will be be converted. + + Returns: + An instance of :class:`.StructuredTextList` + + """ return self._short_description @short_descriptions.setter diff --git a/stix/exploit_target/configuration.py b/stix/exploit_target/configuration.py index 6ab6202e..fa69674b 100644 --- a/stix/exploit_target/configuration.py +++ b/stix/exploit_target/configuration.py @@ -26,23 +26,17 @@ def __init__(self, description=None, short_description=None, cce_id=None): @property def description(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. + """A single description about the contents or purpose of this object. - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`StructuredTextList` object. + Default Value: ``None`` Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + If this object has more than one description set, this will return + the description with the lowest ordinality value. Returns: An instance of - :class:`.StructuredTextList` + :class:`.StructuredText` """ return next(iter(self.descriptions), None) @@ -53,32 +47,48 @@ def description(self, value): @property def descriptions(self): - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - - @property - def short_description(self): """A :class:`.StructuredTextList` object, containing descriptions about the purpose or intent of this object. + This is typically used for the purpose of providing multiple + descriptions with different classificaton markings. + Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of :class:`.StructuredTextList` + """ + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) + + @property + def short_description(self): + """A single short description about the contents or purpose of this + object. + + Default Value: ``None`` + + Note: + If this object has more than one short description set, this will + return the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + """ return next(iter(self.short_descriptions), None) @@ -88,6 +98,27 @@ def short_description(self, value): @property def short_descriptions(self): + """A :class:`.StructuredTextList` object, containing short descriptions + about the purpose or intent of this object. + + This is typically used for the purpose of providing multiple + short descriptions with different classificaton markings. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`.StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`.StructuredText` will be be converted. + + Returns: + An instance of :class:`.StructuredTextList` + + """ return self._short_description @short_descriptions.setter diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index b42171b8..f7ec70b4 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -52,23 +52,17 @@ def title(self, value): @property def description(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. + """A single description about the contents or purpose of this object. - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`StructuredTextList` object. + Default Value: ``None`` Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + If this object has more than one description set, this will return + the description with the lowest ordinality value. Returns: An instance of - :class:`.StructuredTextList` + :class:`.StructuredText` """ return next(iter(self.descriptions), None) @@ -79,32 +73,48 @@ def description(self, value): @property def descriptions(self): - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - - @property - def short_description(self): """A :class:`.StructuredTextList` object, containing descriptions about the purpose or intent of this object. + This is typically used for the purpose of providing multiple + descriptions with different classificaton markings. + Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of :class:`.StructuredTextList` + """ + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) + + @property + def short_description(self): + """A single short description about the contents or purpose of this + object. + + Default Value: ``None`` + + Note: + If this object has more than one short description set, this will + return the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + """ return next(iter(self.short_descriptions), None) @@ -114,6 +124,27 @@ def short_description(self, value): @property def short_descriptions(self): + """A :class:`.StructuredTextList` object, containing short descriptions + about the purpose or intent of this object. + + This is typically used for the purpose of providing multiple + short descriptions with different classificaton markings. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`.StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`.StructuredText` will be be converted. + + Returns: + An instance of :class:`.StructuredTextList` + + """ return self._short_description @short_descriptions.setter diff --git a/stix/exploit_target/weakness.py b/stix/exploit_target/weakness.py index c9e3d22b..370a0073 100644 --- a/stix/exploit_target/weakness.py +++ b/stix/exploit_target/weakness.py @@ -36,33 +36,49 @@ def cwe_id(self, value): @property def description(self): + """A single description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If this object has more than one description set, this will return + the description with the lowest ordinality value. + + Returns: + An instance of + :class:`.StructuredText` + + """ + return next(iter(self.descriptions), None) + + @description.setter + def description(self, value): + self.descriptions = value + + @property + def descriptions(self): """A :class:`.StructuredTextList` object, containing descriptions about the purpose or intent of this object. + This is typically used for the purpose of providing multiple + descriptions with different classificaton markings. + Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of :class:`.StructuredTextList` """ - return next(iter(self.descriptions), None) - - @description.setter - def description(self, value): - self.descriptions = value - - @property - def descriptions(self): return self._description @descriptions.setter diff --git a/stix/extensions/structured_coa/generic_structured_coa.py b/stix/extensions/structured_coa/generic_structured_coa.py index 7b568b77..6b736ba7 100644 --- a/stix/extensions/structured_coa/generic_structured_coa.py +++ b/stix/extensions/structured_coa/generic_structured_coa.py @@ -59,13 +59,13 @@ def descriptions(self): Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index e908fd9b..2df85cca 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -64,13 +64,13 @@ def descriptions(self): Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index 4d189b5e..009a094d 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -40,33 +40,49 @@ def type_(self, value): @property def description(self): + """A single description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If this object has more than one description set, this will return + the description with the lowest ordinality value. + + Returns: + An instance of + :class:`.StructuredText` + + """ + return next(iter(self.descriptions), None) + + @description.setter + def description(self, value): + self.descriptions = value + + @property + def descriptions(self): """A :class:`.StructuredTextList` object, containing descriptions about the purpose or intent of this object. + This is typically used for the purpose of providing multiple + descriptions with different classificaton markings. + Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of :class:`.StructuredTextList` """ - return next(iter(self.descriptions), None) - - @description.setter - def description(self, value): - self.descriptions = value - - @property - def descriptions(self): return self._description @descriptions.setter diff --git a/stix/incident/property_affected.py b/stix/incident/property_affected.py index 85096f5d..7d735620 100644 --- a/stix/incident/property_affected.py +++ b/stix/incident/property_affected.py @@ -88,13 +88,13 @@ def description_of_effect(self): Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index d86bb948..da9b6d73 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -927,14 +927,8 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - skip = ( - 'observables', - 'observable_composition_operator', - 'negate' - ) - - d = super(Indicator, self).to_dict() - utils.remove_entries(d, skip) + keys = ('observables', 'observable_composition_operator', 'negate') + d = utils.to_dict(self, skip=keys) if self.negate: d['negate'] = True diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index 494b05fa..156e7dd6 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -34,33 +34,49 @@ def timestamp(self, value): @property def description(self): + """A single description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If this object has more than one description set, this will return + the description with the lowest ordinality value. + + Returns: + An instance of + :class:`.StructuredText` + + """ + return next(iter(self.descriptions), None) + + @description.setter + def description(self, value): + self.descriptions = value + + @property + def descriptions(self): """A :class:`.StructuredTextList` object, containing descriptions about the purpose or intent of this object. + This is typically used for the purpose of providing multiple + descriptions with different classificaton markings. + Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of :class:`.StructuredTextList` """ - return next(iter(self.descriptions), None) - - @description.setter - def description(self, value): - self.descriptions = value - - @property - def descriptions(self): return self._description @descriptions.setter diff --git a/stix/ttp/attack_pattern.py b/stix/ttp/attack_pattern.py index c68c49d5..819c07c8 100644 --- a/stix/ttp/attack_pattern.py +++ b/stix/ttp/attack_pattern.py @@ -28,23 +28,17 @@ def title(self, value): @property def description(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. + """A single description about the contents or purpose of this object. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: ``None`` Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + If this object has more than one description set, this will return + the description with the lowest ordinality value. Returns: An instance of - :class:`.StructuredTextList` + :class:`.StructuredText` """ return next(iter(self.descriptions), None) @@ -55,32 +49,48 @@ def description(self, value): @property def descriptions(self): - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - - @property - def short_description(self): """A :class:`.StructuredTextList` object, containing descriptions about the purpose or intent of this object. + This is typically used for the purpose of providing multiple + descriptions with different classificaton markings. + Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of :class:`.StructuredTextList` + """ + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) + + @property + def short_description(self): + """A single short description about the contents or purpose of this + object. + + Default Value: ``None`` + + Note: + If this object has more than one short description set, this will + return the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + """ return next(iter(self.short_descriptions), None) @@ -90,6 +100,27 @@ def short_description(self, value): @property def short_descriptions(self): + """A :class:`.StructuredTextList` object, containing short descriptions + about the purpose or intent of this object. + + This is typically used for the purpose of providing multiple + short descriptions with different classificaton markings. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`.StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`.StructuredText` will be be converted. + + Returns: + An instance of :class:`.StructuredTextList` + + """ return self._short_description @short_descriptions.setter diff --git a/stix/ttp/exploit.py b/stix/ttp/exploit.py index f7705f74..9cfa3a04 100644 --- a/stix/ttp/exploit.py +++ b/stix/ttp/exploit.py @@ -28,23 +28,17 @@ def title(self, value): @property def description(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. + """A single description about the contents or purpose of this object. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: ``None`` Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + If this object has more than one description set, this will return + the description with the lowest ordinality value. Returns: An instance of - :class:`.StructuredTextList` + :class:`.StructuredText` """ return next(iter(self.descriptions), None) @@ -55,32 +49,48 @@ def description(self, value): @property def descriptions(self): - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - - @property - def short_description(self): """A :class:`.StructuredTextList` object, containing descriptions about the purpose or intent of this object. + This is typically used for the purpose of providing multiple + descriptions with different classificaton markings. + Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of :class:`.StructuredTextList` + """ + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) + + @property + def short_description(self): + """A single short description about the contents or purpose of this + object. + + Default Value: ``None`` + + Note: + If this object has more than one short description set, this will + return the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + """ return next(iter(self.short_descriptions), None) @@ -90,6 +100,27 @@ def short_description(self, value): @property def short_descriptions(self): + """A :class:`.StructuredTextList` object, containing short descriptions + about the purpose or intent of this object. + + This is typically used for the purpose of providing multiple + short descriptions with different classificaton markings. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`.StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`.StructuredText` will be be converted. + + Returns: + An instance of :class:`.StructuredTextList` + + """ return self._short_description @short_descriptions.setter diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index 2235a3ed..c3ef6781 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -34,23 +34,17 @@ def title(self, value): @property def description(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. + """A single description about the contents or purpose of this object. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: ``None`` Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + If this object has more than one description set, this will return + the description with the lowest ordinality value. Returns: An instance of - :class:`.StructuredTextList` + :class:`.StructuredText` """ return next(iter(self.descriptions), None) @@ -61,32 +55,48 @@ def description(self, value): @property def descriptions(self): - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - - @property - def short_description(self): """A :class:`.StructuredTextList` object, containing descriptions about the purpose or intent of this object. + This is typically used for the purpose of providing multiple + descriptions with different classificaton markings. + Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of :class:`.StructuredTextList` + """ + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) + + @property + def short_description(self): + """A single short description about the contents or purpose of this + object. + + Default Value: ``None`` + + Note: + If this object has more than one short description set, this will + return the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + """ return next(iter(self.short_descriptions), None) @@ -96,6 +106,27 @@ def short_description(self, value): @property def short_descriptions(self): + """A :class:`.StructuredTextList` object, containing short descriptions + about the purpose or intent of this object. + + This is typically used for the purpose of providing multiple + short descriptions with different classificaton markings. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`.StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`.StructuredText` will be be converted. + + Returns: + An instance of :class:`.StructuredTextList` + + """ return self._short_description @short_descriptions.setter diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index 83538d5b..e06b33f0 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -30,23 +30,17 @@ def title(self, value): @property def description(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. + """A single description about the contents or purpose of this object. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: ``None`` Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + If this object has more than one description set, this will return + the description with the lowest ordinality value. Returns: An instance of - :class:`.StructuredTextList` + :class:`.StructuredText` """ return next(iter(self.descriptions), None) @@ -57,32 +51,48 @@ def description(self, value): @property def descriptions(self): - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - - @property - def short_description(self): """A :class:`.StructuredTextList` object, containing descriptions about the purpose or intent of this object. + This is typically used for the purpose of providing multiple + descriptions with different classificaton markings. + Iterating over this object will yield its contents sorted by their ``ordinality`` value. - Default Value: Empty :class:`StructuredTextList` object. + Default Value: Empty :class:`.StructuredTextList` object. Note: IF this is set to a value that is not an instance of :class:`.StructuredText`, an effort will ne made to convert it. If this is set to an iterable, any values contained that are not - an instance of :class:`StructuredText` will be be converted. + an instance of :class:`.StructuredText` will be be converted. Returns: An instance of :class:`.StructuredTextList` + """ + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) + + @property + def short_description(self): + """"A single short description about the contents or purpose of this + object. + + Default Value: ``None`` + + Note: + If this object has more than one short description set, this will + return the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + """ return next(iter(self.short_descriptions), None) @@ -92,6 +102,27 @@ def short_description(self, value): @property def short_descriptions(self): + """A :class:`.StructuredTextList` object, containing short descriptions + about the purpose or intent of this object. + + This is typically used for the purpose of providing multiple + short descriptions with different classificaton markings. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`.StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`.StructuredText` will be be converted. + + Returns: + An instance of :class:`.StructuredTextList` + + """ return self._short_description @short_descriptions.setter From 92fb175f581b7494274bb4135a79a906ad22ea79 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 20:08:36 -0400 Subject: [PATCH 028/438] Updated structured text docstrings. --- stix/common/structured_text.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index dfd8e8be..ea631c2e 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -9,6 +9,15 @@ class StructuredText(stix.Entity): + """Used for storing descriptive text elements. + + Attributes: + id_: An id for the text element, typically used for controlled + structure xpath selectors. + value: The text value of this object. + structuring_format: The format of the text. For example, ``html5``. + + """ _binding = stix_common_binding _binding_class = _binding.StructuredTextType _namespace = 'http://stix.mitre.org/common-1' @@ -25,6 +34,13 @@ def ordinality(self): @ordinality.setter def ordinality(self, value): + """An integer ordinality for this text item. This must be greater than + 1. + + This is used for displaying :class:`.StructuredTextList` items and + provides an order to display text items to a parser. + + """ if value is None: self._ordinality = None return @@ -104,9 +120,15 @@ def from_dict(cls, d, return_obj=None): return return_obj def __str__(self): + """Returns a UTF-8 encoded string representation of the ``value``. + + """ return self.__unicode__().encode("utf-8") def __unicode__(self): + """Returns a ``unicode`` string representation of the ``value``. + + """ return unicode(self.value) From 46474251c6a82381610bdd2cb907b4ff5fc729a4 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 20:33:13 -0400 Subject: [PATCH 029/438] Added docstrings to indicator module. --- stix/common/structured_text.py | 22 ++++++++++++++++++++++ stix/indicator/indicator.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index ea631c2e..8fcb7904 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -55,6 +55,9 @@ def ordinality(self, value): raise ValueError(error) def to_obj(self, return_obj=None, ns_info=None): + """Converts this object into a binding object. + + """ if not return_obj: return_obj = self._binding_class() @@ -80,6 +83,13 @@ def is_plain(self): return plain def to_dict(self): + """Converts this object into a dictionary representation. + + Note: + If no properies or attributes are set other than ``value``, + this will return a string. + + """ # Return a plain string if there is no format specified. if self.is_plain(): return self.value @@ -88,6 +98,12 @@ def to_dict(self): @classmethod def from_obj(cls, obj, return_obj=None): + """Create an object from the input binding object. + + Args: + obj: A generateDS binding object. + + """ if not obj: return None @@ -103,6 +119,12 @@ def from_obj(cls, obj, return_obj=None): @classmethod def from_dict(cls, d, return_obj=None): + """Creates an object from the input dictionary. + + Args: + d: A dictionary representation of this object. + + """ if not d: return None diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index da9b6d73..2727624e 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -398,6 +398,7 @@ def add_valid_time_position(self, value): Raises: ValueError: If the `value` argument is not an instance of :class:`stix.indicator.valid_time.ValidTime`. + """ self.valid_time_positions.append(value) @@ -615,6 +616,34 @@ def related_campaigns(self, value): self._related_campaigns = RelatedCampaignRefs(value) def add_related_campaign(self, value): + """Adds a Related Campaign to this Indicator. + + The `value` parameter must be an instance of :class:`.RelatedCampaignRef` + or :class:`.CampaignRef`. + + If the `value` parameter is ``None``, no item wil be added to the + ``related_campaigns`` collection. + + Calling this method is the same as calling ``append()`` on the + ``related_campaigns`` property. + + See Also: + The :class:`.RelatedCampaignRef` documentation. + + Note: + If the `value` parameter is not an instance of + :class:`.RelatedCampaignRef` an attempt will be made to convert it + to one. + + Args: + value: An instance of :class:`.RelatedCampaignRef` or + :class:`.Campaign`. + + Raises: + ValueError: If the `value` parameter cannot be converted into + an instance of :class:`.RelatedCampaignRef` + + """ self.related_campaigns.append(value) @property From 9938fc313a36174e52faa05d3915f39bcda1df4d Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 23 Apr 2015 20:33:40 -0400 Subject: [PATCH 030/438] Updated rst files for structured text and indicator. --- docs/api/common/structured_text.rst | 10 +++++++++- docs/api/indicator/indicator.rst | 23 ++++++++++++++++++----- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/docs/api/common/structured_text.rst b/docs/api/common/structured_text.rst index 77bcd53c..3ef0bb20 100644 --- a/docs/api/common/structured_text.rst +++ b/docs/api/common/structured_text.rst @@ -8,4 +8,12 @@ Classes .. autoclass:: StructuredText :show-inheritance: - :members: + :members: to_obj, from_obj, to_dict, from_dict, ordinality, + __str__, __unicode__ + +.. autoclass:: StructuredTextList + :show-inheritance: + :members: __getitem__, __delitem__, __iter__, add, update, + insert, remove, reset, sorted, next_ordinality, to_obj, to_dict + + diff --git a/docs/api/indicator/indicator.rst b/docs/api/indicator/indicator.rst index cd6a1c7f..96318f89 100644 --- a/docs/api/indicator/indicator.rst +++ b/docs/api/indicator/indicator.rst @@ -23,20 +23,33 @@ Classes .. autoclass:: Indicator :show-inheritance: - :members: + :members: to_obj, from_obj, to_dict, from_dict, producer, observable, + observables, add_observable, alternative_id, add_alternative_id, + valid_time_positions, add_valid_time_position, indicator_types, + add_indicator_type, confidence, add_indicated_ttp, + add_test_mechanism, add_related_indicator + .. autoclass:: CompositeIndicatorExpression :show-inheritance: - :members: + :members: to_obj, from_obj, to_dict, from_dict + .. autoclass:: RelatedIndicators :show-inheritance: - :members: + :members: to_obj, from_obj, to_dict, from_dict + + +.. autoclass:: RelatedCampaignRefs + :show-inheritance: + :members: to_obj, from_obj, to_dict, from_dict + .. autoclass:: SuggestedCOAs :show-inheritance: - :members: + :members: to_obj, from_obj, to_dict, from_dict + .. autoclass:: IndicatorTypes :show-inheritance: - :members: + :members: to_obj, from_obj, to_dict, from_dict From c7716fab59a111cae2dcf77c382fefd913c09789 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 24 Apr 2015 16:13:07 -0400 Subject: [PATCH 031/438] Refactored self.next_ordinality to call ordinalities property once. --- stix/common/structured_text.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 8fcb7904..e70374e3 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -219,11 +219,13 @@ def next_ordinality(self): """Returns the "+1" of the highest ordinality in the collection. """ - if self.ordinalities: - return self.ordinalities[-1] + 1 - else: + ords = self.ordinalities + + if not ords: return 1 + return ords[-1] + 1 + def __iter__(self): """Returns an iterator for the collection sorted by ordinality. From 7d095f17b72d7984173ba1fa728be42800637467 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 27 Apr 2015 11:19:08 -0400 Subject: [PATCH 032/438] Refactored how binding classes are resolved for xsi:types. --- stix/bindings/__init__.py | 33 ++ stix/bindings/campaign.py | 10 +- stix/bindings/course_of_action.py | 34 +- stix/bindings/data_marking.py | 25 +- stix/bindings/exploit_target.py | 31 +- .../extensions/address/ciq_address_3_0.py | 9 +- .../extensions/attack_pattern/capec_2_7.py | 9 +- .../extensions/identity/ciq_identity_3_0.py | 9 +- stix/bindings/extensions/malware/maec_4_1.py | 9 +- .../extensions/marking/simple_marking.py | 3 +- .../marking/terms_of_use_marking.py | 3 +- stix/bindings/extensions/marking/tlp.py | 2 +- .../extensions/structured_coa/generic.py | 9 +- .../extensions/test_mechanism/generic.py | 9 +- .../test_mechanism/open_ioc_2010.py | 9 +- .../extensions/test_mechanism/oval_5_10.py | 10 +- .../extensions/test_mechanism/snort.py | 9 +- .../extensions/test_mechanism/yara.py | 9 +- .../extensions/vulnerability/cvrf_1_1.py | 9 +- stix/bindings/incident.py | 67 +-- stix/bindings/indicator.py | 43 +- stix/bindings/stix_common.py | 397 +++++++++++------- stix/bindings/stix_core.py | 123 ++---- stix/bindings/threat_actor.py | 27 +- stix/bindings/ttp.py | 82 ++-- stix/test/coa_test.py | 1 - 26 files changed, 473 insertions(+), 508 deletions(-) diff --git a/stix/bindings/__init__.py b/stix/bindings/__init__.py index c88b876c..97814a20 100644 --- a/stix/bindings/__init__.py +++ b/stix/bindings/__init__.py @@ -411,8 +411,41 @@ def get_type_info(node): return TypeInfo(ns=ns, typename=typename) +_EXTENSION_MAP = {} + + +def add_extension(cls): + typeinfo = TypeInfo(ns=cls.xmlns, typename=cls.xml_type) + _EXTENSION_MAP[typeinfo] = cls + + +def register_extension(cls): + add_extension(cls) + return cls + + +def lookup_extension(typeinfo): + if not isinstance(typeinfo, TypeInfo): + typeinfo = get_type_info(typeinfo) + + try: + return _EXTENSION_MAP[typeinfo] + except KeyError: + fmt = "No class implemented or registered for XML type '{%s}%s'" + error = fmt % (typeinfo.ns, typeinfo.typename) + raise NotImplementedError(error) + + +def is_base(node): + return xmlconst.TAG_XSI_TYPE not in node.attrib + + __all__ = [ '_cast', + 'add_extension', + 'lookup_extension', + 'is_base', + 'register_extension', 'etree_', 'ExternalEncoding', 'find_attr_value_', diff --git a/stix/bindings/campaign.py b/stix/bindings/campaign.py index 95acd1e0..4969dc93 100644 --- a/stix/bindings/campaign.py +++ b/stix/bindings/campaign.py @@ -432,17 +432,21 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): super(AttributionType, self).buildChildren(child_, node, nodeName_, True) # end class AttributionType + +@register_extension class CampaignType(stix_common_binding.CampaignBaseType): """The CampaignType characterizes a single cyber threat Campaign.Specifies the relevant STIX-Campaign schema version for this content.""" subclass = None superclass = stix_common_binding.CampaignBaseType + + xmlns = "http://stix.mitre.org/Campaign-1" + xmlns_prefix = "campaign" + xml_type = "CampaignType" + def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None, Description=None, Short_Description=None, Names=None, Intended_Effect=None, Status=None, Related_TTPs=None, Related_Incidents=None, Related_Indicators=None, Attribution=None, Associated_Campaigns=None, Confidence=None, Activity=None, Information_Source=None, Handling=None, Related_Packages=None): super(CampaignType, self).__init__(idref=idref, id=id, timestamp=timestamp) - self.xmlns = "http://stix.mitre.org/Campaign-1" - self.xmlns_prefix = "campaign" - self.xml_type = "CampaignType" self.version = _cast(None, version) self.Title = Title if Description is None: diff --git a/stix/bindings/course_of_action.py b/stix/bindings/course_of_action.py index 13e8e584..1c5a1158 100644 --- a/stix/bindings/course_of_action.py +++ b/stix/bindings/course_of_action.py @@ -43,9 +43,6 @@ class StructuredCOAType(GeneratedsSuper): subclass = None superclass = None def __init__(self, idref=None, id=None): - self.xmlns = "http://stix.mitre.org/CourseOfAction-1" - self.xmlns_prefix = "coa" - self.xml_type = "CourseOfActionType" self.idref = _cast(None, idref) self.id = _cast(None, id) pass @@ -211,6 +208,8 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): self.set_Applicability_Confidence(obj_) # end class ObjectiveType + +@register_extension class CourseOfActionType(stix_common_binding.CourseOfActionBaseType): """The CourseOfActionType characterizes a Course of Action to be taken in regards to one of more cyber threats. NOTE: This construct is @@ -219,11 +218,14 @@ class CourseOfActionType(stix_common_binding.CourseOfActionBaseType): schema version for this content.""" subclass = None superclass = stix_common_binding.CourseOfActionBaseType + + xmlns = "http://stix.mitre.org/CourseOfAction-1" + xmlns_prefix = "coa" + xml_type = "CourseOfActionType" + def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None, Stage=None, Type=None, Description=None, Short_Description=None, Objective=None, Parameter_Observables=None, Structured_COA=None, Impact=None, Cost=None, Efficacy=None, Information_Source=None, Handling=None, Related_COAs=None, Related_Packages=None): super(CourseOfActionType, self).__init__(idref=idref, id=id, timestamp=timestamp) - self.xmlns = "http://stix.mitre.org/CourseOfAction-1" - self.xmlns_prefix = "coa" - self.xml_type = "CourseOfActionType" + self.version = _cast(None, version) self.Title = Title self.Stage = Stage @@ -418,24 +420,8 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): obj_.build(child_) self.set_Parameter_Observables(obj_) elif nodeName_ == 'Structured_COA': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] - - if type_name_ == "GenericStructuredCOAType": - from .extensions.structured_coa import generic - obj_ = generic.GenericStructuredCOAType.factory() - else: - raise NotImplementedError('No implementation class for Structured_COA: ' + type_name_) - else: - raise NotImplementedError('Structured_COA type not declared: missing xsi_type attribute') - + from .extensions.structured_coa import generic + obj_ = lookup_extension(child_).factory() obj_.build(child_) self.set_Structured_COA(obj_) elif nodeName_ == 'Impact': diff --git a/stix/bindings/data_marking.py b/stix/bindings/data_marking.py index fda03e89..5e3dbfc9 100644 --- a/stix/bindings/data_marking.py +++ b/stix/bindings/data_marking.py @@ -12,7 +12,6 @@ # internal from stix.bindings import * -from stix import xmlconst from . import stix_common as stix_common_binding XML_NS = "http://data-marking.mitre.org/Marking-1" @@ -339,20 +338,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): # Look for xsi:type. If not there, build an instance of # MarkingStructureType - if xmlconst.TAG_XSI_TYPE not in child_.attrib: - ref = MarkingStructureType.factory() - ref.build(child_) - self.Marking_Structure.append(ref) - return + if is_base(child_): + obj_ = MarkingStructureType.factory() + else: + obj_ = lookup_extension(child_).factory() - # Extract the xsi:type associated type namespace and type name - typeinfo = get_type_info(child_) - - if typeinfo not in _EXTENSION_MAP: - raise NotImplementedError('Marking structure type not implemented ' + typeinfo.typename) - - klass = _EXTENSION_MAP[typeinfo] - obj_ = klass.factory() obj_.build(child_) self.Marking_Structure.append(obj_) @@ -363,13 +353,6 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): # end class MarkingSpecificationType -_EXTENSION_MAP = {} - -def add_extension(klass): - typeinfo = TypeInfo(ns=klass.xmlns, typename=klass.xml_type) - _EXTENSION_MAP[typeinfo] = klass - - GDSClassesMapping = {} USAGE_TEXT = """ diff --git a/stix/bindings/exploit_target.py b/stix/bindings/exploit_target.py index 86b05da9..0e2317cd 100644 --- a/stix/bindings/exploit_target.py +++ b/stix/bindings/exploit_target.py @@ -754,16 +754,21 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): super(PotentialCOAsType, self).buildChildren(child_, node, nodeName_, True) # end class PotentialCOAsType + +@register_extension class ExploitTargetType(stix_common_binding.ExploitTargetBaseType): """Specifies the relevant STIX-ExploitTarget schema version for this content.""" subclass = None superclass = stix_common_binding.ExploitTargetBaseType + + xmlns = "http://stix.mitre.org/ExploitTarget-1" + xmlns_prefix = "et" + xml_type = "ExploitTargetType" + def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None, Description=None, Short_Description=None, Vulnerability=None, Weakness=None, Configuration=None, Potential_COAs=None, Information_Source=None, Handling=None, Related_Exploit_Targets=None, Related_Packages=None): super(ExploitTargetType, self).__init__(timestamp=timestamp, idref=idref, id=id) - self.xmlns = "http://stix.mitre.org/ExploitTarget-1" - self.xmlns_prefix = "et" - self.xml_type = "ExploitTargetType" + self.version = _cast(None, version) self.Title = Title if Description is None: @@ -933,23 +938,13 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): obj_.build(child_) self.add_Short_Description(obj_) elif nodeName_ == 'Vulnerability': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + import stix.bindings.extensions.vulnerability.cvrf_1_1 as cvrf_1_1_binding - if type_name_ == "CVRF1.1InstanceType": - import stix.bindings.extensions.vulnerability.cvrf_1_1 as cvrf_1_1_binding - obj_ = cvrf_1_1_binding.CVRF1_1InstanceType.factory() - else: - raise NotImplementedError('No implementation class for Vulnerability: ' + type_name_) - else: + if is_base(child_): obj_ = VulnerabilityType.factory() # VulnerabilityType not abstract + else: + obj_ = lookup_extension(child_).factory() + obj_.build(child_) self.Vulnerability.append(obj_) elif nodeName_ == 'Weakness': diff --git a/stix/bindings/extensions/address/ciq_address_3_0.py b/stix/bindings/extensions/address/ciq_address_3_0.py index 6738143a..5ae3a492 100644 --- a/stix/bindings/extensions/address/ciq_address_3_0.py +++ b/stix/bindings/extensions/address/ciq_address_3_0.py @@ -18,6 +18,7 @@ # Data representation classes. # +@register_extension class CIQAddress3_0InstanceType(stix_common_binding.AddressAbstractType): """The CIQAddress3.0InstanceType provides an extension to the stix_common_binding.AddressAbstractType which imports and leverages version 3.0 of @@ -25,12 +26,14 @@ class CIQAddress3_0InstanceType(stix_common_binding.AddressAbstractType): Addresses.""" subclass = None superclass = stix_common_binding.AddressAbstractType + + xmlns = XML_NS + xmlns_prefix = "ciqAddress" + xml_type = "CIQAddress3.0InstanceType" + def __init__(self, Location=None): super(CIQAddress3_0InstanceType, self).__init__() self.Location = Location - self.xmlns = XML_NS - self.xmlns_prefix = "ciqAddress" - self.xml_type = "CIQAddress3.0InstanceType" def factory(*args_, **kwargs_): if CIQAddress3_0InstanceType.subclass: return CIQAddress3_0InstanceType.subclass(*args_, **kwargs_) diff --git a/stix/bindings/extensions/attack_pattern/capec_2_7.py b/stix/bindings/extensions/attack_pattern/capec_2_7.py index e7cfbce5..8cb36966 100644 --- a/stix/bindings/extensions/attack_pattern/capec_2_7.py +++ b/stix/bindings/extensions/attack_pattern/capec_2_7.py @@ -18,18 +18,21 @@ # Data representation classes. # +@register_extension class CAPEC2_7InstanceType(ttp_binding.AttackPatternType): """The CAPECInstanceType provides an extension to the APStructureAbstractType which imports and leverages the CAPEC schema for structured characterization of Attack Patterns.""" subclass = None superclass = ttp_binding.AttackPatternType + + xmlns = XML_NS + xmlns_prefix = "capecInstance" + xml_type = "CAPEC2.7InstanceType" + def __init__(self, capec_id=None, Description=None, CAPEC=None): super(CAPEC2_7InstanceType, self).__init__(capec_id=capec_id, Description=Description) self.CAPEC = CAPEC - self.xmlns = XML_NS - self.xmlns_prefix = "capecInstance" - self.xml_type = "CAPEC2.7InstanceType" def factory(*args_, **kwargs_): if CAPEC2_7InstanceType.subclass: diff --git a/stix/bindings/extensions/identity/ciq_identity_3_0.py b/stix/bindings/extensions/identity/ciq_identity_3_0.py index ad8fd953..d875b191 100644 --- a/stix/bindings/extensions/identity/ciq_identity_3_0.py +++ b/stix/bindings/extensions/identity/ciq_identity_3_0.py @@ -18,6 +18,7 @@ # Data representation classes. # +@register_extension class CIQIdentity3_0InstanceType(stix_common_binding.IdentityType): """The CIQIdentity3.0InstanceType provides an extension to the IdentityStructureAbstractType which imports and leverages @@ -25,11 +26,13 @@ class CIQIdentity3_0InstanceType(stix_common_binding.IdentityType): characterization of Identities.""" subclass = None superclass = stix_common_binding.IdentityType + + xmlns = XML_NS + xmlns_prefix = "stix-ciqidentity" + xml_type = "CIQIdentity3.0InstanceType" + def __init__(self, idref=None, id=None, Name=None, Related_Identities=None, Specification=None, Role=None): super(CIQIdentity3_0InstanceType, self).__init__(idref=idref, id=id, Name=Name, Related_Identities=Related_Identities) - self.xmlns = XML_NS - self.xmlns_prefix = "stix-ciqidentity" - self.xml_type = "CIQIdentity3.0InstanceType" self.xsi_type = None self.Specification = Specification if Role is None: diff --git a/stix/bindings/extensions/malware/maec_4_1.py b/stix/bindings/extensions/malware/maec_4_1.py index 5294cdc4..dd86bcf9 100644 --- a/stix/bindings/extensions/malware/maec_4_1.py +++ b/stix/bindings/extensions/malware/maec_4_1.py @@ -23,17 +23,20 @@ # Data representation classes. # +@register_extension class MAEC4_1InstanceType(ttp_binding.MalwareInstanceType): """The MAEC4.1InstanceType provides an extension to ttp_binding.MalwareInstanceType which imports and leverages the MAEC 4.0.1 schema for structured characterization of Malware.""" subclass = None superclass = ttp_binding.MalwareInstanceType + + xmlns = XML_NS + xmlns_prefix = "stix-maec" + xml_type = "MAEC4.1InstanceType" + def __init__(self, Type=None, Name=None, Description=None, MAEC=None): super(MAEC4_1InstanceType, self).__init__(Type=Type, Name=Name, Description=Description) - self.xmlns = XML_NS - self.xmlns_prefix = "stix-maec" - self.xml_type = "MAEC4.1InstanceType" self.MAEC = MAEC def factory(*args_, **kwargs_): if MAEC4_1InstanceType.subclass: diff --git a/stix/bindings/extensions/marking/simple_marking.py b/stix/bindings/extensions/marking/simple_marking.py index 54f43f17..ac9e5099 100644 --- a/stix/bindings/extensions/marking/simple_marking.py +++ b/stix/bindings/extensions/marking/simple_marking.py @@ -18,6 +18,8 @@ # Data representation classes. # + +@register_extension class SimpleMarkingStructureType(data_marking_binding.MarkingStructureType): """The SimpleMarkingStructureType is a basic implementation of the data marking schema that allows for a string statement to be @@ -101,7 +103,6 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): super(SimpleMarkingStructureType, self).buildChildren(child_, node, nodeName_, True) # end class SimpleMarkingStructureType -data_marking_binding.add_extension(SimpleMarkingStructureType) GDSClassesMapping = {} diff --git a/stix/bindings/extensions/marking/terms_of_use_marking.py b/stix/bindings/extensions/marking/terms_of_use_marking.py index 46c8d5e6..097fcea4 100644 --- a/stix/bindings/extensions/marking/terms_of_use_marking.py +++ b/stix/bindings/extensions/marking/terms_of_use_marking.py @@ -18,6 +18,7 @@ # Data representation classes. # +@register_extension class TermsOfUseMarkingStructureType(data_marking_binding.MarkingStructureType): """The TermsOfUseMarkingStructureType is a basic implementation of the data marking schema that allows for a string statement @@ -104,8 +105,6 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): super(TermsOfUseMarkingStructureType, self).buildChildren(child_, node, nodeName_, True) # end class TermsOfUseMarkingStructureType -data_marking_binding.add_extension(TermsOfUseMarkingStructureType) - GDSClassesMapping = {} USAGE_TEXT = """ diff --git a/stix/bindings/extensions/marking/tlp.py b/stix/bindings/extensions/marking/tlp.py index bf71fbba..e84c85ed 100644 --- a/stix/bindings/extensions/marking/tlp.py +++ b/stix/bindings/extensions/marking/tlp.py @@ -18,6 +18,7 @@ # Data representation classes. # +@register_extension class TLPMarkingStructureType(data_marking_binding.MarkingStructureType): """The TLPMarkingStructureType is an implementation of the data marking schema that allows for a TLP Designation to be attached to an @@ -99,7 +100,6 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass # end class TLPMarkingStructureType -data_marking_binding.add_extension(TLPMarkingStructureType) GDSClassesMapping = {} diff --git a/stix/bindings/extensions/structured_coa/generic.py b/stix/bindings/extensions/structured_coa/generic.py index 52c47949..19401b50 100644 --- a/stix/bindings/extensions/structured_coa/generic.py +++ b/stix/bindings/extensions/structured_coa/generic.py @@ -19,6 +19,7 @@ # Data representation classes. # +@register_extension class GenericStructuredCOAType(StructuredCOAType): """The GenericStructuredCOAType specifies an instantial extension from the abstract course_of_action_binding.StructuredCOAType intended to support the generic @@ -26,11 +27,13 @@ class GenericStructuredCOAType(StructuredCOAType): location of the Generic Structured COA.""" subclass = None superclass = StructuredCOAType + + xmlns = XML_NS + xmlns_prefix = "genericStructuredCOA" + xml_type = "GenericStructuredCOAType" + def __init__(self, idref=None, id=None, reference_location=None, Description=None, Type=None, Specification=None): super(GenericStructuredCOAType, self).__init__(idref=idref, id=id) - self.xmlns = XML_NS - self.xmlns_prefix = "genericStructuredCOA" - self.xml_type = "GenericStructuredCOAType" self.reference_location = _cast(None, reference_location) if Description is None: self.Description = [] diff --git a/stix/bindings/extensions/test_mechanism/generic.py b/stix/bindings/extensions/test_mechanism/generic.py index e84b01aa..574aa617 100644 --- a/stix/bindings/extensions/test_mechanism/generic.py +++ b/stix/bindings/extensions/test_mechanism/generic.py @@ -19,6 +19,7 @@ # Data representation classes. # +@register_extension class GenericTestMechanismType(indicator_binding.TestMechanismType): """The GenericTestMechanismType specifies an instantial extension from the abstract indicator_binding.TestMechanismType intended to support the generic @@ -26,11 +27,13 @@ class GenericTestMechanismType(indicator_binding.TestMechanismType): URL for the location of the Generic Test Mechanism.""" subclass = None superclass = indicator_binding.TestMechanismType + + xmlns = XML_NS + xmlns_prefix = "genericTM" + xml_type = "GenericTestMechanismType" + def __init__(self, idref=None, id=None, Efficacy=None, Producer=None, reference_location=None, Description=None, Type=None, Specification=None): super(GenericTestMechanismType, self).__init__(idref=idref, id=id, Efficacy=Efficacy, Producer=Producer) - self.xmlns = XML_NS - self.xmlns_prefix = "genericTM" - self.xml_type = "GenericTestMechanismType" self.reference_location = _cast(None, reference_location) if Description is None: self.Description = [] diff --git a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py index 42339cb6..a3bd9671 100644 --- a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py +++ b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py @@ -18,6 +18,7 @@ # Data representation classes. # +@register_extension class OpenIOC2010TestMechanismType(indicator_binding.TestMechanismType): """The OpenIOC2010TestMechanismType provides an extension to the indicator_binding.TestMechanismType which imports and leverages the 2010 Open IOC @@ -25,11 +26,13 @@ class OpenIOC2010TestMechanismType(indicator_binding.TestMechanismType): mechanism.""" subclass = None superclass = indicator_binding.TestMechanismType + + xmlns = XML_NS + xmlns_prefix = "stix-openioc" + xml_type = "OpenIOC2010TestMechanismType" + def __init__(self, idref=None, id=None, Efficacy=None, Producer=None, ioc=None): super(OpenIOC2010TestMechanismType, self).__init__(idref=idref, id=id, Efficacy=Efficacy, Producer=Producer) - self.xmlns = XML_NS - self.xmlns_prefix = "stix-openioc" - self.xml_type = "OpenIOC2010TestMechanismType" self.ioc = ioc def factory(*args_, **kwargs_): if OpenIOC2010TestMechanismType.subclass: diff --git a/stix/bindings/extensions/test_mechanism/oval_5_10.py b/stix/bindings/extensions/test_mechanism/oval_5_10.py index 6e5aba15..efb425d5 100644 --- a/stix/bindings/extensions/test_mechanism/oval_5_10.py +++ b/stix/bindings/extensions/test_mechanism/oval_5_10.py @@ -18,17 +18,21 @@ # Data representation classes. # + +@register_extension class OVAL5_10TestMechanismType(indicator_binding.TestMechanismType): """The OVALTestMechanismType provides an extension to the indicator_binding.TestMechanismType which imports and leverages the OVAL schema in order to include OVAL Definitions as the test mechanism.""" subclass = None superclass = indicator_binding.TestMechanismType + + xmlns = XML_NS + xmlns_prefix = "ovalTM" + xml_type = "OVAL5.10TestMechanismType" + def __init__(self, idref=None, id=None, Efficacy=None, Producer=None, oval_definitions=None, oval_variables=None): super(OVAL5_10TestMechanismType, self).__init__(idref=idref, id=id, Efficacy=Efficacy, Producer=Producer) - self.xmlns = XML_NS - self.xmlns_prefix = "ovalTM" - self.xml_type = "OVAL5.10TestMechanismType" self.oval_definitions = oval_definitions self.oval_variables = oval_variables def factory(*args_, **kwargs_): diff --git a/stix/bindings/extensions/test_mechanism/snort.py b/stix/bindings/extensions/test_mechanism/snort.py index 84a384a0..f725b971 100644 --- a/stix/bindings/extensions/test_mechanism/snort.py +++ b/stix/bindings/extensions/test_mechanism/snort.py @@ -19,17 +19,20 @@ # Data representation classes. # +@register_extension class SnortTestMechanismType(indicator_binding.TestMechanismType): """The SnortTestMechanismType specifies an instantial extension from the abstract TestMechanismType intended to support the inclusion of a Snort rule as a test mechanism content.""" subclass = None superclass = indicator_binding.TestMechanismType + + xmlns = XML_NS + xmlns_prefix = "snortTM" + xml_type = "SnortTestMechanismType" + def __init__(self, idref=None, id=None, Efficacy=None, Producer=None, Product_Name=None, Version=None, Rule=None, Event_Filter=None, Rate_Filter=None, Event_Suppression=None): super(SnortTestMechanismType, self).__init__(idref=idref, id=id, Efficacy=Efficacy, Producer=Producer) - self.xmlns = XML_NS - self.xmlns_prefix = "snortTM" - self.xml_type = "SnortTestMechanismType" self.Product_Name = Product_Name self.Version = Version if Rule is None: diff --git a/stix/bindings/extensions/test_mechanism/yara.py b/stix/bindings/extensions/test_mechanism/yara.py index 3bacf92d..cd66dd0d 100644 --- a/stix/bindings/extensions/test_mechanism/yara.py +++ b/stix/bindings/extensions/test_mechanism/yara.py @@ -19,17 +19,20 @@ # Data representation classes. # +@register_extension class YaraTestMechanismType(indicator_binding.TestMechanismType): """The YaraTestMechanismType specifies an instantial extension from the abstract indicator_binding.TestMechanismType intended to support the inclusion of a YARA rule as a test mechanism content.""" subclass = None superclass = indicator_binding.TestMechanismType + + xmlns = XML_NS + xmlns_prefix = "yaraTM" + xml_type = "YaraTestMechanismType" + def __init__(self, idref=None, id=None, Efficacy=None, Producer=None, Version=None, Rule=None): super(YaraTestMechanismType, self).__init__(idref=idref, id=id, Efficacy=Efficacy, Producer=Producer) - self.xmlns = XML_NS - self.xmlns_prefix = "yaraTM" - self.xml_type = "YaraTestMechanismType" self.Version = Version self.Rule = Rule def factory(*args_, **kwargs_): diff --git a/stix/bindings/extensions/vulnerability/cvrf_1_1.py b/stix/bindings/extensions/vulnerability/cvrf_1_1.py index c7eed68e..ed4e357e 100644 --- a/stix/bindings/extensions/vulnerability/cvrf_1_1.py +++ b/stix/bindings/extensions/vulnerability/cvrf_1_1.py @@ -18,6 +18,7 @@ # Data representation classes. # +@register_extension class CVRF1_1InstanceType(exploit_target_binding.VulnerabilityType): """The CVRF1.1InstanceType provides an extension to the exploit_target_binding.VulnerabilityType which imports and leverages the CVRF schema @@ -26,11 +27,13 @@ class CVRF1_1InstanceType(exploit_target_binding.VulnerabilityType): do not have a CVE or OSVDB ID.""" subclass = None superclass = exploit_target_binding.VulnerabilityType + + xmlns = XML_NS + xmlns_prefix = "cvrfVuln" + xml_type = "CVRF1.1InstanceType" + def __init__(self, Description=None, CVE_ID=None, OSVDB_ID=None, CVSS_Score=None, cvrfdoc=None): super(CVRF1_1InstanceType, self).__init__(Description=Description, CVE_ID=CVE_ID, OSVDB_ID=OSVDB_ID, CVSS_Score=CVSS_Score) - self.xmlns = XML_NS - self.xmlns_prefix = "cvrfVuln" - self.xml_type = "CVRF1.1InstanceType" self.cvrfdoc = cvrfdoc def factory(*args_, **kwargs_): if CVRF1_1InstanceType.subclass: diff --git a/stix/bindings/incident.py b/stix/bindings/incident.py index 27e392bb..249fcd5b 100644 --- a/stix/bindings/incident.py +++ b/stix/bindings/incident.py @@ -252,24 +252,8 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): obj_.build(child_) self.set_Location_Class(obj_) elif nodeName_ == 'Location': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] - - if type_name_ == "CIQAddress3.0InstanceType": - import stix.bindings.extensions.address.ciq_address_3_0 as ciq_address_binding - obj_ = ciq_address_binding.CIQAddress3_0InstanceType.factory() - else: - raise NotImplementedError('No implementation class found for: ' + type_name_) - else: - raise NotImplementedError('Class not implemented for element') - + from .extensions.address import ciq_address_3_0 + obj_ = lookup_extension(child_).factory() obj_.build(child_) self.set_Location(obj_) elif nodeName_ == 'Nature_Of_Security_Effect': @@ -565,23 +549,12 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): obj_.build(child_) self.set_Contributors(obj_) elif nodeName_ == 'Course_Of_Action': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + from . import course_of_action - if type_name_ == "CourseOfActionType": - import stix.bindings.course_of_action as coa_binding - obj_ = coa_binding.CourseOfActionType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) - else: + if is_base(child_): obj_ = stix_common_binding.CourseOfActionBaseType.factory() # not abstract + else: + obj_ = lookup_extension(child_).factory() obj_.build(child_) self.set_Course_Of_Action(obj_) @@ -2154,6 +2127,8 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass # end class AssetTypeType + +@register_extension class IncidentType(stix_common_binding.IncidentBaseType): """The IncidentType characterizes a single cyber threat Incident.Specifies the relevant STIX-Incident schema version for @@ -2161,11 +2136,13 @@ class IncidentType(stix_common_binding.IncidentBaseType): Incident specification.""" subclass = None superclass = stix_common_binding.IncidentBaseType + + xmlns = "http://stix.mitre.org/Incident-1" + xmlns_prefix = "incident" + xml_type = "IncidentType" + def __init__(self, idref=None, id=None, timestamp=None, URL=None, version=None, Title=None, External_ID=None, Time=None, Description=None, Short_Description=None, Categories=None, Reporter=None, Responder=None, Coordinator=None, Victim=None, Affected_Assets=None, Impact_Assessment=None, Status=None, Related_Indicators=None, Related_Observables=None, Leveraged_TTPs=None, Attributed_Threat_Actors=None, Intended_Effect=None, Security_Compromise=None, Discovery_Method=None, Related_Incidents=None, COA_Requested=None, COA_Taken=None, Confidence=None, Contact=None, History=None, Information_Source=None, Handling=None, Related_Packages=None): super(IncidentType, self).__init__(timestamp=timestamp, idref=idref, id=id) - self.xmlns = "http://stix.mitre.org/Incident-1" - self.xmlns_prefix = "incident" - self.xml_type = "IncidentType" self.URL = _cast(None, URL) self.version = _cast(None, version) self.Title = Title @@ -2507,21 +2484,13 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): obj_.build(child_) self.Coordinator.append(obj_) elif nodeName_ == 'Victim': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + import stix.bindings.extensions.identity.ciq_identity_3_0 as ciq_identity_binding - if type_name_ == "CIQIdentity3.0InstanceType": - import stix.bindings.extensions.identity.ciq_identity_3_0 as ciq_identity_binding - obj_ = ciq_identity_binding.CIQIdentity3_0InstanceType.factory() - else: + if is_base(child_): obj_ = stix_common_binding.IdentityType.factory() # IdentityType is not abstract + else: + obj_ = lookup_extension(child_).factory() + obj_.build(child_) self.Victim.append(obj_) elif nodeName_ == 'Affected_Assets': diff --git a/stix/bindings/indicator.py b/stix/bindings/indicator.py index 75ce5176..03444fe5 100644 --- a/stix/bindings/indicator.py +++ b/stix/bindings/indicator.py @@ -662,37 +662,8 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Test_Mechanism': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] - - if type_name_ == "OVAL5.10TestMechanismType": - import stix.bindings.extensions.test_mechanism.oval_5_10 as oval_5_10_tm_binding - obj_ = oval_5_10_tm_binding.OVAL5_10TestMechanismType.factory() - elif type_name_ == "YaraTestMechanismType": - import stix.bindings.extensions.test_mechanism.yara as yara_tm_binding - obj_ = yara_tm_binding.YaraTestMechanismType.factory() - elif type_name_ == "SnortTestMechanismType": - import stix.bindings.extensions.test_mechanism.snort as snort_tm_binding - obj_ = snort_tm_binding.SnortTestMechanismType.factory() - elif type_name_ == "OpenIOC2010TestMechanismType": - import stix.bindings.extensions.test_mechanism.open_ioc_2010 as openioc_tm_binding - obj_ = openioc_tm_binding.OpenIOC2010TestMechanismType.factory() - elif type_name_ == "GenericTestMechanismType": - import stix.bindings.extensions.test_mechanism.generic as generic_tm_binding - obj_ = generic_tm_binding.GenericTestMechanismType.factory() - else: - raise NotImplementedError('Class not implemented for element: ' + type_name_) - else: - raise NotImplementedError( - 'Class not implemented for element: no xsi:type attribute found') - + from .extensions.test_mechanism import (generic, oval_5_10, open_ioc_2010, snort, yara) + obj_ = lookup_extension(child_).factory() obj_.build(child_) self.Test_Mechanism.append(obj_) # end class TestMechanismsType @@ -835,6 +806,8 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): super(RelatedIndicatorsType, self).buildChildren(child_, node, nodeName_, True) # end class RelatedIndicatorsType + +@register_extension class IndicatorType(stix_common_binding.IndicatorBaseType): """The IndicatorType characterizes a cyber threat indicator made up of a pattern identifying certain observable conditions as well as @@ -847,11 +820,13 @@ class IndicatorType(stix_common_binding.IndicatorBaseType): specifies the absence of the pattern.""" subclass = None superclass = stix_common_binding.IndicatorBaseType + + xmlns = "http://stix.mitre.org/Indicator-2" + xmlns_prefix = "indicator" + xml_type = "IndicatorType" + def __init__(self, idref=None, id=None, timestamp=None, negate=False, version=None, Title=None, Type=None, Alternative_ID=None, Description=None, Short_Description=None, Valid_Time_Position=None, Observable=None, Composite_Indicator_Expression=None, Indicated_TTP=None, Kill_Chain_Phases=None, Test_Mechanisms=None, Likely_Impact=None, Suggested_COAs=None, Handling=None, Confidence=None, Sightings=None, Related_Indicators=None, Related_Campaigns=None, Related_Packages=None, Producer=None): super(IndicatorType, self).__init__(idref=idref, id=id, timestamp=timestamp) - self.xmlns = "http://stix.mitre.org/Indicator-2" - self.xmlns_prefix = "indicator" - self.xml_type = "IndicatorType" self.negate = _cast(bool, negate) self.version = _cast(None, version) diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index dd12c2b0..6874eee5 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -607,21 +607,12 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): obj_.build(child_) self.add_Description(obj_) elif nodeName_ == 'Identity': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] - - if type_name_ == "CIQIdentity3.0InstanceType": - import stix.bindings.extensions.identity.ciq_identity_3_0 as ciq_identity_binding - obj_ = ciq_identity_binding.CIQIdentity3_0InstanceType.factory() - else: + from .extensions.identity import ciq_identity_3_0 + + if is_base(child_): obj_ = IdentityType.factory() # IdentityType is not abstract + else: + obj_ = lookup_extension(child_).factory() obj_.build(child_) self.set_Identity(obj_) @@ -1491,23 +1482,13 @@ def buildAttributes(self, node, attrs, already_processed): super(RelatedCampaignType, self).buildAttributes(node, attrs, already_processed) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Campaign': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] - - if type_name_ == "CampaignType": - import stix.bindings.campaign as campaign_binding - obj_ = campaign_binding.CampaignType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) - else: + from . import campaign + + if is_base(child_): obj_ = CampaignBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.set_Campaign(obj_) @@ -1573,23 +1554,13 @@ def buildAttributes(self, node, attrs, already_processed): super(RelatedCourseOfActionType, self).buildAttributes(node, attrs, already_processed) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Course_Of_Action': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] - - if type_name_ == "CourseOfActionType": - import stix.bindings.course_of_action as coa_binding - obj_ = coa_binding.CourseOfActionType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) + from . import campaign + + if is_base(child_): + obj_ = CampaignBaseType.factory() # not abstract else: - obj_ = CourseOfActionBaseType.factory() # not abstract + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.set_Course_Of_Action(obj_) @@ -1655,23 +1626,11 @@ def buildAttributes(self, node, attrs, already_processed): super(RelatedExploitTargetType, self).buildAttributes(node, attrs, already_processed) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Exploit_Target': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] - - if type_name_ == "ExploitTargetType": - import stix.bindings.exploit_target as et_binding - obj_ = et_binding.ExploitTargetType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) - else: + if is_base(child_): obj_ = ExploitTargetBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.set_Exploit_Target(obj_) @@ -1737,23 +1696,13 @@ def buildAttributes(self, node, attrs, already_processed): super(RelatedIncidentType, self).buildAttributes(node, attrs, already_processed) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Incident': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] - - if type_name_ == "IncidentType": - import stix.bindings.incident as incident_binding - obj_ = incident_binding.IncidentType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) - else: + from . import incident + + if is_base(child_): obj_ = IncidentBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.set_Incident(obj_) @@ -1819,23 +1768,13 @@ def buildAttributes(self, node, attrs, already_processed): super(RelatedIndicatorType, self).buildAttributes(node, attrs, already_processed) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Indicator': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] - - if type_name_ == "IndicatorType": - import stix.bindings.indicator as indicator_binding - obj_ = indicator_binding.IndicatorType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) + from . import indicator + + if is_base(child_): + obj_ = IndicatorBaseType.factory() else: - obj_ = IndicatorBaseType.factory() # not abstract + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.set_Indicator(obj_) @@ -1966,23 +1905,13 @@ def buildAttributes(self, node, attrs, already_processed): super(RelatedThreatActorType, self).buildAttributes(node, attrs, already_processed) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Threat_Actor': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] - - if type_name_ == "ThreatActorType": - import stix.bindings.threat_actor as ta_binding - obj_ = ta_binding.ThreatActorType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) - else: + from . import threat_actor + + if is_base(child_): obj_ = ThreatActorBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.set_Threat_Actor(obj_) @@ -2048,23 +1977,13 @@ def buildAttributes(self, node, attrs, already_processed): super(RelatedTTPType, self).buildAttributes(node, attrs, already_processed) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'TTP': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] - - if type_name_ == "TTPType": - import stix.bindings.ttp as ttp_binding - obj_ = ttp_binding.TTPType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) - else: + from . import ttp + + if is_base(child_): obj_ = TTPBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.set_TTP(obj_) @@ -2130,21 +2049,12 @@ def buildAttributes(self, node, attrs, already_processed): super(RelatedIdentityType, self).buildAttributes(node, attrs, already_processed) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Identity': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] - - if type_name_ == "CIQIdentity3.0InstanceType": - from .extensions.identity import ciq_identity_3_0 - obj_ = ciq_identity_3_0.CIQIdentity3_0InstanceType.factory() - else: + from .extensions.identity import ciq_identity_3_0 + + if is_base(child_): obj_ = IdentityType.factory() # IdentityType is not abstract + else: + obj_ = lookup_extension(child_).factory() obj_.build(child_) self.set_Identity(obj_) @@ -3132,23 +3042,11 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Exploit_Target': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] - - if type_name_ == "ExploitTargetType": - import stix.bindings.exploit_target as exploit_target_binding - obj_ = exploit_target_binding.ExploitTargetType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) - else: + if is_base(child_): obj_ = ExploitTargetBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.Exploit_Target.append(obj_) @@ -3860,6 +3758,190 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass # end class ControlledVocabularyStringType + +class ReportBaseType(GeneratedsSuper): + """This type represents the STIX Report component. It is extended using + the XML Schema Extension feature by the STIX Report type itself. + Users of this type who wish to express a full report using STIX + must do so using the xsi:type extension feature. The STIX- + defined Report type is ReportType in the + http://stix.mitre.org/Report-1 namespace. This type is defined + in the report.xsd file or at the URL http://stix.mitre.org/XMLSc + hema/report/1.2/report.xsd.Alternatively, uses that require + simply specifying an idref as a reference to a report defined + elsewhere can do so without specifying an xsi:type.Specifies a + globally unique identifier for this Report. Specifies a globally + unique identifier of a Report specified elsewhere.When idref is + specified, the id attribute must not be specified, and any + instance of this Report should not hold content.Specifies a + timestamp for the definition of a specific version of a Report. + When used in conjunction with the id, this field is specifying + the definition time for the specific version of the Report. When + used in conjunction with the idref, this field is specifying a + reference to a specific version of a Report defined elsewhere. + This field has no defined semantic meaning if used in the + absence of either the id or idref fields.""" + subclass = None + superclass = None + def __init__(self, timestamp=None, idref=None, id=None, extensiontype_=None): + self.timestamp = _cast(None, timestamp) + self.idref = _cast(None, idref) + self.id = _cast(None, id) + self.extensiontype_ = extensiontype_ + def factory(*args_, **kwargs_): + if ReportBaseType.subclass: + return ReportBaseType.subclass(*args_, **kwargs_) + else: + return ReportBaseType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_timestamp(self): return self.timestamp + def set_timestamp(self, timestamp): self.timestamp = timestamp + def get_idref(self): return self.idref + def set_idref(self, idref): self.idref = idref + def get_id(self): return self.id + def set_id(self, id): self.id = id + def get_extensiontype_(self): return self.extensiontype_ + def set_extensiontype_(self, extensiontype_): self.extensiontype_ = extensiontype_ + def hasContent_(self): + if ( + + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ReportBaseType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='ReportBaseType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_='report:', name_='ReportBaseType'): + if self.timestamp is not None and 'timestamp' not in already_processed: + already_processed.add('timestamp') + lwrite(' timestamp="%s"' % self.gds_format_datetime(self.timestamp, input_name='timestamp')) + if self.idref is not None and 'idref' not in already_processed: + already_processed.add('idref') + lwrite(' idref=%s' % (quote_attrib(self.idref), )) + if self.id is not None and 'id' not in already_processed: + already_processed.add('id') + lwrite(' id=%s' % (quote_attrib(self.id), )) + if self.extensiontype_ is not None and 'xsi:type' not in already_processed: + already_processed.add('xsi:type') + lwrite(' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"') + lwrite(' xsi:type="%s"' % self.extensiontype_) + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ReportBaseType', fromsubclass_=False, pretty_print=True): + pass + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + value = find_attr_value_('timestamp', node) + if value is not None and 'timestamp' not in already_processed: + already_processed.add('timestamp') + try: + self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') + except ValueError, exp: + raise ValueError('Bad date-time attribute (timestamp): %s' % exp) + value = find_attr_value_('idref', node) + if value is not None and 'idref' not in already_processed: + already_processed.add('idref') + self.idref = value + value = find_attr_value_('id', node) + if value is not None and 'id' not in already_processed: + already_processed.add('id') + self.id = value + value = find_attr_value_('xsi:type', node) + if value is not None and 'xsi:type' not in already_processed: + already_processed.add('xsi:type') + self.extensiontype_ = value + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + pass +# end class ReportBaseType + + +class RelatedReportsType(GenericRelationshipListType): + subclass = None + superclass = GenericRelationshipListType + def __init__(self, scope='exclusive', Related_Report=None): + super(RelatedReportsType, self).__init__(scope, ) + if Related_Report is None: + self.Related_Report = [] + else: + self.Related_Report = Related_Report + def factory(*args_, **kwargs_): + if RelatedReportsType.subclass: + return RelatedReportsType.subclass(*args_, **kwargs_) + else: + return RelatedReportsType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_Related_Report(self): return self.Related_Report + def set_Related_Report(self, Related_Report): self.Related_Report = Related_Report + def add_Related_Report(self, value): self.Related_Report.append(value) + def insert_Related_Report(self, index, value): self.Related_Report[index] = value + def hasContent_(self): + if ( + self.Related_Report or + super(RelatedReportsType, self).hasContent_() + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='RelatedReportsType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='RelatedReportsType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_='report:', name_='RelatedReportsType'): + super(RelatedReportsType, self).exportAttributes(lwrite, level, already_processed, namespace_, name_='RelatedReportsType') + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='RelatedReportsType', fromsubclass_=False, pretty_print=True): + super(RelatedReportsType, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + for Related_Report_ in self.Related_Report: + Related_Report_.export(lwrite, level, nsmap, namespace_, name_='Related_Report', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + super(RelatedReportsType, self).buildAttributes(node, attrs, already_processed) + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'Related_Report': + obj_ = RelatedReportType.factory() + obj_.build(child_) + self.Related_Report.append(obj_) + super(RelatedReportsType, self).buildChildren(child_, node, nodeName_, True) +# end class RelatedReportsType + + + GDSClassesMapping = {} USAGE_TEXT = """ @@ -3985,5 +4067,6 @@ def main(): "StatementType", "StructuredTextType", "EncodedCDATAType", - "ControlledVocabularyStringType" + "ControlledVocabularyStringType", + "ReportBaseType" ] diff --git a/stix/bindings/stix_core.py b/stix/bindings/stix_core.py index 6e2c31a8..56f90b3b 100644 --- a/stix/bindings/stix_core.py +++ b/stix/bindings/stix_core.py @@ -560,26 +560,17 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Indicator': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + from . import indicator - if type_name_ == "IndicatorType": - import stix.bindings.indicator as indicator_binding - obj_ = indicator_binding.IndicatorType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) + if is_base(child_): + obj_ = stix_common_binding.IndicatorBaseType.factory() else: - obj_ = stix_common_binding.IndicatorBaseType.factory() # not abstract + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.Indicator.append(obj_) + # end class IndicatorsType class TTPsType(GeneratedsSuper): @@ -648,26 +639,17 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'TTP': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + from . import ttp - if type_name_ == "TTPType": - import stix.bindings.ttp as ttp_binding - obj_ = ttp_binding.TTPType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) - else: + if is_base(child_): obj_ = stix_common_binding.TTPBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.TTP.append(obj_) + elif nodeName_ == 'Kill_Chains': obj_ = stix_common_binding.KillChainsType.factory() obj_.build(child_) @@ -734,26 +716,17 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Incident': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + from . import incident - if type_name_ == "IncidentType": - import stix.bindings.incident as incident_binding - obj_ = incident_binding.IncidentType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) - else: + if is_base(child_): obj_ = stix_common_binding.IncidentBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.Incident.append(obj_) + # end class IncidentsType class CoursesOfActionType(GeneratedsSuper): @@ -816,23 +789,13 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Course_Of_Action': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + from . import course_of_action - if type_name_ == "CourseOfActionType": - import stix.bindings.course_of_action as coa_binding - obj_ = coa_binding.CourseOfActionType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) - else: + if is_base(child_): obj_ = stix_common_binding.CourseOfActionBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.Course_Of_Action.append(obj_) @@ -898,23 +861,13 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Campaign': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + from . import campaign - if type_name_ == "CampaignType": - import stix.bindings.campaign as campaign_binding - obj_ = campaign_binding.CampaignType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) - else: + if is_base(child_): obj_ = stix_common_binding.CampaignBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.Campaign.append(obj_) @@ -980,23 +933,13 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Threat_Actor': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + from . import threat_actor - if type_name_ == "ThreatActorType": - import stix.bindings.threat_actor as ta_binding - obj_ = ta_binding.ThreatActorType.factory() - else: - raise NotImplementedError('Class not implemented for element type: ' + type_name_) - else: + if is_base(child_): obj_ = stix_common_binding.ThreatActorBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() obj_.build(child_) self.Threat_Actor.append(obj_) diff --git a/stix/bindings/threat_actor.py b/stix/bindings/threat_actor.py index 2b8d0119..7a835d4c 100644 --- a/stix/bindings/threat_actor.py +++ b/stix/bindings/threat_actor.py @@ -227,16 +227,19 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): super(AssociatedActorsType, self).buildChildren(child_, node, nodeName_, True) # end class AssociatedActorsType +@register_extension class ThreatActorType(stix_common_binding.ThreatActorBaseType): """Specifies the relevant STIX-ThreatActor schema version for this content.""" subclass = None superclass = stix_common_binding.ThreatActorBaseType + + xmlns = "http://stix.mitre.org/ThreatActor-1" + xmlns_prefix = "ta" + xml_type = "ThreatActorType" + def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None, Description=None, Short_Description=None, Identity=None, Type=None, Motivation=None, Sophistication=None, Intended_Effect=None, Planning_And_Operational_Support=None, Observed_TTPs=None, Associated_Campaigns=None, Associated_Actors=None, Handling=None, Confidence=None, Information_Source=None, Related_Packages=None): super(ThreatActorType, self).__init__(idref=idref, id=id, timestamp=timestamp) - self.xmlns = "http://stix.mitre.org/ThreatActor-1" - self.xmlns_prefix = "ta" - self.xml_type = "ThreatActorType" self.version = _cast(None, version) self.Title = Title if Description is None: @@ -446,22 +449,14 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): obj_.build(child_) self.add_Short_Description(obj_) elif nodeName_ == 'Identity': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + from .extensions.identity import ciq_identity_3_0 - if type_name_ == "CIQIdentity3.0InstanceType": - from .extensions.identity import ciq_identity_3_0 - obj_ = ciq_identity_3_0.CIQIdentity3_0InstanceType.factory() - else: + if is_base(child_): obj_ = stix_common_binding.IdentityType.factory() # IdentityType is not abstract + else: + obj_ = lookup_extension(child_).factory() + obj_.build(child_) obj_.build(child_) self.set_Identity(obj_) elif nodeName_ == 'Type': diff --git a/stix/bindings/ttp.py b/stix/bindings/ttp.py index 9601b9a4..018dc47d 100644 --- a/stix/bindings/ttp.py +++ b/stix/bindings/ttp.py @@ -765,21 +765,12 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Malware_Instance': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + from .extensions.malware import maec_4_1 - if type_name_ == "MAEC4.1InstanceType": - from .extensions.malware import maec_4_1 - obj_ = maec_4_1.MAEC4_1InstanceType.factory() - else: + if is_base(child_): obj_ = MalwareInstanceType.factory() # MalwareInstanceType is not abstract + else: + obj_ = lookup_extension(child_).factory() obj_.build(child_) self.Malware_Instance.append(obj_) @@ -845,23 +836,12 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Attack_Pattern': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + from .extensions.attack_pattern import capec_2_7 - if type_name_ == "CAPEC2.7InstanceType": - from .extensions.attack_pattern import capec_2_7 - obj_ = capec_2_7.CAPEC2_7InstanceType.factory() - else: - raise NotImplementedError('No implementation for type: ' + type_name_) - else: + if is_base(child_): obj_ = AttackPatternType.factory() # AttackPattern is not abstract + else: + obj_ = lookup_extension(child_).factory() obj_.build(child_) self.Attack_Pattern.append(obj_) @@ -1007,22 +987,14 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Persona': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + from .extensions.identity import ciq_identity_3_0 - if type_name_ == "CIQIdentity3.0InstanceType": - from .extensions.identity import ciq_identity_3_0 - obj_ = ciq_identity_3_0.CIQIdentity3_0InstanceType.factory() - else: + if is_base(child_): obj_ = stix_common_binding.IdentityType.factory() # IdentityType is not abstract + else: + obj_ = lookup_extension(child_).factory() + obj_.build(child_) obj_.build(child_) self.Persona.append(obj_) # end class PersonasType @@ -1191,21 +1163,12 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Identity': - type_name_ = child_.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}type') - if type_name_ is None: - type_name_ = child_.attrib.get('type') - if type_name_ is not None: - type_names_ = type_name_.split(':') - if len(type_names_) == 1: - type_name_ = type_names_[0] - else: - type_name_ = type_names_[1] + from .extensions.identity import ciq_identity_3_0 - if type_name_ == "CIQIdentity3.0InstanceType": - from .extensions.identity import ciq_identity_3_0 - obj_ = ciq_identity_3_0.CIQIdentity3_0InstanceType.factory() - else: + if is_base(child_): obj_ = stix_common_binding.IdentityType.factory() # IdentityType is not abstract + else: + obj_ = lookup_extension(child_).factory() obj_.build(child_) self.set_Identity(obj_) @@ -1292,18 +1255,21 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): super(RelatedTTPsType, self).buildChildren(child_, node, nodeName_, True) # end class RelatedTTPsType + +@register_extension class TTPType(stix_common_binding.TTPBaseType): """TTPType characterizes an individual adversary TTP.Specifies the relevant STIX-TTP schema version for this content.""" subclass = None superclass = stix_common_binding.TTPBaseType + + xmlns = "http://stix.mitre.org/TTP-1" + xmlns_prefix = "ttp" + xml_type = "TTPType" + def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None, Description=None, Short_Description=None, Intended_Effect=None, Behavior=None, Resources=None, Victim_Targeting=None, Exploit_Targets=None, Related_TTPs=None, Kill_Chain_Phases=None, Information_Source=None, Kill_Chains=None, Handling=None, Related_Packages=None): super(TTPType, self).__init__(idref=idref, id=id, timestamp=timestamp) - self.xmlns = "http://stix.mitre.org/TTP-1" - self.xmlns_prefix = "ttp" - self.xml_type = "TTPType" self.version = _cast(None, version) - self.Title = Title if Description is None: self.Description = [] diff --git a/stix/test/coa_test.py b/stix/test/coa_test.py index 7ade2353..2a75b23c 100644 --- a/stix/test/coa_test.py +++ b/stix/test/coa_test.py @@ -70,7 +70,6 @@ class COATests(EntityTestCase, unittest.TestCase): } - def test_structured_coa(self): coa_ = coa.CourseOfAction() From bd14bf9b662627ceb13208311798bcbc8259edc8 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 27 Apr 2015 12:14:21 -0400 Subject: [PATCH 033/438] First pass at report bindings. Still need to add user-level classes and unit tests. --- stix/bindings/report.py | 875 +++++++++++++++++++++++++++++++++++ stix/bindings/stix_common.py | 71 +++ stix/bindings/stix_core.py | 92 +++- 3 files changed, 1032 insertions(+), 6 deletions(-) create mode 100644 stix/bindings/report.py diff --git a/stix/bindings/report.py b/stix/bindings/report.py new file mode 100644 index 00000000..761b830a --- /dev/null +++ b/stix/bindings/report.py @@ -0,0 +1,875 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# +# Generated Mon Apr 27 08:13:59 2015 by generateDS.py version 2.9a. +# + +from stix.bindings import * +from cybox.bindings import cybox_core +import stix.bindings.stix_common as common_binding +from stix import xmlconst + +XML_NS = "http://stix.mitre.org/Report-1" + +# +# Data representation classes. +# + +class HeaderType(GeneratedsSuper): + """The HeaderType provides a structure for characterizing the + contextual information in a Report of STIX content.""" + subclass = None + superclass = None + def __init__(self, Title=None, Intent=None, Description=None, Short_Description=None, Handling=None, Information_Source=None): + self.Title = Title + if Intent is None: + self.Intent = [] + else: + self.Intent = Intent + if Description is None: + self.Description = [] + else: + self.Description = Description + if Short_Description is None: + self.Short_Description = [] + else: + self.Short_Description = Short_Description + self.Handling = Handling + self.Information_Source = Information_Source + def factory(*args_, **kwargs_): + if HeaderType.subclass: + return HeaderType.subclass(*args_, **kwargs_) + else: + return HeaderType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_Title(self): return self.Title + def set_Title(self, Title): self.Title = Title + def get_Intent(self): return self.Intent + def set_Intent(self, Intent): self.Intent = Intent + def add_Intent(self, value): self.Intent.append(value) + def insert_Intent(self, index, value): self.Intent[index] = value + def get_Description(self): return self.Description + def set_Description(self, Description): self.Description = Description + def add_Description(self, value): self.Description.append(value) + def insert_Description(self, index, value): self.Description[index] = value + def get_Short_Description(self): return self.Short_Description + def set_Short_Description(self, Short_Description): self.Short_Description = Short_Description + def add_Short_Description(self, value): self.Short_Description.append(value) + def insert_Short_Description(self, index, value): self.Short_Description[index] = value + def get_Handling(self): return self.Handling + def set_Handling(self, Handling): self.Handling = Handling + def get_Information_Source(self): return self.Information_Source + def set_Information_Source(self, Information_Source): self.Information_Source = Information_Source + def hasContent_(self): + if ( + self.Title is not None or + self.Intent or + self.Description or + self.Short_Description or + self.Handling is not None or + self.Information_Source is not None + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='HeaderType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='HeaderType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_='report:', name_='HeaderType'): + pass + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='HeaderType', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.Title is not None: + showIndent(lwrite, level, pretty_print) + lwrite('<%s:Title>%s%s' % (nsmap[namespace_], self.gds_format_string(quote_xml(self.Title).encode(ExternalEncoding), input_name='Title'), nsmap[namespace_], eol_)) + for Intent_ in self.Intent: + Intent_.export(lwrite, level, nsmap, namespace_, name_='Intent', pretty_print=pretty_print) + for Description_ in self.Description: + Description_.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Short_Description_ in self.Short_Description: + Short_Description_.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) + if self.Handling is not None: + self.Handling.export(lwrite, level, nsmap, namespace_, name_='Handling', pretty_print=pretty_print) + if self.Information_Source is not None: + self.Information_Source.export(lwrite, level, nsmap, namespace_, name_='Information_Source', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + pass + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'Title': + Title_ = child_.text + Title_ = self.gds_validate_string(Title_, node, 'Title') + self.Title = Title_ + elif nodeName_ == 'Intent': + obj_ = common_binding.ControlledVocabularyStringType.factory() + obj_.build(child_) + self.Intent.append(obj_) + elif nodeName_ == 'Description': + obj_ = common_binding.StructuredTextType.factory() + obj_.build(child_) + self.Description.append(obj_) + elif nodeName_ == 'Short_Description': + obj_ = common_binding.StructuredTextType.factory() + obj_.build(child_) + self.Short_Description.append(obj_) + elif nodeName_ == 'Handling': + obj_ = common_binding.MarkingType.factory() + obj_.build(child_) + self.set_Handling(obj_) + elif nodeName_ == 'Information_Source': + obj_ = common_binding.InformationSourceType.factory() + obj_.build(child_) + self.set_Information_Source(obj_) +# end class HeaderType + + +class IndicatorsType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, Indicator=None): + if Indicator is None: + self.Indicator = [] + else: + self.Indicator = Indicator + def factory(*args_, **kwargs_): + if IndicatorsType.subclass: + return IndicatorsType.subclass(*args_, **kwargs_) + else: + return IndicatorsType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_Indicator(self): return self.Indicator + def set_Indicator(self, Indicator): self.Indicator = Indicator + def add_Indicator(self, value): self.Indicator.append(value) + def insert_Indicator(self, index, value): self.Indicator[index] = value + def hasContent_(self): + if ( + self.Indicator + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='IndicatorsType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='IndicatorsType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_=XML_NS, name_='IndicatorsType'): + pass + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='IndicatorsType', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + for Indicator_ in self.Indicator: + Indicator_.export(lwrite, level, nsmap, namespace_, name_='Indicator', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + pass + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'Indicator': + if is_base(child_): + obj_ = common_binding.IndicatorBaseType.factory() + else: + klass = lookup_extension(child_) + obj_ = klass.factory() + obj_.build(child_) + self.Indicator.append(obj_) +# end class IndicatorsType + + +class TTPsType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, TTP=None, Kill_Chains=None): + if TTP is None: + self.TTP = [] + else: + self.TTP = TTP + self.Kill_Chains = Kill_Chains + def factory(*args_, **kwargs_): + if TTPsType.subclass: + return TTPsType.subclass(*args_, **kwargs_) + else: + return TTPsType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_TTP(self): return self.TTP + def set_TTP(self, TTP): self.TTP = TTP + def add_TTP(self, value): self.TTP.append(value) + def insert_TTP(self, index, value): self.TTP[index] = value + def get_Kill_Chains(self): return self.Kill_Chains + def set_Kill_Chains(self, Kill_Chains): self.Kill_Chains = Kill_Chains + def hasContent_(self): + if ( + self.TTP or + self.Kill_Chains is not None + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TTPsType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='TTPsType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_=XML_NS, name_='TTPsType'): + pass + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TTPsType', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + for TTP_ in self.TTP: + TTP_.export(lwrite, level, nsmap, namespace_, name_='TTP', pretty_print=pretty_print) + if self.Kill_Chains is not None: + self.Kill_Chains.export(lwrite, level, nsmap, namespace_, name_='Kill_Chains', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + pass + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'TTP': + from . import ttp + + if is_base(child_): + obj_ = common_binding.TTPBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() + + obj_.build(child_) + self.TTP.append(obj_) + elif nodeName_ == 'Kill_Chains': + obj_ = common_binding.KillChainsType.factory() + obj_.build(child_) + self.set_Kill_Chains(obj_) +# end class TTPsType + +class IncidentsType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, Incident=None): + if Incident is None: + self.Incident = [] + else: + self.Incident = Incident + def factory(*args_, **kwargs_): + if IncidentsType.subclass: + return IncidentsType.subclass(*args_, **kwargs_) + else: + return IncidentsType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_Incident(self): return self.Incident + def set_Incident(self, Incident): self.Incident = Incident + def add_Incident(self, value): self.Incident.append(value) + def insert_Incident(self, index, value): self.Incident[index] = value + def hasContent_(self): + if ( + self.Incident + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='IncidentsType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='IncidentsType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_=XML_NS, name_='IncidentsType'): + pass + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='IncidentsType', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + for Incident_ in self.Incident: + Incident_.export(lwrite, level, nsmap, namespace_, name_='Incident', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + pass + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'Incident': + from . import incident + + if is_base(child_): + obj_ = common_binding.IncidentBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() + + obj_.build(child_) + self.Incident.append(obj_) +# end class IncidentsType + +class CoursesOfActionType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, Course_Of_Action=None): + if Course_Of_Action is None: + self.Course_Of_Action = [] + else: + self.Course_Of_Action = Course_Of_Action + def factory(*args_, **kwargs_): + if CoursesOfActionType.subclass: + return CoursesOfActionType.subclass(*args_, **kwargs_) + else: + return CoursesOfActionType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_Course_Of_Action(self): return self.Course_Of_Action + def set_Course_Of_Action(self, Course_Of_Action): self.Course_Of_Action = Course_Of_Action + def add_Course_Of_Action(self, value): self.Course_Of_Action.append(value) + def insert_Course_Of_Action(self, index, value): self.Course_Of_Action[index] = value + def hasContent_(self): + if ( + self.Course_Of_Action + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CoursesOfActionType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='CoursesOfActionType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_=XML_NS, name_='CoursesOfActionType'): + pass + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CoursesOfActionType', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + for Course_Of_Action_ in self.Course_Of_Action: + Course_Of_Action_.export(lwrite, level, nsmap, namespace_, name_='Course_Of_Action', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + pass + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'Course_Of_Action': + from . import course_of_action + + if is_base(child_): + obj_ = common_binding.CourseOfActionBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() + + obj_.build(child_) + self.Course_Of_Action.append(obj_) +# end class CoursesOfActionType + +class CampaignsType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, Campaign=None): + if Campaign is None: + self.Campaign = [] + else: + self.Campaign = Campaign + def factory(*args_, **kwargs_): + if CampaignsType.subclass: + return CampaignsType.subclass(*args_, **kwargs_) + else: + return CampaignsType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_Campaign(self): return self.Campaign + def set_Campaign(self, Campaign): self.Campaign = Campaign + def add_Campaign(self, value): self.Campaign.append(value) + def insert_Campaign(self, index, value): self.Campaign[index] = value + def hasContent_(self): + if ( + self.Campaign + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CampaignsType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='CampaignsType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_=XML_NS, name_='CampaignsType'): + pass + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CampaignsType', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + for Campaign_ in self.Campaign: + Campaign_.export(lwrite, level, nsmap, namespace_, name_='Campaign', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + pass + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'Campaign': + from . import campaign + + if is_base(child_): + obj_ = common_binding.CampaignBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() + + obj_.build(child_) + self.Campaign.append(obj_) +# end class CampaignsType + +class ThreatActorsType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, Threat_Actor=None): + if Threat_Actor is None: + self.Threat_Actor = [] + else: + self.Threat_Actor = Threat_Actor + def factory(*args_, **kwargs_): + if ThreatActorsType.subclass: + return ThreatActorsType.subclass(*args_, **kwargs_) + else: + return ThreatActorsType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_Threat_Actor(self): return self.Threat_Actor + def set_Threat_Actor(self, Threat_Actor): self.Threat_Actor = Threat_Actor + def add_Threat_Actor(self, value): self.Threat_Actor.append(value) + def insert_Threat_Actor(self, index, value): self.Threat_Actor[index] = value + def hasContent_(self): + if ( + self.Threat_Actor + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ThreatActorsType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='ThreatActorsType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_=XML_NS, name_='ThreatActorsType'): + pass + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ThreatActorsType', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + for Threat_Actor_ in self.Threat_Actor: + Threat_Actor_.export(lwrite, level, nsmap, namespace_, name_='Threat_Actor', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + pass + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'Threat_Actor': + from . import threat_actor + + if is_base(child_): + obj_ = common_binding.ThreatActorBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() + + obj_.build(child_) + self.Threat_Actor.append(obj_) +# end class ThreatActorsType + + +class RelatedReportType(common_binding.GenericRelationshipType): + """Identifies or characterizes a relationship to a report.""" + subclass = None + superclass = common_binding.GenericRelationshipType + def __init__(self, Confidence=None, Information_Source=None, Relationship=None, Report=None): + super(RelatedReportType, self).__init__(Confidence, Information_Source, Relationship, ) + self.Report = Report + def factory(*args_, **kwargs_): + if RelatedReportType.subclass: + return RelatedReportType.subclass(*args_, **kwargs_) + else: + return RelatedReportType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_Report(self): return self.Report + def set_Report(self, Report): self.Report = Report + def hasContent_(self): + if ( + self.Report is not None or + super(RelatedReportType, self).hasContent_() + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='RelatedReportType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='RelatedReportType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_='report:', name_='RelatedReportType'): + super(RelatedReportType, self).exportAttributes(lwrite, level, already_processed, namespace_, name_='RelatedReportType') + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='RelatedReportType', fromsubclass_=False, pretty_print=True): + super(RelatedReportType, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.Report is not None: + self.Report.export(lwrite, level, nsmap, namespace_, name_='Report', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + super(RelatedReportType, self).buildAttributes(node, attrs, already_processed) + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'Report': + class_obj_ = self.get_class_obj_(child_, common_binding.ReportBaseType) + obj_ = class_obj_.factory() + obj_.build(child_) + self.set_Report(obj_) + super(RelatedReportType, self).buildChildren(child_, node, nodeName_, True) +# end class RelatedReportType + + +@register_extension +class ReportType(common_binding.ReportBaseType): + """ReportType defines a contextual wrapper for a grouping of STIX + content.Specifies the relevant Report schema version for this + content.""" + subclass = None + superclass = common_binding.ReportBaseType + + xmlns = XML_NS + xmlns_prefix = "report" + xml_type = "ReportType" + + def __init__(self, timestamp=None, idref=None, id=None, version=None, Header=None, Observables=None, Indicators=None, TTPs=None, Exploit_Targets=None, Incidents=None, Courses_Of_Action=None, Campaigns=None, Threat_Actors=None, Related_Reports=None): + super(ReportType, self).__init__(timestamp, idref, id, ) + self.version = _cast(None, version) + self.Header = Header + self.Observables = Observables + self.Indicators = Indicators + self.TTPs = TTPs + self.Exploit_Targets = Exploit_Targets + self.Incidents = Incidents + self.Courses_Of_Action = Courses_Of_Action + self.Campaigns = Campaigns + self.Threat_Actors = Threat_Actors + self.Related_Reports = Related_Reports + def factory(*args_, **kwargs_): + if ReportType.subclass: + return ReportType.subclass(*args_, **kwargs_) + else: + return ReportType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_Header(self): return self.Header + def set_Header(self, Header): self.Header = Header + def get_Observables(self): return self.Observables + def set_Observables(self, Observables): self.Observables = Observables + def get_Indicators(self): return self.Indicators + def set_Indicators(self, Indicators): self.Indicators = Indicators + def get_TTPs(self): return self.TTPs + def set_TTPs(self, TTPs): self.TTPs = TTPs + def get_Exploit_Targets(self): return self.Exploit_Targets + def set_Exploit_Targets(self, Exploit_Targets): self.Exploit_Targets = Exploit_Targets + def get_Incidents(self): return self.Incidents + def set_Incidents(self, Incidents): self.Incidents = Incidents + def get_Courses_Of_Action(self): return self.Courses_Of_Action + def set_Courses_Of_Action(self, Courses_Of_Action): self.Courses_Of_Action = Courses_Of_Action + def get_Campaigns(self): return self.Campaigns + def set_Campaigns(self, Campaigns): self.Campaigns = Campaigns + def get_Threat_Actors(self): return self.Threat_Actors + def set_Threat_Actors(self, Threat_Actors): self.Threat_Actors = Threat_Actors + def get_Related_Reports(self): return self.Related_Reports + def set_Related_Reports(self, Related_Reports): self.Related_Reports = Related_Reports + def get_version(self): return self.version + def set_version(self, version): self.version = version + def hasContent_(self): + if ( + self.Header is not None or + self.Observables is not None or + self.Indicators is not None or + self.TTPs is not None or + self.Exploit_Targets is not None or + self.Incidents is not None or + self.Courses_Of_Action is not None or + self.Campaigns is not None or + self.Threat_Actors is not None or + self.Related_Reports is not None or + super(ReportType, self).hasContent_() + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ReportType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='ReportType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_='report:', name_='ReportType'): + super(ReportType, self).exportAttributes(lwrite, level, already_processed, namespace_, name_='ReportType') + if self.version is not None and 'version' not in already_processed: + already_processed.add('version') + lwrite(' version=%s' % (quote_attrib(self.version), )) + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ReportType', fromsubclass_=False, pretty_print=True): + super(ReportType, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.Header is not None: + self.Header.export(lwrite, level, nsmap, namespace_, name_='Header', pretty_print=pretty_print) + if self.Observables is not None: + self.Observables.export(lwrite, level, nsmap, namespace_, name_='Observables', pretty_print=pretty_print) + if self.Indicators is not None: + self.Indicators.export(lwrite, level, nsmap, namespace_, name_='Indicators', pretty_print=pretty_print) + if self.TTPs is not None: + self.TTPs.export(lwrite, level, nsmap, namespace_, name_='TTPs', pretty_print=pretty_print) + if self.Exploit_Targets is not None: + self.Exploit_Targets.export(lwrite, level, nsmap, namespace_, name_='Exploit_Targets', pretty_print=pretty_print) + if self.Incidents is not None: + self.Incidents.export(lwrite, level, nsmap, namespace_, name_='Incidents', pretty_print=pretty_print) + if self.Courses_Of_Action is not None: + self.Courses_Of_Action.export(lwrite, level, nsmap, namespace_, name_='Courses_Of_Action', pretty_print=pretty_print) + if self.Campaigns is not None: + self.Campaigns.export(lwrite, level, nsmap, namespace_, name_='Campaigns', pretty_print=pretty_print) + if self.Threat_Actors is not None: + self.Threat_Actors.export(lwrite, level, nsmap, namespace_, name_='Threat_Actors', pretty_print=pretty_print) + if self.Related_Reports is not None: + self.Related_Reports.export(lwrite, level, nsmap, namespace_, name_='Related_Reports', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + value = find_attr_value_('version', node) + if value is not None and 'version' not in already_processed: + already_processed.add('version') + self.version = value + super(ReportType, self).buildAttributes(node, attrs, already_processed) + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'Header': + obj_ = HeaderType.factory() + obj_.build(child_) + self.set_Header(obj_) + elif nodeName_ == 'Observables': + obj_ = cybox_core.ObservablesType.factory() + obj_.build(child_) + self.set_Observables(obj_) + elif nodeName_ == 'Indicators': + obj_ = IndicatorsType.factory() + obj_.build(child_) + self.set_Indicators(obj_) + elif nodeName_ == 'TTPs': + obj_ = TTPsType.factory() + obj_.build(child_) + self.set_TTPs(obj_) + elif nodeName_ == 'Exploit_Targets': + obj_ = common_binding.ExploitTargetsType.factory() + obj_.build(child_) + self.set_Exploit_Targets(obj_) + elif nodeName_ == 'Incidents': + obj_ = IncidentsType.factory() + obj_.build(child_) + self.set_Incidents(obj_) + elif nodeName_ == 'Courses_Of_Action': + obj_ = CoursesOfActionType.factory() + obj_.build(child_) + self.set_Courses_Of_Action(obj_) + elif nodeName_ == 'Campaigns': + obj_ = CampaignsType.factory() + obj_.build(child_) + self.set_Campaigns(obj_) + elif nodeName_ == 'Threat_Actors': + obj_ = ThreatActorsType.factory() + obj_.build(child_) + self.set_Threat_Actors(obj_) + elif nodeName_ == 'Related_Reports': + obj_ = common_binding.RelatedReportsType.factory() + obj_.build(child_) + self.set_Related_Reports(obj_) + super(ReportType, self).buildChildren(child_, node, nodeName_, True) +# end class ReportType + + + +GDSClassesMapping = {} + + +def get_root_tag(node): + tag = Tag_pattern_.match(node.tag).groups()[-1] + rootClass = GDSClassesMapping.get(tag) + if rootClass is None: + rootClass = globals().get(tag) + return tag, rootClass + +# +# def parse(inFileName): +# doc = parsexml_(inFileName) +# rootNode = doc.getroot() +# rootTag, rootClass = get_root_tag(rootNode) +# if rootClass is None: +# rootTag = 'Report' +# rootClass = ReportType +# rootObj = rootClass.factory() +# rootObj.build(rootNode) +# # Enable Python to collect the space used by the DOM. +# # doc = None +# # sys.stdout.write('\n') +# # rootObj.export(sys.stdout, 0, name_=rootTag, +# # namespacedef_='', +# # pretty_print=True) +# return rootObj + + +def parseString(inString): + from StringIO import StringIO + doc = parsexml_(StringIO(inString)) + rootNode = doc.getroot() + rootTag, rootClass = get_root_tag(rootNode) + if rootClass is None: + rootTag = 'Report' + rootClass = ReportType + rootObj = rootClass.factory() + rootObj.build(rootNode) + # # Enable Python to collect the space used by the DOM. + # doc = None + # sys.stdout.write('\n') + # rootObj.export(sys.stdout, 0, name_="Report", + # namespacedef_='') + return rootObj diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index 6874eee5..2b326c39 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -3870,6 +3870,77 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass # end class ReportBaseType +class RelatedReportType(GenericRelationshipType): + """Identifies or characterizes a relationship to a report.""" + subclass = None + superclass = GenericRelationshipType + def __init__(self, Confidence=None, Information_Source=None, Relationship=None, Report=None): + super(RelatedReportType, self).__init__(Confidence, Information_Source, Relationship, ) + self.Report = Report + def factory(*args_, **kwargs_): + if RelatedReportType.subclass: + return RelatedReportType.subclass(*args_, **kwargs_) + else: + return RelatedReportType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_Report(self): return self.Report + def set_Report(self, Report): self.Report = Report + def hasContent_(self): + if ( + self.Report is not None or + super(RelatedReportType, self).hasContent_() + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='RelatedReportType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='RelatedReportType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_='report:', name_='RelatedReportType'): + super(RelatedReportType, self).exportAttributes(lwrite, level, already_processed, namespace_, name_='RelatedReportType') + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='RelatedReportType', fromsubclass_=False, pretty_print=True): + super(RelatedReportType, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.Report is not None: + self.Report.export(lwrite, level, nsmap, namespace_, name_='Report', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + super(RelatedReportType, self).buildAttributes(node, attrs, already_processed) + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'Report': + from . import report + + if is_base(child_): + obj_ = ReportBaseType.factory() + else: + obj_ = lookup_extension(child_).factory() + + obj_.build(child_) + self.set_Report(obj_) + super(RelatedReportType, self).buildChildren(child_, node, nodeName_, True) +# end class RelatedReportType + class RelatedReportsType(GenericRelationshipListType): subclass = None diff --git a/stix/bindings/stix_core.py b/stix/bindings/stix_core.py index 56f90b3b..2e0eb1ff 100644 --- a/stix/bindings/stix_core.py +++ b/stix/bindings/stix_core.py @@ -31,7 +31,7 @@ class STIXType(GeneratedsSuper): version for this content.""" subclass = None superclass = None - def __init__(self, idref=None, id=None, timestamp=None, version=None, STIX_Header=None, Observables=None, Indicators=None, TTPs=None, Exploit_Targets=None, Incidents=None, Courses_Of_Action=None, Campaigns=None, Threat_Actors=None, Related_Packages=None): + def __init__(self, idref=None, id=None, timestamp=None, version=None, STIX_Header=None, Observables=None, Indicators=None, TTPs=None, Exploit_Targets=None, Incidents=None, Courses_Of_Action=None, Campaigns=None, Threat_Actors=None, Related_Packages=None, Reports=None): self.idref = _cast(None, idref) self.id = _cast(None, id) self.timestamp = _cast(None, timestamp) @@ -46,6 +46,7 @@ def __init__(self, idref=None, id=None, timestamp=None, version=None, STIX_Heade self.Campaigns = Campaigns self.Threat_Actors = Threat_Actors self.Related_Packages = Related_Packages + self.Reports = Reports self.nsmap = {} def factory(*args_, **kwargs_): if STIXType.subclass: @@ -73,6 +74,8 @@ def get_Threat_Actors(self): return self.Threat_Actors def set_Threat_Actors(self, Threat_Actors): self.Threat_Actors = Threat_Actors def get_Related_Packages(self): return self.Related_Packages def set_Related_Packages(self, value): self.Related_Packages = value + def get_Reports(self): return self.Reports + def set_Reports(self, value): self.Reports = value def get_idref(self): return self.idref def set_idref(self, idref): self.idref = idref def get_id(self): return self.id @@ -92,7 +95,8 @@ def hasContent_(self): self.Courses_Of_Action is not None or self.Campaigns is not None or self.Threat_Actors is not None or - self.Related_Packages is not None + self.Related_Packages is not None or + self.Reports ): return True else: @@ -127,9 +131,6 @@ def exportAttributes(self, lwrite, level, nsmap, already_processed, namespace_=X already_processed.add('timestamp') lwrite(' timestamp="%s"' % self.gds_format_datetime(self.timestamp, input_name='timestamp')) - #for ns, prefix in nsmap.iteritems(): - # lwrite(' xmlns:%s="%s"' % (prefix, ns)) - def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='STIXType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' @@ -153,9 +154,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='STIXTyp self.Campaigns.export(lwrite, level, nsmap, namespace_, name_='Campaigns', pretty_print=pretty_print) if self.Threat_Actors is not None: self.Threat_Actors.export(lwrite, level, nsmap, namespace_, name_='Threat_Actors', pretty_print=pretty_print) + if self.Reports is not None: + self.Reports.export(lwrite, level, nsmap, namespace_, name_='Reports', pretty_print=pretty_print) if self.Related_Packages is not None: self.Related_Packages.export(lwrite, level, nsmap, namespace_, name_='Related_Packages', pretty_print=pretty_print) - def build(self, node): already_processed = set() self.nsmap = node.nsmap @@ -220,6 +222,10 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): obj_ = ThreatActorsType.factory() obj_.build(child_) self.set_Threat_Actors(obj_) + elif nodeName_ == 'Reports': + obj_ = ReportsType.factory() + obj_.build(child_) + self.set_Reports(obj_) elif nodeName_ == 'Related_Packages': obj_ = RelatedPackagesType.factory() obj_.build(child_) @@ -946,6 +952,80 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): # end class ThreatActorsType +class ReportsType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, Report=None): + if Report is None: + self.Report = [] + else: + self.Report = Report + def factory(*args_, **kwargs_): + if ReportsType.subclass: + return ReportsType.subclass(*args_, **kwargs_) + else: + return ReportsType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_Report(self): return self.Report + def set_Report(self, Report): self.Report = Report + def add_Report(self, value): self.Report.append(value) + def insert_Report(self, index, value): self.Report[index] = value + def hasContent_(self): + if ( + self.Report + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ReportsType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='ReportsType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_=XML_NS, name_='ReportsType'): + pass + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ReportsType', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + for Report_ in self.Report: + Report_.export(lwrite, level, nsmap, namespace_, name_='Report', pretty_print=pretty_print) + + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + pass + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'Report': + from . import report + + if is_base(child_): + obj_ = stix_common_binding.ReportBaseType.factory() # not abstract + else: + klass = lookup_extension(child_) + obj_ = klass.factory() + + obj_.build(child_) + self.Report.append(obj_) +# end class TTPsType + + GDSClassesMapping = {} USAGE_TEXT = """ From be360e00d8aa6386fef9586a2769c56327121b6a Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 27 Apr 2015 12:50:17 -0400 Subject: [PATCH 034/438] Initial cut at Report user-level classes. NEED TESTING. --- stix/bindings/report.py | 139 ++++++------- stix/bindings/stix_common.py | 72 ------- stix/common/__init__.py | 10 +- stix/common/related.py | 18 ++ stix/common/vocabs.py | 28 +++ stix/core/stix_header.py | 1 - stix/core/stix_package.py | 60 ++++-- stix/report/__init__.py | 366 +++++++++++++++++++++++++++++++++++ stix/report/header.py | 219 +++++++++++++++++++++ 9 files changed, 756 insertions(+), 157 deletions(-) create mode 100644 stix/report/__init__.py create mode 100644 stix/report/header.py diff --git a/stix/bindings/report.py b/stix/bindings/report.py index 761b830a..1f78d414 100644 --- a/stix/bindings/report.py +++ b/stix/bindings/report.py @@ -1,3 +1,6 @@ +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + #!/usr/bin/env python # -*- coding: utf-8 -*- @@ -8,7 +11,6 @@ from stix.bindings import * from cybox.bindings import cybox_core import stix.bindings.stix_common as common_binding -from stix import xmlconst XML_NS = "http://stix.mitre.org/Report-1" @@ -586,71 +588,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): # end class ThreatActorsType -class RelatedReportType(common_binding.GenericRelationshipType): - """Identifies or characterizes a relationship to a report.""" - subclass = None - superclass = common_binding.GenericRelationshipType - def __init__(self, Confidence=None, Information_Source=None, Relationship=None, Report=None): - super(RelatedReportType, self).__init__(Confidence, Information_Source, Relationship, ) - self.Report = Report - def factory(*args_, **kwargs_): - if RelatedReportType.subclass: - return RelatedReportType.subclass(*args_, **kwargs_) - else: - return RelatedReportType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_Report(self): return self.Report - def set_Report(self, Report): self.Report = Report - def hasContent_(self): - if ( - self.Report is not None or - super(RelatedReportType, self).hasContent_() - ): - return True - else: - return False - def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='RelatedReportType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - showIndent(lwrite, level, pretty_print) - lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(lwrite, level, already_processed, namespace_, name_='RelatedReportType') - if self.hasContent_(): - lwrite('>%s' % (eol_, )) - self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) - showIndent(lwrite, level, pretty_print) - lwrite('%s' % (nsmap[namespace_], name_, eol_)) - else: - lwrite('/>%s' % (eol_, )) - def exportAttributes(self, lwrite, level, already_processed, namespace_='report:', name_='RelatedReportType'): - super(RelatedReportType, self).exportAttributes(lwrite, level, already_processed, namespace_, name_='RelatedReportType') - def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='RelatedReportType', fromsubclass_=False, pretty_print=True): - super(RelatedReportType, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.Report is not None: - self.Report.export(lwrite, level, nsmap, namespace_, name_='Report', pretty_print=pretty_print) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - def buildAttributes(self, node, attrs, already_processed): - super(RelatedReportType, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'Report': - class_obj_ = self.get_class_obj_(child_, common_binding.ReportBaseType) - obj_ = class_obj_.factory() - obj_.build(child_) - self.set_Report(obj_) - super(RelatedReportType, self).buildChildren(child_, node, nodeName_, True) -# end class RelatedReportType + @register_extension @@ -827,6 +765,75 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): # end class ReportType +class RelatedReportsType(common_binding.GenericRelationshipListType): + subclass = None + superclass = common_binding.GenericRelationshipListType + def __init__(self, scope='exclusive', Related_Report=None): + super(RelatedReportsType, self).__init__(scope, ) + if Related_Report is None: + self.Related_Report = [] + else: + self.Related_Report = Related_Report + def factory(*args_, **kwargs_): + if RelatedReportsType.subclass: + return RelatedReportsType.subclass(*args_, **kwargs_) + else: + return RelatedReportsType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_Related_Report(self): return self.Related_Report + def set_Related_Report(self, Related_Report): self.Related_Report = Related_Report + def add_Related_Report(self, value): self.Related_Report.append(value) + def insert_Related_Report(self, index, value): self.Related_Report[index] = value + def hasContent_(self): + if ( + self.Related_Report or + super(RelatedReportsType, self).hasContent_() + ): + return True + else: + return False + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='RelatedReportsType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='RelatedReportsType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + def exportAttributes(self, lwrite, level, already_processed, namespace_='report:', name_='RelatedReportsType'): + super(RelatedReportsType, self).exportAttributes(lwrite, level, already_processed, namespace_, name_='RelatedReportsType') + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='RelatedReportsType', fromsubclass_=False, pretty_print=True): + super(RelatedReportsType, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + for Related_Report_ in self.Related_Report: + Related_Report_.export(lwrite, level, nsmap, namespace_, name_='Related_Report', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + def buildAttributes(self, node, attrs, already_processed): + super(RelatedReportsType, self).buildAttributes(node, attrs, already_processed) + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'Related_Report': + obj_ = common_binding.RelatedReportType.factory() + obj_.build(child_) + self.Related_Report.append(obj_) + super(RelatedReportsType, self).buildChildren(child_, node, nodeName_, True) +# end class RelatedReportsType + GDSClassesMapping = {} diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index 2b326c39..0ed134ed 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -3941,78 +3941,6 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): super(RelatedReportType, self).buildChildren(child_, node, nodeName_, True) # end class RelatedReportType - -class RelatedReportsType(GenericRelationshipListType): - subclass = None - superclass = GenericRelationshipListType - def __init__(self, scope='exclusive', Related_Report=None): - super(RelatedReportsType, self).__init__(scope, ) - if Related_Report is None: - self.Related_Report = [] - else: - self.Related_Report = Related_Report - def factory(*args_, **kwargs_): - if RelatedReportsType.subclass: - return RelatedReportsType.subclass(*args_, **kwargs_) - else: - return RelatedReportsType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_Related_Report(self): return self.Related_Report - def set_Related_Report(self, Related_Report): self.Related_Report = Related_Report - def add_Related_Report(self, value): self.Related_Report.append(value) - def insert_Related_Report(self, index, value): self.Related_Report[index] = value - def hasContent_(self): - if ( - self.Related_Report or - super(RelatedReportsType, self).hasContent_() - ): - return True - else: - return False - def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='RelatedReportsType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - showIndent(lwrite, level, pretty_print) - lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(lwrite, level, already_processed, namespace_, name_='RelatedReportsType') - if self.hasContent_(): - lwrite('>%s' % (eol_, )) - self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) - showIndent(lwrite, level, pretty_print) - lwrite('%s' % (nsmap[namespace_], name_, eol_)) - else: - lwrite('/>%s' % (eol_, )) - def exportAttributes(self, lwrite, level, already_processed, namespace_='report:', name_='RelatedReportsType'): - super(RelatedReportsType, self).exportAttributes(lwrite, level, already_processed, namespace_, name_='RelatedReportsType') - def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='RelatedReportsType', fromsubclass_=False, pretty_print=True): - super(RelatedReportsType, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for Related_Report_ in self.Related_Report: - Related_Report_.export(lwrite, level, nsmap, namespace_, name_='Related_Report', pretty_print=pretty_print) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - def buildAttributes(self, node, attrs, already_processed): - super(RelatedReportsType, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'Related_Report': - obj_ = RelatedReportType.factory() - obj_.build(child_) - self.Related_Report.append(obj_) - super(RelatedReportsType, self).buildChildren(child_, node, nodeName_, True) -# end class RelatedReportsType - - - GDSClassesMapping = {} USAGE_TEXT = """ diff --git a/stix/common/__init__.py b/stix/common/__init__.py index 28eab16f..d5450373 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -18,7 +18,8 @@ GenericRelationshipList, RelatedCampaign, RelatedCOA, RelatedExploitTarget, RelatedIdentity, RelatedIncident, RelatedIndicator, RelatedObservable, RelatedThreatActor, RelatedTTP, - RelatedPackage, RelatedPackages, RelatedCampaignRef + RelatedPackage, RelatedPackages, RelatedCampaignRef, RelatedReports, + RelatedReport ) # Patch in base types of Related* types @@ -29,6 +30,7 @@ from stix.exploit_target import ExploitTarget from stix.incident import Incident from stix.indicator import Indicator +from stix.report import Report from stix.threat_actor import ThreatActor from stix.ttp import TTP @@ -43,11 +45,13 @@ RelatedTTP._base_type = TTP # noqa RelatedObservable._base_type = Observable # noqa RelatedPackage._base_type = STIXPackage # noqa +RelatedReport._base_type = Report # noqa RelatedCampaignRef._base_type = CampaignRef # noqa -# Path the RelatedPackages _contained_type -RelatedPackages._contained_type = RelatedPackage # noqa +# Patch contained types +RelatedPackages._contained_type = RelatedPackage # noqa +RelatedReports._contained_type = RelatedReport # noqa import stix import stix.utils as utils diff --git a/stix/common/related.py b/stix/common/related.py index f3718dfb..763eced6 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -8,6 +8,7 @@ import stix.utils as utils import stix.bindings.stix_common as common_binding import stix.bindings.stix_core as core_binding +import stix.bindings.report as report_binding # relative from .vocabs import VocabString @@ -267,6 +268,15 @@ class RelatedPackages(GenericRelationshipList): _inner_name = "related_packages" +class RelatedReports(GenericRelationshipList): + _namespace = 'http://stix.mitre.org/Report-1' + _binding = report_binding + _binding_class = report_binding.RelatedReportsType + _binding_var = "Related_Report" + # _contained_type is patched in common/__init__.py + _inner_name = "related_reports" + + class RelatedPackageRefs(stix.EntityList): _namespace = 'http://stix.mitre.org/common-1' _binding = common_binding @@ -444,6 +454,14 @@ class RelatedPackage(_BaseRelated): _inner_var = "Package" +class RelatedReport(_BaseRelated): + _namespace = "http://stix.mitre.org/common-1" + _binding = common_binding + _binding_class = common_binding.RelatedReportType + # _base_type is set in common/__init__.py + _inner_var = "Report" + + class RelatedCampaignRef(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index b311baf3..facef86e 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -725,6 +725,34 @@ class PackageIntent(VocabString): TERM_MALWARE_SAMPLES = "Malware Samples" +@register_vocab +class ReportIntent(VocabString): + _namespace = 'http://stix.mitre.org/default_vocabularies-1' + _XSI_TYPE = 'stixVocabs:ReportIntentVocab-1.0' + + TERM_COLLECTIVE_THREAT_INTELLIGENCE = "Collective Threat Intelligence" + TERM_THREAT_REPORT = "Threat Report" + TERM_INDICATORS = "Indicators" + TERM_INDICATORS_PHISHING = "Indicators - Phishing" + TERM_INDICATORS_WATCHLIST = "Indicators - Watchlist" + TERM_INDICATORS_MALWARE_ARTIFACTS = "Indicators - Malware Artifacts" + TERM_INDICATORS_NETWORK_ACTIVITY = "Indicators - Network Activity" + TERM_INDICATORS_ENDPOINT_CHARACTERISTICS = "Indicators - Endpoint Characteristics" + TERM_CAMPAIGN_CHARACTERIZATION = "Campaign Characterization" + TERM_THREAT_ACTOR_CHARACTERIZATION = "Threat Actor Characterization" + TERM_EXPLOIT_CHARACTERIZATION = "Exploit Characterization" + TERM_ATTACK_PATTERN_CHARACTERIZATION = "Attack Pattern Characterization" + TERM_MALWARE_CHARACTERIZATION = "Malware Characterization" + TERM_TTP_INFRASTRUCTURE = "TTP - Infrastructure" + TERM_TTP_TOOLS = "TTP - Tools" + TERM_COURSES_OF_ACTION = "Courses of Action" + TERM_INCIDENT = "Incident" + TERM_OBSERVATIONS = "Observations" + TERM_OBSERVATIONS_EMAIL = "Observations - Email" + TERM_MALWARE_SAMPLES = "Malware Samples" + + + @register_vocab class LossDuration(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index 195388cb..0691dd83 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -2,7 +2,6 @@ # See LICENSE.txt for complete terms. import stix -import stix.utils as utils import stix.bindings.stix_common as stix_common_binding import stix.bindings.stix_core as stix_core_binding from stix.common import InformationSource, StructuredTextList, VocabString diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 93ad2c00..e297a9f9 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -14,6 +14,7 @@ from stix.exploit_target import ExploitTarget from stix.indicator import Indicator from stix.incident import Incident +from stix.report import Report from stix.threat_actor import ThreatActor from stix.ttp import TTP from stix.common.related import RelatedPackages @@ -36,7 +37,7 @@ class STIXPackage(stix.Entity): def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, courses_of_action=None, exploit_targets=None, indicators=None, observables=None, incidents=None, threat_actors=None, - ttps=None, campaigns=None): + ttps=None, campaigns=None, reports=None): self.id_ = id_ or stix.utils.create_id("Package") self.idref = idref @@ -51,6 +52,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, self.threat_actors = threat_actors self.ttps = ttps self.related_packages = RelatedPackages() + self.reports = reports if timestamp: self.timestamp = timestamp @@ -191,6 +193,17 @@ def ttps(self, value): def add_ttp(self, ttp): self.ttps.append(ttp) + @property + def reports(self): + return self._reports + + @reports.setter + def reports(self, value): + self._reports = Reports(value) + + def add_report(self, report): + self.reports.append(report) + def add(self, entity): """Adds `entity` to a top-level collection. For example, if `entity` is an Indicator object, the `entity` will be added to the ``indicators`` @@ -209,6 +222,7 @@ def add(self, entity): Indicator: self.add_indicator, ThreatActor: self.add_threat_actor, TTP: self.add_threat_actor, + Report: self.add_report, Observable: self.add_observable, } @@ -251,6 +265,8 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.TTPs = self.ttps.to_obj(ns_info=ns_info) if self.related_packages: return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) + if self.reports: + return_obj.Reports = self.reports.to_obj(ns_info=ns_info) return return_obj @@ -275,6 +291,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.threat_actors = ThreatActors.from_obj(obj.Threat_Actors) return_obj.ttps = TTPs.from_obj(obj.TTPs) return_obj.related_packages = RelatedPackages.from_obj(obj.Related_Packages) + return_obj.reports = Reports.from_obj(obj.Reports) # Don't overwrite unless a version is passed in if obj.version: @@ -287,20 +304,23 @@ def from_dict(cls, dict_repr, return_obj=None): if not return_obj: return_obj = cls() - return_obj.id_ = dict_repr.get('id') - return_obj.idref = dict_repr.get('idref') - return_obj.timestamp = dict_repr.get('timestamp') - return_obj.version = dict_repr.get('version', cls._version) - return_obj.stix_header = STIXHeader.from_dict(dict_repr.get('stix_header')) - return_obj.campaigns = Campaigns.from_dict(dict_repr.get('campaigns')) - return_obj.courses_of_action = CoursesOfAction.from_dict(dict_repr.get('courses_of_action')) - return_obj.exploit_targets = ExploitTargets.from_dict(dict_repr.get('exploit_targets')) - return_obj.indicators = Indicators.from_dict(dict_repr.get('indicators')) - return_obj.observables = Observables.from_dict(dict_repr.get('observables')) - return_obj.incidents = Incidents.from_dict(dict_repr.get('incidents')) - return_obj.threat_actors = ThreatActors.from_dict(dict_repr.get('threat_actors')) - return_obj.ttps = TTPs.from_dict(dict_repr.get('ttps')) - return_obj.related_packages = RelatedPackages.from_dict(dict_repr.get('related_packages')) + get = dict_repr.get + + return_obj.id_ = get('id') + return_obj.idref = get('idref') + return_obj.timestamp = get('timestamp') + return_obj.version = get('version', cls._version) + return_obj.stix_header = STIXHeader.from_dict(get('stix_header')) + return_obj.campaigns = Campaigns.from_dict(get('campaigns')) + return_obj.courses_of_action = CoursesOfAction.from_dict(get('courses_of_action')) + return_obj.exploit_targets = ExploitTargets.from_dict(get('exploit_targets')) + return_obj.indicators = Indicators.from_dict(get('indicators')) + return_obj.observables = Observables.from_dict(get('observables')) + return_obj.incidents = Incidents.from_dict(get('incidents')) + return_obj.threat_actors = ThreatActors.from_dict(get('threat_actors')) + return_obj.ttps = TTPs.from_dict(get('ttps')) + return_obj.related_packages = RelatedPackages.from_dict(get('related_packages')) + return_obj.reports = Reports.from_dict(get('reports')) return return_obj @@ -382,3 +402,13 @@ class ThreatActors(stix.EntityList): _binding_var = "Threat_Actor" _inner_name = "threat_actors" _dict_as_list = True + + +class Reports(stix.EntityList): + _binding = stix_core_binding + _namespace = 'http://stix.mitre.org/stix-1' + _binding_class = _binding.ReportsType + _contained_type = Report + _binding_var = "Report" + _inner_name = "reports" + _dict_as_list = True diff --git a/stix/report/__init__.py b/stix/report/__init__.py new file mode 100644 index 00000000..d8cc492c --- /dev/null +++ b/stix/report/__init__.py @@ -0,0 +1,366 @@ +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +# external +from cybox.core import Observable, Observables + +# internal +import stix +import stix.utils as utils +import stix.utils.parser as parser + +from stix.campaign import Campaign +from stix.coa import CourseOfAction +from stix.core.ttps import TTPs +from stix.exploit_target import ExploitTarget +from stix.indicator import Indicator +from stix.incident import Incident +from stix.threat_actor import ThreatActor +from stix.ttp import TTP +from stix.common.related import RelatedReports + +# relative imports +from .header import Header + +# binding imports +import stix.bindings.stix_common as stix_common_binding +import stix.bindings.report as report_binding + + +class Report(stix.Entity): + _binding = report_binding + _binding_class = _binding.ReportType + _namespace = 'http://stix.mitre.org/Report-1' + _version = "1.0" + + def __init__(self, id_=None, idref=None, timestamp=None, header=None, + courses_of_action=None, exploit_targets=None, indicators=None, + observables=None, incidents=None, threat_actors=None, + ttps=None, campaigns=None): + + self.id_ = id_ or stix.utils.create_id("Report") + self.idref = idref + self.version = self._version + self.header = header + self.campaigns = campaigns + self.courses_of_action = courses_of_action + self.exploit_targets = exploit_targets + self.observables = observables + self.indicators = indicators + self.incidents = incidents + self.threat_actors = threat_actors + self.ttps = ttps + self.related_reports = RelatedReports() + + if timestamp: + self.timestamp = timestamp + else: + self.timestamp = utils.dates.now() if not idref else None + + @property + def id_(self): + return self._id + + @id_.setter + def id_(self, value): + if not value: + self._id = None + else: + self._id = value + self.idref = None + + @property + def idref(self): + return self._idref + + @idref.setter + def idref(self, value): + if not value: + self._idref = None + else: + self._idref = value + self.id_ = None # unset id_ if idref is present + + @property + def timestamp(self): + return self._timestamp + + @timestamp.setter + def timestamp(self, value): + self._timestamp = utils.dates.parse_value(value) + + @property + def header(self): + return self._header + + @header.setter + def header(self, value): + self._set_var(Header, try_cast=False, header=value) + + @property + def indicators(self): + return self._indicators + + @indicators.setter + def indicators(self, value): + self._indicators = Indicators(value) + + def add_indicator(self, indicator): + self.indicators.append(indicator) + + @property + def campaigns(self): + return self._campaigns + + @campaigns.setter + def campaigns(self, value): + self._campaigns = Campaigns(value) + + def add_campaign(self, campaign): + self.campaigns.append(campaign) + + @property + def observables(self): + return self._observables + + @observables.setter + def observables(self, value): + self._set_var(Observables, observables=value) + + def add_observable(self, observable): + if not self.observables: + self.observables = Observables(observables=observable) + else: + self.observables.add(observable) + + @property + def incidents(self): + return self._incidents + + @incidents.setter + def incidents(self, value): + self._incidents = Incidents(value) + + def add_incident(self, incident): + self.incidents.append(incident) + + @property + def threat_actors(self): + return self._threat_actors + + @threat_actors.setter + def threat_actors(self, value): + self._threat_actors = ThreatActors(value) + + def add_threat_actor(self, threat_actor): + self._threat_actors.append(threat_actor) + + @property + def courses_of_action(self): + return self._courses_of_action + + @courses_of_action.setter + def courses_of_action(self, value): + self._courses_of_action = CoursesOfAction(value) + + def add_course_of_action(self, course_of_action): + self._courses_of_action.append(course_of_action) + + @property + def exploit_targets(self): + return self._exploit_targets + + @exploit_targets.setter + def exploit_targets(self, value): + self._exploit_targets = ExploitTargets(value) + + def add_exploit_target(self, exploit_target): + self._exploit_targets.append(exploit_target) + + @property + def ttps(self): + return self._ttps + + @ttps.setter + def ttps(self, value): + if isinstance(value, TTPs): + self._ttps = value + else: + self._ttps = TTPs(value) + + def add_ttp(self, ttp): + self.ttps.append(ttp) + + def add(self, entity): + """Adds `entity` to a top-level collection. For example, if `entity` is + an Indicator object, the `entity` will be added to the ``indicators`` + top-level collection. + + """ + if utils.is_cybox(entity): + self.add_observable(entity) + return + + tlo_adds = { + Campaign: self.add_campaign, + CourseOfAction: self.add_course_of_action, + ExploitTarget: self.add_exploit_target, + Incident: self.add_incident, + Indicator: self.add_indicator, + ThreatActor: self.add_threat_actor, + TTP: self.add_threat_actor, + Observable: self.add_observable, + } + + try: + add = tlo_adds[entity.__class__] + add(entity) + except KeyError: + error = "Cannot add type '{0}' to a top-level collection" + error = error.format(type(entity)) + raise TypeError(error) + + def to_obj(self, return_obj=None, ns_info=None): + super(Report, self).to_obj(return_obj=return_obj, ns_info=ns_info) + + if not return_obj: + return_obj = self._binding_class() + + return_obj.id = self.id_ + return_obj.idref = self.idref + return_obj.version = self.version + return_obj.timestamp = utils.dates.serialize_value(self.timestamp) + + if self.header: + return_obj.STIX_Header = self.header.to_obj(ns_info=ns_info) + if self.campaigns: + return_obj.Campaigns = self.campaigns.to_obj(ns_info=ns_info) + if self.courses_of_action: + return_obj.Courses_Of_Action = self.courses_of_action.to_obj(ns_info=ns_info) + if self.exploit_targets: + return_obj.Exploit_Targets = self.exploit_targets.to_obj(ns_info=ns_info) + if self.indicators: + return_obj.Indicators = self.indicators.to_obj(ns_info=ns_info) + if self.observables: + return_obj.Observables = self.observables.to_obj(ns_info=ns_info) + if self.incidents: + return_obj.Incidents = self.incidents.to_obj(ns_info=ns_info) + if self.threat_actors: + return_obj.Threat_Actors = self.threat_actors.to_obj(ns_info=ns_info) + if self.ttps: + return_obj.TTPs = self.ttps.to_obj(ns_info=ns_info) + if self.related_reports: + return_obj.Related_Reports = self.related_reports.to_obj(ns_info=ns_info) + + return return_obj + + def to_dict(self): + return super(Report, self).to_dict() + + @classmethod + def from_obj(cls, obj, return_obj=None): + if not return_obj: + return_obj = cls() + + return_obj.id_ = obj.id + return_obj.idref = obj.idref + return_obj.timestamp = obj.timestamp + return_obj.header = Header.from_obj(obj.STIX_Header) + return_obj.campaigns = Campaigns.from_obj(obj.Campaigns) + return_obj.courses_of_action = CoursesOfAction.from_obj(obj.Courses_Of_Action) + return_obj.exploit_targets = ExploitTargets.from_obj(obj.Exploit_Targets) + return_obj.indicators = Indicators.from_obj(obj.Indicators) + return_obj.observables = Observables.from_obj(obj.Observables) + return_obj.incidents = Incidents.from_obj(obj.Incidents) + return_obj.threat_actors = ThreatActors.from_obj(obj.Threat_Actors) + return_obj.ttps = TTPs.from_obj(obj.TTPs) + return_obj.related_reports = RelatedReports.from_obj(obj.Related_Packages) + + # Don't overwrite unless a version is passed in + if obj.version: + return_obj.version = obj.version + + return return_obj + + @classmethod + def from_dict(cls, dict_repr, return_obj=None): + if not return_obj: + return_obj = cls() + + get = dict_repr.get + return_obj.id_ = get('id') + return_obj.idref = get('idref') + return_obj.timestamp = get('timestamp') + return_obj.version = get('version', cls._version) + return_obj.header = Header.from_dict(get('header')) + return_obj.campaigns = Campaigns.from_dict(get('campaigns')) + return_obj.courses_of_action = CoursesOfAction.from_dict(get('courses_of_action')) + return_obj.exploit_targets = ExploitTargets.from_dict(get('exploit_targets')) + return_obj.indicators = Indicators.from_dict(get('indicators')) + return_obj.observables = Observables.from_dict(get('observables')) + return_obj.incidents = Incidents.from_dict(get('incidents')) + return_obj.threat_actors = ThreatActors.from_dict(get('threat_actors')) + return_obj.ttps = TTPs.from_dict(get('ttps')) + return_obj.related_reports = RelatedReports.from_dict(get('related_reports')) + + return return_obj + + +class Campaigns(stix.EntityList): + _binding = report_binding + _namespace = 'http://stix.mitre.org/Report-1' + _binding_class = _binding.CampaignsType + _contained_type = Campaign + _binding_var = "Campaign" + _inner_name = "campaigns" + _dict_as_list = True + + +class CoursesOfAction(stix.EntityList): + _binding = report_binding + _namespace = 'http://stix.mitre.org/Report-1' + _binding_class = _binding.CoursesOfActionType + _contained_type = CourseOfAction + _binding_var = "Course_Of_Action" + _inner_name = "courses_of_action" + _dict_as_list = True + + +class ExploitTargets(stix.EntityList): + _binding = stix_common_binding + _namespace = 'http://stix.mitre.org/common-1' + _binding_class = _binding.ExploitTargetsType + _contained_type = ExploitTarget + _binding_var = "Exploit_Target" + _inner_name = "exploit_targets" + _dict_as_list = True + + +class Incidents(stix.EntityList): + _binding = report_binding + _namespace = 'http://stix.mitre.org/Report-1' + _binding_class = _binding.IncidentsType + _contained_type = Incident + _binding_var = "Incident" + _inner_name = "incidents" + _dict_as_list = True + + +class Indicators(stix.EntityList): + _binding = report_binding + _namespace = 'http://stix.mitre.org/Report-1' + _binding_class = _binding.IndicatorsType + _contained_type = Indicator + _binding_var = "Indicator" + _inner_name = "indicators" + _dict_as_list = True + + +class ThreatActors(stix.EntityList): + _binding = report_binding + _namespace = 'http://stix.mitre.org/Report-1' + _binding_class = _binding.ThreatActorsType + _contained_type = ThreatActor + _binding_var = "Threat_Actor" + _inner_name = "threat_actors" + _dict_as_list = True diff --git a/stix/report/header.py b/stix/report/header.py new file mode 100644 index 00000000..dff0d416 --- /dev/null +++ b/stix/report/header.py @@ -0,0 +1,219 @@ +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +import stix +import stix.bindings.report as report_binding +from stix.common import InformationSource, StructuredTextList, VocabString +from stix.common.vocabs import ReportIntent +from stix.data_marking import Marking + + +class Header(stix.Entity): + _binding = report_binding + _namespace = 'http://stix.mitre.org/Report-1' + + def __init__(self, title=None, description=None, short_description=None, + handling=None, intents=None, information_source=None): + + self.intents = intents + self.title = title + self.description = description + self.short_description = short_description + self.handling = handling + self.information_source = information_source + + @property + def description(self): + """A single description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If this object has more than one description set, this will return + the description with the lowest ordinality value. + + Returns: + An instance of + :class:`.StructuredText` + + """ + return next(iter(self.descriptions), None) + + @description.setter + def description(self, value): + self.descriptions = value + + @property + def descriptions(self): + """A :class:`.StructuredTextList` object, containing descriptions about + the purpose or intent of this object. + + This is typically used for the purpose of providing multiple + descriptions with different classificaton markings. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`.StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`.StructuredText` will be be converted. + + Returns: + An instance of + :class:`.StructuredTextList` + + """ + return self._description + + @descriptions.setter + def descriptions(self, value): + self._description = StructuredTextList(value) + + @property + def short_description(self): + """A single short description about the contents or purpose of this + object. + + Default Value: ``None`` + + Note: + If this object has more than one short description set, this will + return the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + + """ + return next(iter(self.short_descriptions), None) + + @short_description.setter + def short_description(self, value): + self.short_descriptions = value + + @property + def short_descriptions(self): + """A :class:`.StructuredTextList` object, containing short descriptions + about the purpose or intent of this object. + + This is typically used for the purpose of providing multiple + short descriptions with different classificaton markings. + + Iterating over this object will yield its contents sorted by their + ``ordinality`` value. + + Default Value: Empty :class:`.StructuredTextList` object. + + Note: + IF this is set to a value that is not an instance of + :class:`.StructuredText`, an effort will ne made to convert it. + If this is set to an iterable, any values contained that are not + an instance of :class:`.StructuredText` will be be converted. + + Returns: + An instance of :class:`.StructuredTextList` + + """ + return self._short_description + + @short_descriptions.setter + def short_descriptions(self, value): + self._short_description = StructuredTextList(value) + + @property + def handling(self): + return self._handling + + @handling.setter + def handling(self, value): + self._set_var(Marking, try_cast=False, handling=value) + + @property + def intents(self): + return self._intents + + @intents.setter + def intents(self, value): + self._intents = _ReportIntents(value) + + def add_intent(self, intent): + self.intents.append(intent) + + @property + def information_source(self): + return self._information_source + + @information_source.setter + def information_source(self, value): + self._set_var(InformationSource, try_cast=False, information_source=value) + + @classmethod + def from_obj(cls, obj, return_obj=None): + if not obj: + return None + + if not return_obj: + return_obj = cls() + + return_obj.title = obj.Title + return_obj.descriptions = StructuredTextList.from_obj(obj.Description) + return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) + return_obj.handling = Marking.from_obj(obj.Handling) + return_obj.information_source = InformationSource.from_obj(obj.Information_Source) + return_obj.intents = _ReportIntents.from_obj(obj.Intent) + + return return_obj + + def to_obj(self, return_obj=None, ns_info=None): + super(Header, self).to_obj(return_obj=return_obj, ns_info=ns_info) + + if not return_obj: + return_obj = self._binding.HeaderType() + + if self.title: + return_obj.Title = self.title + if self.intents: + return_obj.Intent = self.intents.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) + if self.short_descriptions: + return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) + if self.handling: + return_obj.Handling = self.handling.to_obj(ns_info=ns_info) + if self.information_source: + return_obj.Information_Source = self.information_source.to_obj(ns_info=ns_info) + + return return_obj + + @classmethod + def from_dict(cls, dict_repr, return_obj=None): + if not dict_repr: + return None + + if not return_obj: + return_obj = cls() + + get = dict_repr.get + + return_obj.title = get('title') + return_obj.intents = _ReportIntents.from_list(get('intents')) + return_obj.descriptions = StructuredTextList.from_dict(get('description')) + return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) + return_obj.handling = Marking.from_dict(get('handling')) + return_obj.information_source = InformationSource.from_dict(get('information_source')) + + return return_obj + + def to_dict(self): + return super(Header, self).to_dict() + + +# NOT AN ACTUAL STIX TYPE! +class _ReportIntents(stix.TypedList): + _contained_type = VocabString + + def _fix_value(self, value): + return ReportIntent(value) From 55c1fbc4b00572a6291d4871ecfb678f3e1b098b Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 08:53:12 -0400 Subject: [PATCH 035/438] Added docstrings to bindings/__init__.py. Changed is_base() to has_xsi_type() --- stix/bindings/__init__.py | 61 ++++++++++++++++++++++++++------- stix/bindings/data_marking.py | 2 +- stix/bindings/exploit_target.py | 2 +- stix/bindings/incident.py | 4 +-- stix/bindings/report.py | 12 +++---- stix/bindings/stix_common.py | 22 ++++++------ stix/bindings/stix_core.py | 14 ++++---- stix/bindings/threat_actor.py | 2 +- stix/bindings/ttp.py | 8 ++--- 9 files changed, 82 insertions(+), 45 deletions(-) diff --git a/stix/bindings/__init__.py b/stix/bindings/__init__.py index 97814a20..93c3d1b1 100644 --- a/stix/bindings/__init__.py +++ b/stix/bindings/__init__.py @@ -398,6 +398,18 @@ def _cast(typ, value): def get_type_info(node): + """Returns a ``TypeInfo`` object for `node`. + + This is accomplished by parsing the ``xsi:type`` attribute found on + `node`. + + Args: + node: An lxml.etree element object. + + Raises: + KeyError: If `node` does not have an ``xsi:type`` attribute. + + """ xsi_type = node.attrib[xmlconst.TAG_XSI_TYPE] typeinfo = xsi_type.split(":") @@ -411,20 +423,42 @@ def get_type_info(node): return TypeInfo(ns=ns, typename=typename) +#: A mapping of namespace/type information to binding classes. _EXTENSION_MAP = {} def add_extension(cls): + """Adds the binding class `cls` to the ``_EXTENSION_MAP``. + + This enables the lookup and instantiation of classes during parse when + ``xsi:type`` attributes are encountered. + + """ typeinfo = TypeInfo(ns=cls.xmlns, typename=cls.xml_type) _EXTENSION_MAP[typeinfo] = cls def register_extension(cls): + """Class decorator for registering a binding class as an implementation of + an xml type. + + Classes must have ``xmlns`` and ``xml_type`` class attributes to be + registered. + + """ add_extension(cls) return cls def lookup_extension(typeinfo): + """Looks up the binding class for `typeinfo`, which is a namespace/typename + pairing. + + Returns: + A binding class that has been registered for the namespace and typename + found on `typeinfo`. + + """ if not isinstance(typeinfo, TypeInfo): typeinfo = get_type_info(typeinfo) @@ -436,30 +470,33 @@ def lookup_extension(typeinfo): raise NotImplementedError(error) -def is_base(node): +def has_xsi_type(node): + """Returns ``True`` if `node` does not have an xsi:type attribute. + + """ return xmlconst.TAG_XSI_TYPE not in node.attrib __all__ = [ + 'CDATA_END', + 'CDATA_START', + 'ExternalEncoding', + 'GeneratedsSuper', + 'Tag_pattern_', + 'TypeInfo', '_cast', 'add_extension', - 'lookup_extension', - 'is_base', - 'register_extension', 'etree_', - 'ExternalEncoding', 'find_attr_value_', 'get_all_text_', 'get_type_info', + 'has_xsi_type', + 'lookup_extension', 'parsexml_', - 'quote_xml', 'quote_attrib', 'quote_python', + 'quote_xml', 'raise_parse_error', - 'showIndent', - 'Tag_pattern_', - 'GeneratedsSuper', - 'CDATA_START', - 'CDATA_END', - 'TypeInfo' + 'register_extension', + 'showIndent' ] diff --git a/stix/bindings/data_marking.py b/stix/bindings/data_marking.py index 5e3dbfc9..c0432928 100644 --- a/stix/bindings/data_marking.py +++ b/stix/bindings/data_marking.py @@ -338,7 +338,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): # Look for xsi:type. If not there, build an instance of # MarkingStructureType - if is_base(child_): + if has_xsi_type(child_): obj_ = MarkingStructureType.factory() else: obj_ = lookup_extension(child_).factory() diff --git a/stix/bindings/exploit_target.py b/stix/bindings/exploit_target.py index 0e2317cd..e05443af 100644 --- a/stix/bindings/exploit_target.py +++ b/stix/bindings/exploit_target.py @@ -940,7 +940,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Vulnerability': import stix.bindings.extensions.vulnerability.cvrf_1_1 as cvrf_1_1_binding - if is_base(child_): + if has_xsi_type(child_): obj_ = VulnerabilityType.factory() # VulnerabilityType not abstract else: obj_ = lookup_extension(child_).factory() diff --git a/stix/bindings/incident.py b/stix/bindings/incident.py index 249fcd5b..36cc9030 100644 --- a/stix/bindings/incident.py +++ b/stix/bindings/incident.py @@ -551,7 +551,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Course_Of_Action': from . import course_of_action - if is_base(child_): + if has_xsi_type(child_): obj_ = stix_common_binding.CourseOfActionBaseType.factory() # not abstract else: obj_ = lookup_extension(child_).factory() @@ -2486,7 +2486,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Victim': import stix.bindings.extensions.identity.ciq_identity_3_0 as ciq_identity_binding - if is_base(child_): + if has_xsi_type(child_): obj_ = stix_common_binding.IdentityType.factory() # IdentityType is not abstract else: obj_ = lookup_extension(child_).factory() diff --git a/stix/bindings/report.py b/stix/bindings/report.py index 1f78d414..cb8ec207 100644 --- a/stix/bindings/report.py +++ b/stix/bindings/report.py @@ -207,7 +207,7 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Indicator': - if is_base(child_): + if has_xsi_type(child_): obj_ = common_binding.IndicatorBaseType.factory() else: klass = lookup_extension(child_) @@ -285,7 +285,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'TTP': from . import ttp - if is_base(child_): + if has_xsi_type(child_): obj_ = common_binding.TTPBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -361,7 +361,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Incident': from . import incident - if is_base(child_): + if has_xsi_type(child_): obj_ = common_binding.IncidentBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -433,7 +433,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Course_Of_Action': from . import course_of_action - if is_base(child_): + if has_xsi_type(child_): obj_ = common_binding.CourseOfActionBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -505,7 +505,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Campaign': from . import campaign - if is_base(child_): + if has_xsi_type(child_): obj_ = common_binding.CampaignBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -577,7 +577,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Threat_Actor': from . import threat_actor - if is_base(child_): + if has_xsi_type(child_): obj_ = common_binding.ThreatActorBaseType.factory() # not abstract else: klass = lookup_extension(child_) diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index 0ed134ed..961860b4 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -609,7 +609,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Identity': from .extensions.identity import ciq_identity_3_0 - if is_base(child_): + if has_xsi_type(child_): obj_ = IdentityType.factory() # IdentityType is not abstract else: obj_ = lookup_extension(child_).factory() @@ -1484,7 +1484,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Campaign': from . import campaign - if is_base(child_): + if has_xsi_type(child_): obj_ = CampaignBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -1556,7 +1556,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Course_Of_Action': from . import campaign - if is_base(child_): + if has_xsi_type(child_): obj_ = CampaignBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -1626,7 +1626,7 @@ def buildAttributes(self, node, attrs, already_processed): super(RelatedExploitTargetType, self).buildAttributes(node, attrs, already_processed) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Exploit_Target': - if is_base(child_): + if has_xsi_type(child_): obj_ = ExploitTargetBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -1698,7 +1698,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Incident': from . import incident - if is_base(child_): + if has_xsi_type(child_): obj_ = IncidentBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -1770,7 +1770,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Indicator': from . import indicator - if is_base(child_): + if has_xsi_type(child_): obj_ = IndicatorBaseType.factory() else: klass = lookup_extension(child_) @@ -1907,7 +1907,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Threat_Actor': from . import threat_actor - if is_base(child_): + if has_xsi_type(child_): obj_ = ThreatActorBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -1979,7 +1979,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'TTP': from . import ttp - if is_base(child_): + if has_xsi_type(child_): obj_ = TTPBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -2051,7 +2051,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Identity': from .extensions.identity import ciq_identity_3_0 - if is_base(child_): + if has_xsi_type(child_): obj_ = IdentityType.factory() # IdentityType is not abstract else: obj_ = lookup_extension(child_).factory() @@ -3042,7 +3042,7 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Exploit_Target': - if is_base(child_): + if has_xsi_type(child_): obj_ = ExploitTargetBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -3931,7 +3931,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Report': from . import report - if is_base(child_): + if has_xsi_type(child_): obj_ = ReportBaseType.factory() else: obj_ = lookup_extension(child_).factory() diff --git a/stix/bindings/stix_core.py b/stix/bindings/stix_core.py index 2e0eb1ff..1ca8ed14 100644 --- a/stix/bindings/stix_core.py +++ b/stix/bindings/stix_core.py @@ -568,7 +568,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Indicator': from . import indicator - if is_base(child_): + if has_xsi_type(child_): obj_ = stix_common_binding.IndicatorBaseType.factory() else: klass = lookup_extension(child_) @@ -647,7 +647,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'TTP': from . import ttp - if is_base(child_): + if has_xsi_type(child_): obj_ = stix_common_binding.TTPBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -724,7 +724,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Incident': from . import incident - if is_base(child_): + if has_xsi_type(child_): obj_ = stix_common_binding.IncidentBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -797,7 +797,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Course_Of_Action': from . import course_of_action - if is_base(child_): + if has_xsi_type(child_): obj_ = stix_common_binding.CourseOfActionBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -869,7 +869,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Campaign': from . import campaign - if is_base(child_): + if has_xsi_type(child_): obj_ = stix_common_binding.CampaignBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -941,7 +941,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Threat_Actor': from . import threat_actor - if is_base(child_): + if has_xsi_type(child_): obj_ = stix_common_binding.ThreatActorBaseType.factory() # not abstract else: klass = lookup_extension(child_) @@ -1015,7 +1015,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Report': from . import report - if is_base(child_): + if has_xsi_type(child_): obj_ = stix_common_binding.ReportBaseType.factory() # not abstract else: klass = lookup_extension(child_) diff --git a/stix/bindings/threat_actor.py b/stix/bindings/threat_actor.py index 7a835d4c..92398acf 100644 --- a/stix/bindings/threat_actor.py +++ b/stix/bindings/threat_actor.py @@ -451,7 +451,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Identity': from .extensions.identity import ciq_identity_3_0 - if is_base(child_): + if has_xsi_type(child_): obj_ = stix_common_binding.IdentityType.factory() # IdentityType is not abstract else: obj_ = lookup_extension(child_).factory() diff --git a/stix/bindings/ttp.py b/stix/bindings/ttp.py index 018dc47d..4f4e07f4 100644 --- a/stix/bindings/ttp.py +++ b/stix/bindings/ttp.py @@ -767,7 +767,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Malware_Instance': from .extensions.malware import maec_4_1 - if is_base(child_): + if has_xsi_type(child_): obj_ = MalwareInstanceType.factory() # MalwareInstanceType is not abstract else: obj_ = lookup_extension(child_).factory() @@ -838,7 +838,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Attack_Pattern': from .extensions.attack_pattern import capec_2_7 - if is_base(child_): + if has_xsi_type(child_): obj_ = AttackPatternType.factory() # AttackPattern is not abstract else: obj_ = lookup_extension(child_).factory() @@ -989,7 +989,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Persona': from .extensions.identity import ciq_identity_3_0 - if is_base(child_): + if has_xsi_type(child_): obj_ = stix_common_binding.IdentityType.factory() # IdentityType is not abstract else: obj_ = lookup_extension(child_).factory() @@ -1165,7 +1165,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Identity': from .extensions.identity import ciq_identity_3_0 - if is_base(child_): + if has_xsi_type(child_): obj_ = stix_common_binding.IdentityType.factory() # IdentityType is not abstract else: obj_ = lookup_extension(child_).factory() From 80bc98aab622b014c5cc92e9118250ca56035e15 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 09:23:05 -0400 Subject: [PATCH 036/438] Added add_description() and add_short_description() method to classes that support descriptions and short_descriptions --- stix/base.py | 16 ++++++++++++ stix/coa/objective.py | 16 ++++++++++++ stix/common/activity.py | 8 ++++++ stix/common/confidence.py | 8 ++++++ stix/common/information_source.py | 8 ++++++ stix/common/statement.py | 8 ++++++ stix/common/tools.py | 8 ++++++ stix/core/stix_header.py | 16 ++++++++++++ stix/exploit_target/configuration.py | 16 ++++++++++++ stix/exploit_target/vulnerability.py | 16 ++++++++++++ stix/exploit_target/weakness.py | 8 ++++++ .../structured_coa/generic_structured_coa.py | 8 ++++++ .../test_mechanism/generic_test_mechanism.py | 10 +++++++- stix/incident/affected_asset.py | 8 ++++++ stix/indicator/sightings.py | 8 ++++++ stix/report/header.py | 16 ++++++++++++ stix/test/campaign_test.py | 24 ++++++++++++++++++ stix/test/coa_test.py | 23 +++++++++++++++++ stix/test/common/structured_text_tests.py | 2 ++ stix/test/exploit_target_test.py | 24 ++++++++++++++++++ stix/test/incident_test.py | 23 +++++++++++++++++ stix/test/indicator_test.py | 25 +++++++++++++++++++ stix/test/threat_actor_test.py | 23 +++++++++++++++++ stix/test/ttp_test.py | 24 ++++++++++++++++++ stix/ttp/attack_pattern.py | 16 ++++++++++++ stix/ttp/exploit.py | 16 ++++++++++++ stix/ttp/infrastructure.py | 16 ++++++++++++ stix/ttp/malware_instance.py | 16 ++++++++++++ 28 files changed, 409 insertions(+), 1 deletion(-) diff --git a/stix/base.py b/stix/base.py index 1fc9c0b4..5a76b5c9 100644 --- a/stix/base.py +++ b/stix/base.py @@ -738,6 +738,14 @@ def descriptions(self, value): from stix.common import StructuredTextList self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def short_description(self): """A single short description about the contents or purpose of this @@ -789,6 +797,14 @@ def short_descriptions(self, value): from stix.common import StructuredTextList self._short_description = StructuredTextList(value) + def add_short_description(self, description): + """Adds a description to the ``short_descriptions`` collection. + + This is the same as calling "foo.short_descriptions.add(bar)". + + """ + self.short_descriptions.add(description) + @property def information_source(self): """Contains information about the source of this object. diff --git a/stix/coa/objective.py b/stix/coa/objective.py index f62df464..0fc35f16 100644 --- a/stix/coa/objective.py +++ b/stix/coa/objective.py @@ -68,6 +68,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def short_description(self): """A single short description about the contents or purpose of this @@ -118,6 +126,14 @@ def short_descriptions(self): def short_descriptions(self, value): self._short_description = StructuredTextList(value) + def add_short_description(self, description): + """Adds a description to the ``short_descriptions`` collection. + + This is the same as calling "foo.short_descriptions.add(bar)". + + """ + self.short_descriptions.add(description) + @property def applicability_confidence(self): return self._applicability_confidence diff --git a/stix/common/activity.py b/stix/common/activity.py index e655b71b..fd2a8eb7 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -74,6 +74,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + def to_obj(self, return_obj=None, ns_info=None): super(Activity, self).to_obj(return_obj=return_obj, ns_info=ns_info) diff --git a/stix/common/confidence.py b/stix/common/confidence.py index c6975a2f..5fffea24 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -98,6 +98,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + # @property # def confidence_assertion_chain(self): # return self._confidence_assertion_chain diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 32e0a0a1..44d9dfef 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -112,6 +112,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def identity(self): return self._identity diff --git a/stix/common/statement.py b/stix/common/statement.py index 48612945..a7284758 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -99,6 +99,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + def to_obj(self, return_obj=None, ns_info=None): super(Statement, self).to_obj(return_obj=return_obj, ns_info=ns_info) diff --git a/stix/common/tools.py b/stix/common/tools.py index e947b685..9515306b 100644 --- a/stix/common/tools.py +++ b/stix/common/tools.py @@ -81,6 +81,14 @@ def short_descriptions(self): def short_descriptions(self, value): self._short_description = StructuredTextList(value) + def add_short_description(self, description): + """Adds a description to the ``short_descriptions`` collection. + + This is the same as calling "foo.short_descriptions.add(bar)". + + """ + self.short_descriptions.add(description) + def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index 0691dd83..76a441c8 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -75,6 +75,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def short_description(self): """A single short description about the contents or purpose of this @@ -125,6 +133,14 @@ def short_descriptions(self): def short_descriptions(self, value): self._short_description = StructuredTextList(value) + def add_short_description(self, description): + """Adds a description to the ``short_descriptions`` collection. + + This is the same as calling "foo.short_descriptions.add(bar)". + + """ + self.short_descriptions.add(description) + @property def handling(self): return self._handling diff --git a/stix/exploit_target/configuration.py b/stix/exploit_target/configuration.py index fa69674b..04400807 100644 --- a/stix/exploit_target/configuration.py +++ b/stix/exploit_target/configuration.py @@ -75,6 +75,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def short_description(self): """A single short description about the contents or purpose of this @@ -125,6 +133,14 @@ def short_descriptions(self): def short_descriptions(self, value): self._short_description = StructuredTextList(value) + def add_short_description(self, description): + """Adds a description to the ``short_descriptions`` collection. + + This is the same as calling "foo.short_descriptions.add(bar)". + + """ + self.short_descriptions.add(description) + @property def cce_id(self): """Common Configuration Enumeration value for this :class:`Configuration`. diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index f7ec70b4..c316e567 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -101,6 +101,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def short_description(self): """A single short description about the contents or purpose of this @@ -151,6 +159,14 @@ def short_descriptions(self): def short_descriptions(self, value): self._short_description = StructuredTextList(value) + def add_short_description(self, description): + """Adds a description to the ``short_descriptions`` collection. + + This is the same as calling "foo.short_descriptions.add(bar)". + + """ + self.short_descriptions.add(description) + @property def discovered_datetime(self): """ diff --git a/stix/exploit_target/weakness.py b/stix/exploit_target/weakness.py index 370a0073..287ba97e 100644 --- a/stix/exploit_target/weakness.py +++ b/stix/exploit_target/weakness.py @@ -85,6 +85,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + def to_obj(self, return_obj=None, ns_info=None): super(Weakness, self).to_obj(return_obj=return_obj, ns_info=ns_info) diff --git a/stix/extensions/structured_coa/generic_structured_coa.py b/stix/extensions/structured_coa/generic_structured_coa.py index 6b736ba7..39902a77 100644 --- a/stix/extensions/structured_coa/generic_structured_coa.py +++ b/stix/extensions/structured_coa/generic_structured_coa.py @@ -78,6 +78,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def type_(self): return self._type diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index 2df85cca..f4e158a3 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -82,7 +82,15 @@ def descriptions(self): @descriptions.setter def descriptions(self, value): self._description = StructuredTextList(value) - + + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def type_(self): return self._type diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index 009a094d..d09f7f88 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -89,6 +89,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def business_function_or_role(self): return next(iter(self.business_functions_or_roles), None) diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index 156e7dd6..56dbd227 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -83,6 +83,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def source(self): return self._source diff --git a/stix/report/header.py b/stix/report/header.py index dff0d416..b7bc5347 100644 --- a/stix/report/header.py +++ b/stix/report/header.py @@ -73,6 +73,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def short_description(self): """A single short description about the contents or purpose of this @@ -123,6 +131,14 @@ def short_descriptions(self): def short_descriptions(self, value): self._short_description = StructuredTextList(value) + def add_short_description(self, description): + """Adds a description to the ``short_descriptions`` collection. + + This is the same as calling "foo.short_descriptions.add(bar)". + + """ + self.short_descriptions.add(description) + @property def handling(self): return self._handling diff --git a/stix/test/campaign_test.py b/stix/test/campaign_test.py index 19f8a019..4b8b26cc 100644 --- a/stix/test/campaign_test.py +++ b/stix/test/campaign_test.py @@ -129,6 +129,30 @@ class CampaignTest(EntityTestCase, unittest.TestCase): 'related_packages': related_test.RelatedPackageRefsTests._full_dict } + def test_add_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_description("Test") + o2.descriptions.add("Test") + + self.assertEqual( + o1.descriptions.to_dict(), + o2.descriptions.to_dict() + ) + + def test_add_short_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_short_description("Test") + o2.short_descriptions.add("Test") + + self.assertEqual( + o1.short_descriptions.to_dict(), + o2.short_descriptions.to_dict() + ) + if __name__ == "__main__": unittest.main() diff --git a/stix/test/coa_test.py b/stix/test/coa_test.py index 2a75b23c..02f1ee53 100644 --- a/stix/test/coa_test.py +++ b/stix/test/coa_test.py @@ -69,6 +69,29 @@ class COATests(EntityTestCase, unittest.TestCase): 'structured_coa': generic_test.GenericStructuredCOATests._full_dict } + def test_add_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_description("Test") + o2.descriptions.add("Test") + + self.assertEqual( + o1.descriptions.to_dict(), + o2.descriptions.to_dict() + ) + + def test_add_short_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_short_description("Test") + o2.short_descriptions.add("Test") + + self.assertEqual( + o1.short_descriptions.to_dict(), + o2.short_descriptions.to_dict() + ) def test_structured_coa(self): coa_ = coa.CourseOfAction() diff --git a/stix/test/common/structured_text_tests.py b/stix/test/common/structured_text_tests.py index 2c23b5d0..4a1269e8 100644 --- a/stix/test/common/structured_text_tests.py +++ b/stix/test/common/structured_text_tests.py @@ -163,6 +163,8 @@ def test_update(self): self.assertTrue(st1 not in slist) self.assertTrue(st2 not in slist) + def test_add_short_description(self): + pass if __name__ == "__main__": unittest.main() diff --git a/stix/test/exploit_target_test.py b/stix/test/exploit_target_test.py index 2965fd17..b58b5255 100644 --- a/stix/test/exploit_target_test.py +++ b/stix/test/exploit_target_test.py @@ -143,5 +143,29 @@ class ExploitTargetTests(EntityTestCase, unittest.TestCase): 'related_packages': related_test.RelatedPackageRefsTests._full_dict } + def test_add_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_description("Test") + o2.descriptions.add("Test") + + self.assertEqual( + o1.descriptions.to_dict(), + o2.descriptions.to_dict() + ) + + def test_add_short_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_short_description("Test") + o2.short_descriptions.add("Test") + + self.assertEqual( + o1.short_descriptions.to_dict(), + o2.short_descriptions.to_dict() + ) + if __name__ == "__main__": unittest.main() diff --git a/stix/test/incident_test.py b/stix/test/incident_test.py index 90bdd57d..320458c1 100644 --- a/stix/test/incident_test.py +++ b/stix/test/incident_test.py @@ -535,6 +535,29 @@ def test_add_related_indicator(self): "THIS SHOULD FAIL" ) + def test_add_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_description("Test") + o2.descriptions.add("Test") + + self.assertEqual( + o1.descriptions.to_dict(), + o2.descriptions.to_dict() + ) + + def test_add_short_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_short_description("Test") + o2.short_descriptions.add("Test") + + self.assertEqual( + o1.short_descriptions.to_dict(), + o2.short_descriptions.to_dict() + ) if __name__ == "__main__": diff --git a/stix/test/indicator_test.py b/stix/test/indicator_test.py index c8dc3e55..38b6f785 100644 --- a/stix/test/indicator_test.py +++ b/stix/test/indicator_test.py @@ -409,5 +409,30 @@ def test_related_packages(self): self._test_partial_dict(d) + def test_add_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_description("Test") + o2.descriptions.add("Test") + + self.assertEqual( + o1.descriptions.to_dict(), + o2.descriptions.to_dict() + ) + + def test_add_short_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_short_description("Test") + o2.short_descriptions.add("Test") + + self.assertEqual( + o1.short_descriptions.to_dict(), + o2.short_descriptions.to_dict() + ) + + if __name__ == "__main__": unittest.main() diff --git a/stix/test/threat_actor_test.py b/stix/test/threat_actor_test.py index c61d26e9..29fc7ed1 100644 --- a/stix/test/threat_actor_test.py +++ b/stix/test/threat_actor_test.py @@ -133,6 +133,29 @@ class ThreatActorTests(EntityTestCase, unittest.TestCase): 'related_packages': related_test.RelatedPackageRefsTests._full_dict } + def test_add_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_description("Test") + o2.descriptions.add("Test") + + self.assertEqual( + o1.descriptions.to_dict(), + o2.descriptions.to_dict() + ) + + def test_add_short_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_short_description("Test") + o2.short_descriptions.add("Test") + + self.assertEqual( + o1.short_descriptions.to_dict(), + o2.short_descriptions.to_dict() + ) if __name__ == "__main__": unittest.main() diff --git a/stix/test/ttp_test.py b/stix/test/ttp_test.py index 73808775..0559d0be 100644 --- a/stix/test/ttp_test.py +++ b/stix/test/ttp_test.py @@ -149,5 +149,29 @@ class TTPTests(EntityTestCase, unittest.TestCase): 'behavior': BehaviorTests._full_dict } + def test_add_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_description("Test") + o2.descriptions.add("Test") + + self.assertEqual( + o1.descriptions.to_dict(), + o2.descriptions.to_dict() + ) + + def test_add_short_description(self): + o1 = self.klass() + o2 = self.klass() + + o1.add_short_description("Test") + o2.short_descriptions.add("Test") + + self.assertEqual( + o1.short_descriptions.to_dict(), + o2.short_descriptions.to_dict() + ) + if __name__ == "__main__": unittest.main() diff --git a/stix/ttp/attack_pattern.py b/stix/ttp/attack_pattern.py index 819c07c8..2b2dbaf6 100644 --- a/stix/ttp/attack_pattern.py +++ b/stix/ttp/attack_pattern.py @@ -77,6 +77,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def short_description(self): """A single short description about the contents or purpose of this @@ -127,6 +135,14 @@ def short_descriptions(self): def short_descriptions(self, value): self._short_description = StructuredTextList(value) + def add_short_description(self, description): + """Adds a description to the ``short_descriptions`` collection. + + This is the same as calling "foo.short_descriptions.add(bar)". + + """ + self.short_descriptions.add(description) + def to_obj(self, return_obj=None, ns_info=None): super(AttackPattern, self).to_obj(return_obj=return_obj, ns_info=ns_info) diff --git a/stix/ttp/exploit.py b/stix/ttp/exploit.py index 9cfa3a04..664b6eaf 100644 --- a/stix/ttp/exploit.py +++ b/stix/ttp/exploit.py @@ -77,6 +77,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def short_description(self): """A single short description about the contents or purpose of this @@ -127,6 +135,14 @@ def short_descriptions(self): def short_descriptions(self, value): self._short_description = StructuredTextList(value) + def add_short_description(self, description): + """Adds a description to the ``short_descriptions`` collection. + + This is the same as calling "foo.short_descriptions.add(bar)". + + """ + self.short_descriptions.add(description) + def to_obj(self, return_obj=None, ns_info=None): super(Exploit, self).to_obj(return_obj=return_obj, ns_info=ns_info) diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index c3ef6781..355e6cf1 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -83,6 +83,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def short_description(self): """A single short description about the contents or purpose of this @@ -133,6 +141,14 @@ def short_descriptions(self): def short_descriptions(self, value): self._short_description = StructuredTextList(value) + def add_short_description(self, description): + """Adds a description to the ``short_descriptions`` collection. + + This is the same as calling "foo.short_descriptions.add(bar)". + + """ + self.short_descriptions.add(description) + @property def types(self): return self._types diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index e06b33f0..2a1dbd4b 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -79,6 +79,14 @@ def descriptions(self): def descriptions(self, value): self._description = StructuredTextList(value) + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + @property def short_description(self): """"A single short description about the contents or purpose of this @@ -129,6 +137,14 @@ def short_descriptions(self): def short_descriptions(self, value): self._short_description = StructuredTextList(value) + def add_short_description(self, description): + """Adds a description to the ``short_descriptions`` collection. + + This is the same as calling "foo.short_descriptions.add(bar)". + + """ + self.short_descriptions.add(description) + @property def names(self): return self._names From 1e07094f75563acc1880435b16e08cf84cdb0d66 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 11:29:03 -0400 Subject: [PATCH 037/438] Fixed issue with multiple descriptions and business_function_or_role values on AffectedAsset --- stix/bindings/incident.py | 32 ++++++++++++++++++++++---------- stix/incident/affected_asset.py | 6 +++--- stix/test/incident_test.py | 2 ++ 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/stix/bindings/incident.py b/stix/bindings/incident.py index 36cc9030..591f370f 100644 --- a/stix/bindings/incident.py +++ b/stix/bindings/incident.py @@ -130,8 +130,16 @@ class AffectedAssetType(GeneratedsSuper): superclass = None def __init__(self, Type=None, Description=None, Business_Function_Or_Role=None, Ownership_Class=None, Management_Class=None, Location_Class=None, Location=None, Nature_Of_Security_Effect=None, Structured_Description=None): self.Type = Type - self.Description = Description - self.Business_Function_Or_Role = Business_Function_Or_Role + if Description is None: + self.Description = [] + else: + self.Description = Description + + if Business_Function_Or_Role is None: + self.Business_Function_Or_Role = [] + else: + self.Business_Function_Or_Role = Business_Function_Or_Role + self.Ownership_Class = Ownership_Class self.Management_Class = Management_Class self.Location_Class = Location_Class @@ -146,8 +154,12 @@ def factory(*args_, **kwargs_): factory = staticmethod(factory) def get_Type(self): return self.Type def set_Type(self, Type): self.Type = Type + def insert_Description(self, index, value): self.Description[index] = value + def add_Description(self, Description): self.Description.append(Description) def get_Description(self): return self.Description def set_Description(self, Description): self.Description = Description + def insert_Business_Function_Or_Role(self, index, value): self.Business_Function_Or_Role[index] = value + def add_Business_Function_Or_Role(self, Business_Function_Or_Role): self.Business_Function_Or_Role.append(Business_Function_Or_Role) def get_Business_Function_Or_Role(self): return self.Business_Function_Or_Role def set_Business_Function_Or_Role(self, Business_Function_Or_Role): self.Business_Function_Or_Role = Business_Function_Or_Role def get_Ownership_Class(self): return self.Ownership_Class @@ -165,8 +177,8 @@ def set_Structured_Description(self, Structured_Description): self.Structured_De def hasContent_(self): if ( self.Type is not None or - self.Description is not None or - self.Business_Function_Or_Role is not None or + self.Description or + self.Business_Function_Or_Role or self.Ownership_Class is not None or self.Management_Class is not None or self.Location_Class is not None or @@ -202,10 +214,10 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Affecte eol_ = '' if self.Type is not None: self.Type.export(lwrite, level, nsmap, namespace_, name_='Type', pretty_print=pretty_print) - if self.Description is not None: - self.Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) - if self.Business_Function_Or_Role is not None: - self.Business_Function_Or_Role.export(lwrite, level, nsmap, namespace_, name_='Business_Function_Or_Role', pretty_print=pretty_print) + for Description in self.Description: + Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) + for Business_Function_Or_Role in self.Business_Function_Or_Role: + Business_Function_Or_Role.export(lwrite, level, nsmap, namespace_, name_='Business_Function_Or_Role', pretty_print=pretty_print) if self.Ownership_Class is not None: self.Ownership_Class.export(lwrite, level, nsmap, namespace_, name_='Ownership_Class', pretty_print=pretty_print) if self.Management_Class is not None: @@ -234,11 +246,11 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): elif nodeName_ == 'Description': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Description(obj_) + self.add_Description(obj_) elif nodeName_ == 'Business_Function_Or_Role': obj_ = stix_common_binding.StructuredTextType.factory() obj_.build(child_) - self.set_Business_Function_Or_Role(obj_) + self.add_Business_Function_Or_Role(obj_) elif nodeName_ == 'Ownership_Class': obj_ = stix_common_binding.ControlledVocabularyStringType.factory() obj_.build(child_) diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index d09f7f88..858512c3 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -185,8 +185,8 @@ def to_obj(self, return_obj=None, ns_info=None): if self.type_: return_obj.Type = self.type_.to_obj(ns_info=ns_info) - if self.description: - return_obj.Description = self.description.to_obj(ns_info=ns_info) + if self.descriptions: + return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) if self.business_functions_or_roles: return_obj.Business_Function_Or_Role = self.business_functions_or_roles.to_obj(ns_info=ns_info) if self.ownership_class: @@ -215,7 +215,7 @@ def from_dict(cls, d, return_obj=None): get = d.get return_obj.type_ = AssetType.from_dict(get('type')) - return_obj.description = StructuredTextList.from_dict(get('description')) + return_obj.descriptions = StructuredTextList.from_dict(get('description')) return_obj.business_functions_or_roles = StructuredTextList.from_dict(get('business_function_or_role')) return_obj.ownership_class = VocabString.from_dict(get('ownership_class')) return_obj.management_class = VocabString.from_dict(get('management_class')) diff --git a/stix/test/incident_test.py b/stix/test/incident_test.py index 320458c1..09e8fa09 100644 --- a/stix/test/incident_test.py +++ b/stix/test/incident_test.py @@ -360,6 +360,8 @@ class AffectedAssetTest(EntityTestCase, unittest.TestCase): _full_dict = { 'type': AssetTypeTest._full_dict, + 'description': 'Foo', + 'business_function_or_role': 'Bar', 'nature_of_security_effect': NatureOfSecurityEffectTest._full_dict, 'ownership_class': { 'value': 'Unknown', From ac262535e812242543e6e86bc687a8d66f3915e4 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 14:16:08 -0400 Subject: [PATCH 038/438] Refactored xsi:type resolution and registration code for stix.Entity classes. * There is one _EXTENSION_MAP for all of python-stix now, whereas there were several previously. * All class resolution code is performed using stix.lookup_extension * Added register_extension() class decorator. * Removed all the add_extension() calls at the bottom of extension modules (using class decorator now). --- stix/__init__.py | 104 +++++++++++++++++- .../extensions/identity/ciq_identity_3_0.py | 2 +- stix/coa/structured_coa.py | 20 +--- stix/common/identity.py | 17 +-- stix/common/vocabs.py | 17 +-- stix/data_marking.py | 18 +-- stix/extensions/identity/ciq_identity_3_0.py | 5 +- stix/extensions/malware/maec_4_1_malware.py | 1 + stix/extensions/marking/simple_marking.py | 8 +- .../marking/terms_of_use_marking.py | 9 +- stix/extensions/marking/tlp.py | 8 +- .../structured_coa/generic_structured_coa.py | 6 +- .../test_mechanism/generic_test_mechanism.py | 4 +- .../open_ioc_2010_test_mechanism.py | 4 +- .../test_mechanism/snort_test_mechanism.py | 3 +- .../test_mechanism/yara_test_mechanism.py | 4 +- stix/incident/affected_asset.py | 1 - stix/indicator/test_mechanism.py | 33 ++---- stix/ttp/malware_instance.py | 21 +--- 19 files changed, 159 insertions(+), 126 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index a6c9e679..c1b7637e 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -7,10 +7,112 @@ BaseCoreComponent ) -from . import common # noqa +#: Mapping of xsi:types to implementation/extension classes +_EXTENSION_MAP = {} + + +def _lookup_unprefixed_extension(typename): + """Attempts to resolve a class for the input XML type `typename`. + + Args: + typename: The name of an STIX XML type (e.g., TLPMarkingStructureType) + without a namespace prefix. + + Returns: + A stix.Entity implementation class for the `typename`. + + + Raises: + ValueError: If no class has been registered for the input `typename`. + + """ + for xsi_type, klass in _EXTENSION_MAP.iteritems(): + if typename in xsi_type: + return klass + + error = "Unregistered extension for unprefixed type: %s" % typename + raise ValueError(error) + + +def _lookup_extension(xsi_type): + """Returns a Python class for the `xsi_type` value. + + Args: + xsi_type: An xsi:type value string. + + Returns: + A stix.Entity implementation class for the `xsi_type`. + + Raises: + ValueError: If no class has been registered for the `xsi_type`. + + """ + if xsi_type in _EXTENSION_MAP: + return _EXTENSION_MAP[xsi_type] + + raise ValueError("Unregistered xsi:type %s" % xsi_type) + + +def lookup_extension(typeinfo): + """Returns a stix.Entity class for that has been registered for the + `typeinfo` value. + + Args: + typeinfo: An object or string containing type information. This can be + either an xsi:type attribute value or a stix.bindings object. + + Returns: + A stix.Entity implementation class for the `xsi_type`. + + Raises: + ValueError: If no class has been registered for the `xsi_type`. + + """ + # If the `typeinfo` was a string, consider it a full xsi:type value. + if isinstance(typeinfo, basestring): + return _lookup_extension(typeinfo) + + # If we didn't pass in string xsi:type, try to look it up by class attr. + # Binding classes have an `xml_type` class attribute. + if not hasattr(typeinfo, 'xml_type'): + error = "Input %s is missing xml_type attribute. Cannot lookup class." + raise ValueError(error) + + # Binding classes usually (always?) have an `xmlns_prefix` class attribute + if hasattr(typeinfo, 'xmlns_prefix'): + xsi_type = "%s:%s" % (typeinfo.xmlns_prefix, typeinfo.xml_type) + return _lookup_extension(xsi_type) + + # no xmlns_prefix found, try to resolve the class by just the `xml_type` + return _lookup_unprefixed_extension(typeinfo.xml_type) + + +def add_extension(cls): + """Registers a stix.Entity class as an implementation of an xml type. + + Classes must have an ``_XSI_TYPE`` class attributes to be registered. The + value of this attribute must be a valid xsi:type. + + """ + _EXTENSION_MAP[cls._XSI_TYPE] = cls # noqa + + +def register_extension(cls): + """Class decorator for registering a stix.Entity class as an implementation + of an xml type. + + Classes must have an ``_XSI_TYPE`` class attributes to be registered. + + """ + add_extension(cls) + return cls + + +from . import common # noqa from .version import __version__ # noqa + def supported_stix_version(): return '.'.join(__version__.split('.')[:3]) diff --git a/stix/bindings/extensions/identity/ciq_identity_3_0.py b/stix/bindings/extensions/identity/ciq_identity_3_0.py index d875b191..a6a1fca5 100644 --- a/stix/bindings/extensions/identity/ciq_identity_3_0.py +++ b/stix/bindings/extensions/identity/ciq_identity_3_0.py @@ -28,7 +28,7 @@ class CIQIdentity3_0InstanceType(stix_common_binding.IdentityType): superclass = stix_common_binding.IdentityType xmlns = XML_NS - xmlns_prefix = "stix-ciqidentity" + xmlns_prefix = "ciqIdentity" xml_type = "CIQIdentity3.0InstanceType" def __init__(self, idref=None, id=None, Name=None, Related_Identities=None, Specification=None, Role=None): diff --git a/stix/coa/structured_coa.py b/stix/coa/structured_coa.py index 1b62138d..b059547f 100644 --- a/stix/coa/structured_coa.py +++ b/stix/coa/structured_coa.py @@ -19,10 +19,11 @@ def from_obj(cls, obj, return_obj=None): if not obj: return None - from stix.extensions.structured_coa.generic_structured_coa import GenericStructuredCOA # noqa + # Registers the class extension + import stix.extensions.structured_coa.generic_structured_coa # noqa if not return_obj: - klass = _BaseStructuredCOA.lookup_class(obj.xml_type) + klass = _BaseStructuredCOA.lookup_class(obj) return_obj = klass.from_obj(obj) else: return_obj.id_ = obj.id @@ -49,13 +50,8 @@ def to_obj(self, return_obj=None, ns_info=None): def lookup_class(xsi_type): if not xsi_type: raise ValueError("xsi:type is required") - for (k, v) in _EXTENSION_MAP.iteritems(): - # TODO: for now we ignore the prefix and just check for - # a partial match - if xsi_type in k: - return v - raise ValueError("Unregistered xsi:type %s" % xsi_type) + return stix.lookup_extension(xsi_type) @classmethod def from_dict(cls, d, return_obj=None): @@ -79,9 +75,5 @@ def to_dict(self): return d -#: Mapping of structured coa extension types to classes -_EXTENSION_MAP = {} - - -def add_extension(cls): - _EXTENSION_MAP[cls._XSI_TYPE] = cls # noqa +# Backwards compatibility +add_extension = stix.add_extension diff --git a/stix/common/identity.py b/stix/common/identity.py index dad8227b..f2d72f72 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -79,13 +79,7 @@ def lookup_class(xsi_type): if not xsi_type: raise ValueError("xsi:type is required") - for (k, v) in _EXTENSION_MAP.iteritems(): - # TODO: for now we ignore the prefix and just check for - # a partial match - if xsi_type in k: - return v - - raise ValueError("Unregistered xsi:type %s" % xsi_type) + return stix.lookup_extension(xsi_type) @classmethod def from_obj(cls, obj, return_obj=None): @@ -96,7 +90,7 @@ def from_obj(cls, obj, return_obj=None): if not return_obj: if hasattr(obj, 'xml_type'): - klass = Identity.lookup_class(obj.xml_type) + klass = Identity.lookup_class(obj) return_obj = klass.from_obj(obj) else: return_obj = Identity.from_obj(obj, cls()) @@ -151,9 +145,6 @@ class RelatedIdentities(stix.EntityList): _inner_name = "identities" -#: Mapping of identity extension types to classes -_EXTENSION_MAP = {} - -def add_extension(cls): - _EXTENSION_MAP[cls._XSI_TYPE] = cls # noqa +# Backwards compatibility +add_extension = stix.add_extension diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index facef86e..83ff0921 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -65,14 +65,11 @@ def is_plain(self): def lookup_class(xsi_type): if not xsi_type: return VocabString - - for (k, v) in _VOCAB_MAP.iteritems(): - # TODO: for now we ignore the prefix and just check for - # a partial match - if xsi_type in k: - return v - return VocabString + try: + return stix.lookup_extension(xsi_type) + except ValueError: + return VocabString def to_obj(self, return_obj=None, ns_info=None): super(VocabString, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -154,10 +151,6 @@ def from_dict(cls, vocab_dict, return_obj=None): return return_obj -#: Mapping of Controlled Vocabulary xsi:type's to their class implementations. -_VOCAB_MAP = {} - - def _get_terms(vocab_class): """Helper function used by register_vocab.""" for k, v in vocab_class.__dict__.items(): @@ -172,7 +165,7 @@ def add_vocab(cls): The :meth:`register_vocab` class decorator has replaced this method. """ - _VOCAB_MAP[cls._XSI_TYPE] = cls + stix.add_extension(cls) def register_vocab(cls): diff --git a/stix/data_marking.py b/stix/data_marking.py index 805f6ad5..5f8d9747 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -209,13 +209,7 @@ def lookup_class(xsi_type): if not xsi_type: return MarkingStructure - for (k, v) in _EXTENSION_MAP.iteritems(): - # TODO: for now we ignore the prefix and just check for - # a partial match - if xsi_type in k: - return v - - raise ValueError("Unregistered xsi:type %s" % xsi_type) + return stix.lookup_extension(xsi_type) @classmethod def from_obj(cls, obj, return_obj=None): @@ -235,7 +229,7 @@ def from_obj(cls, obj, return_obj=None): else: if hasattr(obj, 'xml_type'): - klass = MarkingStructure.lookup_class(obj.xml_type) + klass = MarkingStructure.lookup_class(obj) m = klass.from_obj(obj) else: m = cls.from_obj(obj, cls()) @@ -276,9 +270,5 @@ class _MarkingStructures(stix.TypedList): _contained_type = MarkingStructure -#: Mapping of marking extension types to classes -_EXTENSION_MAP = {} - - -def add_extension(cls): - _EXTENSION_MAP[cls._XSI_TYPE] = cls # noqa +# Backwards compatibility +add_extension = stix.add_extension diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index 8e0b7cf6..75e45af8 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -21,6 +21,7 @@ et.register_namespace('ExtSch', XML_NS_STIX_EXT) +@stix.register_extension class CIQIdentity3_0Instance(common.Identity): _binding = ciq_identity_binding _binding_class = _binding.CIQIdentity3_0InstanceType @@ -1835,7 +1836,3 @@ def from_dict(cls, d, return_obj=None): return_obj.type_ = d.get('type') return_obj.value = d.get('value') return return_obj - - -# Register the extension -identity.add_extension(CIQIdentity3_0Instance) diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index 8c5e45be..e35edc05 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -82,6 +82,7 @@ def is_maec(obj): return isinstance(obj, maecPackage) +@stix.register_extension class MAECInstance(MalwareInstance): _binding = ext_binding _binding_class = _binding.MAEC4_1InstanceType diff --git a/stix/extensions/marking/simple_marking.py b/stix/extensions/marking/simple_marking.py index 9e072f02..b3fafbba 100644 --- a/stix/extensions/marking/simple_marking.py +++ b/stix/extensions/marking/simple_marking.py @@ -1,11 +1,12 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -import stix.bindings.extensions.marking.simple_marking as simple_marking_binding -import stix.data_marking +import stix from stix.data_marking import MarkingStructure +import stix.bindings.extensions.marking.simple_marking as simple_marking_binding +@stix.register_extension class SimpleMarkingStructure(MarkingStructure): _binding = simple_marking_binding _binding_class = simple_marking_binding.SimpleMarkingStructureType @@ -60,6 +61,3 @@ def from_dict(cls, d, return_obj=None): return return_obj - -# Register extension -stix.data_marking.add_extension(SimpleMarkingStructure) diff --git a/stix/extensions/marking/terms_of_use_marking.py b/stix/extensions/marking/terms_of_use_marking.py index 72eadd17..37b25cb5 100644 --- a/stix/extensions/marking/terms_of_use_marking.py +++ b/stix/extensions/marking/terms_of_use_marking.py @@ -1,11 +1,12 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -import stix.bindings.extensions.marking.terms_of_use_marking as tou_marking_binding -import stix.data_marking +import stix from stix.data_marking import MarkingStructure +import stix.bindings.extensions.marking.terms_of_use_marking as tou_marking_binding +@stix.register_extension class TermsOfUseMarkingStructure(MarkingStructure): _binding = tou_marking_binding _binding_class = tou_marking_binding.TermsOfUseMarkingStructureType @@ -60,7 +61,3 @@ def from_dict(cls, d, return_obj=None): return_obj.terms_of_use = d.get('terms_of_use') return return_obj - - -# Register extension -stix.data_marking.add_extension(TermsOfUseMarkingStructure) diff --git a/stix/extensions/marking/tlp.py b/stix/extensions/marking/tlp.py index 9476d87a..a9870c42 100644 --- a/stix/extensions/marking/tlp.py +++ b/stix/extensions/marking/tlp.py @@ -1,11 +1,12 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -import stix.bindings.extensions.marking.tlp as tlp_binding -import stix.data_marking +import stix from stix.data_marking import MarkingStructure +import stix.bindings.extensions.marking.tlp as tlp_binding +@stix.register_extension class TLPMarkingStructure(MarkingStructure): _binding = tlp_binding _binding_class = tlp_binding.TLPMarkingStructureType @@ -60,6 +61,3 @@ def from_dict(cls, d, return_obj=None): return return_obj - -# Register extension -stix.data_marking.add_extension(TLPMarkingStructure) diff --git a/stix/extensions/structured_coa/generic_structured_coa.py b/stix/extensions/structured_coa/generic_structured_coa.py index 39902a77..b9350a09 100644 --- a/stix/extensions/structured_coa/generic_structured_coa.py +++ b/stix/extensions/structured_coa/generic_structured_coa.py @@ -2,13 +2,12 @@ # See LICENSE.txt for complete terms. import stix -import stix.utils as utils -import stix.coa.structured_coa from stix.common import EncodedCDATA, StructuredTextList, VocabString from stix.coa.structured_coa import _BaseStructuredCOA import stix.bindings.extensions.structured_coa.generic as generic_structured_coa_binding +@stix.register_extension class GenericStructuredCOA(_BaseStructuredCOA): _namespace = "http://stix.mitre.org/extensions/StructuredCOA#Generic-1" _binding = generic_structured_coa_binding @@ -144,6 +143,3 @@ def from_dict(cls, d, return_obj=None): def to_dict(self): return super(GenericStructuredCOA, self).to_dict() - -# Register the extension -stix.coa.structured_coa.add_extension(GenericStructuredCOA) diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index f4e158a3..13082be9 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -9,6 +9,7 @@ import stix.bindings.extensions.test_mechanism.generic as generic_tm_binding +@stix.register_extension class GenericTestMechanism(_BaseTestMechanism): _namespace = "http://stix.mitre.org/extensions/TestMechanism#Generic-1" _binding = generic_tm_binding @@ -152,6 +153,3 @@ def from_dict(cls, d, return_obj=None): def to_dict(self): return super(GenericTestMechanism, self).to_dict() - - -stix.indicator.test_mechanism.add_extension(GenericTestMechanism) diff --git a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py index 44a7f37b..7a3d8362 100644 --- a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py +++ b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py @@ -15,6 +15,7 @@ import stix.bindings.extensions.test_mechanism.open_ioc_2010 as open_ioc_tm_binding +@stix.register_extension class OpenIOCTestMechanism(_BaseTestMechanism): _namespace = "http://stix.mitre.org/extensions/TestMechanism#OpenIOC2010-1" _binding = open_ioc_tm_binding @@ -111,5 +112,4 @@ def to_dict(self): d['ioc'] = etree.tostring(self.ioc) return d - -stix.indicator.test_mechanism.add_extension(OpenIOCTestMechanism) + diff --git a/stix/extensions/test_mechanism/snort_test_mechanism.py b/stix/extensions/test_mechanism/snort_test_mechanism.py index 944ce88e..efd12c77 100644 --- a/stix/extensions/test_mechanism/snort_test_mechanism.py +++ b/stix/extensions/test_mechanism/snort_test_mechanism.py @@ -7,6 +7,7 @@ import stix.bindings.extensions.test_mechanism.snort as snort_tm_binding +@stix.register_extension class SnortTestMechanism(test_mechanism._BaseTestMechanism): _namespace = "http://stix.mitre.org/extensions/TestMechanism#Snort-1" _binding = snort_tm_binding @@ -131,5 +132,3 @@ class _EncodedCDATAs(stix.TypedList): _contained_type = EncodedCDATA -# Register this extension -test_mechanism.add_extension(SnortTestMechanism) diff --git a/stix/extensions/test_mechanism/yara_test_mechanism.py b/stix/extensions/test_mechanism/yara_test_mechanism.py index 79f5891e..dea407bb 100644 --- a/stix/extensions/test_mechanism/yara_test_mechanism.py +++ b/stix/extensions/test_mechanism/yara_test_mechanism.py @@ -9,6 +9,7 @@ import stix.bindings.extensions.test_mechanism.yara as yara_tm_binding +@stix.register_extension class YaraTestMechanism(_BaseTestMechanism): _namespace = "http://stix.mitre.org/extensions/TestMechanism#YARA-1" _binding = yara_tm_binding @@ -81,5 +82,4 @@ def to_dict(self): d['rule'] = self.rule.to_dict() return d - -stix.indicator.test_mechanism.add_extension(YaraTestMechanism) + diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index 858512c3..9fd39358 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -6,7 +6,6 @@ # internal import stix -import stix.utils as utils from stix.common import vocabs, VocabString, StructuredTextList import stix.bindings.incident as incident_binding diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index f339b21c..910d74d4 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -38,13 +38,13 @@ def from_obj(cls, obj, return_obj=None): if not obj: return None - from stix.extensions.test_mechanism.snort_test_mechanism import SnortTestMechanism # noqa - from stix.extensions.test_mechanism.open_ioc_2010_test_mechanism import OpenIOCTestMechanism # noqa - from stix.extensions.test_mechanism.yara_test_mechanism import YaraTestMechanism # noqa - from stix.extensions.test_mechanism.generic_test_mechanism import GenericTestMechanism # noqa + import stix.extensions.test_mechanism.snort_test_mechanism # noqa + import stix.extensions.test_mechanism.open_ioc_2010_test_mechanism # noqa + import stix.extensions.test_mechanism.yara_test_mechanism # noqa + import stix.extensions.test_mechanism.generic_test_mechanism # noqa if not return_obj: - klass = _BaseTestMechanism.lookup_class(obj.xml_type) + klass = _BaseTestMechanism.lookup_class(obj) return_obj = klass.from_obj(obj) else: return_obj.id_ = obj.id @@ -75,23 +75,18 @@ def to_obj(self, return_obj=None, ns_info=None): def lookup_class(xsi_type): if not xsi_type: raise ValueError("xsi:type is required") - for (k, v) in _EXTENSION_MAP.iteritems(): - # TODO: for now we ignore the prefix and just check for - # a partial match - if xsi_type in k: - return v - raise ValueError("Unregistered xsi:type %s" % xsi_type) + return stix.lookup_extension(xsi_type) @classmethod def from_dict(cls, d, return_obj=None): if not d: return None - from stix.extensions.test_mechanism.snort_test_mechanism import SnortTestMechanism # noqa - from stix.extensions.test_mechanism.open_ioc_2010_test_mechanism import OpenIOCTestMechanism # noqa - from stix.extensions.test_mechanism.yara_test_mechanism import YaraTestMechanism # noqa - from stix.extensions.test_mechanism.generic_test_mechanism import GenericTestMechanism # noqa + import stix.extensions.test_mechanism.snort_test_mechanism # noqa + import stix.extensions.test_mechanism.open_ioc_2010_test_mechanism # noqa + import stix.extensions.test_mechanism.yara_test_mechanism # noqa + import stix.extensions.test_mechanism.generic_test_mechanism # noqa if not return_obj: klass = _BaseTestMechanism.lookup_class(d.get('xsi:type')) @@ -120,9 +115,5 @@ class TestMechanisms(stix.EntityList): _dict_as_list = True -#: Mapping of test mechanism extension types to classes -_EXTENSION_MAP = {} - - -def add_extension(cls): - _EXTENSION_MAP[cls._XSI_TYPE] = cls # noqa +# Backwards compatibility +add_extension = stix.add_extension diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index 2a1dbd4b..9854e4ee 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -171,13 +171,8 @@ def add_type(self, type_): def lookup_class(xsi_type): if not xsi_type: raise ValueError("xsi:type is required") - for (k, v) in _EXTENSION_MAP.iteritems(): - # TODO: for now we ignore the prefix and just check for - # a partial match - if xsi_type in k: - return v - raise ValueError("Unregistered xsi:type %s" % xsi_type) + return stix.lookup_extension(xsi_type) def to_obj(self, return_obj=None, ns_info=None): super(MalwareInstance, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -201,16 +196,16 @@ def to_obj(self, return_obj=None, ns_info=None): @classmethod def from_obj(cls, obj, return_obj=None): - from stix.extensions.malware import maec_4_1_malware # noqa + import stix.extensions.malware.maec_4_1_malware # noqa if not obj: return None if not return_obj: try: - klass = MalwareInstance.lookup_class(obj.xml_type) + klass = MalwareInstance.lookup_class(obj) return_obj = klass.from_obj(obj) - except AttributeError: + except (ValueError, AttributeError): return_obj = MalwareInstance.from_obj(obj, cls()) else: return_obj.id_ = obj.id @@ -268,9 +263,5 @@ def _fix_value(self, value): return vocabs.MalwareType(value) -#: Mapping of malware instance extension types to classes -_EXTENSION_MAP = {} - - -def add_extension(cls): - _EXTENSION_MAP[cls._XSI_TYPE] = cls # noqa +# Backwards compatibility +add_extension = stix.add_extension From 09f24690243aee8e4a16a3ee1795a18317911589 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 14:19:48 -0400 Subject: [PATCH 039/438] Renamed _lookup_unprefixed_extension to _lookup_unprefixed --- stix/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index c1b7637e..a4a3a71d 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -12,7 +12,7 @@ _EXTENSION_MAP = {} -def _lookup_unprefixed_extension(typename): +def _lookup_unprefixed(typename): """Attempts to resolve a class for the input XML type `typename`. Args: @@ -85,7 +85,7 @@ def lookup_extension(typeinfo): return _lookup_extension(xsi_type) # no xmlns_prefix found, try to resolve the class by just the `xml_type` - return _lookup_unprefixed_extension(typeinfo.xml_type) + return _lookup_unprefixed(typeinfo.xml_type) def add_extension(cls): From 93eecefb079b5e2ed23c8195b5d9bf103eb36396 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 14:57:32 -0400 Subject: [PATCH 040/438] Fixed issue where new StructuredText attributes were being serialized as tuples. --- stix/bindings/stix_common.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index 961860b4..97e0a7e9 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -3516,8 +3516,8 @@ def __init__(self, structuring_format=None, valueOf_=None, id=None, idref=None, ordinality=None): self.structuring_format = _cast(None, structuring_format) self.valueOf_ = valueOf_ - self.id = id, - self.idref = idref, + self.id = id + self.idref = idref self.ordinality = ordinality def factory(*args_, **kwargs_): @@ -3560,13 +3560,13 @@ def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='StructuredTextT def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCommon:', name_='StructuredTextType'): if self.structuring_format is not None and 'structuring_format' not in already_processed: already_processed.add('structuring_format') - lwrite(' structuring_format=%s' % (quote_attrib(self.structuring_format), )) + lwrite(' structuring_format=%s' % quote_attrib(self.structuring_format)) if self.id is not None and 'id' not in already_processed: already_processed.add('id') - lwrite(' id=%s' % (quote_attrib(self.id), )) + lwrite(' id=%s' % quote_attrib(self.id)) if self.ordinality is not None and 'ordinality' not in already_processed: already_processed.add('ordinality') - lwrite(' ordinality=%s' % (quote_attrib(self.ordinality), )) + lwrite(' ordinality=%s' % quote_attrib(self.ordinality)) def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='StructuredTextType', fromsubclass_=False, pretty_print=True): pass def build(self, node): From 667611a4f32654688aabc5a8d0c5c125b3423c93 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 14:57:57 -0400 Subject: [PATCH 041/438] More Report object work. * Added namespaces and schemalocations to nsparser dicts. * Fixed some binding issues. --- stix/bindings/report.py | 13 +++++++++---- stix/report/__init__.py | 4 ++-- stix/utils/nsparser.py | 2 ++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/stix/bindings/report.py b/stix/bindings/report.py index cb8ec207..6cc759d5 100644 --- a/stix/bindings/report.py +++ b/stix/bindings/report.py @@ -11,6 +11,7 @@ from stix.bindings import * from cybox.bindings import cybox_core import stix.bindings.stix_common as common_binding +import stix.bindings.data_marking as data_marking_binding XML_NS = "http://stix.mitre.org/Report-1" @@ -100,7 +101,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='HeaderT eol_ = '' if self.Title is not None: showIndent(lwrite, level, pretty_print) - lwrite('<%s:Title>%s%s' % (nsmap[namespace_], self.gds_format_string(quote_xml(self.Title).encode(ExternalEncoding), input_name='Title'), nsmap[namespace_], eol_)) + lwrite('<%s:Title>%s%s' % (nsmap[namespace_], quote_xml(self.Title), nsmap[namespace_], eol_)) for Intent_ in self.Intent: Intent_.export(lwrite, level, nsmap, namespace_, name_='Intent', pretty_print=pretty_print) for Description_ in self.Description: @@ -137,7 +138,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): obj_.build(child_) self.Short_Description.append(obj_) elif nodeName_ == 'Handling': - obj_ = common_binding.MarkingType.factory() + obj_ = data_marking_binding.MarkingType.factory() obj_.build(child_) self.set_Handling(obj_) elif nodeName_ == 'Information_Source': @@ -679,6 +680,10 @@ def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ReportType', na lwrite('/>%s' % (eol_, )) def exportAttributes(self, lwrite, level, already_processed, namespace_='report:', name_='ReportType'): super(ReportType, self).exportAttributes(lwrite, level, already_processed, namespace_, name_='ReportType') + if 'xsi:type' not in already_processed: + already_processed.add('xsi:type') + xsi_type = " xsi:type='%s:%s'" % (self.xmlns_prefix, self.xml_type) + lwrite(xsi_type) if self.version is not None and 'version' not in already_processed: already_processed.add('version') lwrite(' version=%s' % (quote_attrib(self.version), )) @@ -691,7 +696,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ReportT if self.Header is not None: self.Header.export(lwrite, level, nsmap, namespace_, name_='Header', pretty_print=pretty_print) if self.Observables is not None: - self.Observables.export(lwrite, level, nsmap, namespace_, name_='Observables', pretty_print=pretty_print) + self.Observables.export(lwrite, level, "%s:" % (nsmap[namespace_]), name_='Observables', pretty_print=pretty_print) # no nsmap parameter, so we use this hack to pass the right namespace prefix if self.Indicators is not None: self.Indicators.export(lwrite, level, nsmap, namespace_, name_='Indicators', pretty_print=pretty_print) if self.TTPs is not None: @@ -758,7 +763,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): obj_.build(child_) self.set_Threat_Actors(obj_) elif nodeName_ == 'Related_Reports': - obj_ = common_binding.RelatedReportsType.factory() + obj_ = RelatedReportsType.factory() obj_.build(child_) self.set_Related_Reports(obj_) super(ReportType, self).buildChildren(child_, node, nodeName_, True) diff --git a/stix/report/__init__.py b/stix/report/__init__.py index d8cc492c..83c753b2 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -265,7 +265,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.id_ = obj.id return_obj.idref = obj.idref return_obj.timestamp = obj.timestamp - return_obj.header = Header.from_obj(obj.STIX_Header) + return_obj.header = Header.from_obj(obj.Header) return_obj.campaigns = Campaigns.from_obj(obj.Campaigns) return_obj.courses_of_action = CoursesOfAction.from_obj(obj.Courses_Of_Action) return_obj.exploit_targets = ExploitTargets.from_obj(obj.Exploit_Targets) @@ -274,7 +274,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.incidents = Incidents.from_obj(obj.Incidents) return_obj.threat_actors = ThreatActors.from_obj(obj.Threat_Actors) return_obj.ttps = TTPs.from_obj(obj.TTPs) - return_obj.related_reports = RelatedReports.from_obj(obj.Related_Packages) + return_obj.related_reports = RelatedReports.from_obj(obj.Related_Reports) # Don't overwrite unless a version is passed in if obj.version: diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index eb4050ec..5eb8bdcd 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -410,6 +410,7 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): 'http://stix.mitre.org/ExploitTarget-1': 'http://stix.mitre.org/XMLSchema/exploit_target/1.1.1/exploit_target.xsd', 'http://stix.mitre.org/Incident-1': 'http://stix.mitre.org/XMLSchema/incident/1.1.1/incident.xsd', 'http://stix.mitre.org/Indicator-2': 'http://stix.mitre.org/XMLSchema/indicator/2.1.1/indicator.xsd', + 'http://stix.mitre.org/Report-1': 'http://stix.mitre.org/XMLSchema/report/1.0/report.xsd', 'http://stix.mitre.org/TTP-1': 'http://stix.mitre.org/XMLSchema/ttp/1.1.1/ttp.xsd', 'http://stix.mitre.org/ThreatActor-1': 'http://stix.mitre.org/XMLSchema/threat_actor/1.1.1/threat_actor.xsd', 'http://stix.mitre.org/common-1': 'http://stix.mitre.org/XMLSchema/common/1.1.1/stix_common.xsd', @@ -455,6 +456,7 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): 'http://stix.mitre.org/Indicator-2': 'indicator', 'http://stix.mitre.org/TTP-1': 'ttp', 'http://stix.mitre.org/ThreatActor-1': 'ta', + 'http://stix.mitre.org/Report-1': 'report', 'http://stix.mitre.org/stix-1': 'stix', 'http://stix.mitre.org/common-1': 'stixCommon', 'http://stix.mitre.org/default_vocabularies-1': 'stixVocabs', From 9bcb622fded02264697e6ccc10026e8234b184f0 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 15:45:15 -0400 Subject: [PATCH 042/438] Added Versioning vocabulary support --- stix/common/vocabs.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index 83ff0921..94ce5a56 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -828,3 +828,12 @@ class InformationSourceRole(VocabString): TERM_AGGREGATOR = "Aggregator" TERM_TRANSFORMERORTRANSLATOR = "Transformer/Translator" + +@register_vocab +class Versioning(VocabString): + _namespace = 'http://stix.mitre.org/default_vocabularies-1' + _XSI_TYPE = 'stixVocabs:VersioningVocab-1.0' + + TERM_UPDATES_REVISES = "Updates - Revises" + TERM_UPDATE_CORRECTS = "Updates - Corrects" + TERM_REVOKES = "Revokes" From 4f12868b3eecf5536846802f9c72512316fb4480 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 15:55:50 -0400 Subject: [PATCH 043/438] Updated schemalocations dictionary in nsparser to refer to planned 1.2 urls. --- stix/utils/nsparser.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index 5eb8bdcd..9da93f23 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -401,32 +401,32 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): #: Schema locations for namespaces defined by the STIX language STIX_NS_TO_SCHEMALOCATION = { - 'http://data-marking.mitre.org/Marking-1': 'http://stix.mitre.org/XMLSchema/data_marking/1.1.1/data_marking.xsd', - 'http://data-marking.mitre.org/extensions/MarkingStructure#Simple-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/simple/1.1.1/simple_marking.xsd', - 'http://data-marking.mitre.org/extensions/MarkingStructure#TLP-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/tlp/1.1.1/tlp_marking.xsd', + 'http://data-marking.mitre.org/Marking-1': 'http://stix.mitre.org/XMLSchema/data_marking/1.2/data_marking.xsd', + 'http://data-marking.mitre.org/extensions/MarkingStructure#Simple-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/simple/1.2/simple_marking.xsd', + 'http://data-marking.mitre.org/extensions/MarkingStructure#TLP-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/tlp/1.2/tlp_marking.xsd', 'http://data-marking.mitre.org/extensions/MarkingStructure#Terms_Of_Use-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/terms_of_use/1.0.1/terms_of_use_marking.xsd', - 'http://stix.mitre.org/Campaign-1': 'http://stix.mitre.org/XMLSchema/campaign/1.1.1/campaign.xsd', - 'http://stix.mitre.org/CourseOfAction-1': 'http://stix.mitre.org/XMLSchema/course_of_action/1.1.1/course_of_action.xsd', - 'http://stix.mitre.org/ExploitTarget-1': 'http://stix.mitre.org/XMLSchema/exploit_target/1.1.1/exploit_target.xsd', - 'http://stix.mitre.org/Incident-1': 'http://stix.mitre.org/XMLSchema/incident/1.1.1/incident.xsd', + 'http://stix.mitre.org/Campaign-1': 'http://stix.mitre.org/XMLSchema/campaign/1.2/campaign.xsd', + 'http://stix.mitre.org/CourseOfAction-1': 'http://stix.mitre.org/XMLSchema/course_of_action/1.2/course_of_action.xsd', + 'http://stix.mitre.org/ExploitTarget-1': 'http://stix.mitre.org/XMLSchema/exploit_target/1.2/exploit_target.xsd', + 'http://stix.mitre.org/Incident-1': 'http://stix.mitre.org/XMLSchema/incident/1.2/incident.xsd', 'http://stix.mitre.org/Indicator-2': 'http://stix.mitre.org/XMLSchema/indicator/2.1.1/indicator.xsd', 'http://stix.mitre.org/Report-1': 'http://stix.mitre.org/XMLSchema/report/1.0/report.xsd', - 'http://stix.mitre.org/TTP-1': 'http://stix.mitre.org/XMLSchema/ttp/1.1.1/ttp.xsd', - 'http://stix.mitre.org/ThreatActor-1': 'http://stix.mitre.org/XMLSchema/threat_actor/1.1.1/threat_actor.xsd', - 'http://stix.mitre.org/common-1': 'http://stix.mitre.org/XMLSchema/common/1.1.1/stix_common.xsd', - 'http://stix.mitre.org/default_vocabularies-1': 'http://stix.mitre.org/XMLSchema/default_vocabularies/1.1.1/stix_default_vocabularies.xsd', + 'http://stix.mitre.org/TTP-1': 'http://stix.mitre.org/XMLSchema/ttp/1.2/ttp.xsd', + 'http://stix.mitre.org/ThreatActor-1': 'http://stix.mitre.org/XMLSchema/threat_actor/1.2/threat_actor.xsd', + 'http://stix.mitre.org/common-1': 'http://stix.mitre.org/XMLSchema/common/1.2/stix_common.xsd', + 'http://stix.mitre.org/default_vocabularies-1': 'http://stix.mitre.org/XMLSchema/default_vocabularies/1.2.0/stix_default_vocabularies.xsd', 'http://stix.mitre.org/extensions/AP#CAPEC2.7-1': 'http://stix.mitre.org/XMLSchema/extensions/attack_pattern/capec_2.7/1.0.1/capec_2.7_attack_pattern.xsd', - 'http://stix.mitre.org/extensions/Address#CIQAddress3.0-1': 'http://stix.mitre.org/XMLSchema/extensions/address/ciq_3.0/1.1.1/ciq_3.0_address.xsd', - 'http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1': 'http://stix.mitre.org/XMLSchema/extensions/identity/ciq_3.0/1.1.1/ciq_3.0_identity.xsd', + 'http://stix.mitre.org/extensions/Address#CIQAddress3.0-1': 'http://stix.mitre.org/XMLSchema/extensions/address/ciq_3.0/1.2/ciq_3.0_address.xsd', + 'http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1': 'http://stix.mitre.org/XMLSchema/extensions/identity/ciq_3.0/1.2/ciq_3.0_identity.xsd', 'http://stix.mitre.org/extensions/Malware#MAEC4.1-1': 'http://stix.mitre.org/XMLSchema/extensions/malware/maec_4.1/1.0.1/maec_4.1_malware.xsd', - 'http://stix.mitre.org/extensions/StructuredCOA#Generic-1': 'http://stix.mitre.org/XMLSchema/extensions/structured_coa/generic/1.1.1/generic_structured_coa.xsd', - 'http://stix.mitre.org/extensions/TestMechanism#Generic-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/generic/1.1.1/generic_test_mechanism.xsd', - 'http://stix.mitre.org/extensions/TestMechanism#OVAL5.10-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/oval_5.10/1.1.1/oval_5.10_test_mechanism.xsd', - 'http://stix.mitre.org/extensions/TestMechanism#OpenIOC2010-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/open_ioc_2010/1.1.1/open_ioc_2010_test_mechanism.xsd', - 'http://stix.mitre.org/extensions/TestMechanism#Snort-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/snort/1.1.1/snort_test_mechanism.xsd', - 'http://stix.mitre.org/extensions/TestMechanism#YARA-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/yara/1.1.1/yara_test_mechanism.xsd', + 'http://stix.mitre.org/extensions/StructuredCOA#Generic-1': 'http://stix.mitre.org/XMLSchema/extensions/structured_coa/generic/1.2/generic_structured_coa.xsd', + 'http://stix.mitre.org/extensions/TestMechanism#Generic-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/generic/1.2/generic_test_mechanism.xsd', + 'http://stix.mitre.org/extensions/TestMechanism#OVAL5.10-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/oval_5.10/1.2/oval_5.10_test_mechanism.xsd', + 'http://stix.mitre.org/extensions/TestMechanism#OpenIOC2010-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/open_ioc_2010/1.2/open_ioc_2010_test_mechanism.xsd', + 'http://stix.mitre.org/extensions/TestMechanism#Snort-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/snort/1.2/snort_test_mechanism.xsd', + 'http://stix.mitre.org/extensions/TestMechanism#YARA-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/yara/1.2/yara_test_mechanism.xsd', 'http://stix.mitre.org/extensions/Vulnerability#CVRF-1': 'http://stix.mitre.org/XMLSchema/extensions/vulnerability/cvrf_1.1/1.1.1/cvrf_1.1_vulnerability.xsd', - 'http://stix.mitre.org/stix-1': 'http://stix.mitre.org/XMLSchema/core/1.1.1/stix_core.xsd' + 'http://stix.mitre.org/stix-1': 'http://stix.mitre.org/XMLSchema/core/1.2/stix_core.xsd' } #: Schema locations for namespaces defined by the CybOX language From d254e2fd64011d79993480c3c8f8b024eb18319d Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 16:16:09 -0400 Subject: [PATCH 044/438] Updated core component class versions. --- stix/campaign/__init__.py | 4 ++-- stix/coa/__init__.py | 4 ++-- stix/core/stix_package.py | 1 + stix/exploit_target/__init__.py | 4 ++-- stix/incident/__init__.py | 4 ++-- stix/indicator/indicator.py | 4 ++-- stix/threat_actor/__init__.py | 4 ++-- stix/ttp/__init__.py | 4 ++-- stix/utils/nsparser.py | 2 +- 9 files changed, 16 insertions(+), 15 deletions(-) diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 5de638fb..298f9f0b 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -70,8 +70,8 @@ class Campaign(stix.BaseCoreComponent): _binding = campaign_binding _binding_class = _binding.CampaignType _namespace = "http://stix.mitre.org/Campaign-1" - _version = "1.1.1" - _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1") + _version = "1.2" + _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'campaign' def __init__(self, id_=None, idref=None, timestamp=None, title=None, diff --git a/stix/coa/__init__.py b/stix/coa/__init__.py index de79b406..c2740796 100644 --- a/stix/coa/__init__.py +++ b/stix/coa/__init__.py @@ -32,8 +32,8 @@ class CourseOfAction(stix.BaseCoreComponent): _binding = coa_binding _binding_class = coa_binding.CourseOfActionType _namespace = "http://stix.mitre.org/CourseOfAction-1" - _version = "1.1.1" - _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1") + _version = "1.2" + _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'coa' def __init__(self, id_=None, idref=None, timestamp=None, title=None, diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index e297a9f9..999bbf85 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -33,6 +33,7 @@ class STIXPackage(stix.Entity): _binding_class = _binding.STIXType _namespace = 'http://stix.mitre.org/stix-1' _version = "1.2" + _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, courses_of_action=None, exploit_targets=None, indicators=None, diff --git a/stix/exploit_target/__init__.py b/stix/exploit_target/__init__.py index 98214d5b..863bd33d 100644 --- a/stix/exploit_target/__init__.py +++ b/stix/exploit_target/__init__.py @@ -35,8 +35,8 @@ class ExploitTarget(stix.BaseCoreComponent): _binding = exploit_target_binding _binding_class = _binding.ExploitTargetType _namespace = "http://stix.mitre.org/ExploitTarget-1" - _version = "1.1.1" - _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1") + _version = "1.2" + _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'et' def __init__(self, id_=None, idref=None, timestamp=None, title=None, diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index 26f96008..f91ba101 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -28,8 +28,8 @@ class Incident(stix.BaseCoreComponent): _binding = incident_binding _binding_class = _binding.IncidentType _namespace = "http://stix.mitre.org/Incident-1" - _version = "1.1.1" - _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1") + _version = "1.2" + _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'incident' def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 2727624e..bbab5074 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -174,8 +174,8 @@ class Indicator(stix.BaseCoreComponent): _binding = indicator_binding _binding_class = indicator_binding.IndicatorType _namespace = 'http://stix.mitre.org/Indicator-2' - _version = "2.1.1" - _ALL_VERSIONS = ("2.0", "2.0.1", "2.1", "2.1.1") + _version = "2.2" + _ALL_VERSIONS = ("2.0", "2.0.1", "2.1", "2.1.1", "2.2") _ALLOWED_COMPOSITION_OPERATORS = ('AND', 'OR') _ID_PREFIX = "indicator" diff --git a/stix/threat_actor/__init__.py b/stix/threat_actor/__init__.py index 53346b94..a0747679 100644 --- a/stix/threat_actor/__init__.py +++ b/stix/threat_actor/__init__.py @@ -42,8 +42,8 @@ class ThreatActor(stix.BaseCoreComponent): _binding = threat_actor_binding _binding_class = threat_actor_binding.ThreatActorType _namespace = 'http://stix.mitre.org/ThreatActor-1' - _version = "1.1.1" - _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1") + _version = "1.2" + _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'threatactor' def __init__(self, id_=None, idref=None, timestamp=None, title=None, diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index 19656ffa..9afd618c 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -17,8 +17,8 @@ class TTP(stix.BaseCoreComponent): _binding = ttp_binding _binding_class = _binding.TTPType _namespace = "http://stix.mitre.org/TTP-1" - _version = "1.1.1" - _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1") + _version = "1.2" + _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = "ttp" def __init__(self, id_=None, idref=None, timestamp=None, title=None, diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index 9da93f23..648b624e 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -409,7 +409,7 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): 'http://stix.mitre.org/CourseOfAction-1': 'http://stix.mitre.org/XMLSchema/course_of_action/1.2/course_of_action.xsd', 'http://stix.mitre.org/ExploitTarget-1': 'http://stix.mitre.org/XMLSchema/exploit_target/1.2/exploit_target.xsd', 'http://stix.mitre.org/Incident-1': 'http://stix.mitre.org/XMLSchema/incident/1.2/incident.xsd', - 'http://stix.mitre.org/Indicator-2': 'http://stix.mitre.org/XMLSchema/indicator/2.1.1/indicator.xsd', + 'http://stix.mitre.org/Indicator-2': 'http://stix.mitre.org/XMLSchema/indicator/2.2/indicator.xsd', 'http://stix.mitre.org/Report-1': 'http://stix.mitre.org/XMLSchema/report/1.0/report.xsd', 'http://stix.mitre.org/TTP-1': 'http://stix.mitre.org/XMLSchema/ttp/1.2/ttp.xsd', 'http://stix.mitre.org/ThreatActor-1': 'http://stix.mitre.org/XMLSchema/threat_actor/1.2/threat_actor.xsd', From 7deafb3ec9d9a3a5d2c5f1962c3704f861ffdf71 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 16:20:46 -0400 Subject: [PATCH 045/438] Updated unit tests to use new component version numbers. --- stix/test/campaign_test.py | 2 +- stix/test/common/related_test.py | 6 +++--- .../extensions/malware/maec_4_1_malware_test.py | 13 +------------ stix/test/incident_test.py | 6 +++--- 4 files changed, 8 insertions(+), 19 deletions(-) diff --git a/stix/test/campaign_test.py b/stix/test/campaign_test.py index 4b8b26cc..b2b388d4 100644 --- a/stix/test/campaign_test.py +++ b/stix/test/campaign_test.py @@ -107,7 +107,7 @@ class CampaignTest(EntityTestCase, unittest.TestCase): _full_dict = { 'id': "example:test-1", 'timestamp': "2014-01-31T06:14:46", - 'version': '1.1.1', + 'version': '1.2', 'title': 'Purple Elephant', 'description': 'A pretty novice set of actors.', 'short_description': 'novices', diff --git a/stix/test/common/related_test.py b/stix/test/common/related_test.py index ae0d8df8..5e611bda 100644 --- a/stix/test/common/related_test.py +++ b/stix/test/common/related_test.py @@ -192,7 +192,7 @@ class RelatedPackageTests(EntityTestCase, unittest.TestCase): 'relationship': "Associated", 'package': { 'id': 'example:bar-1', - 'version': '1.1.1', + 'version': '1.2', 'stix_header': { 'title': 'Test' } @@ -212,7 +212,7 @@ class RelatedPackagesTests(EntityTestCase, unittest.TestCase): 'relationship': "Associated", 'package': { 'id': 'example:bar-1', - 'version': '1.1.1', + 'version': '1.2', 'stix_header': { 'title': 'Test' } @@ -226,7 +226,7 @@ class RelatedPackagesTests(EntityTestCase, unittest.TestCase): 'relationship': "Associated", 'package': { 'id': 'example:bar-2', - 'version': '1.1.1', + 'version': '1.2', 'stix_header': { 'title': 'Test' } diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index 66f19d63..2aeea093 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -48,18 +48,7 @@ class PythonMAECEtreeTests(unittest.TestCase): xmlns:stix-maec="http://stix.mitre.org/extensions/Malware#MAEC4.1-1" xmlns:stix="http://stix.mitre.org/stix-1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation=" - http://cybox.mitre.org/common-2 http://cybox.mitre.org/XMLSchema/common/2.1/cybox_common.xsd - http://cybox.mitre.org/cybox-2 http://cybox.mitre.org/XMLSchema/core/2.1/cybox_core.xsd - http://cybox.mitre.org/default_vocabularies-2 http://cybox.mitre.org/XMLSchema/default_vocabularies/2.1/cybox_default_vocabularies.xsd - http://cybox.mitre.org/objects#FileObject-2 http://cybox.mitre.org/XMLSchema/objects/File/2.1/File_Object.xsd - http://maec.mitre.org/XMLSchema/maec-package-2 http://maec.mitre.org/language/version4.1/maec_package_schema.xsd - http://maec.mitre.org/default_vocabularies-1 http://maec.mitre.org/language/version4.1/maec_default_vocabularies.xsd - http://stix.mitre.org/TTP-1 http://stix.mitre.org/XMLSchema/ttp/1.1.1/ttp.xsd - http://stix.mitre.org/common-1 http://stix.mitre.org/XMLSchema/common/1.1.1/stix_common.xsd - http://stix.mitre.org/default_vocabularies-1 http://stix.mitre.org/XMLSchema/default_vocabularies/1.1.1/stix_default_vocabularies.xsd - http://stix.mitre.org/extensions/Malware#MAEC4.1-1 http://stix.mitre.org/XMLSchema/extensions/malware/maec_4.1/1.0.1/maec_4.1_malware.xsd - http://stix.mitre.org/stix-1 http://stix.mitre.org/XMLSchema/core/1.1.1/stix_core.xsd" xsi:type='stix-maec:MAEC4.1InstanceType' + xsi:type='stix-maec:MAEC4.1InstanceType' id="example:package-2fb96bef-1b11-436e-af4a-15588ac3198b" schema_version="2.1"> diff --git a/stix/test/incident_test.py b/stix/test/incident_test.py index 09e8fa09..eaf79a98 100644 --- a/stix/test/incident_test.py +++ b/stix/test/incident_test.py @@ -55,7 +55,7 @@ class COATakenTest(EntityTestCase, unittest.TestCase): 'time': COATimeTest._full_dict, #'coordinators': None, # need to implement this! 'course_of_action': { - 'version': '1.1.1', + 'version': '1.2', 'title': 'Test Title', 'description': 'Test Description', 'short_description': "Test Short Description", @@ -80,7 +80,7 @@ class COARequestedTest(EntityTestCase, unittest.TestCase): 'priority': "High", #'coordinators': None, # need to implement this! 'course_of_action': { - 'version': '1.1.1', + 'version': '1.2', 'title': 'Test Title', 'description': 'Test Description', 'short_description': "Test Short Description", @@ -430,7 +430,7 @@ class IncidentTest(EntityTestCase, unittest.TestCase): klass = incident.Incident _full_dict = { 'id': 'example:test-1', - 'version': '1.1.1', + 'version': '1.2', 'timestamp': '2014-05-05T14:50:25.992383+00:00', 'title': 'Test Title', 'description': 'The Datacenter was broken into.', From bda2f76fbf36d7a5bd905139cb7ab2c0d2caf906 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 16:23:35 -0400 Subject: [PATCH 046/438] Updated sample xml file for 1.2 --- examples/sample.xml | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/examples/sample.xml b/examples/sample.xml index ce6d3e72..4e260dbc 100755 --- a/examples/sample.xml +++ b/examples/sample.xml @@ -1,20 +1,9 @@ + version="1.2"> Example watchlist that contains IP information. Indicators - Watchlist From 350ea7d2279490a32554bcbf29ec79551e750c77 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 20:48:38 -0400 Subject: [PATCH 047/438] More Report work. Added unit tests. --- stix/report/__init__.py | 19 ++++- stix/test/common/related_test.py | 59 ++++++++++++++- stix/test/report_test.py | 120 +++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 stix/test/report_test.py diff --git a/stix/report/__init__.py b/stix/report/__init__.py index 83c753b2..fbf5c9dc 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -9,6 +9,7 @@ import stix.utils as utils import stix.utils.parser as parser +# components from stix.campaign import Campaign from stix.coa import CourseOfAction from stix.core.ttps import TTPs @@ -17,6 +18,8 @@ from stix.incident import Incident from stix.threat_actor import ThreatActor from stix.ttp import TTP + +# relationships from stix.common.related import RelatedReports # relative imports @@ -191,6 +194,20 @@ def ttps(self, value): def add_ttp(self, ttp): self.ttps.append(ttp) + @property + def related_reports(self): + return self._related_reports + + @related_reports.setter + def related_reports(self, value): + if isinstance(value, RelatedReports): + self._related_reports = value + else: + self._related_reports = RelatedReports(value) + + def add_related_report(self, related_report): + self.related_reports.append(related_report) + def add(self, entity): """Adds `entity` to a top-level collection. For example, if `entity` is an Indicator object, the `entity` will be added to the ``indicators`` @@ -232,7 +249,7 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.timestamp = utils.dates.serialize_value(self.timestamp) if self.header: - return_obj.STIX_Header = self.header.to_obj(ns_info=ns_info) + return_obj.Header = self.header.to_obj(ns_info=ns_info) if self.campaigns: return_obj.Campaigns = self.campaigns.to_obj(ns_info=ns_info) if self.courses_of_action: diff --git a/stix/test/common/related_test.py b/stix/test/common/related_test.py index 5e611bda..7294eee1 100644 --- a/stix/test/common/related_test.py +++ b/stix/test/common/related_test.py @@ -9,9 +9,66 @@ RelatedCampaign, RelatedCampaignRef, RelatedIdentity, RelatedCOA, RelatedPackage, RelatedPackageRef, RelatedExploitTarget, RelatedIncident, RelatedIndicator, RelatedObservable, RelatedThreatActor, RelatedTTP, - RelatedPackageRefs, RelatedPackages + RelatedPackageRefs, RelatedPackages, RelatedReports, RelatedReport ) + +class RelatedReportTests(EntityTestCase, unittest.TestCase): + klass = RelatedReport + _full_dict = { + 'confidence': {'value': {'value': "Medium", 'xsi:type':'stixVocabs:HighMediumLowVocab-1.0'}}, + 'information_source': { + 'description': "Source of the relationship", + }, + 'relationship': "Associated", + 'report': { + 'id': 'example:bar-1', + 'version': '1.0', + 'header': { + 'title': 'Test' + } + } + } + + +class RelatedReportsTests(EntityTestCase, unittest.TestCase): + klass = RelatedReports + + _full_dict = { + 'scope': 'inclusive', + 'related_reports': [ + { + 'confidence': {'value': {'value': "Medium", 'xsi:type':'stixVocabs:HighMediumLowVocab-1.0'}}, + 'information_source': { + 'description': "Source of the relationship", + }, + 'relationship': "Associated", + 'report': { + 'id': 'example:bar-1', + 'version': '1.2', + 'header': { + 'title': 'Test' + } + } + }, + { + 'confidence': {'value': {'value': "Medium", 'xsi:type':'stixVocabs:HighMediumLowVocab-1.0'}}, + 'information_source': { + 'description': "Source of the relationship", + }, + 'relationship': "Associated", + 'report': { + 'id': 'example:bar-2', + 'version': '1.2', + 'header': { + 'title': 'Test' + } + } + } + ] + } + + class RelatedPackageRefsTests(EntityTestCase, unittest.TestCase): klass = RelatedPackageRefs _full_dict = { diff --git a/stix/test/report_test.py b/stix/test/report_test.py new file mode 100644 index 00000000..8786d3d9 --- /dev/null +++ b/stix/test/report_test.py @@ -0,0 +1,120 @@ +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +import unittest + +from stix import report + +from stix.test import EntityTestCase, data_marking_test +from stix.test.common import (kill_chains_test, information_source_test, + structured_text_tests, related_test) + + +class HeaderTests(EntityTestCase, unittest.TestCase): + klass = report.Header + _full_dict = { + 'title': "A Title", + 'description': "A really, really long description", + 'short_description': 'A really, really short description', + 'handling': data_marking_test.MarkingTests._full_dict, + 'information_source': information_source_test.InformationSourceTests._full_dict, + } + + def test_duplicate_package_intent(self): + # Recreate https://github.com/STIXProject/python-stix/issues/63 + hdr = report.Header(intents=["Indicators - Watchlist"]) + self.assertEqual(1, len(hdr.intents)) + + +class HeaderMultiDescTests(EntityTestCase, unittest.TestCase): + klass = report.Header + _full_dict = { + 'description': structured_text_tests.StructuredTextListTests._full_dict, + 'short_description': structured_text_tests.StructuredTextListTests._full_dict + } + + +class CampaignsTests(EntityTestCase, unittest.TestCase): + klass = report.Campaigns + + _full_dict = [ + {'idref': 'example:test-1'} + ] + + +class COAsTests(EntityTestCase, unittest.TestCase): + klass = report.CoursesOfAction + + _full_dict = [ + {'idref': 'example:test-1'} + ] + +class ExploitTargetsTests(EntityTestCase, unittest.TestCase): + klass = report.ExploitTargets + + _full_dict = [ + {'idref': 'example:test-1'} + ] + +class IncidentsTests(EntityTestCase, unittest.TestCase): + klass = report.Incidents + + _full_dict = [ + {'idref': 'example:test-1'} + ] + +class IndicatorsTests(EntityTestCase, unittest.TestCase): + klass = report.Indicators + + _full_dict = [ + {'idref': 'example:test-1'} + ] + + +class ThreatActorsTests(EntityTestCase, unittest.TestCase): + klass = report.ThreatActors + + _full_dict = [ + {'idref': 'example:test-1'} + ] + + +class TTPsTests(EntityTestCase, unittest.TestCase): + klass = report.TTPs + + _full_dict = { + 'kill_chains': kill_chains_test.KillChainsTests._full_dict, + 'ttps': [ + {'idref': 'example:test-1'} + ] + } + + +class ReportTests(EntityTestCase, unittest.TestCase): + klass = report.Report + _full_dict = { + 'header': HeaderTests._full_dict, + 'campaigns': CampaignsTests._full_dict, + 'courses_of_action': COAsTests._full_dict, + 'exploit_targets': ExploitTargetsTests._full_dict, + 'incidents': IncidentsTests._full_dict, + 'indicators': IndicatorsTests._full_dict, + 'observables': { + 'major_version': 2, + 'minor_version': 1, + 'update_version': 0, + 'observables': [ + { + 'idref': "example:Observable-1" + } + ] + }, + 'threat_actors': ThreatActorsTests._full_dict, + 'ttps': TTPsTests._full_dict, + 'related_reports': related_test.RelatedReportsTests._full_dict, + 'version': "1.0" + } + + +if __name__ == "__main__": + unittest.main() From d05b9ea688ac3de91541c10d3493c79aee741d5d Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 20:49:41 -0400 Subject: [PATCH 048/438] * Moved non STIXPackage classes out of stix_package.py to stix.core __init__.py * Added reports support to STIXPackage. * Updated unit tests for report code. --- stix/core/__init__.py | 90 ++++++++++++++++++++++++- stix/core/stix_package.py | 101 +++++++--------------------- stix/test/core/stix_package_test.py | 14 +++- 3 files changed, 127 insertions(+), 78 deletions(-) diff --git a/stix/core/__init__.py b/stix/core/__init__.py index f744e7d1..44105521 100644 --- a/stix/core/__init__.py +++ b/stix/core/__init__.py @@ -1,5 +1,93 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# base import +import stix + +# component imports +from stix.campaign import Campaign +from stix.coa import CourseOfAction +from stix.exploit_target import ExploitTarget +from stix.indicator import Indicator +from stix.incident import Incident +from stix.report import Report +from stix.threat_actor import ThreatActor + +# binding imports +from stix.bindings import stix_core as stix_core_binding +from stix.bindings import stix_common as stix_common_binding + + +class Campaigns(stix.EntityList): + _binding = stix_core_binding + _namespace = 'http://stix.mitre.org/stix-1' + _binding_class = _binding.CampaignsType + _contained_type = Campaign + _binding_var = "Campaign" + _inner_name = "campaigns" + _dict_as_list = True + + +class CoursesOfAction(stix.EntityList): + _binding = stix_core_binding + _namespace = 'http://stix.mitre.org/stix-1' + _binding_class = _binding.CoursesOfActionType + _contained_type = CourseOfAction + _binding_var = "Course_Of_Action" + _inner_name = "courses_of_action" + _dict_as_list = True + + +class ExploitTargets(stix.EntityList): + _binding = stix_common_binding + _namespace = 'http://stix.mitre.org/common-1' + _binding_class = _binding.ExploitTargetsType + _contained_type = ExploitTarget + _binding_var = "Exploit_Target" + _inner_name = "exploit_targets" + _dict_as_list = True + + +class Incidents(stix.EntityList): + _binding = stix_core_binding + _namespace = 'http://stix.mitre.org/stix-1' + _binding_class = _binding.IncidentsType + _contained_type = Incident + _binding_var = "Incident" + _inner_name = "incidents" + _dict_as_list = True + + +class Indicators(stix.EntityList): + _binding = stix_core_binding + _namespace = 'http://stix.mitre.org/stix-1' + _binding_class = _binding.IndicatorsType + _contained_type = Indicator + _binding_var = "Indicator" + _inner_name = "indicators" + _dict_as_list = True + + +class ThreatActors(stix.EntityList): + _binding = stix_core_binding + _namespace = 'http://stix.mitre.org/stix-1' + _binding_class = _binding.ThreatActorsType + _contained_type = ThreatActor + _binding_var = "Threat_Actor" + _inner_name = "threat_actors" + _dict_as_list = True + + +class Reports(stix.EntityList): + _binding = stix_core_binding + _namespace = 'http://stix.mitre.org/stix-1' + _binding_class = _binding.ReportsType + _contained_type = Report + _binding_var = "Report" + _inner_name = "reports" + _dict_as_list = True + + +# Namespace flattening from stix_package import STIXPackage # noqa -from stix_header import STIXHeader # noqa +from stix_header import STIXHeader # noqa \ No newline at end of file diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 999bbf85..50e6860c 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -4,27 +4,33 @@ # external from cybox.core import Observable, Observables -# internal +# base import stix + +# utility imports import stix.utils as utils import stix.utils.parser as parser +# component imports from stix.campaign import Campaign from stix.coa import CourseOfAction from stix.exploit_target import ExploitTarget from stix.indicator import Indicator from stix.incident import Incident -from stix.report import Report from stix.threat_actor import ThreatActor from stix.ttp import TTP +from stix.report import Report + +# relationship imports from stix.common.related import RelatedPackages # relative imports from .stix_header import STIXHeader from .ttps import TTPs +from . import (Campaigns, CoursesOfAction, ExploitTargets, Incidents, + Indicators, ThreatActors, Reports) # binding imports -import stix.bindings.stix_common as stix_common_binding import stix.bindings.stix_core as stix_core_binding @@ -38,7 +44,8 @@ class STIXPackage(stix.Entity): def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, courses_of_action=None, exploit_targets=None, indicators=None, observables=None, incidents=None, threat_actors=None, - ttps=None, campaigns=None, reports=None): + ttps=None, campaigns=None, related_packages=None, + reports=None): self.id_ = id_ or stix.utils.create_id("Package") self.idref = idref @@ -52,7 +59,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, self.incidents = incidents self.threat_actors = threat_actors self.ttps = ttps - self.related_packages = RelatedPackages() + self.related_packages = related_packages self.reports = reports if timestamp: @@ -205,6 +212,20 @@ def reports(self, value): def add_report(self, report): self.reports.append(report) + @property + def related_packages(self): + return self._related_packages + + @related_packages.setter + def related_packages(self, value): + if isinstance(value, RelatedPackages): + self._related_packages = value + else: + self._related_packages = RelatedPackages(value) + + def add_related_package(self, related_package): + self.related_packages.append(related_package) + def add(self, entity): """Adds `entity` to a top-level collection. For example, if `entity` is an Indicator object, the `entity` will be added to the ``indicators`` @@ -343,73 +364,3 @@ def from_xml(cls, xml_file, encoding=None): """ entity_parser = parser.EntityParser() return entity_parser.parse_xml(xml_file, encoding=encoding) - - -class Campaigns(stix.EntityList): - _binding = stix_core_binding - _namespace = 'http://stix.mitre.org/stix-1' - _binding_class = _binding.CampaignsType - _contained_type = Campaign - _binding_var = "Campaign" - _inner_name = "campaigns" - _dict_as_list = True - - -class CoursesOfAction(stix.EntityList): - _binding = stix_core_binding - _namespace = 'http://stix.mitre.org/stix-1' - _binding_class = _binding.CoursesOfActionType - _contained_type = CourseOfAction - _binding_var = "Course_Of_Action" - _inner_name = "courses_of_action" - _dict_as_list = True - - -class ExploitTargets(stix.EntityList): - _binding = stix_common_binding - _namespace = 'http://stix.mitre.org/common-1' - _binding_class = _binding.ExploitTargetsType - _contained_type = ExploitTarget - _binding_var = "Exploit_Target" - _inner_name = "exploit_targets" - _dict_as_list = True - - -class Incidents(stix.EntityList): - _binding = stix_core_binding - _namespace = 'http://stix.mitre.org/stix-1' - _binding_class = _binding.IncidentsType - _contained_type = Incident - _binding_var = "Incident" - _inner_name = "incidents" - _dict_as_list = True - - -class Indicators(stix.EntityList): - _binding = stix_core_binding - _namespace = 'http://stix.mitre.org/stix-1' - _binding_class = _binding.IndicatorsType - _contained_type = Indicator - _binding_var = "Indicator" - _inner_name = "indicators" - _dict_as_list = True - - -class ThreatActors(stix.EntityList): - _binding = stix_core_binding - _namespace = 'http://stix.mitre.org/stix-1' - _binding_class = _binding.ThreatActorsType - _contained_type = ThreatActor - _binding_var = "Threat_Actor" - _inner_name = "threat_actors" - _dict_as_list = True - - -class Reports(stix.EntityList): - _binding = stix_core_binding - _namespace = 'http://stix.mitre.org/stix-1' - _binding_class = _binding.ReportsType - _contained_type = Report - _binding_var = "Report" - _inner_name = "reports" - _dict_as_list = True diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index d952a84d..6ee62814 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -5,8 +5,8 @@ import StringIO import unittest -from stix.test import EntityTestCase -from stix.test.common import kill_chains_test +from stix.test import EntityTestCase, report_test +from stix.test.common import kill_chains_test, related_test from . import stix_header_test @@ -69,6 +69,14 @@ class TTPsTests(EntityTestCase, unittest.TestCase): } +class ReportsTests(EntityTestCase, unittest.TestCase): + klass = stix_package.Reports + + _full_dict = [ + report_test.ReportTests._full_dict + ] + + class STIXPackageTests(EntityTestCase, unittest.TestCase): klass = core.STIXPackage _full_dict = { @@ -90,6 +98,8 @@ class STIXPackageTests(EntityTestCase, unittest.TestCase): }, 'threat_actors': ThreatActorsTests._full_dict, 'ttps': TTPsTests._full_dict, + 'related_packages': related_test.RelatedPackagesTests._full_dict, + 'reports': ReportsTests._full_dict, 'version': "1.2" } From 015e5e504148222288a843e3072886053d97cdca Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 21:00:51 -0400 Subject: [PATCH 049/438] Updated extension versions in schemalocation urls. --- stix/utils/nsparser.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index 648b624e..00f46fc3 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -415,17 +415,17 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): 'http://stix.mitre.org/ThreatActor-1': 'http://stix.mitre.org/XMLSchema/threat_actor/1.2/threat_actor.xsd', 'http://stix.mitre.org/common-1': 'http://stix.mitre.org/XMLSchema/common/1.2/stix_common.xsd', 'http://stix.mitre.org/default_vocabularies-1': 'http://stix.mitre.org/XMLSchema/default_vocabularies/1.2.0/stix_default_vocabularies.xsd', - 'http://stix.mitre.org/extensions/AP#CAPEC2.7-1': 'http://stix.mitre.org/XMLSchema/extensions/attack_pattern/capec_2.7/1.0.1/capec_2.7_attack_pattern.xsd', + 'http://stix.mitre.org/extensions/AP#CAPEC2.7-1': 'http://stix.mitre.org/XMLSchema/extensions/attack_pattern/capec_2.7/1.1/capec_2.7_attack_pattern.xsd', 'http://stix.mitre.org/extensions/Address#CIQAddress3.0-1': 'http://stix.mitre.org/XMLSchema/extensions/address/ciq_3.0/1.2/ciq_3.0_address.xsd', 'http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1': 'http://stix.mitre.org/XMLSchema/extensions/identity/ciq_3.0/1.2/ciq_3.0_identity.xsd', - 'http://stix.mitre.org/extensions/Malware#MAEC4.1-1': 'http://stix.mitre.org/XMLSchema/extensions/malware/maec_4.1/1.0.1/maec_4.1_malware.xsd', + 'http://stix.mitre.org/extensions/Malware#MAEC4.1-1': 'http://stix.mitre.org/XMLSchema/extensions/malware/maec_4.1/1.1/maec_4.1_malware.xsd', 'http://stix.mitre.org/extensions/StructuredCOA#Generic-1': 'http://stix.mitre.org/XMLSchema/extensions/structured_coa/generic/1.2/generic_structured_coa.xsd', 'http://stix.mitre.org/extensions/TestMechanism#Generic-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/generic/1.2/generic_test_mechanism.xsd', 'http://stix.mitre.org/extensions/TestMechanism#OVAL5.10-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/oval_5.10/1.2/oval_5.10_test_mechanism.xsd', 'http://stix.mitre.org/extensions/TestMechanism#OpenIOC2010-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/open_ioc_2010/1.2/open_ioc_2010_test_mechanism.xsd', 'http://stix.mitre.org/extensions/TestMechanism#Snort-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/snort/1.2/snort_test_mechanism.xsd', 'http://stix.mitre.org/extensions/TestMechanism#YARA-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/yara/1.2/yara_test_mechanism.xsd', - 'http://stix.mitre.org/extensions/Vulnerability#CVRF-1': 'http://stix.mitre.org/XMLSchema/extensions/vulnerability/cvrf_1.1/1.1.1/cvrf_1.1_vulnerability.xsd', + 'http://stix.mitre.org/extensions/Vulnerability#CVRF-1': 'http://stix.mitre.org/XMLSchema/extensions/vulnerability/cvrf_1.1/1.2/cvrf_1.1_vulnerability.xsd', 'http://stix.mitre.org/stix-1': 'http://stix.mitre.org/XMLSchema/core/1.2/stix_core.xsd' } From b668d6e43a3f1f97568a5cc989414024da87c1de Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 21:02:27 -0400 Subject: [PATCH 050/438] Removed unnecessary extension registration call for MAEC malware extension. --- stix/extensions/malware/maec_4_1_malware.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index e35edc05..32b5398f 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -220,6 +220,3 @@ def to_dict(self): d['maec'] = etree.tostring(self.maec) return d - -# Register the extension -stix.ttp.malware_instance.add_extension(MAECInstance) From 5fe39f835b486f5143ff8ff0dbdd47946613a4d9 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 21:03:15 -0400 Subject: [PATCH 051/438] Removed unused import --- stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py | 1 - 1 file changed, 1 deletion(-) diff --git a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py index 7a3d8362..d6b1492f 100644 --- a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py +++ b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py @@ -10,7 +10,6 @@ # internal import stix import stix.utils.parser as parser -import stix.indicator.test_mechanism from stix.indicator.test_mechanism import _BaseTestMechanism import stix.bindings.extensions.test_mechanism.open_ioc_2010 as open_ioc_tm_binding From 556ba12b4fabc9af37eb500ebedb8fe4466ec6f1 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 21:12:15 -0400 Subject: [PATCH 052/438] Added related_reports __init__ param on Report class. --- stix/report/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stix/report/__init__.py b/stix/report/__init__.py index fbf5c9dc..c090f92d 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -39,7 +39,7 @@ class Report(stix.Entity): def __init__(self, id_=None, idref=None, timestamp=None, header=None, courses_of_action=None, exploit_targets=None, indicators=None, observables=None, incidents=None, threat_actors=None, - ttps=None, campaigns=None): + ttps=None, campaigns=None, related_reports=None): self.id_ = id_ or stix.utils.create_id("Report") self.idref = idref @@ -53,7 +53,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, header=None, self.incidents = incidents self.threat_actors = threat_actors self.ttps = ttps - self.related_reports = RelatedReports() + self.related_reports = related_reports if timestamp: self.timestamp = timestamp From e81a26363b2df370d601b81222eff75bf4b20ef8 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 21:31:00 -0400 Subject: [PATCH 053/438] Fixed __len__ in TypedCollection --- stix/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/base.py b/stix/base.py index 5a76b5c9..1aa7dc69 100644 --- a/stix/base.py +++ b/stix/base.py @@ -432,7 +432,7 @@ def __init__(self): self._inner = [] def __len__(self): - return bool(self._inner) + return len(self._inner) def __nonzero__(self): return bool(self._inner) From 367767b0ff7f0224f3394d678e715dec3d10b9d2 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 21:57:33 -0400 Subject: [PATCH 054/438] Cleanup in StructuredTextList. Replaced wonky to_list() implementation with a slightly less wonky version. --- stix/common/structured_text.py | 79 ++++++++++++----------- stix/test/common/structured_text_tests.py | 21 ++++-- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index e70374e3..a4d7e4cc 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -2,11 +2,15 @@ # See LICENSE.txt for complete terms. import itertools +import contextlib import stix import stix.utils as utils import stix.bindings.stix_common as stix_common_binding +#: Default ordinality value for StructuredText. +DEFAULT_ORDINALITY = 1 + class StructuredText(stix.Entity): """Used for storing descriptive text elements. @@ -154,6 +158,27 @@ def __unicode__(self): return unicode(self.value) +@contextlib.contextmanager +def _unset_default(text): + """Unsets the ordinality of the StructuredText object `text` if the + ordinality is equal to the DEFAULT_ORDINALITY. + + The ordinaity will be returned to its original state after exiting the + context manager. + + """ + ordinality = text.ordinality + + try: + if ordinality == DEFAULT_ORDINALITY: + text.ordinality = None # Unset + + yield # Return to caller + finally: + # Reset + text.ordinality = ordinality + + class StructuredTextList(stix.TypedSequence): """A sequence type used to store StructureText objects. @@ -367,19 +392,19 @@ def to_obj(self, ns_info=None): the ordinality will be unset. """ - objlist = super(StructuredTextList, self).to_obj(ns_info=ns_info) + if not self: + return [] - if len(objlist) > 1: - return objlist + if len(self) > 1: + return super(StructuredTextList, self).to_obj(ns_info=ns_info) - # List has a size of 1. Get the only member - obj = objlist[0] + # One item. Temporarily unset the ordinality if its the default value. + text = self._inner[0] - # If the ordinality is 1, unset it. - if obj.ordinality == 1: - obj.ordinality = None + with _unset_default(text): + l = [text.to_obj(ns_info=ns_info)] - return objlist + return l def to_list(self): """Returns a list of dictionary representations of the contained @@ -399,37 +424,19 @@ def to_list(self): just return the value of ``value`` (a string). """ - # Build the list representation - l = super(StructuredTextList, self).to_list() - - # No items. Just return the empty list. - if not l: - return l - - # If we have more than one StructuredText list item, return the list. - if len(l) > 1: - return l - - # Only one item. - d = l[0] - - # If the item is not a dictionary (e.g., a string), return it. - if not isinstance(d, dict): - return d + if not self: + return [] - # Item was a dictionary. Check if there is an 'ordinality' value. - ordinality = int(d.pop('ordinality', 1)) + if len(self) > 1: + return super(StructuredTextList, self).to_list() - # Reinsert it if the value is different than the default. - if ordinality != 1: - d['ordinality'] = ordinality + # One item. Temporarily unset the ordinality if its the default value. + text = self._inner[0] - # If the only key we have left is ``value``, just return the - # corresponding string. - if len(d) == 1 and 'value' in d: - return d['value'] + # Temporarily unset the ordinality to create our dictionary + with _unset_default(text): + d = text.to_dict() - # The dictionary has more than one key, so we can't flatten it. return d to_dict = to_list diff --git a/stix/test/common/structured_text_tests.py b/stix/test/common/structured_text_tests.py index 4a1269e8..ace6f5ad 100644 --- a/stix/test/common/structured_text_tests.py +++ b/stix/test/common/structured_text_tests.py @@ -32,11 +32,6 @@ class StructuredTextListTests(unittest.TestCase, TypedListTestCase): } ] - def test_with_ordinality(self): - for idx in xrange(1, len(self.slist)): - text = self.slist.with_ordinality(idx) - self.assertEqual(text.ordinality, idx) - @classmethod def _get_text_list(cls): slist = [] @@ -163,8 +158,20 @@ def test_update(self): self.assertTrue(st1 not in slist) self.assertTrue(st2 not in slist) - def test_add_short_description(self): - pass + def test_len(self): + slist = common.StructuredTextList() + st1 = common.StructuredText("foo", ordinality=1) + st2 = common.StructuredText("bar", ordinality=2) + + slist.add(st1) + slist.add(st2) + + self.assertEqual(len(slist), 2) + + del slist[1] + + self.assertEqual(len(slist), 1) + if __name__ == "__main__": unittest.main() From 066836fe251c139bf2a4d3e9f7b94d595e4a5e60 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 30 Apr 2015 22:39:56 -0400 Subject: [PATCH 055/438] First pass at raising DeprecationWarnings when idrefs are used in a deprecated manner. --- stix/common/related.py | 9 +++++++++ stix/core/__init__.py | 30 ++++++++++++++++++++++++++++++ stix/utils/deprecated.py | 23 +++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 stix/utils/deprecated.py diff --git a/stix/common/related.py b/stix/common/related.py index 763eced6..dcc412e7 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -1,7 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# stdlib from __future__ import absolute_import +import warnings # internal import stix @@ -10,6 +12,9 @@ import stix.bindings.stix_core as core_binding import stix.bindings.report as report_binding +# deprecation warnings +from stix.utils.deprecated import idref_deprecated + # relative from .vocabs import VocabString from .information_source import InformationSource @@ -453,6 +458,10 @@ class RelatedPackage(_BaseRelated): # _base_type is set in common/__init__.py _inner_var = "Package" + @_BaseRelated.item.setter + @idref_deprecated + def item(self, value): + _BaseRelated.item.fset(self, value) class RelatedReport(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" diff --git a/stix/core/__init__.py b/stix/core/__init__.py index 44105521..58f97d7b 100644 --- a/stix/core/__init__.py +++ b/stix/core/__init__.py @@ -4,6 +4,9 @@ # base import import stix +# deprecations +from stix.utils.deprecated import idref_deprecated + # component imports from stix.campaign import Campaign from stix.coa import CourseOfAction @@ -27,6 +30,10 @@ class Campaigns(stix.EntityList): _inner_name = "campaigns" _dict_as_list = True + @idref_deprecated + def _is_valid(self, value): + return stix.EntityList._is_valid(self, value) + class CoursesOfAction(stix.EntityList): _binding = stix_core_binding @@ -37,6 +44,9 @@ class CoursesOfAction(stix.EntityList): _inner_name = "courses_of_action" _dict_as_list = True + @idref_deprecated + def _is_valid(self, value): + return stix.EntityList._is_valid(self, value) class ExploitTargets(stix.EntityList): _binding = stix_common_binding @@ -47,6 +57,10 @@ class ExploitTargets(stix.EntityList): _inner_name = "exploit_targets" _dict_as_list = True + @idref_deprecated + def _is_valid(self, value): + return stix.EntityList._is_valid(self, value) + class Incidents(stix.EntityList): _binding = stix_core_binding @@ -57,6 +71,10 @@ class Incidents(stix.EntityList): _inner_name = "incidents" _dict_as_list = True + @idref_deprecated + def _is_valid(self, value): + return stix.EntityList._is_valid(self, value) + class Indicators(stix.EntityList): _binding = stix_core_binding @@ -67,6 +85,10 @@ class Indicators(stix.EntityList): _inner_name = "indicators" _dict_as_list = True + @idref_deprecated + def _is_valid(self, value): + return stix.EntityList._is_valid(self, value) + class ThreatActors(stix.EntityList): _binding = stix_core_binding @@ -77,6 +99,10 @@ class ThreatActors(stix.EntityList): _inner_name = "threat_actors" _dict_as_list = True + @idref_deprecated + def _is_valid(self, value): + return stix.EntityList._is_valid(self, value) + class Reports(stix.EntityList): _binding = stix_core_binding @@ -87,6 +113,10 @@ class Reports(stix.EntityList): _inner_name = "reports" _dict_as_list = True + @idref_deprecated + def _is_valid(self, value): + return stix.EntityList._is_valid(self, value) + # Namespace flattening from stix_package import STIXPackage # noqa diff --git a/stix/utils/deprecated.py b/stix/utils/deprecated.py new file mode 100644 index 00000000..21765552 --- /dev/null +++ b/stix/utils/deprecated.py @@ -0,0 +1,23 @@ +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +import functools +import warnings + + +def idref_deprecated(func): + """Raises a deprecation warning if the input value has an idref attribute + set. + + """ + @functools.wraps(func) + def inner(*args, **kwargs): + val = args[1] + + if val and val.idref: + msg = "The use of idrefs has been deprecated for this field." + warnings.warn(msg, category=DeprecationWarning) + + return func(*args, **kwargs) + + return inner \ No newline at end of file From dcb76c91e9fc6298de74ced2ae88f924caddcd4d Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 1 May 2015 14:31:47 -0400 Subject: [PATCH 056/438] Modifed idref_deprecated to try and parse kwargs --- stix/utils/deprecated.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/stix/utils/deprecated.py b/stix/utils/deprecated.py index 21765552..cc722b09 100644 --- a/stix/utils/deprecated.py +++ b/stix/utils/deprecated.py @@ -6,17 +6,21 @@ def idref_deprecated(func): - """Raises a deprecation warning if the input value has an idref attribute + """Raises a python warning if the input value has an idref attribute set. """ @functools.wraps(func) def inner(*args, **kwargs): - val = args[1] + if kwargs: + val = next(kwargs.itervalues()) + else: + val = args[1] - if val and val.idref: - msg = "The use of idrefs has been deprecated for this field." - warnings.warn(msg, category=DeprecationWarning) + if getattr(val, 'idref', None): + msg = ("The use of idrefs has been deprecated for this field. " + "'{0}' object with idref: '{1}'.") + warnings.warn(msg.format(type(val).__name__, val.idref)) return func(*args, **kwargs) From 179f2709892ad73864988be8e705d7ccbfc99740 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 1 May 2015 14:32:31 -0400 Subject: [PATCH 057/438] Added idref deprecation warnings to STIXPackage.add_observable() --- stix/core/stix_package.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 50e6860c..d35d1dcf 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -10,6 +10,7 @@ # utility imports import stix.utils as utils import stix.utils.parser as parser +from stix.utils.deprecated import idref_deprecated # component imports from stix.campaign import Campaign @@ -137,6 +138,7 @@ def observables(self): def observables(self, value): self._set_var(Observables, observables=value) + @idref_deprecated def add_observable(self, observable): if not self.observables: self.observables = Observables(observables=observable) From e01d7109a1e612983e892843aaaedf0963eaa2f5 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 1 May 2015 14:32:44 -0400 Subject: [PATCH 058/438] Added idref deprecation warnings to TTPs --- stix/core/ttps.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/stix/core/ttps.py b/stix/core/ttps.py index 071280c1..6128d135 100644 --- a/stix/core/ttps.py +++ b/stix/core/ttps.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. import stix +from stix.utils.deprecated import idref_deprecated from stix.ttp import TTP from stix.bindings import stix_core as core_binding from stix.common.kill_chains import KillChains @@ -33,7 +34,11 @@ def ttps(self, value): def add_ttp(self, ttp): self.ttps.append(ttp) - + + @idref_deprecated + def _is_valid(self, value): + return stix.EntityList._is_valid(self, value) + def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() From e2101e1a305dc32fb8fee0518a991733e2cbfb37 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 1 May 2015 14:32:52 -0400 Subject: [PATCH 059/438] Silence warnings in tests --- stix/test/__init__.py | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/stix/test/__init__.py b/stix/test/__init__.py index b43ebb6d..5ce46e2f 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -3,6 +3,7 @@ import json import itertools +import warnings import cybox.utils @@ -106,9 +107,11 @@ def test_round_trip_full_dict(self): if type(self) == type(EntityTestCase): return - dict2 = round_trip_dict(self.klass, self._full_dict) - self.maxDiff = None - self.assertEqual(self._full_dict, dict2) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + dict2 = round_trip_dict(self.klass, self._full_dict) + self.maxDiff = None + self.assertEqual(self._full_dict, dict2) def _combine(self, d): items = itertools.chain( @@ -123,21 +126,25 @@ def test_round_trip_full(self): if type(self) == type(EntityTestCase): return - ent = self.klass.from_dict(self._full_dict) - ent2 = round_trip(ent, output=True) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + ent = self.klass.from_dict(self._full_dict) + ent2 = round_trip(ent, output=True) - #TODO: eventually we want to test the objects are the same, but for - # now, just make sure there aren't any errors. def _test_round_trip_dict(self, input): - dict2 = round_trip_dict(self.klass, input) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + dict2 = round_trip_dict(self.klass, input) - self.maxDiff = None - self.assertEqual(input, dict2) + self.maxDiff = None + self.assertEqual(input, dict2) def _test_partial_dict(self, partial): - d = self._combine(partial) - self._test_round_trip_dict(d) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + d = self._combine(partial) + self._test_round_trip_dict(d) class TypedListTestCase(object): @@ -145,6 +152,9 @@ def test_round_trip_rt(self): if type(self) == type(TypedListTestCase): return - obj = self.klass.from_dict(self._full_dict) - dict2 = obj.to_dict() - self.assertEqual(self._full_dict, dict2) \ No newline at end of file + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + + obj = self.klass.from_dict(self._full_dict) + dict2 = obj.to_dict() + self.assertEqual(self._full_dict, dict2) \ No newline at end of file From a92bcdf401ce09d1292eb677b9abd1ccbb5c86d7 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 4 May 2015 11:20:36 -0400 Subject: [PATCH 060/438] * Refactored idref_dprecated to be a general utility function rather than a decorator. * Added raise_warnings and silence_warnings function decorators. * Added idref deprecation tests for STIXPackage. --- stix/__init__.py | 1 - stix/common/related.py | 2 +- stix/core/__init__.py | 14 +++--- stix/core/stix_package.py | 3 +- stix/core/ttps.py | 16 ++++-- stix/test/__init__.py | 48 ++++++++---------- stix/test/core/stix_package_test.py | 78 ++++++++++++++++++++++++++++- stix/utils/__init__.py | 34 +++++++++++++ stix/utils/deprecated.py | 27 ++++------ 9 files changed, 164 insertions(+), 59 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index a4a3a71d..a2d920a4 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -7,7 +7,6 @@ BaseCoreComponent ) - #: Mapping of xsi:types to implementation/extension classes _EXTENSION_MAP = {} diff --git a/stix/common/related.py b/stix/common/related.py index dcc412e7..76045db8 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -459,8 +459,8 @@ class RelatedPackage(_BaseRelated): _inner_var = "Package" @_BaseRelated.item.setter - @idref_deprecated def item(self, value): + _BaseRelated.item.fset(self, value) class RelatedReport(_BaseRelated): diff --git a/stix/core/__init__.py b/stix/core/__init__.py index 58f97d7b..f5870750 100644 --- a/stix/core/__init__.py +++ b/stix/core/__init__.py @@ -30,8 +30,8 @@ class Campaigns(stix.EntityList): _inner_name = "campaigns" _dict_as_list = True - @idref_deprecated def _is_valid(self, value): + idref_deprecated(value) return stix.EntityList._is_valid(self, value) @@ -44,8 +44,8 @@ class CoursesOfAction(stix.EntityList): _inner_name = "courses_of_action" _dict_as_list = True - @idref_deprecated def _is_valid(self, value): + idref_deprecated(value) return stix.EntityList._is_valid(self, value) class ExploitTargets(stix.EntityList): @@ -57,8 +57,8 @@ class ExploitTargets(stix.EntityList): _inner_name = "exploit_targets" _dict_as_list = True - @idref_deprecated def _is_valid(self, value): + idref_deprecated(value) return stix.EntityList._is_valid(self, value) @@ -71,8 +71,8 @@ class Incidents(stix.EntityList): _inner_name = "incidents" _dict_as_list = True - @idref_deprecated def _is_valid(self, value): + idref_deprecated(value) return stix.EntityList._is_valid(self, value) @@ -85,8 +85,8 @@ class Indicators(stix.EntityList): _inner_name = "indicators" _dict_as_list = True - @idref_deprecated def _is_valid(self, value): + idref_deprecated(value) return stix.EntityList._is_valid(self, value) @@ -99,8 +99,8 @@ class ThreatActors(stix.EntityList): _inner_name = "threat_actors" _dict_as_list = True - @idref_deprecated def _is_valid(self, value): + idref_deprecated(value) return stix.EntityList._is_valid(self, value) @@ -113,8 +113,8 @@ class Reports(stix.EntityList): _inner_name = "reports" _dict_as_list = True - @idref_deprecated def _is_valid(self, value): + idref_deprecated(value) return stix.EntityList._is_valid(self, value) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index d35d1dcf..d1e02847 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -138,8 +138,9 @@ def observables(self): def observables(self, value): self._set_var(Observables, observables=value) - @idref_deprecated def add_observable(self, observable): + idref_deprecated(observable) + if not self.observables: self.observables = Observables(observables=observable) else: diff --git a/stix/core/ttps.py b/stix/core/ttps.py index 6128d135..fbbf74a4 100644 --- a/stix/core/ttps.py +++ b/stix/core/ttps.py @@ -2,11 +2,13 @@ # See LICENSE.txt for complete terms. import stix -from stix.utils.deprecated import idref_deprecated +import stix.utils as utils from stix.ttp import TTP -from stix.bindings import stix_core as core_binding from stix.common.kill_chains import KillChains +from stix.bindings import stix_core as core_binding +# deprecation warnings +from stix.utils.deprecated import idref_deprecated class TTPs(stix.EntityList): _binding = core_binding @@ -30,13 +32,17 @@ def ttps(self): @ttps.setter def ttps(self, value): self._inner = [] - self.append(value) + + if utils.is_sequence(value): + self.extend(value) + else: + self.append(value) def add_ttp(self, ttp): - self.ttps.append(ttp) + self.append(ttp) - @idref_deprecated def _is_valid(self, value): + idref_deprecated(value) return stix.EntityList._is_valid(self, value) def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/test/__init__.py b/stix/test/__init__.py index 5ce46e2f..70698bcd 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -3,12 +3,11 @@ import json import itertools -import warnings import cybox.utils import stix.bindings as bindings -from stix.utils import NamespaceInfo +from stix.utils import NamespaceInfo, silence_warnings def round_trip_dict(cls, dict_): @@ -102,16 +101,15 @@ def setUp(self): self.assertNotEqual(self.klass, None) self.assertNotEqual(self._full_dict, None) + @silence_warnings def test_round_trip_full_dict(self): # Don't run this test on the base class if type(self) == type(EntityTestCase): return - with warnings.catch_warnings(): - warnings.simplefilter('ignore') - dict2 = round_trip_dict(self.klass, self._full_dict) - self.maxDiff = None - self.assertEqual(self._full_dict, dict2) + dict2 = round_trip_dict(self.klass, self._full_dict) + self.maxDiff = None + self.assertEqual(self._full_dict, dict2) def _combine(self, d): items = itertools.chain( @@ -121,40 +119,36 @@ def _combine(self, d): return dict(items) + + @silence_warnings def test_round_trip_full(self): # Don't run this test on the base class if type(self) == type(EntityTestCase): return - with warnings.catch_warnings(): - warnings.simplefilter('ignore') - ent = self.klass.from_dict(self._full_dict) - ent2 = round_trip(ent, output=True) - + ent = self.klass.from_dict(self._full_dict) + ent2 = round_trip(ent, output=True) + @silence_warnings def _test_round_trip_dict(self, input): - with warnings.catch_warnings(): - warnings.simplefilter('ignore') - dict2 = round_trip_dict(self.klass, input) - - self.maxDiff = None - self.assertEqual(input, dict2) + dict2 = round_trip_dict(self.klass, input) + self.maxDiff = None + self.assertEqual(input, dict2) + @silence_warnings def _test_partial_dict(self, partial): - with warnings.catch_warnings(): - warnings.simplefilter('ignore') - d = self._combine(partial) - self._test_round_trip_dict(d) + d = self._combine(partial) + self._test_round_trip_dict(d) class TypedListTestCase(object): + + @silence_warnings def test_round_trip_rt(self): if type(self) == type(TypedListTestCase): return - with warnings.catch_warnings(): - warnings.simplefilter('ignore') + obj = self.klass.from_dict(self._full_dict) + dict2 = obj.to_dict() + self.assertEqual(self._full_dict, dict2) - obj = self.klass.from_dict(self._full_dict) - dict2 = obj.to_dict() - self.assertEqual(self._full_dict, dict2) \ No newline at end of file diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index 6ee62814..df53836e 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -4,14 +4,26 @@ import copy import StringIO import unittest +import warnings -from stix.test import EntityTestCase, report_test +from stix.test import EntityTestCase +from stix.test import report_test from stix.test.common import kill_chains_test, related_test from . import stix_header_test from stix import core from stix.core import stix_package +from stix.campaign import Campaign +from stix.coa import CourseOfAction +from stix.exploit_target import ExploitTarget +from stix.indicator import Indicator +from stix.incident import Incident +from stix.threat_actor import ThreatActor +from stix.ttp import TTP + +# utilities +from stix.utils import raise_warnings class CampaignsTests(EntityTestCase, unittest.TestCase): @@ -125,5 +137,69 @@ def test_deepcopy(self): self.assertEqual(package.timestamp, copied.timestamp) + @raise_warnings + def test_campaign_idref_deprecation(self): + package = core.STIXPackage() + self.assertRaises( + Warning, + package.add_campaign, + Campaign(idref='test-idref-dep') + ) + + @raise_warnings + def test_coa_idref_deprecation(self): + package = core.STIXPackage() + self.assertRaises( + Warning, + package.add, + CourseOfAction(idref='test-idref-dep') + ) + + @raise_warnings + def test_et_idref_deprecation(self): + package = core.STIXPackage() + self.assertRaises( + Warning, + package.add, + ExploitTarget(idref='test-idref-dep') + ) + + @raise_warnings + def test_incident_idref_deprecation(self): + package = core.STIXPackage() + self.assertRaises( + Warning, + package.add, + Incident(idref='test-idref-dep') + ) + + @raise_warnings + def test_indicator_idref_deprecation(self): + package = core.STIXPackage() + self.assertRaises( + Warning, + package.add, + Indicator(idref='test-idref-dep') + ) + + @raise_warnings + def test_ta_idref_deprecation(self): + package = core.STIXPackage() + self.assertRaises( + Warning, + package.add, + ThreatActor(idref='test-idref-dep') + ) + + @raise_warnings + def test_ttp_idref_deprecation(self): + package = core.STIXPackage() + self.assertRaises( + Warning, + package.add, + TTP(idref='test-idref-dep') + ) + + if __name__ == "__main__": unittest.main() diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index b1800539..578d2e86 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -5,6 +5,7 @@ import collections import contextlib import keyword +import functools import warnings # external @@ -335,10 +336,43 @@ def cast_var(item, klass, arg=None): def remove_entries(map, keys): + """Removes all the `keys` from `map`. + + Args: + map: A dictionary. + keys: An iterable collection of dictionary keys to remove. + + """ for key in keys: map.pop(key, None) +def raise_warnings(func): + """Function decorator that causes all Python warnings to be raised as + exceptions in the wrapped function. + + """ + @functools.wraps(func) + def inner(*args, **kwargs): + with warnings.catch_warnings(): + warnings.simplefilter('error') + return func(*args, **kwargs) + return inner + + +def silence_warnings(func): + """Function decorator that silences/ignores all Python warnings in the + wrapped function. + + """ + @functools.wraps(func) + def inner(*args, **kwargs): + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + return func(*args, **kwargs) + return inner + + # Namespace flattening from .nsparser import * # noqa from .dates import * # noqa diff --git a/stix/utils/deprecated.py b/stix/utils/deprecated.py index cc722b09..cbbaac50 100644 --- a/stix/utils/deprecated.py +++ b/stix/utils/deprecated.py @@ -1,27 +1,22 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -import functools import warnings -def idref_deprecated(func): - """Raises a python warning if the input value has an idref attribute - set. +def idref_deprecated(entity): + """Raises a Python UserWarning if `entity` arguments contains an idref + value. """ - @functools.wraps(func) - def inner(*args, **kwargs): - if kwargs: - val = next(kwargs.itervalues()) - else: - val = args[1] + if not getattr(entity, 'idref', None): + return + + fmt = ("The use of idrefs has been deprecated for this field. " + "Received '{0}' object with idref: '{1}'.") + + msg = fmt.format(type(entity).__name__, entity.idref) + warnings.warn(msg) - if getattr(val, 'idref', None): - msg = ("The use of idrefs has been deprecated for this field. " - "'{0}' object with idref: '{1}'.") - warnings.warn(msg.format(type(val).__name__, val.idref)) - return func(*args, **kwargs) - return inner \ No newline at end of file From 8d5acc898409563af05567d9bd83d6b1f4b33314 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 4 May 2015 12:27:54 -0400 Subject: [PATCH 061/438] * Added deprecated() to utils.deprecated. * Added idref_deprecated() call to RelatedPackage item setter. * Added deprecated() call to RelatedPackageRefs._is_valid() --- stix/common/related.py | 9 ++++++--- stix/test/core/stix_package_test.py | 11 +++++++++++ stix/utils/deprecated.py | 9 +++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/stix/common/related.py b/stix/common/related.py index 76045db8..6e33c104 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -3,7 +3,6 @@ # stdlib from __future__ import absolute_import -import warnings # internal import stix @@ -13,7 +12,7 @@ import stix.bindings.report as report_binding # deprecation warnings -from stix.utils.deprecated import idref_deprecated +from stix.utils.deprecated import idref_deprecated, deprecated # relative from .vocabs import VocabString @@ -290,6 +289,10 @@ class RelatedPackageRefs(stix.EntityList): _contained_type = RelatedPackageRef _inner_name = "packages" + def _is_valid(self, value): + deprecated(value) + return stix.EntityList._is_valid(self, value) + class _BaseRelated(GenericRelationship): """A base class for related types. @@ -460,7 +463,7 @@ class RelatedPackage(_BaseRelated): @_BaseRelated.item.setter def item(self, value): - + idref_deprecated(value) _BaseRelated.item.fset(self, value) class RelatedReport(_BaseRelated): diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index df53836e..a3eea2ec 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -200,6 +200,17 @@ def test_ttp_idref_deprecation(self): TTP(idref='test-idref-dep') ) + @raise_warnings + def test_related_package_idref_deprecation(self): + package = core.STIXPackage() + + # Entitylist._fix_value() will catch the Warning and re-raise + # as a ValueError + self.assertRaises( + ValueError, + package.add_related_package, + core.STIXPackage(idref='foo') + ) if __name__ == "__main__": unittest.main() diff --git a/stix/utils/deprecated.py b/stix/utils/deprecated.py index cbbaac50..ce10aa27 100644 --- a/stix/utils/deprecated.py +++ b/stix/utils/deprecated.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. import warnings +import functools def idref_deprecated(entity): @@ -19,4 +20,12 @@ def idref_deprecated(entity): warnings.warn(msg) +def deprecated(value): + if value is None: + return + + fmt = "The use of this field has been deprecated. Received '{0}' object." + + msg = fmt.format(type(value).__name__) + warnings.warn(msg) From f53be4822349a7a91e083792e822c0dfb983810c Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 4 May 2015 12:40:50 -0400 Subject: [PATCH 062/438] General cleanup. Use silence_warnings decorator rather than catch_warnings() explicitly. --- stix/bindings/extensions/malware/maec_4_1.py | 2 + stix/coa/objective.py | 1 - stix/common/__init__.py | 1 - stix/common/activity.py | 1 - stix/common/datetimewithprecision.py | 8 +- stix/data_marking.py | 4 +- stix/exploit_target/weakness.py | 1 - stix/extensions/identity/ciq_identity_3_0.py | 11 +-- .../test_mechanism/generic_test_mechanism.py | 1 - stix/incident/external_id.py | 7 +- stix/test/core/stix_package_test.py | 1 - stix/test/utils/nsparser_test.py | 16 ++- stix/utils/__init__.py | 99 +++++++++---------- stix/utils/idgen.py | 6 +- stix/utils/nsparser.py | 2 +- 15 files changed, 74 insertions(+), 87 deletions(-) diff --git a/stix/bindings/extensions/malware/maec_4_1.py b/stix/bindings/extensions/malware/maec_4_1.py index dd86bcf9..44aefc15 100644 --- a/stix/bindings/extensions/malware/maec_4_1.py +++ b/stix/bindings/extensions/malware/maec_4_1.py @@ -11,10 +11,12 @@ import sys from stix.bindings import * import stix.bindings.ttp as ttp_binding + try: from maec.bindings.maec_package import PackageType maec_installed = True except ImportError: + PackageType = None maec_installed = False XML_NS = "http://stix.mitre.org/extensions/Malware#MAEC4.1-1" diff --git a/stix/coa/objective.py b/stix/coa/objective.py index 0fc35f16..0c7a5764 100644 --- a/stix/coa/objective.py +++ b/stix/coa/objective.py @@ -2,7 +2,6 @@ # See LICENSE.txt for complete terms. import stix -import stix.utils as utils from stix.common import StructuredTextList, Confidence import stix.bindings.course_of_action as coa_binding diff --git a/stix/common/__init__.py b/stix/common/__init__.py index d5450373..5782fe1b 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -48,7 +48,6 @@ RelatedReport._base_type = Report # noqa RelatedCampaignRef._base_type = CampaignRef # noqa - # Patch contained types RelatedPackages._contained_type = RelatedPackage # noqa RelatedReports._contained_type = RelatedReport # noqa diff --git a/stix/common/activity.py b/stix/common/activity.py index fd2a8eb7..ed4e23aa 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -2,7 +2,6 @@ # See LICENSE.txt for complete terms. import stix -import stix.utils as utils import stix.bindings.stix_common as common_binding from .datetimewithprecision import DateTimeWithPrecision diff --git a/stix/common/datetimewithprecision.py b/stix/common/datetimewithprecision.py index 248da5f2..503e706e 100644 --- a/stix/common/datetimewithprecision.py +++ b/stix/common/datetimewithprecision.py @@ -66,9 +66,11 @@ def to_dict(self): if self.precision == 'second': return utils.dates.serialize_value(self.value) - d = {} - d['value'] = utils.dates.serialize_value(self.value) - d['precision'] = self.precision + d = { + 'value': utils.dates.serialize_value(self.value), + 'precision':self.precision + } + return d @classmethod diff --git a/stix/data_marking.py b/stix/data_marking.py index 5f8d9747..7feb131e 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -253,8 +253,8 @@ def from_dict(cls, d, return_obj=None): m.marking_model_ref = d.get('marking_model_ref') else: if 'xsi:type' in d: - cls = MarkingStructure.lookup_class(d.get('xsi:type')) - m = cls.from_dict(d) + klass = MarkingStructure.lookup_class(d.get('xsi:type')) + m = klass.from_dict(d) else: m = cls.from_dict(d, cls()) diff --git a/stix/exploit_target/weakness.py b/stix/exploit_target/weakness.py index 287ba97e..1bb9c9e3 100644 --- a/stix/exploit_target/weakness.py +++ b/stix/exploit_target/weakness.py @@ -2,7 +2,6 @@ # See LICENSE.txt for complete terms. import stix -import stix.utils as utils import stix.bindings.exploit_target as exploit_target_binding from stix.common import StructuredTextList diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index 75e45af8..e20e6185 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -6,7 +6,6 @@ import stix import stix.utils as utils import stix.common as common -import stix.common.identity as identity import stix.bindings.extensions.identity.ciq_identity_3_0 as ciq_identity_binding @@ -967,8 +966,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - d = {} - d['value'] = self.value + d = {'value': self.value} if self.type: d['type'] = self.type @@ -1292,8 +1290,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - d = {} - d['value'] = self.value + d = {'value': self.value} if self.element_type: d['element_type'] = self.element_type @@ -1446,8 +1443,8 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - d = {} - d['value'] = self.value + d = {'value': self.value} + if self.type: d['type'] = self.type diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index 13082be9..ba8d35e9 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -2,7 +2,6 @@ # See LICENSE.txt for complete terms. import stix -import stix.utils as utils import stix.indicator.test_mechanism from stix.common import EncodedCDATA, StructuredTextList, VocabString from stix.indicator.test_mechanism import _BaseTestMechanism diff --git a/stix/incident/external_id.py b/stix/incident/external_id.py index dcb86d5b..85eb4cd3 100644 --- a/stix/incident/external_id.py +++ b/stix/incident/external_id.py @@ -52,9 +52,10 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): - d = {} - d['value'] = self.value - d['source'] = self.source + d = { + 'value': self.value, + 'source': self.source + } return d @classmethod diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index a3eea2ec..3ac3c1cd 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -4,7 +4,6 @@ import copy import StringIO import unittest -import warnings from stix.test import EntityTestCase from stix.test import report_test diff --git a/stix/test/utils/nsparser_test.py b/stix/test/utils/nsparser_test.py index 9b3ee82d..2e6baaad 100644 --- a/stix/test/utils/nsparser_test.py +++ b/stix/test/utils/nsparser_test.py @@ -12,7 +12,7 @@ # internal import stix from stix.core import STIXPackage -from stix.utils import nsparser +from stix.utils import nsparser, silence_warnings NSMAP = { @@ -76,6 +76,8 @@ def test_namespace_collect(self): self.assertTrue(all(ns in namespaces for ns in NSMAP.iterkeys())) + + @silence_warnings def test_user_provided_ns(self): """Test that user-provided namespaces are serialized. @@ -102,12 +104,9 @@ def test_user_provided_ns(self): self.assertEqual(finalized.get(TEST_PREFIX), TEST_NS) self.assertEqual(finalized.get(NEW_STIX_PREFIX), NEW_STIX_NS) - with warnings.catch_warnings(): - warnings.simplefilter('ignore') - xml = p.to_xml(ns_dict=test_dict) - # Parse the exported document and make sure that the namespaces # made it through the serialization process. + xml = p.to_xml(ns_dict=test_dict) e = lxml.etree.XML(xml) self.assertEqual(e.nsmap.get(TEST_PREFIX), TEST_NS) self.assertEqual(e.nsmap.get(NEW_STIX_PREFIX), NEW_STIX_NS) @@ -144,6 +143,8 @@ def test_duplicate_ns_prefix(self): p.to_xml ) + + @silence_warnings def test_parsed_namespaces(self): """Test that non-default namespaces make it through the parse-serialize process. @@ -170,10 +171,7 @@ def test_parsed_namespaces(self): sio = StringIO.StringIO(xml) p = STIXPackage.from_xml(sio) - with warnings.catch_warnings(): - warnings.simplefilter('ignore') - serialized = p.to_xml() - + serialized = p.to_xml() e = lxml.etree.XML(serialized) self.assertEqual(e.nsmap.get('TEST'), 'a:test') self.assertEqual(e.nsmap.get('FOO'), 'a:foo') diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index 578d2e86..31e372ef 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -2,11 +2,10 @@ # See LICENSE.txt for complete terms. # stdlib -import collections import contextlib import keyword import functools -import warnings + # external import cybox @@ -37,6 +36,32 @@ def ignored(*exceptions): pass +def raise_warnings(func): + """Function decorator that causes all Python warnings to be raised as + exceptions in the wrapped function. + + """ + @functools.wraps(func) + def inner(*args, **kwargs): + with warnings.catch_warnings(): + warnings.simplefilter('error') + return func(*args, **kwargs) + return inner + + +def silence_warnings(func): + """Function decorator that silences/ignores all Python warnings in the + wrapped function. + + """ + @functools.wraps(func) + def inner(*args, **kwargs): + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + return func(*args, **kwargs) + return inner + + def is_cdata(text): if not text: return False @@ -250,6 +275,7 @@ def has_value(var): return bool(var) or (var in (False, 0)) +@silence_warnings def to_dict(entity, skip=()): """Returns a dictionary representation of `entity`. This will iterate over the instance vars of `entity` and construct keys and values from those @@ -268,33 +294,26 @@ def to_dict(entity, skip=()): def dict_iter(items): return [x.to_dict() if is_dictable(x) else x for x in items] - def dictify(entity): - d = {} - for name, field in iter_vars(entity): - key = key_name(name) - - if key in skip or not has_value(field): - continue - - if is_dictable(field): - d[key] = field.to_dict() - elif is_timestamp(field): - d[key] = dates.serialize_value(field) - elif is_date(field): - d[key] = dates.serialize_date(field) - elif is_element(field) or is_etree(field): - d[key] = lxml.etree.tostring(field) - elif is_sequence(field): - d[key] = dict_iter(field) - else: - d[key] = field - - return d d = {} - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - d.update(dictify(entity)) + for name, field in iter_vars(entity): + key = key_name(name) + + if key in skip or not has_value(field): + continue + + if is_dictable(field): + d[key] = field.to_dict() + elif is_timestamp(field): + d[key] = dates.serialize_value(field) + elif is_date(field): + d[key] = dates.serialize_date(field) + elif is_element(field) or is_etree(field): + d[key] = lxml.etree.tostring(field) + elif is_sequence(field): + d[key] = dict_iter(field) + else: + d[key] = field return d @@ -347,32 +366,6 @@ def remove_entries(map, keys): map.pop(key, None) -def raise_warnings(func): - """Function decorator that causes all Python warnings to be raised as - exceptions in the wrapped function. - - """ - @functools.wraps(func) - def inner(*args, **kwargs): - with warnings.catch_warnings(): - warnings.simplefilter('error') - return func(*args, **kwargs) - return inner - - -def silence_warnings(func): - """Function decorator that silences/ignores all Python warnings in the - wrapped function. - - """ - @functools.wraps(func) - def inner(*args, **kwargs): - with warnings.catch_warnings(): - warnings.simplefilter('ignore') - return func(*args, **kwargs) - return inner - - # Namespace flattening from .nsparser import * # noqa from .dates import * # noqa diff --git a/stix/utils/idgen.py b/stix/utils/idgen.py index 32da0ddb..ecb661db 100644 --- a/stix/utils/idgen.py +++ b/stix/utils/idgen.py @@ -66,7 +66,7 @@ def create_id(self, prefix="guid"): else: raise InvalidMethodError(self.method) - ns_prefix = self.namespace.itervalues().next() + ns_prefix = next(self.namespace.itervalues()) return "%s:%s-%s" % (ns_prefix, prefix, id_) @@ -110,12 +110,12 @@ def set_id_method(method): def get_id_namespace(): """Return the namespace associated with generated ids""" - return _get_generator().namespace.iterkeys().next() + return next(_get_generator().namespace.iterkeys()) def get_id_namespace_alias(): """Returns the namespace alias assoicated with generated ids""" - return _get_generator().namespace.itervalues().next() + return next(_get_generator().namespace.itervalues()) def create_id(prefix=None): diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index 00f46fc3..0574f0a5 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -216,7 +216,7 @@ def _finalize_namespaces(self, ns_dict=None): collected_prefixed = dict(self._collected_namespaces.iteritems()) # Pop the unprefixed entries. - no_prefix = collected_prefixed.pop(None, ()) + no_prefix = collected_prefixed.pop(None, set()) # Resolve namespace aliases for the unprefixed namespaces. collected_unprefixed = self._resolve_unprefixed(no_prefix) From abbb32b7ace84b5362664ef801ed4160b97180af Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 5 May 2015 10:47:55 -0400 Subject: [PATCH 063/438] Added related_packages to incident and ttp --- stix/common/related.py | 26 ++++++++++++++++++++++---- stix/incident/__init__.py | 25 ++++++++++++++++++++----- stix/ttp/__init__.py | 17 +++++++++++++++++ 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/stix/common/related.py b/stix/common/related.py index 6e33c104..24f08f85 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -114,10 +114,17 @@ class RelatedPackageRef(GenericRelationship): _binding = common_binding _binding_class = common_binding.RelatedPackageRefType - def __init__(self, **kwargs): - super(RelatedPackageRef, self).__init__(**kwargs) - self.idref = None - self.timestamp = None + def __init__(self, idref=None, timestamp=None, confidence=None, + information_source=None, relationship=None): + + super(RelatedPackageRef, self).__init__( + confidence=confidence, + information_source=information_source, + relationship=relationship + ) + + self.idref = idref + self.timestamp = timestamp def to_obj(self, return_obj=None, ns_info=None): if not return_obj: @@ -289,6 +296,17 @@ class RelatedPackageRefs(stix.EntityList): _contained_type = RelatedPackageRef _inner_name = "packages" + def _fix_value(self, value): + from stix.core import STIXPackage + + if isinstance(value, STIXPackage) and value.id_: + return RelatedPackageRef(idref=value.id_, timestamp=value.timestamp) + + fmt = ("Cannot add type '{0}' to RelatedPackageRefs collection. " + "Expected RelatedPackageRef or STIXPackage") + error = fmt.format(type(value)) + raise TypeError(error) + def _is_valid(self, value): deprecated(value) return stix.EntityList._is_valid(self, value) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index f91ba101..d44491f7 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -5,12 +5,11 @@ import stix import stix.bindings.incident as incident_binding from stix.common import ( - vocabs, Identity, Statement, VocabString, - InformationSource, Confidence + vocabs, Identity, Statement, VocabString,InformationSource, Confidence ) from stix.common.related import ( GenericRelationshipList, RelatedIndicator, RelatedThreatActor, RelatedTTP, - RelatedObservable, RelatedIncident + RelatedObservable, RelatedIncident, RelatedPackageRefs ) from stix.data_marking import Marking @@ -49,6 +48,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, description self.related_indicators = RelatedIndicators() self.related_observables = RelatedObservables() self.related_incidents = RelatedIncidents() + self.related_packages = RelatedPackageRefs() self.affected_assets = None self.categories = None self.intended_effects = None @@ -313,6 +313,17 @@ def add_related_observable(self, value): """ self.related_observables.append(value) + @property + def related_packages(self): + return self._related_packages + + @related_packages.setter + def related_packages(self, value): + self._related_packages = RelatedPackageRefs(value) + + def add_related_package(self, value): + self.related_packages.append(value) + def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() @@ -365,6 +376,8 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Handling = self.handling.to_obj(ns_info=ns_info) if self.history: return_obj.History = self.history.to_obj(ns_info=ns_info) + if self.related_packages: + return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) return return_obj @@ -402,7 +415,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.reporter = InformationSource.from_obj(obj.Reporter) return_obj.impact_assessment = ImpactAssessment.from_obj(obj.Impact_Assessment) return_obj.security_compromise = VocabString.from_obj(obj.Security_Compromise) - + return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) + return return_obj def to_dict(self): @@ -442,7 +456,8 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.status = VocabString.from_dict(get('status')) return_obj.handling = Marking.from_dict(get('handling')) return_obj.history = History.from_dict(get('history')) - + return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) + return return_obj diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index 9afd618c..54885be2 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -6,6 +6,7 @@ import stix.bindings.ttp as ttp_binding from stix.common import vocabs, Statement from stix.data_marking import Marking +from stix.common.related import RelatedPackageRefs # relative from .behavior import Behavior @@ -40,6 +41,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.victim_targeting = None self.handling = None self.exploit_targets = ExploitTargets() + self.related_packages = None @property def behavior(self): @@ -106,6 +108,17 @@ def handling(self): def handling(self, value): self._set_var(Marking, try_cast=False, handling=value) + @property + def related_packages(self): + return self._related_packages + + @related_packages.setter + def related_packages(self, value): + self._related_packages = RelatedPackageRefs(value) + + def add_related_package(self, value): + self.related_packages.append(value) + def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() @@ -126,6 +139,8 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Victim_Targeting = self.victim_targeting.to_obj(ns_info=ns_info) if self.handling: return_obj.Handling = self.handling.to_obj(ns_info=ns_info) + if self.related_packages: + return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) return return_obj @@ -147,6 +162,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.victim_targeting = VictimTargeting.from_obj(obj.Victim_Targeting) return_obj.handling = Marking.from_obj(obj.Handling) return_obj.intended_effects = _IntendedEffects.from_obj(obj.Intended_Effect) + return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) return return_obj @@ -171,6 +187,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.resources = Resource.from_dict(get('resources')) return_obj.victim_targeting = VictimTargeting.from_dict(get('victim_targeting')) return_obj.handling = Marking.from_dict(get('handling')) + return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) return return_obj From 74fde8b5b81b8fa2de17837f47fc8541b698088a Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 5 May 2015 10:48:38 -0400 Subject: [PATCH 064/438] Modified silence_warnings to use 'always' filter but redirect message to buffer. Added sequence check on deprecated() --- stix/utils/__init__.py | 4 ++-- stix/utils/deprecated.py | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index 31e372ef..d5f5cd5b 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -56,8 +56,8 @@ def silence_warnings(func): """ @functools.wraps(func) def inner(*args, **kwargs): - with warnings.catch_warnings(): - warnings.simplefilter('ignore') + with warnings.catch_warnings(record=True): + warnings.simplefilter('always') return func(*args, **kwargs) return inner diff --git a/stix/utils/deprecated.py b/stix/utils/deprecated.py index ce10aa27..7d56fb96 100644 --- a/stix/utils/deprecated.py +++ b/stix/utils/deprecated.py @@ -2,7 +2,8 @@ # See LICENSE.txt for complete terms. import warnings -import functools + +from . import is_sequence def idref_deprecated(entity): @@ -21,11 +22,20 @@ def idref_deprecated(entity): def deprecated(value): + """Raises a Python UserWarning if `value` is not None. + + This is typically going to be used inside setter functions for deprecated + fields. The deprecation warning shouldn't be raised when the field is being + initialized to ``None``. + + """ if value is None: return - fmt = "The use of this field has been deprecated. Received '{0}' object." + if is_sequence(value) and not value: + return + fmt = "The use of this field has been deprecated. Received '{0}' object." msg = fmt.format(type(value).__name__) warnings.warn(msg) From d4e72ac119d9b3e29faffe2784ab1c2ebb464677 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 5 May 2015 10:49:02 -0400 Subject: [PATCH 065/438] Added assert_warnings() decorator for testing warning output --- stix/test/__init__.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/stix/test/__init__.py b/stix/test/__init__.py index 70698bcd..9acfc09e 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -3,6 +3,8 @@ import json import itertools +import warnings +import functools import cybox.utils @@ -10,6 +12,20 @@ from stix.utils import NamespaceInfo, silence_warnings +def assert_warnings(func): + @functools.wraps(func) + def inner(*args, **kwargs): + self = args[0] + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + results = func(*args, **kwargs) + self.assertTrue(len(w) > 0) + return results + + return inner + + def round_trip_dict(cls, dict_): obj = cls.object_from_dict(dict_) dict2 = cls.dict_from_object(obj) From 11d2b717aa508a2cfc30df37c1d8ca6f7c1f2da3 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 5 May 2015 10:49:32 -0400 Subject: [PATCH 066/438] * Changed raise_warnings to assert_warnings on warning tests. * Added tests for RelatedPackageRefs deprecation warnings. * Added tests for RelatedPackages deprecation warnings. --- stix/test/campaign_test.py | 10 +++- stix/test/coa_test.py | 15 ++++-- stix/test/common/related_test.py | 31 ++++++++++++- stix/test/core/stix_package_test.py | 72 +++++++---------------------- stix/test/exploit_target_test.py | 9 +++- stix/test/incident_test.py | 12 ++++- stix/test/indicator_test.py | 39 +++++++++++++++- stix/test/threat_actor_test.py | 10 +++- stix/test/ttp_test.py | 13 +++++- 9 files changed, 142 insertions(+), 69 deletions(-) mode change 100644 => 100755 stix/test/campaign_test.py diff --git a/stix/test/campaign_test.py b/stix/test/campaign_test.py old mode 100644 new mode 100755 index b2b388d4..5fcc0870 --- a/stix/test/campaign_test.py +++ b/stix/test/campaign_test.py @@ -3,12 +3,15 @@ import unittest -from stix.test import EntityTestCase, TypedListTestCase, data_marking_test +from stix.test import EntityTestCase, TypedListTestCase, assert_warnings +import stix.test.data_marking_test as data_marking_test from stix.test.common import ( confidence_test, information_source_test, statement_test, related_test, activity_test ) +from stix.test import assert_warnings +from stix.core import STIXPackage import stix.campaign as campaign @@ -153,6 +156,11 @@ def test_add_short_description(self): o2.short_descriptions.to_dict() ) + @assert_warnings + def test_deprecated_related_packages(self): + c = campaign.Campaign() + c.related_packages.append(STIXPackage()) + if __name__ == "__main__": unittest.main() diff --git a/stix/test/coa_test.py b/stix/test/coa_test.py index 02f1ee53..d7d05df5 100644 --- a/stix/test/coa_test.py +++ b/stix/test/coa_test.py @@ -3,15 +3,17 @@ import unittest -from stix.test import EntityTestCase, data_marking_test -from stix.test.common import ( - confidence_test, information_source_test, statement_test, related_test, -) +from stix.test import EntityTestCase, assert_warnings +from stix.test import data_marking_test +from stix.test.common import (confidence_test, information_source_test, + statement_test, related_test) +from stix.core import STIXPackage from stix.test.extensions.structured_coa import generic_test import stix.coa as coa import stix.coa.objective as objective + class RelatedCOAsTests(EntityTestCase, unittest.TestCase): klass = coa.RelatedCOAs @@ -112,6 +114,11 @@ def should_fail(): self.assertTrue(str(coa_.structured_coa.description) == "SUCCESS") + @assert_warnings + def test_deprecated_related_packages(self): + c = coa.CourseOfAction() + c.related_packages.append(STIXPackage()) + if __name__ == "__main__": unittest.main() diff --git a/stix/test/common/related_test.py b/stix/test/common/related_test.py index 7294eee1..e41a4b66 100644 --- a/stix/test/common/related_test.py +++ b/stix/test/common/related_test.py @@ -3,8 +3,9 @@ import unittest -from stix.test import EntityTestCase +from stix.test import EntityTestCase, assert_warnings +from stix.utils import silence_warnings from stix.common.related import ( RelatedCampaign, RelatedCampaignRef, RelatedIdentity, RelatedCOA, RelatedPackage, RelatedPackageRef, RelatedExploitTarget, RelatedIncident, @@ -94,6 +95,34 @@ class RelatedPackageRefsTests(EntityTestCase, unittest.TestCase): ] } + @silence_warnings + def test_add_stix_package(self): + from stix.core import STIXPackage + + l = RelatedPackageRefs() + l.append(STIXPackage()) + + self.assertEqual(1, len(l)) + + + @silence_warnings + def test_add_bad_type(self): + from stix.indicator import Indicator + + l = RelatedPackageRefs() + + self.assertRaises( + TypeError, + l.append, + Indicator() + ) + + @assert_warnings + def test_deprecated_warning(self): + from stix.core import STIXPackage + + l = RelatedPackageRefs() + l.append(STIXPackage()) class RelatedPackageRefTests(EntityTestCase, unittest.TestCase): diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index 3ac3c1cd..b589afb3 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -5,7 +5,7 @@ import StringIO import unittest -from stix.test import EntityTestCase +from stix.test import EntityTestCase, assert_warnings from stix.test import report_test from stix.test.common import kill_chains_test, related_test @@ -21,9 +21,6 @@ from stix.threat_actor import ThreatActor from stix.ttp import TTP -# utilities -from stix.utils import raise_warnings - class CampaignsTests(EntityTestCase, unittest.TestCase): klass = stix_package.Campaigns @@ -135,81 +132,46 @@ def test_deepcopy(self): copied = copy.deepcopy(package) self.assertEqual(package.timestamp, copied.timestamp) - - @raise_warnings + @assert_warnings def test_campaign_idref_deprecation(self): package = core.STIXPackage() - self.assertRaises( - Warning, - package.add_campaign, - Campaign(idref='test-idref-dep') - ) + package.add(Campaign(idref='test-idref-dep')) - @raise_warnings + @assert_warnings def test_coa_idref_deprecation(self): package = core.STIXPackage() - self.assertRaises( - Warning, - package.add, - CourseOfAction(idref='test-idref-dep') - ) + package.add(CourseOfAction(idref='test-idref-dep')) - @raise_warnings + @assert_warnings def test_et_idref_deprecation(self): package = core.STIXPackage() - self.assertRaises( - Warning, - package.add, - ExploitTarget(idref='test-idref-dep') - ) + package.add(ExploitTarget(idref='test-idref-dep')) - @raise_warnings + @assert_warnings def test_incident_idref_deprecation(self): package = core.STIXPackage() - self.assertRaises( - Warning, - package.add, - Incident(idref='test-idref-dep') - ) + package.add(Incident(idref='test-idref-dep')) - @raise_warnings + @assert_warnings def test_indicator_idref_deprecation(self): package = core.STIXPackage() - self.assertRaises( - Warning, - package.add, - Indicator(idref='test-idref-dep') - ) + package.add(Indicator(idref='test-idref-dep')) - @raise_warnings + @assert_warnings def test_ta_idref_deprecation(self): package = core.STIXPackage() - self.assertRaises( - Warning, - package.add, - ThreatActor(idref='test-idref-dep') - ) + package.add(ThreatActor(idref='test-idref-dep')) - @raise_warnings + @assert_warnings def test_ttp_idref_deprecation(self): package = core.STIXPackage() - self.assertRaises( - Warning, - package.add, - TTP(idref='test-idref-dep') - ) + package.add(TTP(idref='test-idref-dep')) - @raise_warnings + @assert_warnings def test_related_package_idref_deprecation(self): package = core.STIXPackage() + package.add_related_package(core.STIXPackage(idref='foo')) - # Entitylist._fix_value() will catch the Warning and re-raise - # as a ValueError - self.assertRaises( - ValueError, - package.add_related_package, - core.STIXPackage(idref='foo') - ) if __name__ == "__main__": unittest.main() diff --git a/stix/test/exploit_target_test.py b/stix/test/exploit_target_test.py index b58b5255..c9564bed 100644 --- a/stix/test/exploit_target_test.py +++ b/stix/test/exploit_target_test.py @@ -3,9 +3,11 @@ import unittest -from stix.test import EntityTestCase, TypedListTestCase, data_marking_test +from stix.test import EntityTestCase, TypedListTestCase, assert_warnings +from stix.test import data_marking_test from stix.test.common import information_source_test, related_test +from stix.core import STIXPackage import stix.exploit_target as et from stix.exploit_target import weakness, vulnerability, configuration @@ -167,5 +169,10 @@ def test_add_short_description(self): o2.short_descriptions.to_dict() ) + @assert_warnings + def test_deprecated_related_packages(self): + e = et.ExploitTarget() + e.related_packages.append(STIXPackage()) + if __name__ == "__main__": unittest.main() diff --git a/stix/test/incident_test.py b/stix/test/incident_test.py index eaf79a98..b4d5ead9 100644 --- a/stix/test/incident_test.py +++ b/stix/test/incident_test.py @@ -4,9 +4,11 @@ import unittest import StringIO +from stix.core import STIXPackage from cybox.common import StructuredText -from stix.test import EntityTestCase, TypedListTestCase, data_marking_test +from stix.test import EntityTestCase, TypedListTestCase, assert_warnings +from stix.test import data_marking_test from stix.test.common import ( confidence_test, information_source_test, statement_test, related_test ) @@ -464,7 +466,8 @@ class IncidentTest(EntityTestCase, unittest.TestCase): 'related_incidents': RelatedIncidentsTests._full_dict, 'intended_effects': IntendedEffectsTests._full_dict, 'discovery_methods': DiscoveryMethodsTests._full_dict, - 'confidence': confidence_test.ConfidenceTests._full_dict + 'confidence': confidence_test.ConfidenceTests._full_dict, + 'related_packages': related_test.RelatedPackageRefsTests._full_dict, } def test_parse_category(self): @@ -561,6 +564,11 @@ def test_add_short_description(self): o2.short_descriptions.to_dict() ) + @assert_warnings + def test_deprecated_related_packages(self): + i = incident.Incident() + i.related_packages.append(STIXPackage()) + if __name__ == "__main__": unittest.main() diff --git a/stix/test/indicator_test.py b/stix/test/indicator_test.py index 38b6f785..3e095e70 100644 --- a/stix/test/indicator_test.py +++ b/stix/test/indicator_test.py @@ -3,8 +3,12 @@ import unittest -from stix.indicator import Indicator -from stix.test import EntityTestCase, round_trip, round_trip_dict +from stix.core import STIXPackage +from stix.indicator import Indicator, RelatedCampaignRefs + +from stix.test import EntityTestCase, assert_warnings +from stix.test.common import related_test + class IndicatorTest(EntityTestCase, unittest.TestCase): klass = Indicator @@ -433,6 +437,37 @@ def test_add_short_description(self): o2.short_descriptions.to_dict() ) + @assert_warnings + def test_deprecated_related_packages(self): + i = Indicator() + i.related_packages.append(STIXPackage()) + + +class RelatedCampaignReferencesTests(unittest.TestCase, EntityTestCase): + klass = RelatedCampaignRefs + _full_dict = { + 'related_campaigns': [ + related_test.RelatedCampaignRefTests._full_dict + ] + } + + def test_add_campaign(self): + from stix.campaign import Campaign + + l = RelatedCampaignRefs() + l.append(Campaign()) + + self.assertEqual(1, len(l)) + + def test_append_bad_type(self): + l = RelatedCampaignRefs() + + self.assertRaises( + Exception, + l.append, + Indicator() + ) + if __name__ == "__main__": unittest.main() diff --git a/stix/test/threat_actor_test.py b/stix/test/threat_actor_test.py index 29fc7ed1..cb876594 100644 --- a/stix/test/threat_actor_test.py +++ b/stix/test/threat_actor_test.py @@ -3,7 +3,10 @@ import unittest -from stix.test import EntityTestCase, TypedListTestCase, data_marking_test +from stix.core import STIXPackage + +from stix.test import EntityTestCase, TypedListTestCase, assert_warnings +from stix.test import data_marking_test from stix.test.common import ( confidence_test, information_source_test, related_test,identity_test ) @@ -157,5 +160,10 @@ def test_add_short_description(self): o2.short_descriptions.to_dict() ) + @assert_warnings + def test_deprecated_related_packages(self): + i = ta.ThreatActor() + i.related_packages.append(STIXPackage()) + if __name__ == "__main__": unittest.main() diff --git a/stix/test/ttp_test.py b/stix/test/ttp_test.py index 0559d0be..b4b46b47 100644 --- a/stix/test/ttp_test.py +++ b/stix/test/ttp_test.py @@ -3,9 +3,11 @@ import unittest -from stix.test import EntityTestCase, data_marking_test +from stix.test import EntityTestCase, assert_warnings +from stix.test import data_marking_test from stix.test.common import related_test, identity_test +from stix.core import STIXPackage import stix.ttp as ttp from stix.ttp import ( resource, infrastructure, exploit_targets, malware_instance, exploit, @@ -146,7 +148,8 @@ class TTPTests(EntityTestCase, unittest.TestCase): 'resources': ResourcesTests._full_dict, 'handling': data_marking_test.MarkingTests._full_dict, 'exploit_targets': ExploitTargetsTests._full_dict, - 'behavior': BehaviorTests._full_dict + 'behavior': BehaviorTests._full_dict, + 'related_packages': related_test.RelatedPackageRefsTests._full_dict, } def test_add_description(self): @@ -173,5 +176,11 @@ def test_add_short_description(self): o2.short_descriptions.to_dict() ) + @assert_warnings + def test_deprecated_related_packages(self): + t = ttp.TTP() + t.related_packages.append(STIXPackage()) + + if __name__ == "__main__": unittest.main() From 524d04feec041f5f0c4663da84146bb53bfe83b1 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 5 May 2015 11:01:28 -0400 Subject: [PATCH 067/438] Added length assertions to related_package deprecation tests. --- stix/test/coa_test.py | 1 + stix/test/exploit_target_test.py | 1 + stix/test/incident_test.py | 1 + stix/test/indicator_test.py | 1 + stix/test/threat_actor_test.py | 5 +++-- stix/test/ttp_test.py | 1 + 6 files changed, 8 insertions(+), 2 deletions(-) diff --git a/stix/test/coa_test.py b/stix/test/coa_test.py index d7d05df5..b66c6591 100644 --- a/stix/test/coa_test.py +++ b/stix/test/coa_test.py @@ -118,6 +118,7 @@ def should_fail(): def test_deprecated_related_packages(self): c = coa.CourseOfAction() c.related_packages.append(STIXPackage()) + self.assertEqual(len(c.related_packages), 1) if __name__ == "__main__": diff --git a/stix/test/exploit_target_test.py b/stix/test/exploit_target_test.py index c9564bed..2395fa4e 100644 --- a/stix/test/exploit_target_test.py +++ b/stix/test/exploit_target_test.py @@ -173,6 +173,7 @@ def test_add_short_description(self): def test_deprecated_related_packages(self): e = et.ExploitTarget() e.related_packages.append(STIXPackage()) + self.assertEqual(len(e.related_packages), 1) if __name__ == "__main__": unittest.main() diff --git a/stix/test/incident_test.py b/stix/test/incident_test.py index b4d5ead9..c4e26440 100644 --- a/stix/test/incident_test.py +++ b/stix/test/incident_test.py @@ -568,6 +568,7 @@ def test_add_short_description(self): def test_deprecated_related_packages(self): i = incident.Incident() i.related_packages.append(STIXPackage()) + self.assertEqual(len(i.related_packages), 1) if __name__ == "__main__": diff --git a/stix/test/indicator_test.py b/stix/test/indicator_test.py index 3e095e70..2aa218f9 100644 --- a/stix/test/indicator_test.py +++ b/stix/test/indicator_test.py @@ -441,6 +441,7 @@ def test_add_short_description(self): def test_deprecated_related_packages(self): i = Indicator() i.related_packages.append(STIXPackage()) + self.assertEqual(len(i.related_packages), 1) class RelatedCampaignReferencesTests(unittest.TestCase, EntityTestCase): diff --git a/stix/test/threat_actor_test.py b/stix/test/threat_actor_test.py index cb876594..e4571ccd 100644 --- a/stix/test/threat_actor_test.py +++ b/stix/test/threat_actor_test.py @@ -162,8 +162,9 @@ def test_add_short_description(self): @assert_warnings def test_deprecated_related_packages(self): - i = ta.ThreatActor() - i.related_packages.append(STIXPackage()) + t = ta.ThreatActor() + t.related_packages.append(STIXPackage()) + self.assertEqual(len(t.related_packages), 1) if __name__ == "__main__": unittest.main() diff --git a/stix/test/ttp_test.py b/stix/test/ttp_test.py index b4b46b47..88ebd81b 100644 --- a/stix/test/ttp_test.py +++ b/stix/test/ttp_test.py @@ -180,6 +180,7 @@ def test_add_short_description(self): def test_deprecated_related_packages(self): t = ttp.TTP() t.related_packages.append(STIXPackage()) + self.assertEqual(len(t.related_packages), 1) if __name__ == "__main__": From 0e50ab45ce748ef732bd915b231e006459ae3ee0 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 5 May 2015 11:03:47 -0400 Subject: [PATCH 068/438] Added docstrings to assert_warnings decorator. --- stix/test/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stix/test/__init__.py b/stix/test/__init__.py index 9acfc09e..ceabf71c 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -13,6 +13,10 @@ def assert_warnings(func): + """Test function decorator which asserts that a warning has been raised + during the execution of the test. + + """ @functools.wraps(func) def inner(*args, **kwargs): self = args[0] From cb6b462bfc61af4e33d189c9990598478862d0c2 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 5 May 2015 20:42:25 -0400 Subject: [PATCH 069/438] chmod 644 --- stix/test/campaign_test.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 stix/test/campaign_test.py diff --git a/stix/test/campaign_test.py b/stix/test/campaign_test.py old mode 100755 new mode 100644 From c80fb0262a57b03468e5fdb21110df7e09ea37ff Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 5 May 2015 21:07:37 -0400 Subject: [PATCH 070/438] Added deprecated warnings to 1.2 deprecated fields. --- stix/campaign/__init__.py | 5 +++++ stix/core/stix_header.py | 17 ++++++++++++++-- stix/core/stix_package.py | 5 ++++- stix/test/campaign_test.py | 8 ++++++++ stix/test/core/stix_header_test.py | 31 +++++++++++++++++++++++++++++ stix/test/core/stix_package_test.py | 15 ++++++++++++++ stix/test/encoding_test.py | 14 ++++++++++--- stix/test/utils/nsparser_test.py | 2 +- 8 files changed, 90 insertions(+), 7 deletions(-) diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 298f9f0b..8c528f19 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. import stix +from stix.utils.deprecated import deprecated from stix.common import Activity, Confidence, Statement, VocabString from stix.common.related import ( GenericRelationshipList, RelatedCampaign, RelatedIncident, RelatedIndicator, @@ -47,6 +48,10 @@ class RelatedIndicators(GenericRelationshipList): _contained_type = RelatedIndicator _inner_name = "indicators" + def _is_valid(self, value): + deprecated(value) + return super(RelatedIndicators, self)._is_valid(value) + class RelatedTTPs(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index 76a441c8..5dea59f3 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -2,11 +2,12 @@ # See LICENSE.txt for complete terms. import stix -import stix.bindings.stix_common as stix_common_binding -import stix.bindings.stix_core as stix_core_binding +from stix.utils.deprecated import deprecated from stix.common import InformationSource, StructuredTextList, VocabString from stix.common.vocabs import PackageIntent from stix.data_marking import Marking +import stix.bindings.stix_common as stix_common_binding +import stix.bindings.stix_core as stix_core_binding class STIXHeader(stix.Entity): @@ -24,6 +25,15 @@ def __init__(self, package_intents=None, description=None, handling=None, self.information_source = information_source self.profiles = [] + @property + def title(self): + return self._title + + @title.setter + def title(self, value): + deprecated(value) + self._title = value + @property def description(self): """A single description about the contents or purpose of this object. @@ -73,6 +83,7 @@ def descriptions(self): @descriptions.setter def descriptions(self, value): + deprecated(value) self._description = StructuredTextList(value) def add_description(self, description): @@ -131,6 +142,7 @@ def short_descriptions(self): @short_descriptions.setter def short_descriptions(self, value): + deprecated(value) self._short_description = StructuredTextList(value) def add_short_description(self, description): @@ -155,6 +167,7 @@ def package_intents(self): @package_intents.setter def package_intents(self, value): + deprecated(value) self._package_intents = _PackageIntents(value) def add_package_intent(self, package_intent): diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index d1e02847..d9ed21f6 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -10,7 +10,7 @@ # utility imports import stix.utils as utils import stix.utils.parser as parser -from stix.utils.deprecated import idref_deprecated +from stix.utils.deprecated import idref_deprecated, deprecated # component imports from stix.campaign import Campaign @@ -86,6 +86,8 @@ def idref(self): @idref.setter def idref(self, value): + deprecated(value) + if not value: self._idref = None else: @@ -98,6 +100,7 @@ def timestamp(self): @timestamp.setter def timestamp(self, value): + deprecated(value) self._timestamp = utils.dates.parse_value(value) @property diff --git a/stix/test/campaign_test.py b/stix/test/campaign_test.py index 5fcc0870..d675c3c2 100644 --- a/stix/test/campaign_test.py +++ b/stix/test/campaign_test.py @@ -161,6 +161,14 @@ def test_deprecated_related_packages(self): c = campaign.Campaign() c.related_packages.append(STIXPackage()) + @assert_warnings + def test_deprecated_related_indicators(self): + from stix.indicator import Indicator + + c = campaign.Campaign() + c.related_indicators.append(Indicator()) + self.assertEqual(1, len(c.related_indicators)) + if __name__ == "__main__": unittest.main() diff --git a/stix/test/core/stix_header_test.py b/stix/test/core/stix_header_test.py index 1dde21aa..fb7c3791 100644 --- a/stix/test/core/stix_header_test.py +++ b/stix/test/core/stix_header_test.py @@ -3,10 +3,13 @@ import unittest +from stix.test import assert_warnings from stix.test import EntityTestCase, data_marking_test from stix.test.common import information_source_test, structured_text_tests from stix import core +from stix.utils import silence_warnings +from stix.common.vocabs import PackageIntent class STIXHeaderTests(EntityTestCase, unittest.TestCase): @@ -20,11 +23,39 @@ class STIXHeaderTests(EntityTestCase, unittest.TestCase): 'profiles': ['foo', 'bar'] } + @silence_warnings def test_duplicate_package_intent(self): # Recreate https://github.com/STIXProject/python-stix/issues/63 hdr = core.STIXHeader(package_intents=["Indicators - Watchlist"]) self.assertEqual(1, len(hdr.package_intents)) + @assert_warnings + def test_deprecated_title(self): + h = core.STIXHeader() + t = "title" + h.title = t + self.assertEqual(h.title, t) + + @assert_warnings + def test_deprecated_description(self): + h = core.STIXHeader() + d = "description" + h.description = d + self.assertEqual(str(h.description), d) + + @assert_warnings + def test_deprecated_short_description(self): + h = core.STIXHeader() + sd = "short_description" + h.short_description = sd + self.assertEqual(str(h.short_description), sd) + + @assert_warnings + def test_deprecated_package_intents(self): + h = core.STIXHeader() + h.package_intents = PackageIntent.TERM_INCIDENT + self.assertEqual(str(h.package_intents[0]), PackageIntent.TERM_INCIDENT) + class STIXHeaderMultiDescTests(EntityTestCase, unittest.TestCase): klass = core.STIXHeader diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index b589afb3..02d1d1a1 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -20,6 +20,7 @@ from stix.incident import Incident from stix.threat_actor import ThreatActor from stix.ttp import TTP +from stix.utils import silence_warnings, now class CampaignsTests(EntityTestCase, unittest.TestCase): @@ -112,6 +113,7 @@ class STIXPackageTests(EntityTestCase, unittest.TestCase): } + @silence_warnings def test_deepcopy(self): """Test copy.deepcopy() against parsed document. @@ -132,6 +134,19 @@ def test_deepcopy(self): copied = copy.deepcopy(package) self.assertEqual(package.timestamp, copied.timestamp) + @assert_warnings + def test_deprecated_idref(self): + p = core.STIXPackage() + p.idref = "test" + self.assertEqual(p.idref, "test") + + @assert_warnings + def test_deprecated_timestamp(self): + p = core.STIXPackage() + ts = now() + p.timestamp = ts + self.assertEqual(ts, p.timestamp) + @assert_warnings def test_campaign_idref_deprecation(self): package = core.STIXPackage() diff --git a/stix/test/encoding_test.py b/stix/test/encoding_test.py index 787bc77d..78c84ff2 100644 --- a/stix/test/encoding_test.py +++ b/stix/test/encoding_test.py @@ -7,7 +7,7 @@ import unittest from StringIO import StringIO -import stix.bindings as bindings + from stix.core import STIXHeader, STIXPackage from stix.campaign import Campaign from stix.indicator import Indicator @@ -16,7 +16,9 @@ from stix.threat_actor import ThreatActor from stix.ttp import TTP from stix.common import StructuredText -import stix.incident.affected_asset as affected_asset +from stix.incident import affected_asset +from stix.utils import silence_warnings +import stix.bindings as bindings from stix.test import round_trip @@ -63,6 +65,7 @@ def test_asset_type(self): a2 = round_trip(a) self.assertEqual(a.count_affected, a2.count_affected) + @silence_warnings def test_stix_header(self): header = STIXHeader() header.title = UNICODE_STR @@ -198,6 +201,7 @@ def test_quote_xml_empty(self): s = bindings.quote_xml(i) self.assertEqual(u'', s) + @silence_warnings def test_to_xml_utf16_encoded(self): encoding = 'utf-16' s = STIXHeader() @@ -205,12 +209,14 @@ def test_to_xml_utf16_encoded(self): xml = s.to_xml(encoding=encoding) self.assertTrue(UNICODE_STR in xml.decode(encoding)) + @silence_warnings def test_to_xml_default_encoded(self): s = STIXHeader() s.title = UNICODE_STR xml = s.to_xml() self.assertTrue(UNICODE_STR in xml.decode('utf-8')) + @silence_warnings def test_to_xml_no_encoding(self): s = STIXHeader() s.title = UNICODE_STR @@ -218,6 +224,7 @@ def test_to_xml_no_encoding(self): self.assertTrue(isinstance(xml, unicode)) self.assertTrue(UNICODE_STR in xml) + @silence_warnings def test_from_xml_utf16_encoded(self): utf16_xml = XML.encode('utf-16') sio = StringIO(utf16_xml) @@ -225,6 +232,7 @@ def test_from_xml_utf16_encoded(self): header = sp.stix_header self.assertEqual(header.title, UNICODE_STR) + @silence_warnings def test_from_xml_default_encoded(self): utf8_xml = XML.encode('utf-8') sio = StringIO(utf8_xml) @@ -232,7 +240,7 @@ def test_from_xml_default_encoded(self): header = sp.stix_header self.assertEqual(header.title, UNICODE_STR) - + @silence_warnings def test_utf16_roundtrip(self): sh = STIXHeader() sh.title = UNICODE_STR diff --git a/stix/test/utils/nsparser_test.py b/stix/test/utils/nsparser_test.py index 2e6baaad..da4cdaa9 100644 --- a/stix/test/utils/nsparser_test.py +++ b/stix/test/utils/nsparser_test.py @@ -4,7 +4,6 @@ # stdlib import StringIO import unittest -import warnings # external import lxml.etree @@ -111,6 +110,7 @@ def test_user_provided_ns(self): self.assertEqual(e.nsmap.get(TEST_PREFIX), TEST_NS) self.assertEqual(e.nsmap.get(NEW_STIX_PREFIX), NEW_STIX_NS) + @silence_warnings def test_duplicate_ns_prefix(self): """Test that duplicate namespace prefix mappings raise errors. From df132397da4be7a8a5c6484c0ae6ba94af3c9880 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 5 May 2015 21:25:43 -0400 Subject: [PATCH 071/438] Fixed AttributeErrors when compiling docs. --- docs/api/common/identity.rst | 4 ---- docs/api/common/vocabs.rst | 6 +----- docs/api/data_marking.rst | 4 ---- docs/api/indicator/test_mechanism.rst | 3 --- docs/api/ttp/malware_instance.rst | 5 ----- stix/__init__.py | 9 +++++++++ 6 files changed, 10 insertions(+), 21 deletions(-) diff --git a/docs/api/common/identity.rst b/docs/api/common/identity.rst index b1dcb283..c30ddc6c 100644 --- a/docs/api/common/identity.rst +++ b/docs/api/common/identity.rst @@ -19,7 +19,3 @@ Functions .. autofunction:: add_extension -Constants ---------- - -.. autodata:: _EXTENSION_MAP diff --git a/docs/api/common/vocabs.rst b/docs/api/common/vocabs.rst index 3dce840b..6af0120f 100644 --- a/docs/api/common/vocabs.rst +++ b/docs/api/common/vocabs.rst @@ -138,8 +138,4 @@ Functions --------- .. autofunction:: add_vocab - -Constants ---------- - -.. autodata:: _VOCAB_MAP +.. autofunction:: register_vocab diff --git a/docs/api/data_marking.rst b/docs/api/data_marking.rst index 37f96699..cb1ff492 100644 --- a/docs/api/data_marking.rst +++ b/docs/api/data_marking.rst @@ -23,7 +23,3 @@ Functions .. autofunction:: add_extension -Constants ---------- - -.. autodata:: _EXTENSION_MAP diff --git a/docs/api/indicator/test_mechanism.rst b/docs/api/indicator/test_mechanism.rst index 9267a96d..fc61bce0 100644 --- a/docs/api/indicator/test_mechanism.rst +++ b/docs/api/indicator/test_mechanism.rst @@ -15,7 +15,4 @@ Functions .. autofunction:: add_extension -Constants ---------- -.. autodata:: _EXTENSION_MAP diff --git a/docs/api/ttp/malware_instance.rst b/docs/api/ttp/malware_instance.rst index 19786fe2..669e2d80 100644 --- a/docs/api/ttp/malware_instance.rst +++ b/docs/api/ttp/malware_instance.rst @@ -14,8 +14,3 @@ Functions --------- .. autofunction:: add_extension - -Constants ---------- - -.. autodata:: _EXTENSION_MAP diff --git a/stix/__init__.py b/stix/__init__.py index a2d920a4..685f5587 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -57,6 +57,9 @@ def lookup_extension(typeinfo): """Returns a stix.Entity class for that has been registered for the `typeinfo` value. + Note: + This is for internal use only. + Args: typeinfo: An object or string containing type information. This can be either an xsi:type attribute value or a stix.bindings object. @@ -93,6 +96,9 @@ def add_extension(cls): Classes must have an ``_XSI_TYPE`` class attributes to be registered. The value of this attribute must be a valid xsi:type. + Note: + This was designed for internal use. + """ _EXTENSION_MAP[cls._XSI_TYPE] = cls # noqa @@ -103,6 +109,9 @@ def register_extension(cls): Classes must have an ``_XSI_TYPE`` class attributes to be registered. + Note: + This was designed for internal use. + """ add_extension(cls) return cls From 6e383bfd274c31c27bc9224d8b5927e12b0be7ce Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 7 May 2015 15:59:58 -0400 Subject: [PATCH 072/438] Added ctx_assert_warnings() to stix.test. --- stix/test/__init__.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/stix/test/__init__.py b/stix/test/__init__.py index ceabf71c..eb009e21 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -1,10 +1,11 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -import json +import contextlib +import functools import itertools +import json import warnings -import functools import cybox.utils @@ -12,6 +13,23 @@ from stix.utils import NamespaceInfo, silence_warnings +@contextlib.contextmanager +def ctx_assert_warnings(self): + """Context manager for verifying that a block of code has raised a + warning. + + """ + with warnings.catch_warnings(record=True) as w: + # Raise all warnings + warnings.simplefilter('always') + + # Return to caller + yield + + # Assert that a warning was raised. + self.assertTrue(len(w) > 0) + + def assert_warnings(func): """Test function decorator which asserts that a warning has been raised during the execution of the test. @@ -20,12 +38,8 @@ def assert_warnings(func): @functools.wraps(func) def inner(*args, **kwargs): self = args[0] - - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter('always') - results = func(*args, **kwargs) - self.assertTrue(len(w) > 0) - return results + with ctx_assert_warnings(self): + return func(*args, **kwargs) return inner From e1d150214016f688d1973dcdfbfec60db20ef9bb Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 7 May 2015 16:00:08 -0400 Subject: [PATCH 073/438] Removed comment. --- stix/exploit_target/vulnerability.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index c316e567..89c0563b 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -9,7 +9,6 @@ from stix.common.related import GenericRelationshipList, RelatedObservable -# TODO document these class Vulnerability(stix.Entity): """Implementation of STIX ``Vulnerability``. @@ -19,7 +18,6 @@ class Vulnerability(stix.Entity): short_description (optional): A string short description. """ - _binding = exploit_target_binding _binding_class = _binding.VulnerabilityType _namespace = "http://stix.mitre.org/ExploitTarget-1" From 169801887f9edf5f4a0828194bfcf74ccf1a185d Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 8 May 2015 22:03:45 -0400 Subject: [PATCH 074/438] Added documentation for Report, Header, STIXPackage, STIXHeader. --- docs/api/common/related.rst | 11 ++- docs/api/index.rst | 13 ++++ docs/api/report/header.rst | 11 +++ docs/api/report/report.rst | 12 ++++ stix/core/stix_header.py | 62 +++++++++++++--- stix/core/stix_package.py | 138 ++++++++++++++++++++++++++++++++---- stix/report/__init__.py | 108 ++++++++++++++++++++++++++++ stix/report/header.py | 36 ++++++++++ 8 files changed, 369 insertions(+), 22 deletions(-) create mode 100644 docs/api/report/header.rst create mode 100644 docs/api/report/report.rst diff --git a/docs/api/common/related.rst b/docs/api/common/related.rst index 8ae200c3..2a6e5294 100644 --- a/docs/api/common/related.rst +++ b/docs/api/common/related.rst @@ -1,5 +1,5 @@ :mod:`stix.common.related` Module -================================== +================================= .. module:: stix.common.related @@ -61,3 +61,12 @@ Classes .. autoclass:: RelatedTTP :show-inheritance: :members: + +.. autoclass:: RelatedReports + :show-inheritance: + :members: + +.. autoclass:: RelatedReport + :show-inheritance: + :members: + diff --git a/docs/api/index.rst b/docs/api/index.rst index 71e5c6ab..1acb8343 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -120,6 +120,19 @@ Modules located in the `stix.indicator`_ package indicator/indicator indicator/* +STIX Report +----------- +Modules located in the `stix.report`_ package + +.. _stix.report: https://github.com/STIXProject/python-stix/tree/master/stix/report + +.. toctree:: + :titlesonly: + :glob: + + report/report + report/* + STIX Threat Actor ----------------- Modules located in the `stix.threat_actor`_ package diff --git a/docs/api/report/header.rst b/docs/api/report/header.rst new file mode 100644 index 00000000..e38e27c7 --- /dev/null +++ b/docs/api/report/header.rst @@ -0,0 +1,11 @@ +:mod:`stix.report.header` Module +================================ + +.. module:: stix.report.header + +Classes +------- + +.. autoclass:: Header + :show-inheritance: + :members: diff --git a/docs/api/report/report.rst b/docs/api/report/report.rst new file mode 100644 index 00000000..a60bfcaf --- /dev/null +++ b/docs/api/report/report.rst @@ -0,0 +1,12 @@ +:mod:`stix.report` Module +========================= + +.. module:: stix.report + +Classes +------- + +.. autoclass:: Report + :show-inheritance: + :members: + diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index 5dea59f3..d5d22924 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -11,6 +11,26 @@ class STIXHeader(stix.Entity): + """The STIX Package Header. + + Args: + handling: The data marking section of the Header. + information_source: The :class:`.InformationSource` section of the + Header. + package_intents: **DEPRECATED**. A collection of :class:`.VocabString` + defining the intent of the parent :class:`.STIXPackage`. + description: **DEPRECATED**. A description of the intent or purpose + of the parent :class:`.STIXPackage`. + short_description: **DEPRECATED**. A short description of the intent + or purpose of the parent :class:`.STIXPackage`. + title: **DEPRECATED**. The title of the :class:`.STIXPackage`. + + Attributes: + profiles: A collection of STIX Profiles the parent + :class:`.STIXPackage` conforms to. + title: **DEPRECATED**. The title of the parent :class:`.STIXPackage`. + + """ _binding = stix_core_binding _namespace = 'http://stix.mitre.org/stix-1' @@ -36,7 +56,8 @@ def title(self, value): @property def description(self): - """A single description about the contents or purpose of this object. + """**DEPRECATED**. A single description about the contents or + purpose of this object. Default Value: ``None`` @@ -57,8 +78,8 @@ def description(self, value): @property def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. + """**DEPRECATED**. A :class:`.StructuredTextList` object, containing + descriptions about the purpose or intent of this object. This is typically used for the purpose of providing multiple descriptions with different classificaton markings. @@ -87,17 +108,19 @@ def descriptions(self, value): self._description = StructuredTextList(value) def add_description(self, description): - """Adds a description to the ``descriptions`` collection. + """**DEPRECATED**. Adds a description to the ``descriptions`` + collection. This is the same as calling "foo.descriptions.add(bar)". """ + deprecated(description) self.descriptions.add(description) @property def short_description(self): - """A single short description about the contents or purpose of this - object. + """**DEPRECATED**. A single short description about the contents or + purpose of this object. Default Value: ``None`` @@ -117,8 +140,8 @@ def short_description(self, value): @property def short_descriptions(self): - """A :class:`.StructuredTextList` object, containing short descriptions - about the purpose or intent of this object. + """**DEPRECATED**. A :class:`.StructuredTextList` object, containing + short descriptions about the purpose or intent of this object. This is typically used for the purpose of providing multiple short descriptions with different classificaton markings. @@ -146,15 +169,21 @@ def short_descriptions(self, value): self._short_description = StructuredTextList(value) def add_short_description(self, description): - """Adds a description to the ``short_descriptions`` collection. + """**DEPRECATED**. Adds a description to the ``short_descriptions`` + collection. This is the same as calling "foo.short_descriptions.add(bar)". """ + deprecated(description) self.short_descriptions.add(description) @property def handling(self): + """The :class:`.Marking` section of this Header. This section contains + data marking information. + + """ return self._handling @handling.setter @@ -163,6 +192,10 @@ def handling(self, value): @property def package_intents(self): + """**DEPRECATED**. A collection of :class:`.VocabString` controlled + vocabulary objects defining the intent of the STIX PAckage. + + """ return self._package_intents @package_intents.setter @@ -171,10 +204,21 @@ def package_intents(self, value): self._package_intents = _PackageIntents(value) def add_package_intent(self, package_intent): + """**DEPRECATED**. Adds :class:`.VocabString` object to the + :attr:`package_intents` collection. + + If the input is not an instance of :class:`.VocabString`, an effort + will be made to convert it into an instance of :class:`.PackageIntent`. + + """ + deprecated(package_intent) self.package_intents.append(package_intent) @property def information_source(self): + """The :class:`.InformationSource` section of the STIX Header. + + """ return self._information_source @information_source.setter diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index d9ed21f6..8debdbc7 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -36,6 +36,29 @@ class STIXPackage(stix.Entity): + """A STIX Package object. + + Args: + id_ (optional): An identifier. If ``None``, a value will be generated + via ``stix.utils.create_id()``. If set, this will unset the + ``idref`` property. + idref (optional): An identifier reference. If set this will unset the + ``id_`` property. + timestamp (optional): A timestamp value. Can be an instance of + ``datetime.datetime`` or ``str``. + header: A Report :class:`.Header` object. + campaigns: A collection of :class:`.Campaign` objects. + course_of_action: A collection of :class:`.CourseOfAction` objects. + exploit_targets: A collection of :class:`.ExploitTarget` objects. + incidents: A collection of :class:`.Incident` objects. + indicators: A collection of :class:`.Indicator` objects. + threat_actors: A collection of :class:`.ThreatActor` objects. + ttps: A collection of :class:`.TTP` objects. + related_packages: **DEPRECATED**. A collection of + :class:`.RelatedPackage` objects. + reports: A collection of :class:`.Report` objects. + + """ _binding = stix_core_binding _binding_class = _binding.STIXType _namespace = 'http://stix.mitre.org/stix-1' @@ -70,8 +93,12 @@ def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, @property def id_(self): + """A globally unique identifier for this Report. By default, one + will be generated automatically. + + """ return self._id - + @id_.setter def id_(self, value): if not value: @@ -79,11 +106,15 @@ def id_(self, value): else: self._id = value self.idref = None - + @property def idref(self): + """A reference to another Report identifier. Setting this will unset + any previous ``id`` values. + + """ return self._idref - + @idref.setter def idref(self, value): deprecated(value) @@ -93,9 +124,13 @@ def idref(self, value): else: self._idref = value self.id_ = None # unset id_ if idref is present - + @property def timestamp(self): + """Specifies a timestamp for the definition of this specifc Report + object. + + """ return self._timestamp @timestamp.setter @@ -105,6 +140,9 @@ def timestamp(self, value): @property def stix_header(self): + """The :class:`.STIXHeader` section of the STIX Package. + + """ return self._stix_header @stix_header.setter @@ -113,6 +151,10 @@ def stix_header(self, value): @property def indicators(self): + """The top-level :class:`.Indicator` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._indicators @indicators.setter @@ -120,10 +162,18 @@ def indicators(self, value): self._indicators = Indicators(value) def add_indicator(self, indicator): + """Adds an :class:`.Indicator` object to the :attr:`indicators` + collection. + + """ self.indicators.append(indicator) @property def campaigns(self): + """The top-level :class:`.Campaign` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._campaigns @campaigns.setter @@ -131,10 +181,17 @@ def campaigns(self, value): self._campaigns = Campaigns(value) def add_campaign(self, campaign): + """Adds a :class:`Campaign` object to the :attr:`campaigns` collection. + + """ self.campaigns.append(campaign) @property def observables(self): + """The top-level ``Observable`` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._observables @observables.setter @@ -142,8 +199,12 @@ def observables(self, value): self._set_var(Observables, observables=value) def add_observable(self, observable): - idref_deprecated(observable) + """Adds an ``Observable`` object to the :attr:`observables` collection. + + If `observable` is not an ``Observable`` instance, an effort will be + made to convert it to one. + """ if not self.observables: self.observables = Observables(observables=observable) else: @@ -151,64 +212,107 @@ def add_observable(self, observable): @property def incidents(self): + """The top-level :class:`.Incident` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._incidents - + @incidents.setter def incidents(self, value): self._incidents = Incidents(value) - + def add_incident(self, incident): + """Adds an :class:`.Incident` object to the :attr:`incidents` + collection. + + """ self.incidents.append(incident) @property def threat_actors(self): + """The top-level :class:`.ThreatActor` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._threat_actors - + @threat_actors.setter def threat_actors(self, value): self._threat_actors = ThreatActors(value) def add_threat_actor(self, threat_actor): + """Adds an :class:`.ThreatActor` object to the :attr:`threat_actors` + collection. + + """ self._threat_actors.append(threat_actor) @property def courses_of_action(self): + """The top-level :class:`.CourseOfAction` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._courses_of_action - + @courses_of_action.setter def courses_of_action(self, value): self._courses_of_action = CoursesOfAction(value) def add_course_of_action(self, course_of_action): + """Adds an :class:`.CourseOfAction` object to the + :attr:`courses_of_action` collection. + + """ self._courses_of_action.append(course_of_action) @property def exploit_targets(self): + """The top-level :class:`.ExploitTarget` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._exploit_targets - + @exploit_targets.setter def exploit_targets(self, value): self._exploit_targets = ExploitTargets(value) def add_exploit_target(self, exploit_target): + """Adds an :class:`.ExploitTarget` object to the + :attr:`exploit_targets` collection. + + """ self._exploit_targets.append(exploit_target) @property def ttps(self): + """The top-level :class:`.TTP` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._ttps - + @ttps.setter def ttps(self, value): if isinstance(value, TTPs): self._ttps = value else: self._ttps = TTPs(value) - + def add_ttp(self, ttp): + """Adds an :class:`.TTP` object to the :attr:`ttps` collection. + + """ self.ttps.append(ttp) @property def reports(self): + """A collection of :class:`.Report` objects. This behaves like a + ``MutableSequence`` object. + + """ return self._reports @reports.setter @@ -216,10 +320,16 @@ def reports(self, value): self._reports = Reports(value) def add_report(self, report): + """Adds a :class:`.Report` object to the :attr:`reports` collection. + + """ self.reports.append(report) @property def related_packages(self): + """**DEPRECATED**. A collection of :class:`.RelatedPackage` objects. + + """ return self._related_packages @related_packages.setter @@ -230,6 +340,10 @@ def related_packages(self, value): self._related_packages = RelatedPackages(value) def add_related_package(self, related_package): + """Adds a :class:`.RelatedPackage` object to the + :attr:`related_packages` collection. + + """ self.related_packages.append(related_package) def add(self, entity): diff --git a/stix/report/__init__.py b/stix/report/__init__.py index c090f92d..6c7d42ec 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -31,6 +31,27 @@ class Report(stix.Entity): + """A STIX Report Object. + + Args: + id_ (optional): An identifier. If ``None``, a value will be generated + via ``stix.utils.create_id()``. If set, this will unset the + ``idref`` property. + idref (optional): An identifier reference. If set this will unset the + ``id_`` property. + timestamp (optional): A timestamp value. Can be an instance of + ``datetime.datetime`` or ``str``. + header: A Report :class:`.Header` object. + campaigns: A collection of :class:`.Campaign` objects. + course_of_action: A collection of :class:`.CourseOfAction` objects. + exploit_targets: A collection of :class:`.ExploitTarget` objects. + incidents: A collection of :class:`.Incident` objects. + indicators: A collection of :class:`.Indicator` objects. + threat_actors: A collection of :class:`.ThreatActor` objects. + ttps: A collection of :class:`.TTP` objects. + related_reports: A collection of :class:`.RelatedReport` objects. + + """ _binding = report_binding _binding_class = _binding.ReportType _namespace = 'http://stix.mitre.org/Report-1' @@ -62,6 +83,10 @@ def __init__(self, id_=None, idref=None, timestamp=None, header=None, @property def id_(self): + """A globally unique identifier for this Report. By default, one + will be generated automatically. + + """ return self._id @id_.setter @@ -74,6 +99,10 @@ def id_(self, value): @property def idref(self): + """A reference to another Report identifier. Setting this will unset + any previous ``id`` values. + + """ return self._idref @idref.setter @@ -86,6 +115,10 @@ def idref(self, value): @property def timestamp(self): + """Specifies a timestamp for the definition of this specific Report + object. + + """ return self._timestamp @timestamp.setter @@ -94,6 +127,9 @@ def timestamp(self, value): @property def header(self): + """The :class:`.Header` section for the Report. + + """ return self._header @header.setter @@ -102,6 +138,10 @@ def header(self, value): @property def indicators(self): + """The top-level :class:`.Indicator` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._indicators @indicators.setter @@ -109,10 +149,18 @@ def indicators(self, value): self._indicators = Indicators(value) def add_indicator(self, indicator): + """Adds an :class:`.Indicator` object to the :attr:`indicators` + collection. + + """ self.indicators.append(indicator) @property def campaigns(self): + """The top-level :class:`.Campaign` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._campaigns @campaigns.setter @@ -120,10 +168,17 @@ def campaigns(self, value): self._campaigns = Campaigns(value) def add_campaign(self, campaign): + """Adds a :class:`Campaign` object to the :attr:`campaigns` collection. + + """ self.campaigns.append(campaign) @property def observables(self): + """The top-level ``Observable`` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._observables @observables.setter @@ -131,6 +186,12 @@ def observables(self, value): self._set_var(Observables, observables=value) def add_observable(self, observable): + """Adds an ``Observable`` object to the :attr:`observables` collection. + + If `observable` is not an ``Observable`` instance, an effort will be + made to convert it to one. + + """ if not self.observables: self.observables = Observables(observables=observable) else: @@ -138,6 +199,10 @@ def add_observable(self, observable): @property def incidents(self): + """The top-level :class:`.Incident` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._incidents @incidents.setter @@ -145,10 +210,18 @@ def incidents(self, value): self._incidents = Incidents(value) def add_incident(self, incident): + """Adds an :class:`.Incident` object to the :attr:`incidents` + collection. + + """ self.incidents.append(incident) @property def threat_actors(self): + """The top-level :class:`.ThreatActor` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._threat_actors @threat_actors.setter @@ -156,10 +229,18 @@ def threat_actors(self, value): self._threat_actors = ThreatActors(value) def add_threat_actor(self, threat_actor): + """Adds an :class:`.ThreatActor` object to the :attr:`threat_actors` + collection. + + """ self._threat_actors.append(threat_actor) @property def courses_of_action(self): + """The top-level :class:`.CourseOfAction` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._courses_of_action @courses_of_action.setter @@ -167,10 +248,18 @@ def courses_of_action(self, value): self._courses_of_action = CoursesOfAction(value) def add_course_of_action(self, course_of_action): + """Adds an :class:`.CourseOfAction` object to the + :attr:`courses_of_action` collection. + + """ self._courses_of_action.append(course_of_action) @property def exploit_targets(self): + """The top-level :class:`.ExploitTarget` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._exploit_targets @exploit_targets.setter @@ -178,10 +267,18 @@ def exploit_targets(self, value): self._exploit_targets = ExploitTargets(value) def add_exploit_target(self, exploit_target): + """Adds an :class:`.ExploitTarget` object to the + :attr:`exploit_targets` collection. + + """ self._exploit_targets.append(exploit_target) @property def ttps(self): + """The top-level :class:`.TTP` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._ttps @ttps.setter @@ -192,10 +289,17 @@ def ttps(self, value): self._ttps = TTPs(value) def add_ttp(self, ttp): + """Adds an :class:`.TTP` object to the :attr:`ttps` collection. + + """ self.ttps.append(ttp) @property def related_reports(self): + """The top-level :class:`.RelatedReports` collection. This behaves like + a ``MutableSequence`` type. + + """ return self._related_reports @related_reports.setter @@ -206,6 +310,10 @@ def related_reports(self, value): self._related_reports = RelatedReports(value) def add_related_report(self, related_report): + """Adds an :class:`.RelatedReport` object to the + :attr:`related_reports` collection. + + """ self.related_reports.append(related_report) def add(self, entity): diff --git a/stix/report/header.py b/stix/report/header.py index b7bc5347..fd3ebfa4 100644 --- a/stix/report/header.py +++ b/stix/report/header.py @@ -9,6 +9,24 @@ class Header(stix.Entity): + """The Report Header. + + Args: + handling: The data marking section of the Header. + information_source: The :class:`.InformationSource` section of the + Header. + intents: A collection of :class:`.VocabString` defining the intent + of the parent :class:`.Report`. + description: A description of the intent or purpose of the parent + :class:`.Report`. + short_description: A short description of the intent or purpose of + the parent :class:`.Report`. + title: The title of the :class:`.Report`. + + Attributes: + title: The title of the parent :class:`.Report`. + + """ _binding = report_binding _namespace = 'http://stix.mitre.org/Report-1' @@ -141,6 +159,10 @@ def add_short_description(self, description): @property def handling(self): + """The :class:`.Marking` section of this Header. This section contains + data marking information. + + """ return self._handling @handling.setter @@ -149,6 +171,10 @@ def handling(self, value): @property def intents(self): + """A collection of :class:`.VocabString` controlled vocabulary + objects. + + """ return self._intents @intents.setter @@ -156,10 +182,20 @@ def intents(self, value): self._intents = _ReportIntents(value) def add_intent(self, intent): + """Adds :class:`.VocabString` object to the :attr:`intents` + collection. + + If the input is not an instance of :class:`.VocabString`, an effort + will be made to convert it into an instance of :class:`.ReportIntent`. + + """ self.intents.append(intent) @property def information_source(self): + """The :class:`.InformationSource` section of the Header. + + """ return self._information_source @information_source.setter From 02d94de590f5883a5a8cf2411dc7737158352501 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 8 May 2015 22:31:22 -0400 Subject: [PATCH 075/438] Added default parameter to stix.bindings.lookup_extension() --- stix/bindings/__init__.py | 9 ++-- stix/bindings/data_marking.py | 6 +-- stix/bindings/exploit_target.py | 7 +-- stix/bindings/incident.py | 14 +----- stix/bindings/report.py | 46 +++--------------- stix/bindings/stix_common.py | 85 +++++---------------------------- stix/bindings/stix_core.py | 56 +++------------------- stix/bindings/threat_actor.py | 8 +--- stix/bindings/ttp.py | 29 ++--------- 9 files changed, 40 insertions(+), 220 deletions(-) diff --git a/stix/bindings/__init__.py b/stix/bindings/__init__.py index 93c3d1b1..d9e31592 100644 --- a/stix/bindings/__init__.py +++ b/stix/bindings/__init__.py @@ -450,7 +450,7 @@ def register_extension(cls): return cls -def lookup_extension(typeinfo): +def lookup_extension(typeinfo, default=None): """Looks up the binding class for `typeinfo`, which is a namespace/typename pairing. @@ -460,7 +460,10 @@ def lookup_extension(typeinfo): """ if not isinstance(typeinfo, TypeInfo): - typeinfo = get_type_info(typeinfo) + if has_xsi_type(typeinfo): + typeinfo = get_type_info(typeinfo) + elif default: + return default try: return _EXTENSION_MAP[typeinfo] @@ -474,7 +477,7 @@ def has_xsi_type(node): """Returns ``True`` if `node` does not have an xsi:type attribute. """ - return xmlconst.TAG_XSI_TYPE not in node.attrib + return xmlconst.TAG_XSI_TYPE in node.attrib __all__ = [ diff --git a/stix/bindings/data_marking.py b/stix/bindings/data_marking.py index c0432928..240bfbaa 100644 --- a/stix/bindings/data_marking.py +++ b/stix/bindings/data_marking.py @@ -338,11 +338,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): # Look for xsi:type. If not there, build an instance of # MarkingStructureType - if has_xsi_type(child_): - obj_ = MarkingStructureType.factory() - else: - obj_ = lookup_extension(child_).factory() - + obj_ = lookup_extension(child_, MarkingStructureType).factory() obj_.build(child_) self.Marking_Structure.append(obj_) diff --git a/stix/bindings/exploit_target.py b/stix/bindings/exploit_target.py index e05443af..f72c97ed 100644 --- a/stix/bindings/exploit_target.py +++ b/stix/bindings/exploit_target.py @@ -939,12 +939,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): self.add_Short_Description(obj_) elif nodeName_ == 'Vulnerability': import stix.bindings.extensions.vulnerability.cvrf_1_1 as cvrf_1_1_binding - - if has_xsi_type(child_): - obj_ = VulnerabilityType.factory() # VulnerabilityType not abstract - else: - obj_ = lookup_extension(child_).factory() - + obj_ = lookup_extension(child_, VulnerabilityType).factory() obj_.build(child_) self.Vulnerability.append(obj_) elif nodeName_ == 'Weakness': diff --git a/stix/bindings/incident.py b/stix/bindings/incident.py index 591f370f..eeb165e5 100644 --- a/stix/bindings/incident.py +++ b/stix/bindings/incident.py @@ -562,12 +562,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): self.set_Contributors(obj_) elif nodeName_ == 'Course_Of_Action': from . import course_of_action - - if has_xsi_type(child_): - obj_ = stix_common_binding.CourseOfActionBaseType.factory() # not abstract - else: - obj_ = lookup_extension(child_).factory() - + obj_ = lookup_extension(child_, stix_common_binding.CourseOfActionBaseType).factory() obj_.build(child_) self.set_Course_Of_Action(obj_) # end class COATakenType @@ -2497,12 +2492,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): self.Coordinator.append(obj_) elif nodeName_ == 'Victim': import stix.bindings.extensions.identity.ciq_identity_3_0 as ciq_identity_binding - - if has_xsi_type(child_): - obj_ = stix_common_binding.IdentityType.factory() # IdentityType is not abstract - else: - obj_ = lookup_extension(child_).factory() - + obj_ = lookup_extension(child_, stix_common_binding.IdentityType).factory() obj_.build(child_) self.Victim.append(obj_) elif nodeName_ == 'Affected_Assets': diff --git a/stix/bindings/report.py b/stix/bindings/report.py index 6cc759d5..94faf8d5 100644 --- a/stix/bindings/report.py +++ b/stix/bindings/report.py @@ -208,11 +208,7 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Indicator': - if has_xsi_type(child_): - obj_ = common_binding.IndicatorBaseType.factory() - else: - klass = lookup_extension(child_) - obj_ = klass.factory() + obj_ = lookup_extension(child_, common_binding.IndicatorBaseType).factory() obj_.build(child_) self.Indicator.append(obj_) # end class IndicatorsType @@ -285,13 +281,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'TTP': from . import ttp - - if has_xsi_type(child_): - obj_ = common_binding.TTPBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, common_binding.TTPBaseType).factory() obj_.build(child_) self.TTP.append(obj_) elif nodeName_ == 'Kill_Chains': @@ -361,13 +351,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Incident': from . import incident - - if has_xsi_type(child_): - obj_ = common_binding.IncidentBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, common_binding.IncidentBaseType).factory() obj_.build(child_) self.Incident.append(obj_) # end class IncidentsType @@ -433,13 +417,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Course_Of_Action': from . import course_of_action - - if has_xsi_type(child_): - obj_ = common_binding.CourseOfActionBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, common_binding.CourseOfActionBaseType).factory() obj_.build(child_) self.Course_Of_Action.append(obj_) # end class CoursesOfActionType @@ -505,13 +483,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Campaign': from . import campaign - - if has_xsi_type(child_): - obj_ = common_binding.CampaignBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, common_binding.CampaignBaseType).factory() obj_.build(child_) self.Campaign.append(obj_) # end class CampaignsType @@ -577,13 +549,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Threat_Actor': from . import threat_actor - - if has_xsi_type(child_): - obj_ = common_binding.ThreatActorBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, common_binding.ThreatActorBaseType).factory() obj_.build(child_) self.Threat_Actor.append(obj_) # end class ThreatActorsType diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index 97e0a7e9..22d1bfa3 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -608,12 +608,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): self.add_Description(obj_) elif nodeName_ == 'Identity': from .extensions.identity import ciq_identity_3_0 - - if has_xsi_type(child_): - obj_ = IdentityType.factory() # IdentityType is not abstract - else: - obj_ = lookup_extension(child_).factory() - + obj_ = lookup_extension(child_, IdentityType).factory() obj_.build(child_) self.set_Identity(obj_) elif nodeName_ == 'Role': @@ -1483,13 +1478,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Campaign': from . import campaign - - if has_xsi_type(child_): - obj_ = CampaignBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, CampaignBaseType).factory() obj_.build(child_) self.set_Campaign(obj_) super(RelatedCampaignType, self).buildChildren(child_, node, nodeName_, True) @@ -1554,14 +1543,8 @@ def buildAttributes(self, node, attrs, already_processed): super(RelatedCourseOfActionType, self).buildAttributes(node, attrs, already_processed) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Course_Of_Action': - from . import campaign - - if has_xsi_type(child_): - obj_ = CampaignBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + from . import course_of_action + obj_ = lookup_extension(child_, CourseOfActionBaseType).factory() obj_.build(child_) self.set_Course_Of_Action(obj_) super(RelatedCourseOfActionType, self).buildChildren(child_, node, nodeName_, True) @@ -1626,12 +1609,7 @@ def buildAttributes(self, node, attrs, already_processed): super(RelatedExploitTargetType, self).buildAttributes(node, attrs, already_processed) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Exploit_Target': - if has_xsi_type(child_): - obj_ = ExploitTargetBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, ExploitTargetBaseType).factory() obj_.build(child_) self.set_Exploit_Target(obj_) super(RelatedExploitTargetType, self).buildChildren(child_, node, nodeName_, True) @@ -1697,13 +1675,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Incident': from . import incident - - if has_xsi_type(child_): - obj_ = IncidentBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, IncidentBaseType).factory() obj_.build(child_) self.set_Incident(obj_) super(RelatedIncidentType, self).buildChildren(child_, node, nodeName_, True) @@ -1769,13 +1741,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Indicator': from . import indicator - - if has_xsi_type(child_): - obj_ = IndicatorBaseType.factory() - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, IncidentBaseType).factory() obj_.build(child_) self.set_Indicator(obj_) super(RelatedIndicatorType, self).buildChildren(child_, node, nodeName_, True) @@ -1906,13 +1872,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Threat_Actor': from . import threat_actor - - if has_xsi_type(child_): - obj_ = ThreatActorBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, ThreatActorBaseType).factory() obj_.build(child_) self.set_Threat_Actor(obj_) super(RelatedThreatActorType, self).buildChildren(child_, node, nodeName_, True) @@ -1978,13 +1938,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'TTP': from . import ttp - - if has_xsi_type(child_): - obj_ = TTPBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, TTPBaseType).factory() obj_.build(child_) self.set_TTP(obj_) super(RelatedTTPType, self).buildChildren(child_, node, nodeName_, True) @@ -2050,12 +2004,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Identity': from .extensions.identity import ciq_identity_3_0 - - if has_xsi_type(child_): - obj_ = IdentityType.factory() # IdentityType is not abstract - else: - obj_ = lookup_extension(child_).factory() - + obj_ = lookup_extension(child_, IdentityType).factory() obj_.build(child_) self.set_Identity(obj_) super(RelatedIdentityType, self).buildChildren(child_, node, nodeName_, True) @@ -3042,12 +2991,7 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Exploit_Target': - if has_xsi_type(child_): - obj_ = ExploitTargetBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, ExploitTargetBaseType).factory() obj_.build(child_) self.Exploit_Target.append(obj_) @@ -3930,12 +3874,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Report': from . import report - - if has_xsi_type(child_): - obj_ = ReportBaseType.factory() - else: - obj_ = lookup_extension(child_).factory() - + obj_ = lookup_extension(child_, ReportBaseType).factory() obj_.build(child_) self.set_Report(obj_) super(RelatedReportType, self).buildChildren(child_, node, nodeName_, True) diff --git a/stix/bindings/stix_core.py b/stix/bindings/stix_core.py index 1ca8ed14..9de68033 100644 --- a/stix/bindings/stix_core.py +++ b/stix/bindings/stix_core.py @@ -567,13 +567,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Indicator': from . import indicator - - if has_xsi_type(child_): - obj_ = stix_common_binding.IndicatorBaseType.factory() - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, stix_common_binding.IndicatorBaseType).factory() obj_.build(child_) self.Indicator.append(obj_) @@ -646,13 +640,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'TTP': from . import ttp - - if has_xsi_type(child_): - obj_ = stix_common_binding.TTPBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, stix_common_binding.TTPBaseType).factory() obj_.build(child_) self.TTP.append(obj_) @@ -723,13 +711,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Incident': from . import incident - - if has_xsi_type(child_): - obj_ = stix_common_binding.IncidentBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, stix_common_binding.IncidentBaseType).factory() obj_.build(child_) self.Incident.append(obj_) @@ -796,13 +778,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Course_Of_Action': from . import course_of_action - - if has_xsi_type(child_): - obj_ = stix_common_binding.CourseOfActionBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, stix_common_binding.CourseOfActionBaseType).factory() obj_.build(child_) self.Course_Of_Action.append(obj_) # end class CoursesOfActionType @@ -868,13 +844,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Campaign': from . import campaign - - if has_xsi_type(child_): - obj_ = stix_common_binding.CampaignBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, stix_common_binding.CampaignBaseType).factory() obj_.build(child_) self.Campaign.append(obj_) # end class CampaignsType @@ -940,13 +910,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Threat_Actor': from . import threat_actor - - if has_xsi_type(child_): - obj_ = stix_common_binding.ThreatActorBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, stix_common_binding.ThreatActorBaseType).factory() obj_.build(child_) self.Threat_Actor.append(obj_) # end class ThreatActorsType @@ -1014,13 +978,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Report': from . import report - - if has_xsi_type(child_): - obj_ = stix_common_binding.ReportBaseType.factory() # not abstract - else: - klass = lookup_extension(child_) - obj_ = klass.factory() - + obj_ = lookup_extension(child_, stix_common_binding.ReportBaseType).factory() obj_.build(child_) self.Report.append(obj_) # end class TTPsType diff --git a/stix/bindings/threat_actor.py b/stix/bindings/threat_actor.py index 92398acf..2252ec42 100644 --- a/stix/bindings/threat_actor.py +++ b/stix/bindings/threat_actor.py @@ -450,13 +450,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): self.add_Short_Description(obj_) elif nodeName_ == 'Identity': from .extensions.identity import ciq_identity_3_0 - - if has_xsi_type(child_): - obj_ = stix_common_binding.IdentityType.factory() # IdentityType is not abstract - else: - obj_ = lookup_extension(child_).factory() - - obj_.build(child_) + obj_ = lookup_extension(child_, stix_common_binding.IdentityType).factory() obj_.build(child_) self.set_Identity(obj_) elif nodeName_ == 'Type': diff --git a/stix/bindings/ttp.py b/stix/bindings/ttp.py index 4f4e07f4..44d3e1cd 100644 --- a/stix/bindings/ttp.py +++ b/stix/bindings/ttp.py @@ -766,12 +766,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Malware_Instance': from .extensions.malware import maec_4_1 - - if has_xsi_type(child_): - obj_ = MalwareInstanceType.factory() # MalwareInstanceType is not abstract - else: - obj_ = lookup_extension(child_).factory() - + obj_ = lookup_extension(child_, MalwareInstanceType).factory() obj_.build(child_) self.Malware_Instance.append(obj_) # end class MalwareType @@ -837,12 +832,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Attack_Pattern': from .extensions.attack_pattern import capec_2_7 - - if has_xsi_type(child_): - obj_ = AttackPatternType.factory() # AttackPattern is not abstract - else: - obj_ = lookup_extension(child_).factory() - + obj_ = lookup_extension(child_, AttackPatternType).factory() obj_.build(child_) self.Attack_Pattern.append(obj_) # end class AttackPatternsType @@ -988,13 +978,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Persona': from .extensions.identity import ciq_identity_3_0 - - if has_xsi_type(child_): - obj_ = stix_common_binding.IdentityType.factory() # IdentityType is not abstract - else: - obj_ = lookup_extension(child_).factory() - - obj_.build(child_) + obj_ = lookup_extension(child_, stix_common_binding.IdentityType).factory() obj_.build(child_) self.Persona.append(obj_) # end class PersonasType @@ -1164,12 +1148,7 @@ def buildAttributes(self, node, attrs, already_processed): def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Identity': from .extensions.identity import ciq_identity_3_0 - - if has_xsi_type(child_): - obj_ = stix_common_binding.IdentityType.factory() # IdentityType is not abstract - else: - obj_ = lookup_extension(child_).factory() - + obj_ = lookup_extension(child_, stix_common_binding.IdentityType).factory() obj_.build(child_) self.set_Identity(obj_) elif nodeName_ == 'Targeted_Systems': From 8bf5470c89a9ddc06c7da75b9cccb4327770ca86 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 8 May 2015 22:33:58 -0400 Subject: [PATCH 076/438] Updated stix.bindings.lookup_extension() docstrings. --- stix/bindings/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/stix/bindings/__init__.py b/stix/bindings/__init__.py index d9e31592..f893b389 100644 --- a/stix/bindings/__init__.py +++ b/stix/bindings/__init__.py @@ -454,6 +454,11 @@ def lookup_extension(typeinfo, default=None): """Looks up the binding class for `typeinfo`, which is a namespace/typename pairing. + Args: + typeinfo: An lxml Element node or a stix.bindings.TypeInfo namedtuple. + default: A binding class that will be returned if typeinfo is an + Element without an xsi:type attribute. + Returns: A binding class that has been registered for the namespace and typename found on `typeinfo`. From 1cde016ea6959714898e5e89da1f34101a458b0c Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 8 May 2015 23:22:05 -0400 Subject: [PATCH 077/438] TestMechanism impls are responsible for serializing their xsi:types. --- stix/bindings/extensions/test_mechanism/generic.py | 8 ++++---- .../extensions/test_mechanism/open_ioc_2010.py | 8 ++++---- stix/bindings/extensions/test_mechanism/oval_5_10.py | 8 ++++---- stix/bindings/extensions/test_mechanism/snort.py | 8 ++++---- stix/bindings/extensions/test_mechanism/yara.py | 8 ++++---- stix/bindings/indicator.py | 10 +++++----- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/stix/bindings/extensions/test_mechanism/generic.py b/stix/bindings/extensions/test_mechanism/generic.py index 574aa617..2f01d4f4 100644 --- a/stix/bindings/extensions/test_mechanism/generic.py +++ b/stix/bindings/extensions/test_mechanism/generic.py @@ -89,10 +89,10 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='generic # already_processed.add('xmlns') # xmlns = " xmlns:%s='%s'" % (self.xmlns_prefix, self.xmlns) # lwrite(xmlns) - # if 'xsi:type' not in already_processed: - # already_processed.add('xsi:type') - # xsi_type = " xsi:type='%s:%s'" % (self.xmlns_prefix, self.xml_type) - # lwrite(xsi_type) + if 'xsi:type' not in already_processed: + already_processed.add('xsi:type') + xsi_type = " xsi:type='%s:%s'" % (self.xmlns_prefix, self.xml_type) + lwrite(xsi_type) if self.reference_location is not None and 'reference_location' not in already_processed: already_processed.add('reference_location') lwrite(' reference_location=%s' % (quote_attrib(self.reference_location), )) diff --git a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py index a3bd9671..29773b5f 100644 --- a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py +++ b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py @@ -72,10 +72,10 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='', name # already_processed.add('xmlns') # xmlns = " xmlns:%s='%s'" % (self.xmlns_prefix, self.xmlns) # lwrite(xmlns) - # if 'xsi:type' not in already_processed: - # already_processed.add('xsi:type') - # xsi_type = " xsi:type='%s:%s'" % (self.xmlns_prefix, self.xml_type) - # lwrite(xsi_type) + if 'xsi:type' not in already_processed: + already_processed.add('xsi:type') + xsi_type = " xsi:type='%s:%s'" % (self.xmlns_prefix, self.xml_type) + lwrite(xsi_type) def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='OpenIOC2010TestMechanismType', fromsubclass_=False, pretty_print=True): super(OpenIOC2010TestMechanismType, self).exportChildren(lwrite, level, nsmap, indicator_binding.XML_NS, name_, True, pretty_print=pretty_print) if pretty_print: diff --git a/stix/bindings/extensions/test_mechanism/oval_5_10.py b/stix/bindings/extensions/test_mechanism/oval_5_10.py index efb425d5..7938df10 100644 --- a/stix/bindings/extensions/test_mechanism/oval_5_10.py +++ b/stix/bindings/extensions/test_mechanism/oval_5_10.py @@ -76,10 +76,10 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='', name # already_processed.add('xmlns') # xmlns = " xmlns:%s='%s'" % (self.xmlns_prefix, self.xmlns) # lwrite(xmlns) - # if 'xsi:type' not in already_processed: - # already_processed.add('xsi:type') - # xsi_type = " xsi:type='%s:%s'" % (self.xmlns_prefix, self.xml_type) - # lwrite(xsi_type) + if 'xsi:type' not in already_processed: + already_processed.add('xsi:type') + xsi_type = " xsi:type='%s:%s'" % (self.xmlns_prefix, self.xml_type) + lwrite(xsi_type) def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='OVAL5.10TestMechanismType', fromsubclass_=False, pretty_print=True): super(OVAL5_10TestMechanismType, self).exportChildren(lwrite, level, nsmap, indicator_binding.XML_NS, name_, True, pretty_print=pretty_print) if pretty_print: diff --git a/stix/bindings/extensions/test_mechanism/snort.py b/stix/bindings/extensions/test_mechanism/snort.py index f725b971..0553bdbb 100644 --- a/stix/bindings/extensions/test_mechanism/snort.py +++ b/stix/bindings/extensions/test_mechanism/snort.py @@ -112,10 +112,10 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='snortTM # already_processed.add('xmlns') # xmlns = " xmlns:%s='%s'" % (self.xmlns_prefix, self.xmlns) # lwrite(xmlns) - # if 'xsi:type' not in already_processed: - # already_processed.add('xsi:type') - # xsi_type = " xsi:type='%s:%s'" % (self.xmlns_prefix, self.xml_type) - # lwrite(xsi_type) + if 'xsi:type' not in already_processed: + already_processed.add('xsi:type') + xsi_type = " xsi:type='%s:%s'" % (self.xmlns_prefix, self.xml_type) + lwrite(xsi_type) def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='SnortTestMechanismType', fromsubclass_=False, pretty_print=True): super(SnortTestMechanismType, self).exportChildren(lwrite, level, nsmap, indicator_binding.XML_NS, name_, True, pretty_print=pretty_print) if pretty_print: diff --git a/stix/bindings/extensions/test_mechanism/yara.py b/stix/bindings/extensions/test_mechanism/yara.py index cd66dd0d..f479faf5 100644 --- a/stix/bindings/extensions/test_mechanism/yara.py +++ b/stix/bindings/extensions/test_mechanism/yara.py @@ -76,10 +76,10 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='yaraTM: # already_processed.add('xmlns') # xmlns = " xmlns:%s='%s'" % (self.xmlns_prefix, self.xmlns) # lwrite(xmlns) - # if 'xsi:type' not in already_processed: - # already_processed.add('xsi:type') - # xsi_type = " xsi:type='%s:%s'" % (self.xmlns_prefix, self.xml_type) - # lwrite(xsi_type) + if 'xsi:type' not in already_processed: + already_processed.add('xsi:type') + xsi_type = " xsi:type='%s:%s'" % (self.xmlns_prefix, self.xml_type) + lwrite(xsi_type) def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='YaraTestMechanismType', fromsubclass_=False, pretty_print=True): super(YaraTestMechanismType, self).exportChildren(lwrite, level, nsmap, indicator_binding.XML_NS, name_, True, pretty_print=pretty_print) if pretty_print: diff --git a/stix/bindings/indicator.py b/stix/bindings/indicator.py index 03444fe5..5782bdd8 100644 --- a/stix/bindings/indicator.py +++ b/stix/bindings/indicator.py @@ -220,12 +220,12 @@ class TestMechanismType(GeneratedsSuper): reference to the ID of a Test Mechanism specified elsewhere.""" subclass = None superclass = None - def __init__(self, idref=None, id=None, Efficacy=None, Producer=None, xsi_type=None): + def __init__(self, idref=None, id=None, Efficacy=None, Producer=None): self.idref = _cast(None, idref) self.id = _cast(None, id) self.Efficacy = Efficacy self.Producer = Producer - self.xsi_type = xsi_type + # self.xsi_type = xsi_type def factory(*args_, **kwargs_): if TestMechanismType.subclass: return TestMechanismType.subclass(*args_, **kwargs_) @@ -273,9 +273,9 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='indicat if self.id is not None and 'id' not in already_processed: already_processed.add('id') lwrite(' id=%s' % (quote_attrib(self.id), )) - if self.xsi_type is not None and 'xsi:type' not in already_processed: - already_processed.add('xsi:type') - lwrite(' xsi:type="%s"' % self.xsi_type) + # if self.xsi_type is not None and 'xsi:type' not in already_processed: + # already_processed.add('xsi:type') + # lwrite(' xsi:type="%s"' % self.xsi_type) def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TestMechanismType', fromsubclass_=False, pretty_print=True): if pretty_print: From 04c7b47e9564b5ba8f51a104cd806c986f6b525c Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 8 May 2015 23:27:04 -0400 Subject: [PATCH 078/438] Added 'default' to stix.lookup_extension() --- stix/__init__.py | 18 +++++++++++++----- stix/coa/structured_coa.py | 6 +++--- stix/common/identity.py | 15 ++++----------- stix/common/vocabs.py | 28 ++++++++++++---------------- stix/data_marking.py | 24 ++++++++++-------------- stix/indicator/test_mechanism.py | 6 +++--- stix/ttp/malware_instance.py | 15 ++++----------- 7 files changed, 49 insertions(+), 63 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index 685f5587..0ad6a236 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -30,7 +30,7 @@ def _lookup_unprefixed(typename): if typename in xsi_type: return klass - error = "Unregistered extension for unprefixed type: %s" % typename + error = "Unregistered extension type: %s" % typename raise ValueError(error) @@ -53,7 +53,7 @@ def _lookup_extension(xsi_type): raise ValueError("Unregistered xsi:type %s" % xsi_type) -def lookup_extension(typeinfo): +def lookup_extension(typeinfo, default=None): """Returns a stix.Entity class for that has been registered for the `typeinfo` value. @@ -63,6 +63,8 @@ def lookup_extension(typeinfo): Args: typeinfo: An object or string containing type information. This can be either an xsi:type attribute value or a stix.bindings object. + default: Return class if typeinfo is None or contains no xml type + information. Returns: A stix.Entity implementation class for the `xsi_type`. @@ -71,17 +73,23 @@ def lookup_extension(typeinfo): ValueError: If no class has been registered for the `xsi_type`. """ + if typeinfo is None and default: + return default + # If the `typeinfo` was a string, consider it a full xsi:type value. if isinstance(typeinfo, basestring): return _lookup_extension(typeinfo) - # If we didn't pass in string xsi:type, try to look it up by class attr. - # Binding classes have an `xml_type` class attribute. + # Most extension bindings include this attribute. if not hasattr(typeinfo, 'xml_type'): + if default: + return default + error = "Input %s is missing xml_type attribute. Cannot lookup class." raise ValueError(error) - # Binding classes usually (always?) have an `xmlns_prefix` class attribute + # Extension binding classes usually (always?) have an `xmlns_prefix` + # class attribute. if hasattr(typeinfo, 'xmlns_prefix'): xsi_type = "%s:%s" % (typeinfo.xmlns_prefix, typeinfo.xml_type) return _lookup_extension(xsi_type) diff --git a/stix/coa/structured_coa.py b/stix/coa/structured_coa.py index b059547f..e77a1f72 100644 --- a/stix/coa/structured_coa.py +++ b/stix/coa/structured_coa.py @@ -23,7 +23,7 @@ def from_obj(cls, obj, return_obj=None): import stix.extensions.structured_coa.generic_structured_coa # noqa if not return_obj: - klass = _BaseStructuredCOA.lookup_class(obj) + klass = stix.lookup_extension(obj) return_obj = klass.from_obj(obj) else: return_obj.id_ = obj.id @@ -58,10 +58,10 @@ def from_dict(cls, d, return_obj=None): if not d: return None - from stix.extensions.structured_coa.generic_structured_coa import GenericStructuredCOA # noqa + import stix.extensions.structured_coa.generic_structured_coa # noqa if not return_obj: - klass = _BaseStructuredCOA.lookup_class(d.get('xsi:type')) + klass = stix.lookup_extension(d.get('xsi:type')) return_obj = klass.from_dict(d) else: return_obj.id_ = d.get('id') diff --git a/stix/common/identity.py b/stix/common/identity.py index f2d72f72..c66a487d 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -89,11 +89,8 @@ def from_obj(cls, obj, return_obj=None): return None if not return_obj: - if hasattr(obj, 'xml_type'): - klass = Identity.lookup_class(obj) - return_obj = klass.from_obj(obj) - else: - return_obj = Identity.from_obj(obj, cls()) + klass = stix.lookup_extension(obj, default=cls) + return_obj = klass.from_obj(obj, return_obj=klass()) else: return_obj.id_ = obj.id return_obj.idref = obj.idref @@ -116,12 +113,8 @@ def from_dict(cls, dict_repr, return_obj=None): get = dict_repr.get if not return_obj: - xsi_type = get('xsi:type') - if xsi_type: - klass = Identity.lookup_class(get('xsi:type')) - return_obj = klass.from_dict(dict_repr) - else: - return_obj = Identity.from_dict(dict_repr, cls()) + klass = stix.lookup_extension(get('xsi:type'), default=cls) + return_obj = klass.from_dict(dict_repr, klass()) else: return_obj.name = get('name') return_obj.id_ = get('id') diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index 94ce5a56..783b4390 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -63,13 +63,7 @@ def is_plain(self): @staticmethod def lookup_class(xsi_type): - if not xsi_type: - return VocabString - - try: - return stix.lookup_extension(xsi_type) - except ValueError: - return VocabString + return stix.lookup_extension(xsi_type, default=VocabString) def to_obj(self, return_obj=None, ns_info=None): super(VocabString, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -111,8 +105,8 @@ def from_obj(cls, vocab_obj, return_obj=None): return None if not return_obj: - klass = VocabString.lookup_class(vocab_obj.xsi_type) - return klass.from_obj(vocab_obj, klass()) + klass = stix.lookup_extension(vocab_obj.xsi_type, default=cls) + return klass.from_obj(vocab_obj, return_obj=klass()) # xsi_type should be set automatically by the class's constructor. @@ -129,11 +123,12 @@ def from_obj(cls, vocab_obj, return_obj=None): def from_dict(cls, vocab_dict, return_obj=None): if not vocab_dict: return None - + if not return_obj: if isinstance(vocab_dict, dict): - klass = VocabString.lookup_class(vocab_dict.get('xsi:type')) - return klass.from_dict(vocab_dict, klass()) + get = vocab_dict.get + klass = stix.lookup_extension(get('xsi:type'), default=cls) + return klass.from_dict(vocab_dict, return_obj=klass()) else: return_obj = cls() @@ -143,10 +138,11 @@ def from_dict(cls, vocab_dict, return_obj=None): if not isinstance(vocab_dict, dict): return_obj.value = vocab_dict else: - return_obj.value = vocab_dict.get('value') - return_obj.vocab_name = vocab_dict.get('vocab_name') - return_obj.vocab_reference = vocab_dict.get('vocab_reference') - return_obj.xsi_type = vocab_dict.get('xsi:type') + get = vocab_dict.get + return_obj.value = get('value') + return_obj.vocab_name = get('vocab_name') + return_obj.vocab_reference = get('vocab_reference') + return_obj.xsi_type = get('xsi:type') return return_obj diff --git a/stix/data_marking.py b/stix/data_marking.py index 7feb131e..4caba8a8 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -228,11 +228,8 @@ def from_obj(cls, obj, return_obj=None): m.marking_model_ref = obj.marking_model_ref else: - if hasattr(obj, 'xml_type'): - klass = MarkingStructure.lookup_class(obj) - m = klass.from_obj(obj) - else: - m = cls.from_obj(obj, cls()) + klass = stix.lookup_extension(obj, default=cls) + m = klass.from_obj(obj, return_obj=klass()) return m @@ -245,18 +242,17 @@ def from_dict(cls, d, return_obj=None): if not d: return None + get = d.get + if return_obj is not None: m = return_obj - m.id_ = d.get('id') - m.idref = d.get('idref') - m.marking_model_name = d.get('marking_model_name') - m.marking_model_ref = d.get('marking_model_ref') + m.id_ = get('id') + m.idref = get('idref') + m.marking_model_name = get('marking_model_name') + m.marking_model_ref = get('marking_model_ref') else: - if 'xsi:type' in d: - klass = MarkingStructure.lookup_class(d.get('xsi:type')) - m = klass.from_dict(d) - else: - m = cls.from_dict(d, cls()) + klass = stix.lookup_extension(get('xsi:type'), default=cls) + m = klass.from_dict(d, return_obj=klass()) return m diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index 910d74d4..bc255f5a 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -44,7 +44,7 @@ def from_obj(cls, obj, return_obj=None): import stix.extensions.test_mechanism.generic_test_mechanism # noqa if not return_obj: - klass = _BaseTestMechanism.lookup_class(obj) + klass = stix.lookup_extension(obj) return_obj = klass.from_obj(obj) else: return_obj.id_ = obj.id @@ -62,7 +62,7 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.id = self.id_ return_obj.idref = self.idref - return_obj.xsi_type = self._XSI_TYPE + # return_obj.xsi_type = self._XSI_TYPE if self.efficacy: return_obj.Efficacy = self.efficacy.to_obj(ns_info=ns_info) @@ -89,7 +89,7 @@ def from_dict(cls, d, return_obj=None): import stix.extensions.test_mechanism.generic_test_mechanism # noqa if not return_obj: - klass = _BaseTestMechanism.lookup_class(d.get('xsi:type')) + klass = stix.lookup_extension(d.get('xsi:type')) return_obj = klass.from_dict(d) else: return_obj.id_ = d.get('id') diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index 9854e4ee..9239d748 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -202,11 +202,8 @@ def from_obj(cls, obj, return_obj=None): return None if not return_obj: - try: - klass = MalwareInstance.lookup_class(obj) - return_obj = klass.from_obj(obj) - except (ValueError, AttributeError): - return_obj = MalwareInstance.from_obj(obj, cls()) + klass = stix.lookup_extension(obj, default=cls) + return_obj = klass.from_obj(obj, klass()) else: return_obj.id_ = obj.id return_obj.title = obj.Title @@ -235,12 +232,8 @@ def from_dict(cls, dict_repr, return_obj=None): get = dict_repr.get if not return_obj: - xsi_type = get('xsi:type') - if xsi_type: - klass = MalwareInstance.lookup_class(get('xsi:type')) - return_obj = klass.from_dict(dict_repr) - else: - return_obj = MalwareInstance.from_dict(dict_repr, cls()) + klass = stix.lookup_extension(get('xsi:type'), cls) + return_obj = klass.from_dict(dict_repr, klass()) else: return_obj.id_ = get('id') return_obj.title = get('title') From 832bab648e6793440c84db6cf4f0017e762e6d3a Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 11 May 2015 08:13:08 -0400 Subject: [PATCH 079/438] Modified ControlledVocabularyStringType binding to override prefixes for known STIX namespaces. --- stix/bindings/__init__.py | 10 +++++----- stix/bindings/stix_common.py | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/stix/bindings/__init__.py b/stix/bindings/__init__.py index f893b389..a28df452 100644 --- a/stix/bindings/__init__.py +++ b/stix/bindings/__init__.py @@ -470,12 +470,12 @@ def lookup_extension(typeinfo, default=None): elif default: return default - try: + if typeinfo in _EXTENSION_MAP: return _EXTENSION_MAP[typeinfo] - except KeyError: - fmt = "No class implemented or registered for XML type '{%s}%s'" - error = fmt % (typeinfo.ns, typeinfo.typename) - raise NotImplementedError(error) + + fmt = "No class implemented or registered for XML type '{%s}%s'" + error = fmt % (typeinfo.ns, typeinfo.typename) + raise NotImplementedError(error) def has_xsi_type(node): diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index 22d1bfa3..eacf55a3 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -3697,7 +3697,22 @@ def buildAttributes(self, node, attrs, already_processed): value = find_attr_value_('xsi:type', node) if value is not None and 'xsi:type' not in already_processed: already_processed.add('xsi:type') - self.xsi_type = value + + from stix.utils import DEFAULT_STIX_NAMESPACES + typeinfo = get_type_info(node) + + # Override the prefix if its mapped to a known STIX namespace. + # This will help prevent class resolution failures in + # stix.lookup_extension(). + if typeinfo.ns in DEFAULT_STIX_NAMESPACES: + ns = typeinfo.ns + typename = typeinfo.typename + xsi_type = "%s:%s" % (DEFAULT_STIX_NAMESPACES[ns], typename) + else: + xsi_type = value + + self.xsi_type = xsi_type + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass # end class ControlledVocabularyStringType From d33651339a441baffb3182d11138545382739221 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 11 May 2015 09:19:55 -0400 Subject: [PATCH 080/438] Added check for ReportBaseType instances in from_obj(). This is similar to the way other STIX components are parsed. --- stix/report/__init__.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/stix/report/__init__.py b/stix/report/__init__.py index 6c7d42ec..89333f65 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -387,23 +387,27 @@ def from_obj(cls, obj, return_obj=None): if not return_obj: return_obj = cls() + # ReportBaseType fields return_obj.id_ = obj.id return_obj.idref = obj.idref return_obj.timestamp = obj.timestamp - return_obj.header = Header.from_obj(obj.Header) - return_obj.campaigns = Campaigns.from_obj(obj.Campaigns) - return_obj.courses_of_action = CoursesOfAction.from_obj(obj.Courses_Of_Action) - return_obj.exploit_targets = ExploitTargets.from_obj(obj.Exploit_Targets) - return_obj.indicators = Indicators.from_obj(obj.Indicators) - return_obj.observables = Observables.from_obj(obj.Observables) - return_obj.incidents = Incidents.from_obj(obj.Incidents) - return_obj.threat_actors = ThreatActors.from_obj(obj.Threat_Actors) - return_obj.ttps = TTPs.from_obj(obj.TTPs) - return_obj.related_reports = RelatedReports.from_obj(obj.Related_Reports) - - # Don't overwrite unless a version is passed in - if obj.version: - return_obj.version = obj.version + + # ReportType fields + if isinstance(obj, cls._binding_class): + return_obj.header = Header.from_obj(obj.Header) + return_obj.campaigns = Campaigns.from_obj(obj.Campaigns) + return_obj.courses_of_action = CoursesOfAction.from_obj(obj.Courses_Of_Action) + return_obj.exploit_targets = ExploitTargets.from_obj(obj.Exploit_Targets) + return_obj.indicators = Indicators.from_obj(obj.Indicators) + return_obj.observables = Observables.from_obj(obj.Observables) + return_obj.incidents = Incidents.from_obj(obj.Incidents) + return_obj.threat_actors = ThreatActors.from_obj(obj.Threat_Actors) + return_obj.ttps = TTPs.from_obj(obj.TTPs) + return_obj.related_reports = RelatedReports.from_obj(obj.Related_Reports) + + # Don't overwrite unless a version is passed in + if obj.version: + return_obj.version = obj.version return return_obj From b8ebdacfa41394a145654c5e5413978b8e095633 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 11 May 2015 09:20:13 -0400 Subject: [PATCH 081/438] Use XML_NS rather than redefine it. --- stix/bindings/indicator.py | 2 +- stix/bindings/report.py | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/stix/bindings/indicator.py b/stix/bindings/indicator.py index 5782bdd8..b14ded68 100644 --- a/stix/bindings/indicator.py +++ b/stix/bindings/indicator.py @@ -821,7 +821,7 @@ class IndicatorType(stix_common_binding.IndicatorBaseType): subclass = None superclass = stix_common_binding.IndicatorBaseType - xmlns = "http://stix.mitre.org/Indicator-2" + xmlns = XML_NS xmlns_prefix = "indicator" xml_type = "IndicatorType" diff --git a/stix/bindings/report.py b/stix/bindings/report.py index 94faf8d5..c12b2ef3 100644 --- a/stix/bindings/report.py +++ b/stix/bindings/report.py @@ -555,9 +555,6 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): # end class ThreatActorsType - - - @register_extension class ReportType(common_binding.ReportBaseType): """ReportType defines a contextual wrapper for a grouping of STIX From 0731c9df39fa8e68103feb57d24ab9bfd34ba3e4 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 11 May 2015 12:20:47 -0400 Subject: [PATCH 082/438] Changed _EXTENSION_MAP in bindings to _BINDING_EXTENSION_MAP --- stix/bindings/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stix/bindings/__init__.py b/stix/bindings/__init__.py index a28df452..61483315 100644 --- a/stix/bindings/__init__.py +++ b/stix/bindings/__init__.py @@ -424,7 +424,7 @@ def get_type_info(node): #: A mapping of namespace/type information to binding classes. -_EXTENSION_MAP = {} +_BINDING_EXTENSION_MAP = {} def add_extension(cls): @@ -435,7 +435,7 @@ def add_extension(cls): """ typeinfo = TypeInfo(ns=cls.xmlns, typename=cls.xml_type) - _EXTENSION_MAP[typeinfo] = cls + _BINDING_EXTENSION_MAP[typeinfo] = cls def register_extension(cls): @@ -470,8 +470,8 @@ def lookup_extension(typeinfo, default=None): elif default: return default - if typeinfo in _EXTENSION_MAP: - return _EXTENSION_MAP[typeinfo] + if typeinfo in _BINDING_EXTENSION_MAP: + return _BINDING_EXTENSION_MAP[typeinfo] fmt = "No class implemented or registered for XML type '{%s}%s'" error = fmt % (typeinfo.ns, typeinfo.typename) From 20181def6409491b5d004d53f95729d294c955ad Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 12 May 2015 10:15:14 -0400 Subject: [PATCH 083/438] Attempt at retaining parsing of 1.1.1 content --- stix/__init__.py | 3 ++- stix/common/vocabs.py | 58 +++++++++++++++++++++++++++++++++++++++++++ stix/utils/parser.py | 5 +++- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index 0ad6a236..d97d9e4e 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -130,5 +130,6 @@ def register_extension(cls): def supported_stix_version(): - return '.'.join(__version__.split('.')[:3]) + #return '.'.join(__version__.split('.')[:3]) + return ('1.1.1', '1.2') diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index 783b4390..95374841 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -182,6 +182,7 @@ def register_vocab(cls): class AvailabilityLossType(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:AvailabilityLossTypeVocab-1.1.1' + _VOCAB_VERSION = '1.1.1' TERM_DESTRUCTION = "Destruction" TERM_LOSS = "Loss" @@ -196,6 +197,7 @@ class AvailabilityLossType(VocabString): class ThreatActorType(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:ThreatActorTypeVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_CYBER_ESPIONAGE_OPERATIONS = "Cyber Espionage Operations" TERM_HACKER = "Hacker" @@ -220,6 +222,7 @@ class ThreatActorType(VocabString): class AttackerInfrastructureType(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:AttackerInfrastructureTypeVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_ANONYMIZATION = "Anonymization" TERM_ANONYMIZATION_PROXY = "Anonymization - Proxy" @@ -251,6 +254,7 @@ class AttackerInfrastructureType(VocabString): class DiscoveryMethod(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:DiscoveryMethodVocab-2.0' + _VOCAB_VERSION = '2.0' TERM_AGENT_DISCLOSURE = "Agent Disclosure" TERM_EXTERNAL_FRAUD_DETECTION = "External - Fraud Detection" @@ -272,10 +276,36 @@ class DiscoveryMethod(VocabString): TERM_UNKNOWN = "Unknown" +@register_vocab +class DiscoveryMethod_1_0(VocabString): + _namespace = 'http://stix.mitre.org/default_vocabularies-1' + _XSI_TYPE = 'stixVocabs:DiscoveryMethodVocab-1.0' + _VOCAB_VERSION = '1.0' + + TERM_AGENT_DISCLOSURE = "Agent Disclosure" + TERM_FRAUD_DETECTION = "Fraud Detection" + TERM_MONITORING_SERVICE = "Monitoring Service" + TERM_LAW_ENFORCEMENT = "Law Enforcement" + TERM_CUSTOMER = "Customer" + TERM_UNRELATED_PARTY = "Unrelated Party" + TERM_AUDIT = "Audit" + TERM_ANTIVIRUS = "Antivirus" + TERM_INCIDENT_RESPONSE = "Incident Response" + TERM_FINANCIAL_AUDIT = "Financial Audit" + TERM_HIPS = "HIPS" + TERM_IT_AUDIT = "IT Audit" + TERM_LOG_REVIEW = "Log Review" + TERM_NIDS = "NIDS" + TERM_SECURITY_ALARM = "Security Alarm" + TERM_USER = "User" + TERM_UNKNOWN = "Unknown" + + @register_vocab class AttackerToolType(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:AttackerToolTypeVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_MALWARE = "Malware" TERM_PENETRATION_TESTING = "Penetration Testing" @@ -290,6 +320,7 @@ class AttackerToolType(VocabString): class IndicatorType(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:IndicatorTypeVocab-1.1' + _VOCAB_VERSION = '1.1' TERM_MALICIOUS_EMAIL = "Malicious E-mail" TERM_IP_WATCHLIST = "IP Watchlist" @@ -311,6 +342,7 @@ class IndicatorType(VocabString): class SystemType(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:SystemTypeVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_ENTERPRISE_SYSTEMS = "Enterprise Systems" TERM_ENTERPRISE_SYSTEMS_APPLICATION_LAYER = "Enterprise Systems - Application Layer" @@ -345,6 +377,7 @@ class SystemType(VocabString): class CampaignStatus(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:CampaignStatusVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_ONGOING = "Ongoing" TERM_HISTORIC = "Historic" @@ -356,6 +389,7 @@ class IncidentStatus(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:IncidentStatusVocab-1.0' + TERM_NEW = "New" TERM_OPEN = "Open" TERM_STALLED = "Stalled" @@ -382,6 +416,7 @@ class ManagementClass(VocabString): class Motivation(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:MotivationVocab-1.1' + _VOCAB_VERSION = '1.1' TERM_IDEOLOGICAL = "Ideological" TERM_IDEOLOGICAL_ANTICORRUPTION = "Ideological - Anti-Corruption" @@ -403,6 +438,7 @@ class Motivation(VocabString): class IncidentCategory(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:IncidentCategoryVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_EXERCISEORNETWORK_DEFENSE_TESTING = "Exercise/Network Defense Testing" TERM_UNAUTHORIZED_ACCESS = "Unauthorized Access" @@ -417,6 +453,7 @@ class IncidentCategory(VocabString): class ImpactQualification(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:ImpactQualificationVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_INSIGNIFICANT = "Insignificant" TERM_DISTRACTING = "Distracting" @@ -430,6 +467,7 @@ class ImpactQualification(VocabString): class PlanningAndOperationalSupport(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:PlanningAndOperationalSupportVocab-1.0.1' + _VOCAB_VERSION = '1.0.1' TERM_DATA_EXPLOITATION = "Data Exploitation" TERM_DATA_EXPLOITATION_ANALYTIC_SUPPORT = "Data Exploitation - Analytic Support" @@ -459,6 +497,7 @@ class PlanningAndOperationalSupport(VocabString): class CourseOfActionType(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:CourseOfActionTypeVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_PERIMETER_BLOCKING = "Perimeter Blocking" TERM_INTERNAL_BLOCKING = "Internal Blocking" @@ -482,6 +521,7 @@ class CourseOfActionType(VocabString): class SecurityCompromise(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:SecurityCompromiseVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_YES = "Yes" TERM_SUSPECTED = "Suspected" @@ -493,6 +533,7 @@ class SecurityCompromise(VocabString): class ImpactRating(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:ImpactRatingVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_NONE = "None" TERM_MINOR = "Minor" @@ -505,6 +546,7 @@ class ImpactRating(VocabString): class AssetType(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:AssetTypeVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_BACKUP = "Backup" TERM_DATABASE = "Database" @@ -587,6 +629,7 @@ class AssetType(VocabString): class COAStage(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:COAStageVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_REMEDY = "Remedy" TERM_RESPONSE = "Response" @@ -596,6 +639,7 @@ class COAStage(VocabString): class LocationClass(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:LocationClassVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_INTERNALLYLOCATED = "Internally-Located" TERM_EXTERNALLYLOCATED = "Externally-Located" @@ -608,6 +652,7 @@ class LocationClass(VocabString): class InformationType(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:InformationTypeVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_INFORMATION_ASSETS = "Information Assets" TERM_INFORMATION_ASSETS_CORPORATE_EMPLOYEE_INFORMATION = "Information Assets - Corporate Employee Information" @@ -624,6 +669,7 @@ class InformationType(VocabString): class ThreatActorSophistication(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:ThreatActorSophisticationVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_INNOVATOR = "Innovator" TERM_EXPERT = "Expert" @@ -636,6 +682,7 @@ class ThreatActorSophistication(VocabString): class HighMediumLow(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:HighMediumLowVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_HIGH = "High" TERM_MEDIUM = "Medium" @@ -648,6 +695,7 @@ class HighMediumLow(VocabString): class LossProperty(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:LossPropertyVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_CONFIDENTIALITY = "Confidentiality" TERM_INTEGRITY = "Integrity" @@ -660,6 +708,7 @@ class LossProperty(VocabString): class IntendedEffect(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:IntendedEffectVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_ADVANTAGE = "Advantage" TERM_ADVANTAGE_ECONOMIC = "Advantage - Economic" @@ -691,6 +740,7 @@ class IntendedEffect(VocabString): class PackageIntent(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:PackageIntentVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_COLLECTIVE_THREAT_INTELLIGENCE = "Collective Threat Intelligence" TERM_THREAT_REPORT = "Threat Report" @@ -718,6 +768,7 @@ class PackageIntent(VocabString): class ReportIntent(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:ReportIntentVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_COLLECTIVE_THREAT_INTELLIGENCE = "Collective Threat Intelligence" TERM_THREAT_REPORT = "Threat Report" @@ -746,6 +797,7 @@ class ReportIntent(VocabString): class LossDuration(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:LossDurationVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_PERMANENT = "Permanent" TERM_WEEKS = "Weeks" @@ -760,6 +812,7 @@ class LossDuration(VocabString): class OwnershipClass(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:OwnershipClassVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_INTERNALLYOWNED = "Internally-Owned" TERM_EMPLOYEEOWNED = "Employee-Owned" @@ -772,6 +825,7 @@ class OwnershipClass(VocabString): class MalwareType(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:MalwareTypeVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_AUTOMATED_TRANSFER_SCRIPTS = "Automated Transfer Scripts" TERM_ADWARE = "Adware" @@ -797,6 +851,7 @@ class MalwareType(VocabString): class IncidentEffect(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:IncidentEffectVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_BRAND_OR_IMAGE_DEGRADATION = "Brand or Image Degradation" TERM_LOSS_OF_COMPETITIVE_ADVANTAGE = "Loss of Competitive Advantage" @@ -818,6 +873,7 @@ class IncidentEffect(VocabString): class InformationSourceRole(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:InformationSourceRoleVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_INITIAL_AUTHOR = "Initial Author" TERM_CONTENT_ENHANCERORREFINER = "Content Enhancer/Refiner" @@ -829,6 +885,8 @@ class InformationSourceRole(VocabString): class Versioning(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:VersioningVocab-1.0' + _VOCAB_VERSION = '1.0' + TERM_UPDATES_REVISES = "Updates - Revises" TERM_UPDATE_CORRECTS = "Updates - Corrects" diff --git a/stix/utils/parser.py b/stix/utils/parser.py index f79365a6..65e2f762 100644 --- a/stix/utils/parser.py +++ b/stix/utils/parser.py @@ -144,7 +144,10 @@ def _check_version(self, tree): document_version = get_document_version(tree) supported = stix.supported_stix_version() - if StrictVersion(supported) == StrictVersion(document_version): + doc_version = StrictVersion(document_version) + api_versions = [StrictVersion(x) for x in supported] + + if doc_version in api_versions: return error = ( From f56f6435c87ef897a6a5f91981de4858c699e936 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 12 May 2015 12:10:38 -0400 Subject: [PATCH 084/438] * Added older versions of VocabString implementations. * Versioned existing classnames (e.g., IndicatorType becomes IndicatorType_1_0) * Made non-versioned aliases resolve to the 'most recent' vocabulary. * Sorted TERM_ class attributes. --- stix/common/vocabs.py | 655 +++++++++++++++++++++++++----------------- 1 file changed, 398 insertions(+), 257 deletions(-) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index 95374841..e98bc6fc 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -179,33 +179,43 @@ def register_vocab(cls): @register_vocab -class AvailabilityLossType(VocabString): +class AvailabilityLossType_1_0(VocabString): + _namespace = 'http://stix.mitre.org/default_vocabularies-1' + _XSI_TYPE = 'stixVocabs:AvailabilityLossTypeVocab-1.0' + _VOCAB_VERSION = '1.0' + + TERM_ACCELERATION = 'Acceleration' + TERM_DEGREDATION = 'Degredation' + TERM_DESTRUCTION = 'Destruction' + TERM_INTERRUPTION = 'Interruption' + TERM_LOSS = 'Loss' + TERM_OBSCURATION = 'Obscuration' + TERM_UNKNOWN = 'Unknown' + + +@register_vocab +class AvailabilityLossType_1_1_1(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:AvailabilityLossTypeVocab-1.1.1' _VOCAB_VERSION = '1.1.1' - TERM_DESTRUCTION = "Destruction" - TERM_LOSS = "Loss" - TERM_INTERRUPTION = "Interruption" - TERM_DEGRADATION = "Degradation" - TERM_ACCELERATION = "Acceleration" - TERM_OBSCURATION = "Obscuration" - TERM_UNKNOWN = "Unknown" + TERM_ACCELERATION = 'Acceleration' + TERM_DEGRADATION = 'Degradation' + TERM_DESTRUCTION = 'Destruction' + TERM_INTERRUPTION = 'Interruption' + TERM_LOSS = 'Loss' + TERM_OBSCURATION = 'Obscuration' + TERM_UNKNOWN = 'Unknown' @register_vocab -class ThreatActorType(VocabString): +class ThreatActorType_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:ThreatActorTypeVocab-1.0' _VOCAB_VERSION = '1.0' TERM_CYBER_ESPIONAGE_OPERATIONS = "Cyber Espionage Operations" - TERM_HACKER = "Hacker" - TERM_HACKER_WHITE_HAT = "Hacker - White hat" - TERM_HACKER_GRAY_HAT = "Hacker - Gray hat" - TERM_HACKER_BLACK_HAT = "Hacker - Black hat" - TERM_HACKTIVIST = "Hacktivist" - TERM_STATE_ACTOR_OR_AGENCY = "State Actor / Agency" + TERM_DISGRUNTLED_CUSTOMER_OR_USER = "Disgruntled Customer / User" TERM_ECRIME_ACTOR_CREDENTIAL_THEFT_BOTNET_OPERATOR = "eCrime Actor - Credential Theft Botnet Operator" TERM_ECRIME_ACTOR_CREDENTIAL_THEFT_BOTNET_SERVICE = "eCrime Actor - Credential Theft Botnet Service" TERM_ECRIME_ACTOR_MALWARE_DEVELOPER = "eCrime Actor - Malware Developer" @@ -214,12 +224,17 @@ class ThreatActorType(VocabString): TERM_ECRIME_ACTOR_SPAM_SERVICE = "eCrime Actor - Spam Service" TERM_ECRIME_ACTOR_TRAFFIC_SERVICE = "eCrime Actor - Traffic Service" TERM_ECRIME_ACTOR_UNDERGROUND_CALL_SERVICE = "eCrime Actor - Underground Call Service" + TERM_HACKER = "Hacker" + TERM_HACKER_BLACK_HAT = "Hacker - Black hat" + TERM_HACKER_GRAY_HAT = "Hacker - Gray hat" + TERM_HACKER_WHITE_HAT = "Hacker - White hat" + TERM_HACKTIVIST = "Hacktivist" TERM_INSIDER_THREAT = "Insider Threat" - TERM_DISGRUNTLED_CUSTOMER_OR_USER = "Disgruntled Customer / User" + TERM_STATE_ACTOR_OR_AGENCY = "State Actor / Agency" @register_vocab -class AttackerInfrastructureType(VocabString): +class AttackerInfrastructureType_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:AttackerInfrastructureTypeVocab-1.0' _VOCAB_VERSION = '1.0' @@ -241,105 +256,122 @@ class AttackerInfrastructureType(VocabString): TERM_DOMAIN_REGISTRATION_LEGITIMATE_DOMAIN_REGISTRATION_SERVICES = "Domain Registration - Legitimate Domain Registration Services" TERM_DOMAIN_REGISTRATION_MALICIOUS_DOMAIN_REGISTRARS = "Domain Registration - Malicious Domain Registrars" TERM_DOMAIN_REGISTRATION_TOPLEVEL_DOMAIN_REGISTRARS = "Domain Registration - Top-Level Domain Registrars" + TERM_ELECTRONIC_PAYMENT_METHODS = "Electronic Payment Methods" TERM_HOSTING = "Hosting" TERM_HOSTING_BULLETPROOF_OR_ROGUE_HOSTING = "Hosting - Bulletproof / Rogue Hosting" TERM_HOSTING_CLOUD_HOSTING = "Hosting - Cloud Hosting" TERM_HOSTING_COMPROMISED_SERVER = "Hosting - Compromised Server" TERM_HOSTING_FAST_FLUX_BOTNET_HOSTING = "Hosting - Fast Flux Botnet Hosting" TERM_HOSTING_LEGITIMATE_HOSTING = "Hosting - Legitimate Hosting" - TERM_ELECTRONIC_PAYMENT_METHODS = "Electronic Payment Methods" @register_vocab -class DiscoveryMethod(VocabString): +class DiscoveryMethod_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' - _XSI_TYPE = 'stixVocabs:DiscoveryMethodVocab-2.0' - _VOCAB_VERSION = '2.0' + _XSI_TYPE = 'stixVocabs:DiscoveryMethodVocab-1.0' + _VOCAB_VERSION = '1.0' TERM_AGENT_DISCLOSURE = "Agent Disclosure" - TERM_EXTERNAL_FRAUD_DETECTION = "External - Fraud Detection" - TERM_INTERNAL_FRAUD_DETECTION = "Internal - Fraud Detection" - TERM_MONITORING_SERVICE = "Monitoring Service" - TERM_LAW_ENFORCEMENT = "Law Enforcement" - TERM_CUSTOMER = "Customer" - TERM_UNRELATED_PARTY = "Unrelated Party" - TERM_AUDIT = "Audit" TERM_ANTIVIRUS = "Antivirus" - TERM_INCIDENT_RESPONSE = "Incident Response" + TERM_AUDIT = "Audit" + TERM_CUSTOMER = "Customer" TERM_FINANCIAL_AUDIT = "Financial Audit" + TERM_FRAUD_DETECTION = "Fraud Detection" TERM_HIPS = "HIPS" + TERM_INCIDENT_RESPONSE = "Incident Response" TERM_IT_AUDIT = "IT Audit" + TERM_LAW_ENFORCEMENT = "Law Enforcement" TERM_LOG_REVIEW = "Log Review" + TERM_MONITORING_SERVICE = "Monitoring Service" TERM_NIDS = "NIDS" TERM_SECURITY_ALARM = "Security Alarm" - TERM_USER = "User" TERM_UNKNOWN = "Unknown" - + TERM_UNRELATED_PARTY = "Unrelated Party" + TERM_USER = "User" @register_vocab -class DiscoveryMethod_1_0(VocabString): +class DiscoveryMethod_2_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' - _XSI_TYPE = 'stixVocabs:DiscoveryMethodVocab-1.0' - _VOCAB_VERSION = '1.0' + _XSI_TYPE = 'stixVocabs:DiscoveryMethodVocab-2.0' + _VOCAB_VERSION = '2.0' TERM_AGENT_DISCLOSURE = "Agent Disclosure" - TERM_FRAUD_DETECTION = "Fraud Detection" - TERM_MONITORING_SERVICE = "Monitoring Service" - TERM_LAW_ENFORCEMENT = "Law Enforcement" - TERM_CUSTOMER = "Customer" - TERM_UNRELATED_PARTY = "Unrelated Party" - TERM_AUDIT = "Audit" TERM_ANTIVIRUS = "Antivirus" - TERM_INCIDENT_RESPONSE = "Incident Response" + TERM_AUDIT = "Audit" + TERM_CUSTOMER = "Customer" + TERM_EXTERNAL_FRAUD_DETECTION = "External - Fraud Detection" TERM_FINANCIAL_AUDIT = "Financial Audit" TERM_HIPS = "HIPS" + TERM_INCIDENT_RESPONSE = "Incident Response" + TERM_INTERNAL_FRAUD_DETECTION = "Internal - Fraud Detection" TERM_IT_AUDIT = "IT Audit" + TERM_LAW_ENFORCEMENT = "Law Enforcement" TERM_LOG_REVIEW = "Log Review" + TERM_MONITORING_SERVICE = "Monitoring Service" TERM_NIDS = "NIDS" TERM_SECURITY_ALARM = "Security Alarm" - TERM_USER = "User" TERM_UNKNOWN = "Unknown" + TERM_UNRELATED_PARTY = "Unrelated Party" + TERM_USER = "User" @register_vocab -class AttackerToolType(VocabString): +class AttackerToolType_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:AttackerToolTypeVocab-1.0' _VOCAB_VERSION = '1.0' + TERM_APPLICATION_SCANNER = "Application Scanner" TERM_MALWARE = "Malware" + TERM_PASSWORD_CRACKING = "Password Cracking" TERM_PENETRATION_TESTING = "Penetration Testing" TERM_PORT_SCANNER = "Port Scanner" TERM_TRAFFIC_SCANNER = "Traffic Scanner" TERM_VULNERABILITY_SCANNER = "Vulnerability Scanner" - TERM_APPLICATION_SCANNER = "Application Scanner" - TERM_PASSWORD_CRACKING = "Password Cracking" @register_vocab -class IndicatorType(VocabString): +class IndicatorType_1_0(VocabString): + _namespace = 'http://stix.mitre.org/default_vocabularies-1' + _XSI_TYPE = 'stixVocabs:IndicatorTypeVocab-1.0' + _VOCAB_VERSION = '1.0' + + TERM_ANONYMIZATION = 'Anonymization' + TERM_C2 = 'C2' + TERM_DOMAIN_WATCHLIST = 'Domain Watchlist' + TERM_EXFILTRATION = 'Exfiltration' + TERM_FILE_HASH_WATCHLIST = 'File Hash Watchlist' + TERM_HOST_CHARACTERISTICS = 'Host Characteristics' + TERM_IP_WATCHLIST = 'IP Watchlist' + TERM_MALICIOUS_EMAIL = 'Malicious E-mail' + TERM_MALWARE_ARTIFACTS = 'Malware Artifacts' + TERM_URL_WATCHLIST = 'URL Watchlist' + + +@register_vocab +class IndicatorType_1_1(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:IndicatorTypeVocab-1.1' _VOCAB_VERSION = '1.1' - TERM_MALICIOUS_EMAIL = "Malicious E-mail" - TERM_IP_WATCHLIST = "IP Watchlist" - TERM_FILE_HASH_WATCHLIST = "File Hash Watchlist" - TERM_DOMAIN_WATCHLIST = "Domain Watchlist" - TERM_URL_WATCHLIST = "URL Watchlist" - TERM_MALWARE_ARTIFACTS = "Malware Artifacts" - TERM_C2 = "C2" - TERM_ANONYMIZATION = "Anonymization" - TERM_EXFILTRATION = "Exfiltration" - TERM_HOST_CHARACTERISTICS = "Host Characteristics" - TERM_COMPROMISED_PKI_CERTIFICATE = "Compromised PKI Certificate" - TERM_LOGIN_NAME = "Login Name" - TERM_IMEI_WATCHLIST = "IMEI Watchlist" - TERM_IMSI_WATCHLIST = "IMSI Watchlist" + TERM_ANONYMIZATION = 'Anonymization' + TERM_C2 = 'C2' + TERM_COMPROMISED_PKI_CERTIFICATE = 'Compromised PKI Certificate' + TERM_DOMAIN_WATCHLIST = 'Domain Watchlist' + TERM_EXFILTRATION = 'Exfiltration' + TERM_FILE_HASH_WATCHLIST = 'File Hash Watchlist' + TERM_HOST_CHARACTERISTICS = 'Host Characteristics' + TERM_IMEI_WATCHLIST = 'IMEI Watchlist' + TERM_IMSI_WATCHLIST = 'IMSI Watchlist' + TERM_IP_WATCHLIST = 'IP Watchlist' + TERM_LOGIN_NAME = 'Login Name' + TERM_MALICIOUS_EMAIL = 'Malicious E-mail' + TERM_MALWARE_ARTIFACTS = 'Malware Artifacts' + TERM_URL_WATCHLIST = 'URL Watchlist' @register_vocab -class SystemType(VocabString): +class SystemType_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:SystemTypeVocab-1.0' _VOCAB_VERSION = '1.0' @@ -348,19 +380,19 @@ class SystemType(VocabString): TERM_ENTERPRISE_SYSTEMS_APPLICATION_LAYER = "Enterprise Systems - Application Layer" TERM_ENTERPRISE_SYSTEMS_DATABASE_LAYER = "Enterprise Systems - Database Layer" TERM_ENTERPRISE_SYSTEMS_ENTERPRISE_TECHNOLOGIES_AND_SUPPORT_INFRASTRUCTURE = "Enterprise Systems - Enterprise Technologies and Support Infrastructure" - TERM_ENTERPRISE_SYSTEMS_NETWORK_SYSTEMS = "Enterprise Systems - Network Systems" TERM_ENTERPRISE_SYSTEMS_NETWORKING_DEVICES = "Enterprise Systems - Networking Devices" - TERM_ENTERPRISE_SYSTEMS_WEB_LAYER = "Enterprise Systems - Web Layer" + TERM_ENTERPRISE_SYSTEMS_NETWORK_SYSTEMS = "Enterprise Systems - Network Systems" TERM_ENTERPRISE_SYSTEMS_VOIP = "Enterprise Systems - VoIP" + TERM_ENTERPRISE_SYSTEMS_WEB_LAYER = "Enterprise Systems - Web Layer" TERM_INDUSTRIAL_CONTROL_SYSTEMS = "Industrial Control Systems" TERM_INDUSTRIAL_CONTROL_SYSTEMS_EQUIPMENT_UNDER_CONTROL = "Industrial Control Systems - Equipment Under Control" TERM_INDUSTRIAL_CONTROL_SYSTEMS_OPERATIONS_MANAGEMENT = "Industrial Control Systems - Operations Management" TERM_INDUSTRIAL_CONTROL_SYSTEMS_SAFETY_PROTECTION_AND_LOCAL_CONTROL = "Industrial Control Systems - Safety, Protection and Local Control" TERM_INDUSTRIAL_CONTROL_SYSTEMS_SUPERVISORY_CONTROL = "Industrial Control Systems - Supervisory Control" TERM_MOBILE_SYSTEMS = "Mobile Systems" + TERM_MOBILE_SYSTEMS_MOBILE_DEVICES = "Mobile Systems - Mobile Devices" TERM_MOBILE_SYSTEMS_MOBILE_OPERATING_SYSTEMS = "Mobile Systems - Mobile Operating Systems" TERM_MOBILE_SYSTEMS_NEAR_FIELD_COMMUNICATIONS = "Mobile Systems - Near Field Communications" - TERM_MOBILE_SYSTEMS_MOBILE_DEVICES = "Mobile Systems - Mobile Devices" TERM_THIRDPARTY_SERVICES = "Third-Party Services" TERM_THIRDPARTY_SERVICES_APPLICATION_STORES = "Third-Party Services - Application Stores" TERM_THIRDPARTY_SERVICES_CLOUD_SERVICES = "Third-Party Services - Cloud Services" @@ -369,102 +401,177 @@ class SystemType(VocabString): TERM_THIRDPARTY_SERVICES_SOFTWARE_UPDATE = "Third-Party Services - Software Update" TERM_USERS = "Users" TERM_USERS_APPLICATION_AND_SOFTWARE = "Users - Application And Software" - TERM_USERS_WORKSTATION = "Users - Workstation" TERM_USERS_REMOVABLE_MEDIA = "Users - Removable Media" + TERM_USERS_WORKSTATION = "Users - Workstation" @register_vocab -class CampaignStatus(VocabString): +class CampaignStatus_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:CampaignStatusVocab-1.0' _VOCAB_VERSION = '1.0' - TERM_ONGOING = "Ongoing" - TERM_HISTORIC = "Historic" TERM_FUTURE = "Future" + TERM_HISTORIC = "Historic" + TERM_ONGOING = "Ongoing" @register_vocab -class IncidentStatus(VocabString): +class IncidentStatus_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:IncidentStatusVocab-1.0' + _VOCAB_VERSION = '1.0' - - TERM_NEW = "New" - TERM_OPEN = "Open" - TERM_STALLED = "Stalled" + TERM_CLOSED = "Closed" TERM_CONTAINMENT_ACHIEVED = "Containment Achieved" - TERM_RESTORATION_ACHIEVED = "Restoration Achieved" + TERM_DELETED = "Deleted" TERM_INCIDENT_REPORTED = "Incident Reported" - TERM_CLOSED = "Closed" + TERM_NEW = "New" + TERM_OPEN = "Open" TERM_REJECTED = "Rejected" - TERM_DELETED = "Deleted" + TERM_RESTORATION_ACHIEVED = "Restoration Achieved" + TERM_STALLED = "Stalled" @register_vocab -class ManagementClass(VocabString): +class ManagementClass_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:ManagementClassVocab-1.0' + _VOCAB_VERSION = '1.0' - TERM_INTERNALLYMANAGED = "Internally-Managed" - TERM_EXTERNALLYMANAGEMENT = "Externally-Management" TERM_COMANAGEMENT = "Co-Management" + TERM_EXTERNALLYMANAGEMENT = "Externally-Management" + TERM_INTERNALLYMANAGED = "Internally-Managed" TERM_UNKNOWN = "Unknown" @register_vocab -class Motivation(VocabString): +class Motivation_1_0(VocabString): + _namespace = 'http://stix.mitre.org/default_vocabularies-1' + _XSI_TYPE = 'stixVocabs:MotivationVocab-1.0' + _VOCAB_VERSION = '1.0' + + TERM_EGO = 'Ego' + TERM_FINANCIAL_OR_ECONOMIC = 'Financial or Economic' + TERM_IDEOLOGICAL = 'Ideological' + TERM_IDEOLOGICAL_ANTICORRUPTION = 'Ideological - Anti-Corruption' + TERM_IDEOLOGICAL_ANTIESTABLISMENT = 'Ideological - Anti-Establisment' + TERM_IDEOLOGICAL_ENVIRONMENTAL = 'Ideological - Environmental' + TERM_IDEOLOGICAL_ETHNIC_NATIONALIST = 'Ideological - Ethnic / Nationalist' + TERM_IDEOLOGICAL_HUMAN_RIGHTS = 'Ideological - Human Rights' + TERM_IDEOLOGICAL_INFORMATION_FREEDOM = 'Ideological - Information Freedom' + TERM_IDEOLOGICAL_RELIGIOUS = 'Ideological - Religious' + TERM_IDEOLOGICAL_SECURITY_AWARENESS = 'Ideological - Security Awareness' + TERM_MILITARY = 'Military' + TERM_OPPORTUNISTIC = 'Opportunistic' + TERM_POLICITAL = 'Policital' + + +@register_vocab +class Motivation_1_0_1(VocabString): + _namespace = 'http://stix.mitre.org/default_vocabularies-1' + _XSI_TYPE = 'stixVocabs:MotivationVocab-1.0.1' + _VOCAB_VERSION = '1.0.1' + + TERM_EGO = 'Ego' + TERM_FINANCIAL_OR_ECONOMIC = 'Financial or Economic' + TERM_IDEOLOGICAL = 'Ideological' + TERM_IDEOLOGICAL_ANTI_CORRUPTION = 'Ideological - Anti-Corruption' + TERM_IDEOLOGICAL_ANTI_ESTABLISHMENT = 'Ideological - Anti-Establishment' + TERM_IDEOLOGICAL_ENVIRONMENTAL = 'Ideological - Environmental' + TERM_IDEOLOGICAL_ETHNIC_NATIONALIST = 'Ideological - Ethnic / Nationalist' + TERM_IDEOLOGICAL_HUMAN_RIGHTS = 'Ideological - Human Rights' + TERM_IDEOLOGICAL_INFORMATION_FREEDOM = 'Ideological - Information Freedom' + TERM_IDEOLOGICAL_SECURITY_AWARENESS = 'Ideological - Security Awareness' + TERM_IDEOLOGICAL__RELIGIOUS = 'Ideological - Religious' + TERM_MILITARY = 'Military' + TERM_OPPORTUNISTIC = 'Opportunistic' + TERM_POLICITAL = 'Policital' + + +@register_vocab +class Motivation_1_1(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:MotivationVocab-1.1' _VOCAB_VERSION = '1.1' - TERM_IDEOLOGICAL = "Ideological" - TERM_IDEOLOGICAL_ANTICORRUPTION = "Ideological - Anti-Corruption" - TERM_IDEOLOGICAL_ANTIESTABLISHMENT = "Ideological - Anti-Establishment" - TERM_IDEOLOGICAL_ENVIRONMENTAL = "Ideological - Environmental" - TERM_IDEOLOGICAL_ETHNIC_OR_NATIONALIST = "Ideological - Ethnic / Nationalist" - TERM_IDEOLOGICAL_INFORMATION_FREEDOM = "Ideological - Information Freedom" - TERM_IDEOLOGICAL_RELIGIOUS = "Ideological - Religious" - TERM_IDEOLOGICAL_SECURITY_AWARENESS = "Ideological - Security Awareness" - TERM_IDEOLOGICAL_HUMAN_RIGHTS = "Ideological - Human Rights" - TERM_EGO = "Ego" - TERM_FINANCIAL_OR_ECONOMIC = "Financial or Economic" - TERM_MILITARY = "Military" - TERM_OPPORTUNISTIC = "Opportunistic" - TERM_POLITICAL = "Political" + TERM_EGO = 'Ego' + TERM_FINANCIAL_OR_ECONOMIC = 'Financial or Economic' + TERM_IDEOLOGICAL = 'Ideological' + TERM_IDEOLOGICAL_ANTICORRUPTION = 'Ideological - Anti-Corruption' + TERM_IDEOLOGICAL_ANTIESTABLISHMENT = 'Ideological - Anti-Establishment' + TERM_IDEOLOGICAL_ENVIRONMENTAL = 'Ideological - Environmental' + TERM_IDEOLOGICAL_ETHNIC_NATIONALIST = 'Ideological - Ethnic / Nationalist' + TERM_IDEOLOGICAL_HUMAN_RIGHTS = 'Ideological - Human Rights' + TERM_IDEOLOGICAL_INFORMATION_FREEDOM = 'Ideological - Information Freedom' + TERM_IDEOLOGICAL_RELIGIOUS = 'Ideological - Religious' + TERM_IDEOLOGICAL_SECURITY_AWARENESS = 'Ideological - Security Awareness' + TERM_MILITARY = 'Military' + TERM_OPPORTUNISTIC = 'Opportunistic' + TERM_POLITICAL = 'Political' @register_vocab -class IncidentCategory(VocabString): +class IncidentCategory_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:IncidentCategoryVocab-1.0' _VOCAB_VERSION = '1.0' - TERM_EXERCISEORNETWORK_DEFENSE_TESTING = "Exercise/Network Defense Testing" - TERM_UNAUTHORIZED_ACCESS = "Unauthorized Access" TERM_DENIAL_OF_SERVICE = "Denial of Service" - TERM_MALICIOUS_CODE = "Malicious Code" + TERM_EXERCISEORNETWORK_DEFENSE_TESTING = "Exercise/Network Defense Testing" TERM_IMPROPER_USAGE = "Improper Usage" - TERM_SCANSORPROBESORATTEMPTED_ACCESS = "Scans/Probes/Attempted Access" TERM_INVESTIGATION = "Investigation" + TERM_MALICIOUS_CODE = "Malicious Code" + TERM_SCANSORPROBESORATTEMPTED_ACCESS = "Scans/Probes/Attempted Access" + TERM_UNAUTHORIZED_ACCESS = "Unauthorized Access" @register_vocab -class ImpactQualification(VocabString): +class ImpactQualification_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:ImpactQualificationVocab-1.0' _VOCAB_VERSION = '1.0' - TERM_INSIGNIFICANT = "Insignificant" + TERM_CATASTROPHIC = "Catastrophic" + TERM_DAMAGING = "Damaging" TERM_DISTRACTING = "Distracting" + TERM_INSIGNIFICANT = "Insignificant" TERM_PAINFUL = "Painful" - TERM_DAMAGING = "Damaging" - TERM_CATASTROPHIC = "Catastrophic" TERM_UNKNOWN = "Unknown" @register_vocab -class PlanningAndOperationalSupport(VocabString): +class PlanningAndOperationalSupport_1_0(VocabString): + _namespace = 'http://stix.mitre.org/default_vocabularies-1' + _XSI_TYPE = 'stixVocabs:PlanningAndOperationalSupportVocab-1.0' + _VOCAB_VERSION = '1.0' + + TERM_DATA_EXPLOITATION = 'Data Exploitation' + TERM_DATA_EXPLOITATION_ANALYTIC_SUPPORT = 'Data Exploitation - Analytic Support' + TERM_DATA_EXPLOITATION_TRANSLATION_SUPPORT = 'Data Exploitation - Translation Support' + TERM_FINANCIAL_RESOURCES = 'Financial Resources' + TERM_FINANCIAL_RESOURCES_ACADEMIC = 'Financial Resources - Academic' + TERM_FINANCIAL_RESOURCES_COMMERCIAL = 'Financial Resources - Commercial' + TERM_FINANCIAL_RESOURCES_GOVERNMENT = 'Financial Resources - Government' + TERM_FINANCIAL_RESOURCES_HACKTIVIST_OR_GRASSROOT = 'Financial Resources - Hacktivist or Grassroot' + TERM_FINANCIAL_RESOURCES_NONATTRIBUTABLE_FINANCE = 'Financial Resources - Non-Attributable Finance' + TERM_PLANNING = 'Planning ' + TERM_PLANNING_OPEN_SOURCE_INTELLIGENCE_OSINT_GETHERING = 'Planning - Open-Source Intelligence (OSINT) Gethering' + TERM_PLANNING_OPERATIONAL_COVER_PLAN = 'Planning - Operational Cover Plan' + TERM_PLANNING_PRE_OPERATIONAL_SURVEILLANCE_AND_RECONNAISSANCE = 'Planning - Pre-Operational Surveillance and Reconnaissance' + TERM_PLANNING_TARGET_SELECTION = 'Planning - Target Selection' + TERM_SKILL_DEVELOPMENT_RECRUITMENT = 'Skill Development / Recruitment' + TERM_SKILL_DEVELOPMENT_RECRUITMENT_CONTRACTING_AND_HIRING = 'Skill Development / Recruitment - Contracting and Hiring' + TERM_SKILL_DEVELOPMENT_RECRUITMENT_DOCUMENT_EXPLOITATION_DOCEX_TRAINING = 'Skill Development / Recruitment - Document Exploitation (DOCEX) Training' + TERM_SKILL_DEVELOPMENT_RECRUITMENT_INTERNAL_TRAINING = 'Skill Development / Recruitment - Internal Training' + TERM_SKILL_DEVELOPMENT_RECRUITMENT_MILITARY_PROGRAMS = 'Skill Development / Recruitment - Military Programs' + TERM_SKILL_DEVELOPMENT_RECRUITMENT_SECURITY_HACKER_CONFERENCES = 'Skill Development / Recruitment - Security / Hacker Conferences' + TERM_SKILL_DEVELOPMENT_RECRUITMENT_UNDERGROUND_FORUMS = 'Skill Development / Recruitment - Underground Forums' + TERM_SKILL_DEVELOPMENT_RECRUITMENT_UNIVERSITY_PROGRAMS = 'Skill Development / Recruitment - University Programs' + + +@register_vocab +class PlanningAndOperationalSupport_1_0_1(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:PlanningAndOperationalSupportVocab-1.0.1' _VOCAB_VERSION = '1.0.1' @@ -478,6 +585,11 @@ class PlanningAndOperationalSupport(VocabString): TERM_FINANCIAL_RESOURCES_GOVERNMENT = "Financial Resources - Government" TERM_FINANCIAL_RESOURCES_HACKTIVIST_OR_GRASSROOT = "Financial Resources - Hacktivist or Grassroot" TERM_FINANCIAL_RESOURCES_NONATTRIBUTABLE_FINANCE = "Financial Resources - Non-Attributable Finance" + TERM_PLANNING = "Planning" + TERM_PLANNING_OPENSOURCE_INTELLIGENCE_OSINT_GATHERING = "Planning - Open-Source Intelligence (OSINT) Gathering" + TERM_PLANNING_OPERATIONAL_COVER_PLAN = "Planning - Operational Cover Plan" + TERM_PLANNING_PREOPERATIONAL_SURVEILLANCE_AND_RECONNAISSANCE = "Planning - Pre-Operational Surveillance and Reconnaissance" + TERM_PLANNING_TARGET_SELECTION = "Planning - Target Selection" TERM_SKILL_DEVELOPMENT_OR_RECRUITMENT = "Skill Development / Recruitment" TERM_SKILL_DEVELOPMENT_OR_RECRUITMENT_CONTRACTING_AND_HIRING = "Skill Development / Recruitment - Contracting and Hiring" TERM_SKILL_DEVELOPMENT_OR_RECRUITMENT_DOCUMENT_EXPLOITATION_DOCEX_TRAINING = "Skill Development / Recruitment - Document Exploitation (DOCEX) Training" @@ -486,147 +598,142 @@ class PlanningAndOperationalSupport(VocabString): TERM_SKILL_DEVELOPMENT_OR_RECRUITMENT_SECURITY_OR_HACKER_CONFERENCES = "Skill Development / Recruitment - Security / Hacker Conferences" TERM_SKILL_DEVELOPMENT_OR_RECRUITMENT_UNDERGROUND_FORUMS = "Skill Development / Recruitment - Underground Forums" TERM_SKILL_DEVELOPMENT_OR_RECRUITMENT_UNIVERSITY_PROGRAMS = "Skill Development / Recruitment - University Programs" - TERM_PLANNING = "Planning" - TERM_PLANNING_OPERATIONAL_COVER_PLAN = "Planning - Operational Cover Plan" - TERM_PLANNING_OPENSOURCE_INTELLIGENCE_OSINT_GATHERING = "Planning - Open-Source Intelligence (OSINT) Gathering" - TERM_PLANNING_PREOPERATIONAL_SURVEILLANCE_AND_RECONNAISSANCE = "Planning - Pre-Operational Surveillance and Reconnaissance" - TERM_PLANNING_TARGET_SELECTION = "Planning - Target Selection" @register_vocab -class CourseOfActionType(VocabString): +class CourseOfActionType_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:CourseOfActionTypeVocab-1.0' _VOCAB_VERSION = '1.0' - TERM_PERIMETER_BLOCKING = "Perimeter Blocking" - TERM_INTERNAL_BLOCKING = "Internal Blocking" - TERM_REDIRECTION = "Redirection" - TERM_REDIRECTION_HONEY_POT = "Redirection (Honey Pot)" - TERM_HARDENING = "Hardening" - TERM_PATCHING = "Patching" + TERM_DIPLOMATIC_ACTIONS = "Diplomatic Actions" TERM_ERADICATION = "Eradication" - TERM_REBUILDING = "Rebuilding" - TERM_TRAINING = "Training" + TERM_HARDENING = "Hardening" + TERM_INTERNAL_BLOCKING = "Internal Blocking" + TERM_LOGICAL_ACCESS_RESTRICTIONS = "Logical Access Restrictions" TERM_MONITORING = "Monitoring" + TERM_OTHER = "Other" + TERM_PATCHING = "Patching" + TERM_PERIMETER_BLOCKING = "Perimeter Blocking" TERM_PHYSICAL_ACCESS_RESTRICTIONS = "Physical Access Restrictions" - TERM_LOGICAL_ACCESS_RESTRICTIONS = "Logical Access Restrictions" - TERM_PUBLIC_DISCLOSURE = "Public Disclosure" - TERM_DIPLOMATIC_ACTIONS = "Diplomatic Actions" TERM_POLICY_ACTIONS = "Policy Actions" - TERM_OTHER = "Other" + TERM_PUBLIC_DISCLOSURE = "Public Disclosure" + TERM_REBUILDING = "Rebuilding" + TERM_REDIRECTION = "Redirection" + TERM_REDIRECTION_HONEY_POT = "Redirection (Honey Pot)" + TERM_TRAINING = "Training" @register_vocab -class SecurityCompromise(VocabString): +class SecurityCompromise_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:SecurityCompromiseVocab-1.0' _VOCAB_VERSION = '1.0' - TERM_YES = "Yes" - TERM_SUSPECTED = "Suspected" TERM_NO = "No" + TERM_SUSPECTED = "Suspected" TERM_UNKNOWN = "Unknown" + TERM_YES = "Yes" @register_vocab -class ImpactRating(VocabString): +class ImpactRating_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:ImpactRatingVocab-1.0' _VOCAB_VERSION = '1.0' - TERM_NONE = "None" + TERM_MAJOR = "Major" TERM_MINOR = "Minor" TERM_MODERATE = "Moderate" - TERM_MAJOR = "Major" + TERM_NONE = "None" TERM_UNKNOWN = "Unknown" @register_vocab -class AssetType(VocabString): +class AssetType_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:AssetTypeVocab-1.0' _VOCAB_VERSION = '1.0' - TERM_BACKUP = "Backup" - TERM_DATABASE = "Database" - TERM_DHCP = "DHCP" - TERM_DIRECTORY = "Directory" - TERM_DCS = "DCS" - TERM_DNS = "DNS" - TERM_FILE = "File" - TERM_LOG = "Log" - TERM_MAIL = "Mail" - TERM_MAINFRAME = "Mainframe" - TERM_PAYMENT_SWITCH = "Payment switch" - TERM_POS_CONTROLLER = "POS controller" - TERM_PRINT = "Print" - TERM_PROXY = "Proxy" - TERM_REMOTE_ACCESS = "Remote access" - TERM_SCADA = "SCADA" - TERM_WEB_APPLICATION = "Web application" - TERM_SERVER = "Server" + TERM_ACCESS_READER = "Access reader" - TERM_CAMERA = "Camera" - TERM_FIREWALL = "Firewall" - TERM_HSM = "HSM" - TERM_IDS = "IDS" - TERM_BROADBAND = "Broadband" - TERM_PBX = "PBX" - TERM_PRIVATE_WAN = "Private WAN" - TERM_PLC = "PLC" - TERM_PUBLIC_WAN = "Public WAN" - TERM_RTU = "RTU" - TERM_ROUTER_OR_SWITCH = "Router or switch" - TERM_SAN = "SAN" - TERM_TELEPHONE = "Telephone" - TERM_VOIP_ADAPTER = "VoIP adapter" - TERM_LAN = "LAN" - TERM_WLAN = "WLAN" - TERM_NETWORK = "Network" - TERM_AUTH_TOKEN = "Auth token" - TERM_ATM = "ATM" - TERM_DESKTOP = "Desktop" - TERM_PED_PAD = "PED pad" - TERM_GAS_TERMINAL = "Gas terminal" - TERM_LAPTOP = "Laptop" - TERM_MEDIA = "Media" - TERM_MOBILE_PHONE = "Mobile phone" - TERM_PERIPHERAL = "Peripheral" - TERM_POS_TERMINAL = "POS terminal" - TERM_KIOSK = "Kiosk" - TERM_TABLET = "Tablet" - TERM_VOIP_PHONE = "VoIP phone" - TERM_USER_DEVICE = "User Device" - TERM_TAPES = "Tapes" - TERM_DISK_MEDIA = "Disk media" - TERM_DOCUMENTS = "Documents" - TERM_FLASH_DRIVE = "Flash drive" - TERM_DISK_DRIVE = "Disk drive" - TERM_SMART_CARD = "Smart card" - TERM_PAYMENT_CARD = "Payment card" TERM_ADMINISTRATOR = "Administrator" + TERM_ATM = "ATM" TERM_AUDITOR = "Auditor" + TERM_AUTH_TOKEN = "Auth token" + TERM_BACKUP = "Backup" + TERM_BROADBAND = "Broadband" TERM_CALL_CENTER = "Call center" + TERM_CAMERA = "Camera" TERM_CASHIER = "Cashier" TERM_CUSTOMER = "Customer" + TERM_DATABASE = "Database" + TERM_DCS = "DCS" + TERM_DESKTOP = "Desktop" TERM_DEVELOPER = "Developer" + TERM_DHCP = "DHCP" + TERM_DIRECTORY = "Directory" + TERM_DISK_DRIVE = "Disk drive" + TERM_DISK_MEDIA = "Disk media" + TERM_DNS = "DNS" + TERM_DOCUMENTS = "Documents" TERM_ENDUSER = "End-user" TERM_EXECUTIVE = "Executive" + TERM_FILE = "File" TERM_FINANCE = "Finance" + TERM_FIREWALL = "Firewall" + TERM_FLASH_DRIVE = "Flash drive" TERM_FORMER_EMPLOYEE = "Former employee" + TERM_GAS_TERMINAL = "Gas terminal" TERM_GUARD = "Guard" TERM_HELPDESK = "Helpdesk" + TERM_HSM = "HSM" TERM_HUMAN_RESOURCES = "Human resources" + TERM_IDS = "IDS" + TERM_KIOSK = "Kiosk" + TERM_LAN = "LAN" + TERM_LAPTOP = "Laptop" + TERM_LOG = "Log" + TERM_MAIL = "Mail" + TERM_MAINFRAME = "Mainframe" TERM_MAINTENANCE = "Maintenance" TERM_MANAGER = "Manager" + TERM_MEDIA = "Media" + TERM_MOBILE_PHONE = "Mobile phone" + TERM_NETWORK = "Network" TERM_PARTNER = "Partner" + TERM_PAYMENT_CARD = "Payment card" + TERM_PAYMENT_SWITCH = "Payment switch" + TERM_PBX = "PBX" + TERM_PED_PAD = "PED pad" + TERM_PERIPHERAL = "Peripheral" TERM_PERSON = "Person" + TERM_PLC = "PLC" + TERM_POS_CONTROLLER = "POS controller" + TERM_POS_TERMINAL = "POS terminal" + TERM_PRINT = "Print" + TERM_PRIVATE_WAN = "Private WAN" + TERM_PROXY = "Proxy" + TERM_PUBLIC_WAN = "Public WAN" + TERM_REMOTE_ACCESS = "Remote access" + TERM_ROUTER_OR_SWITCH = "Router or switch" + TERM_RTU = "RTU" + TERM_SAN = "SAN" + TERM_SCADA = "SCADA" + TERM_SERVER = "Server" + TERM_SMART_CARD = "Smart card" + TERM_TABLET = "Tablet" + TERM_TAPES = "Tapes" + TERM_TELEPHONE = "Telephone" TERM_UNKNOWN = "Unknown" - + TERM_USER_DEVICE = "User Device" + TERM_VOIP_ADAPTER = "VoIP adapter" + TERM_VOIP_PHONE = "VoIP phone" + TERM_WEB_APPLICATION = "Web application" + TERM_WLAN = "WLAN" @register_vocab -class COAStage(VocabString): +class COAStage_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:COAStageVocab-1.0' _VOCAB_VERSION = '1.0' @@ -636,24 +743,25 @@ class COAStage(VocabString): @register_vocab -class LocationClass(VocabString): +class LocationClass_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:LocationClassVocab-1.0' _VOCAB_VERSION = '1.0' - TERM_INTERNALLYLOCATED = "Internally-Located" - TERM_EXTERNALLYLOCATED = "Externally-Located" TERM_COLOCATED = "Co-Located" + TERM_EXTERNALLYLOCATED = "Externally-Located" + TERM_INTERNALLYLOCATED = "Internally-Located" TERM_MOBILE = "Mobile" TERM_UNKNOWN = "Unknown" @register_vocab -class InformationType(VocabString): +class InformationType_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:InformationTypeVocab-1.0' _VOCAB_VERSION = '1.0' + TERM_AUTHENTICATION_COOKIES = "Authentication Cookies" TERM_INFORMATION_ASSETS = "Information Assets" TERM_INFORMATION_ASSETS_CORPORATE_EMPLOYEE_INFORMATION = "Information Assets - Corporate Employee Information" TERM_INFORMATION_ASSETS_CUSTOMER_PII = "Information Assets - Customer PII" @@ -662,64 +770,58 @@ class InformationType(VocabString): TERM_INFORMATION_ASSETS_INTELLECTUAL_PROPERTY = "Information Assets - Intellectual Property" TERM_INFORMATION_ASSETS_MOBILE_PHONE_CONTACTS = "Information Assets - Mobile Phone Contacts" TERM_INFORMATION_ASSETS_USER_CREDENTIALS = "Information Assets - User Credentials" - TERM_AUTHENTICATION_COOKIES = "Authentication Cookies" @register_vocab -class ThreatActorSophistication(VocabString): +class ThreatActorSophistication_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:ThreatActorSophisticationVocab-1.0' _VOCAB_VERSION = '1.0' - TERM_INNOVATOR = "Innovator" + TERM_ASPIRANT = "Aspirant" TERM_EXPERT = "Expert" - TERM_PRACTITIONER = "Practitioner" + TERM_INNOVATOR = "Innovator" TERM_NOVICE = "Novice" - TERM_ASPIRANT = "Aspirant" + TERM_PRACTITIONER = "Practitioner" @register_vocab -class HighMediumLow(VocabString): +class HighMediumLow_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:HighMediumLowVocab-1.0' _VOCAB_VERSION = '1.0' TERM_HIGH = "High" - TERM_MEDIUM = "Medium" TERM_LOW = "Low" + TERM_MEDIUM = "Medium" TERM_NONE = "None" TERM_UNKNOWN = "Unknown" @register_vocab -class LossProperty(VocabString): +class LossProperty_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:LossPropertyVocab-1.0' _VOCAB_VERSION = '1.0' + TERM_ACCOUNTABILITY = "Accountability" + TERM_AVAILABILITY = "Availability" TERM_CONFIDENTIALITY = "Confidentiality" TERM_INTEGRITY = "Integrity" - TERM_AVAILABILITY = "Availability" - TERM_ACCOUNTABILITY = "Accountability" TERM_NONREPUDIATION = "Non-Repudiation" @register_vocab -class IntendedEffect(VocabString): +class IntendedEffect_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:IntendedEffectVocab-1.0' _VOCAB_VERSION = '1.0' + TERM_ACCOUNT_TAKEOVER = "Account Takeover" TERM_ADVANTAGE = "Advantage" TERM_ADVANTAGE_ECONOMIC = "Advantage - Economic" TERM_ADVANTAGE_MILITARY = "Advantage - Military" TERM_ADVANTAGE_POLITICAL = "Advantage - Political" - TERM_THEFT = "Theft" - TERM_THEFT_INTELLECTUAL_PROPERTY = "Theft - Intellectual Property" - TERM_THEFT_CREDENTIAL_THEFT = "Theft - Credential Theft" - TERM_THEFT_IDENTITY_THEFT = "Theft - Identity Theft" - TERM_THEFT_THEFT_OF_PROPRIETARY_INFORMATION = "Theft - Theft of Proprietary Information" - TERM_ACCOUNT_TAKEOVER = "Account Takeover" TERM_BRAND_DAMAGE = "Brand Damage" TERM_COMPETITIVE_ADVANTAGE = "Competitive Advantage" TERM_DEGRADATION_OF_SERVICE = "Degradation of Service" @@ -732,109 +834,113 @@ class IntendedEffect(VocabString): TERM_FRAUD = "Fraud" TERM_HARASSMENT = "Harassment" TERM_ICS_CONTROL = "ICS Control" + TERM_THEFT = "Theft" + TERM_THEFT_CREDENTIAL_THEFT = "Theft - Credential Theft" + TERM_THEFT_IDENTITY_THEFT = "Theft - Identity Theft" + TERM_THEFT_INTELLECTUAL_PROPERTY = "Theft - Intellectual Property" + TERM_THEFT_THEFT_OF_PROPRIETARY_INFORMATION = "Theft - Theft of Proprietary Information" TERM_TRAFFIC_DIVERSION = "Traffic Diversion" TERM_UNAUTHORIZED_ACCESS = "Unauthorized Access" @register_vocab -class PackageIntent(VocabString): +class PackageIntent_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:PackageIntentVocab-1.0' _VOCAB_VERSION = '1.0' + TERM_ATTACK_PATTERN_CHARACTERIZATION = "Attack Pattern Characterization" + TERM_CAMPAIGN_CHARACTERIZATION = "Campaign Characterization" TERM_COLLECTIVE_THREAT_INTELLIGENCE = "Collective Threat Intelligence" - TERM_THREAT_REPORT = "Threat Report" + TERM_COURSES_OF_ACTION = "Courses of Action" + TERM_EXPLOIT_CHARACTERIZATION = "Exploit Characterization" + TERM_INCIDENT = "Incident" TERM_INDICATORS = "Indicators" - TERM_INDICATORS_PHISHING = "Indicators - Phishing" - TERM_INDICATORS_WATCHLIST = "Indicators - Watchlist" + TERM_INDICATORS_ENDPOINT_CHARACTERISTICS = "Indicators - Endpoint Characteristics" TERM_INDICATORS_MALWARE_ARTIFACTS = "Indicators - Malware Artifacts" TERM_INDICATORS_NETWORK_ACTIVITY = "Indicators - Network Activity" - TERM_INDICATORS_ENDPOINT_CHARACTERISTICS = "Indicators - Endpoint Characteristics" - TERM_CAMPAIGN_CHARACTERIZATION = "Campaign Characterization" - TERM_THREAT_ACTOR_CHARACTERIZATION = "Threat Actor Characterization" - TERM_EXPLOIT_CHARACTERIZATION = "Exploit Characterization" - TERM_ATTACK_PATTERN_CHARACTERIZATION = "Attack Pattern Characterization" + TERM_INDICATORS_PHISHING = "Indicators - Phishing" + TERM_INDICATORS_WATCHLIST = "Indicators - Watchlist" TERM_MALWARE_CHARACTERIZATION = "Malware Characterization" - TERM_TTP_INFRASTRUCTURE = "TTP - Infrastructure" - TERM_TTP_TOOLS = "TTP - Tools" - TERM_COURSES_OF_ACTION = "Courses of Action" - TERM_INCIDENT = "Incident" + TERM_MALWARE_SAMPLES = "Malware Samples" TERM_OBSERVATIONS = "Observations" TERM_OBSERVATIONS_EMAIL = "Observations - Email" - TERM_MALWARE_SAMPLES = "Malware Samples" + TERM_THREAT_ACTOR_CHARACTERIZATION = "Threat Actor Characterization" + TERM_THREAT_REPORT = "Threat Report" + TERM_TTP_INFRASTRUCTURE = "TTP - Infrastructure" + TERM_TTP_TOOLS = "TTP - Tools" @register_vocab -class ReportIntent(VocabString): +class ReportIntent_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:ReportIntentVocab-1.0' _VOCAB_VERSION = '1.0' + TERM_ATTACK_PATTERN_CHARACTERIZATION = "Attack Pattern Characterization" + TERM_CAMPAIGN_CHARACTERIZATION = "Campaign Characterization" TERM_COLLECTIVE_THREAT_INTELLIGENCE = "Collective Threat Intelligence" - TERM_THREAT_REPORT = "Threat Report" + TERM_COURSES_OF_ACTION = "Courses of Action" + TERM_EXPLOIT_CHARACTERIZATION = "Exploit Characterization" + TERM_INCIDENT = "Incident" TERM_INDICATORS = "Indicators" - TERM_INDICATORS_PHISHING = "Indicators - Phishing" - TERM_INDICATORS_WATCHLIST = "Indicators - Watchlist" + TERM_INDICATORS_ENDPOINT_CHARACTERISTICS = "Indicators - Endpoint Characteristics" TERM_INDICATORS_MALWARE_ARTIFACTS = "Indicators - Malware Artifacts" TERM_INDICATORS_NETWORK_ACTIVITY = "Indicators - Network Activity" - TERM_INDICATORS_ENDPOINT_CHARACTERISTICS = "Indicators - Endpoint Characteristics" - TERM_CAMPAIGN_CHARACTERIZATION = "Campaign Characterization" - TERM_THREAT_ACTOR_CHARACTERIZATION = "Threat Actor Characterization" - TERM_EXPLOIT_CHARACTERIZATION = "Exploit Characterization" - TERM_ATTACK_PATTERN_CHARACTERIZATION = "Attack Pattern Characterization" + TERM_INDICATORS_PHISHING = "Indicators - Phishing" + TERM_INDICATORS_WATCHLIST = "Indicators - Watchlist" TERM_MALWARE_CHARACTERIZATION = "Malware Characterization" - TERM_TTP_INFRASTRUCTURE = "TTP - Infrastructure" - TERM_TTP_TOOLS = "TTP - Tools" - TERM_COURSES_OF_ACTION = "Courses of Action" - TERM_INCIDENT = "Incident" + TERM_MALWARE_SAMPLES = "Malware Samples" TERM_OBSERVATIONS = "Observations" TERM_OBSERVATIONS_EMAIL = "Observations - Email" - TERM_MALWARE_SAMPLES = "Malware Samples" - + TERM_THREAT_ACTOR_CHARACTERIZATION = "Threat Actor Characterization" + TERM_THREAT_REPORT = "Threat Report" + TERM_TTP_INFRASTRUCTURE = "TTP - Infrastructure" + TERM_TTP_TOOLS = "TTP - Tools" @register_vocab -class LossDuration(VocabString): +class LossDuration_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:LossDurationVocab-1.0' _VOCAB_VERSION = '1.0' - TERM_PERMANENT = "Permanent" - TERM_WEEKS = "Weeks" TERM_DAYS = "Days" TERM_HOURS = "Hours" TERM_MINUTES = "Minutes" + TERM_PERMANENT = "Permanent" TERM_SECONDS = "Seconds" TERM_UNKNOWN = "Unknown" + TERM_WEEKS = "Weeks" @register_vocab -class OwnershipClass(VocabString): +class OwnershipClass_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:OwnershipClassVocab-1.0' _VOCAB_VERSION = '1.0' - TERM_INTERNALLYOWNED = "Internally-Owned" + TERM_CUSTOMEROWNED = "Customer-Owned" TERM_EMPLOYEEOWNED = "Employee-Owned" + TERM_INTERNALLYOWNED = "Internally-Owned" TERM_PARTNEROWNED = "Partner-Owned" - TERM_CUSTOMEROWNED = "Customer-Owned" TERM_UNKNOWN = "Unknown" @register_vocab -class MalwareType(VocabString): +class MalwareType_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:MalwareTypeVocab-1.0' _VOCAB_VERSION = '1.0' - TERM_AUTOMATED_TRANSFER_SCRIPTS = "Automated Transfer Scripts" TERM_ADWARE = "Adware" - TERM_DIALER = "Dialer" + TERM_AUTOMATED_TRANSFER_SCRIPTS = "Automated Transfer Scripts" TERM_BOT = "Bot" TERM_BOT_CREDENTIAL_THEFT = "Bot - Credential Theft" TERM_BOT_DDOS = "Bot - DDoS" TERM_BOT_LOADER = "Bot - Loader" TERM_BOT_SPAM = "Bot - Spam" + TERM_DIALER = "Dialer" TERM_DOS_OR_DDOS = "DoS / DDoS" TERM_DOS_OR_DDOS_PARTICIPATORY = "DoS / DDoS - Participatory" TERM_DOS_OR_DDOS_SCRIPT = "DoS / DDoS - Script" @@ -848,21 +954,21 @@ class MalwareType(VocabString): @register_vocab -class IncidentEffect(VocabString): +class IncidentEffect_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:IncidentEffectVocab-1.0' _VOCAB_VERSION = '1.0' TERM_BRAND_OR_IMAGE_DEGRADATION = "Brand or Image Degradation" - TERM_LOSS_OF_COMPETITIVE_ADVANTAGE = "Loss of Competitive Advantage" - TERM_LOSS_OF_COMPETITIVE_ADVANTAGE_ECONOMIC = "Loss of Competitive Advantage - Economic" - TERM_LOSS_OF_COMPETITIVE_ADVANTAGE_MILITARY = "Loss of Competitive Advantage - Military" - TERM_LOSS_OF_COMPETITIVE_ADVANTAGE_POLITICAL = "Loss of Competitive Advantage - Political" TERM_DATA_BREACH_OR_COMPROMISE = "Data Breach or Compromise" TERM_DEGRADATION_OF_SERVICE = "Degradation of Service" TERM_DESTRUCTION = "Destruction" TERM_DISRUPTION_OF_SERVICE_OR_OPERATIONS = "Disruption of Service / Operations" TERM_FINANCIAL_LOSS = "Financial Loss" + TERM_LOSS_OF_COMPETITIVE_ADVANTAGE = "Loss of Competitive Advantage" + TERM_LOSS_OF_COMPETITIVE_ADVANTAGE_ECONOMIC = "Loss of Competitive Advantage - Economic" + TERM_LOSS_OF_COMPETITIVE_ADVANTAGE_MILITARY = "Loss of Competitive Advantage - Military" + TERM_LOSS_OF_COMPETITIVE_ADVANTAGE_POLITICAL = "Loss of Competitive Advantage - Political" TERM_LOSS_OF_CONFIDENTIAL_OR_PROPRIETARY_INFORMATION_OR_INTELLECTUAL_PROPERTY = "Loss of Confidential / Proprietary Information or Intellectual Property" TERM_REGULATORY_COMPLIANCE_OR_LEGAL_IMPACT = "Regulatory, Compliance or Legal Impact" TERM_UNINTENDED_ACCESS = "Unintended Access" @@ -870,24 +976,59 @@ class IncidentEffect(VocabString): @register_vocab -class InformationSourceRole(VocabString): +class InformationSourceRole_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:InformationSourceRoleVocab-1.0' _VOCAB_VERSION = '1.0' - TERM_INITIAL_AUTHOR = "Initial Author" - TERM_CONTENT_ENHANCERORREFINER = "Content Enhancer/Refiner" TERM_AGGREGATOR = "Aggregator" + TERM_CONTENT_ENHANCERORREFINER = "Content Enhancer/Refiner" + TERM_INITIAL_AUTHOR = "Initial Author" TERM_TRANSFORMERORTRANSLATOR = "Transformer/Translator" @register_vocab -class Versioning(VocabString): +class Versioning_1_0(VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:VersioningVocab-1.0' _VOCAB_VERSION = '1.0' - + TERM_REVOKES = "Revokes" TERM_UPDATES_REVISES = "Updates - Revises" TERM_UPDATE_CORRECTS = "Updates - Corrects" - TERM_REVOKES = "Revokes" + + +# Vocab aliases which resolve to the most recent version of the +# associated VocabString. +AssetType = AssetType_1_0 +AttackerInfrastructureType = AttackerInfrastructureType_1_0 +AttackerToolType = AttackerToolType_1_0 +AvailabilityLossType = AvailabilityLossType_1_1_1 +CampaignStatus = CampaignStatus_1_0 +COAStage = COAStage_1_0 +CourseOfActionType = CourseOfActionType_1_0 +HighMediumLow = HighMediumLow_1_0 +ImpactQualification = ImpactQualification_1_0 +ImpactRating = ImpactRating_1_0 +IncidentCategory = IncidentCategory_1_0 +IncidentEffect = IncidentEffect_1_0 +IncidentStatus = IncidentStatus_1_0 +IndicatorType = IndicatorType_1_1 +InformationSourceRole = InformationSourceRole_1_0 +InformationType = InformationType_1_0 +IntendedEffect = IntendedEffect_1_0 +LocationClass = LocationClass_1_0 +LossDuration = LossDuration_1_0 +LossProperty = LossProperty_1_0 +MalwareType = MalwareType_1_0 +ManagementClass = ManagementClass_1_0 +Motivation = Motivation_1_1 +OwnershipClass = OwnershipClass_1_0 +PackageIntent = PackageIntent_1_0 +PlanningAndOperationalSupport = PlanningAndOperationalSupport_1_0_1 +ReportIntent = ReportIntent_1_0 +SecurityCompromise = SecurityCompromise_1_0 +SystemType = SystemType_1_0 +ThreatActorSophistication = ThreatActorSophistication_1_0 +ThreatActorType = ThreatActorType_1_0 +Versioning = Versioning_1_0 From c57ab63af635f19e8682aa484386a910971543f1 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 12 May 2015 12:21:35 -0400 Subject: [PATCH 085/438] Added missing DiscoveryMethod class alias. --- stix/common/vocabs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index e98bc6fc..ef3ceb40 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -1007,6 +1007,7 @@ class Versioning_1_0(VocabString): CampaignStatus = CampaignStatus_1_0 COAStage = COAStage_1_0 CourseOfActionType = CourseOfActionType_1_0 +DiscoveryMethod = DiscoveryMethod_2_0 HighMediumLow = HighMediumLow_1_0 ImpactQualification = ImpactQualification_1_0 ImpactRating = ImpactRating_1_0 From 751ef1c35fdc7ba50b89185f63c4d94088dd7930 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 12 May 2015 12:21:58 -0400 Subject: [PATCH 086/438] Cleaned up code which enables the parsing of 1.1.1 content by default. --- stix/__init__.py | 5 ++++- stix/utils/parser.py | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index d97d9e4e..f7c7f08e 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -130,6 +130,9 @@ def register_extension(cls): def supported_stix_version(): - #return '.'.join(__version__.split('.')[:3]) + """Returns a tuple of STIX version strings that this version of python-stix + supports (i.e., can parse). + + """ return ('1.1.1', '1.2') diff --git a/stix/utils/parser.py b/stix/utils/parser.py index 65e2f762..a777c034 100644 --- a/stix/utils/parser.py +++ b/stix/utils/parser.py @@ -144,15 +144,15 @@ def _check_version(self, tree): document_version = get_document_version(tree) supported = stix.supported_stix_version() - doc_version = StrictVersion(document_version) - api_versions = [StrictVersion(x) for x in supported] + sv_doc_version = StrictVersion(document_version) + sv_api_versions = [StrictVersion(x) for x in supported] - if doc_version in api_versions: + if sv_doc_version in sv_api_versions: return error = ( - "Your python-stix library supports STIX %s. Document version was " - "%s" % (supported, document_version) + "Your python-stix library supports STIX versions: %s. Document " + "version was %s" % (supported, document_version) ) raise UnsupportedVersionError( From 9086c4613d2c09a605a8fdc47634ecd63adb9788 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 12 May 2015 12:28:35 -0400 Subject: [PATCH 087/438] Changed STIXPackage.version to always print the default version unless manually set. --- stix/core/stix_package.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 8debdbc7..6129d79f 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -435,10 +435,6 @@ def from_obj(cls, obj, return_obj=None): return_obj.related_packages = RelatedPackages.from_obj(obj.Related_Packages) return_obj.reports = Reports.from_obj(obj.Reports) - # Don't overwrite unless a version is passed in - if obj.version: - return_obj.version = obj.version - return return_obj @classmethod @@ -451,7 +447,6 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.id_ = get('id') return_obj.idref = get('idref') return_obj.timestamp = get('timestamp') - return_obj.version = get('version', cls._version) return_obj.stix_header = STIXHeader.from_dict(get('stix_header')) return_obj.campaigns = Campaigns.from_dict(get('campaigns')) return_obj.courses_of_action = CoursesOfAction.from_dict(get('courses_of_action')) From 3b3c30c736f54fc94860b551dadae3ae5ce1dbba Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 12 May 2015 12:31:26 -0400 Subject: [PATCH 088/438] Added version property to STIXPackage --- stix/core/stix_package.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 6129d79f..d1f1b41f 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -138,6 +138,28 @@ def timestamp(self, value): deprecated(value) self._timestamp = utils.dates.parse_value(value) + @property + def version(self): + """The schematic version of this component. + + Note: + This property refers to the version of the schema component + type and should not be used for the purpose of content versioning. + + Default Value: '1.2' + + """ + return self._version + + @version.setter + def version(self, value): + if not value: + self._version = None + else: + utils.check_version(self._ALL_VERSIONS, value) + self._version = value + + @property def stix_header(self): """The :class:`.STIXHeader` section of the STIX Package. From aa9a00b9dd6293dd1e1e86ff7999ce0a79575a18 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 12 May 2015 12:32:36 -0400 Subject: [PATCH 089/438] Modified docstrings on version property. --- stix/core/stix_package.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index d1f1b41f..8015fea4 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -141,7 +141,7 @@ def timestamp(self, value): @property def version(self): """The schematic version of this component. - + Note: This property refers to the version of the schema component type and should not be used for the purpose of content versioning. @@ -465,7 +465,6 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj = cls() get = dict_repr.get - return_obj.id_ = get('id') return_obj.idref = get('idref') return_obj.timestamp = get('timestamp') From e0318904ce8ec3e4452fa2610aca92d1eb66c569 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 12 May 2015 12:41:20 -0400 Subject: [PATCH 090/438] Removed unused imports. --- stix/core/stix_package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 8015fea4..a9ae2607 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -10,7 +10,7 @@ # utility imports import stix.utils as utils import stix.utils.parser as parser -from stix.utils.deprecated import idref_deprecated, deprecated +from stix.utils.deprecated import deprecated # component imports from stix.campaign import Campaign From 70070e58f7c19028bc340897559f8b68eee8864b Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 12 May 2015 18:30:06 -0400 Subject: [PATCH 091/438] Allow STIX Package version attribute to be parsed and accessible, but always export STIXPackage.version. --- stix/core/stix_package.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index a9ae2607..30c2ec7d 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -73,7 +73,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, self.id_ = id_ or stix.utils.create_id("Package") self.idref = idref - self.version = self._version + self.version = STIXPackage._version self.stix_header = stix_header self.campaigns = campaigns self.courses_of_action = courses_of_action @@ -406,7 +406,7 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.id = self.id_ return_obj.idref = self.idref - return_obj.version = self.version + return_obj.version = STIXPackage._version # noqa return_obj.timestamp = utils.dates.serialize_value(self.timestamp) if self.stix_header: @@ -435,7 +435,12 @@ def to_obj(self, return_obj=None, ns_info=None): return return_obj def to_dict(self): - return super(STIXPackage, self).to_dict() + d = utils.to_dict(self) + + if 'version' in d: + d['version'] = STIXPackage._version # noqa + + return d @classmethod def from_obj(cls, obj, return_obj=None): @@ -457,6 +462,10 @@ def from_obj(cls, obj, return_obj=None): return_obj.related_packages = RelatedPackages.from_obj(obj.Related_Packages) return_obj.reports = Reports.from_obj(obj.Reports) + # Don't overwrite this unless passed in. + if obj.version: + return_obj.version = obj.version + return return_obj @classmethod @@ -468,6 +477,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.id_ = get('id') return_obj.idref = get('idref') return_obj.timestamp = get('timestamp') + return_obj.version = get('version', cls._version) return_obj.stix_header = STIXHeader.from_dict(get('stix_header')) return_obj.campaigns = Campaigns.from_dict(get('campaigns')) return_obj.courses_of_action = CoursesOfAction.from_dict(get('courses_of_action')) From 6ca20b17216b6df0073995fcca1d856d8d56583c Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 12 May 2015 18:30:24 -0400 Subject: [PATCH 092/438] Fix EncodingTests version attribute on STIX xml. --- stix/test/encoding_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/test/encoding_test.py b/stix/test/encoding_test.py index 78c84ff2..8d9a466d 100644 --- a/stix/test/encoding_test.py +++ b/stix/test/encoding_test.py @@ -30,7 +30,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:stix="http://stix.mitre.org/stix-1" xmlns:example="http://example.com/" - id="example:Indicator-ba1d406e-937c-414f-9231-6e1dbe64fe8b" version="1.2.0" timestamp="2014-05-08T09:00:00.000000Z"> + id="example:Indicator-ba1d406e-937c-414f-9231-6e1dbe64fe8b" version="1.2" timestamp="2014-05-08T09:00:00.000000Z"> {0} From a088c8e307905795e70c450b4b3ca09a746c2248 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Wed, 13 May 2015 19:25:05 -0400 Subject: [PATCH 093/438] Added kill_chain_phases to TTP --- stix/test/ttp_test.py | 3 ++- stix/ttp/__init__.py | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/stix/test/ttp_test.py b/stix/test/ttp_test.py index 88ebd81b..a95544d8 100644 --- a/stix/test/ttp_test.py +++ b/stix/test/ttp_test.py @@ -5,7 +5,7 @@ from stix.test import EntityTestCase, assert_warnings from stix.test import data_marking_test -from stix.test.common import related_test, identity_test +from stix.test.common import related_test, identity_test, kill_chains_test from stix.core import STIXPackage import stix.ttp as ttp @@ -150,6 +150,7 @@ class TTPTests(EntityTestCase, unittest.TestCase): 'exploit_targets': ExploitTargetsTests._full_dict, 'behavior': BehaviorTests._full_dict, 'related_packages': related_test.RelatedPackageRefsTests._full_dict, + 'kill_chain_phases': kill_chains_test.KillChainPhasesReferenceTests._full_dict } def test_add_description(self): diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index 54885be2..afd7d766 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -5,6 +5,7 @@ import stix import stix.bindings.ttp as ttp_binding from stix.common import vocabs, Statement +from stix.common.kill_chains import KillChainPhasesReference from stix.data_marking import Marking from stix.common.related import RelatedPackageRefs @@ -42,6 +43,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.handling = None self.exploit_targets = ExploitTargets() self.related_packages = None + self.kill_chain_phases = None @property def behavior(self): @@ -108,6 +110,25 @@ def handling(self): def handling(self, value): self._set_var(Marking, try_cast=False, handling=value) + @property + def kill_chain_phases(self): + return self._kill_chain_phases + + @kill_chain_phases.setter + def kill_chain_phases(self, value): + self._kill_chain_phases = KillChainPhasesReference(value) + + def add_kill_chain_phase(self, value): + """Add a new Kill Chain Phase reference to this Indicator. + + Args: + value: a :class:`stix.common.kill_chains.KillChainPhase` or a `str` + representing the phase_id of. Note that you if you are defining + a custom Kill Chain, you need to add it to the STIX package + separately. + """ + self.kill_chain_phases.append(value) + @property def related_packages(self): return self._related_packages @@ -137,6 +158,8 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Resources = self.resources.to_obj(ns_info=ns_info) if self.victim_targeting: return_obj.Victim_Targeting = self.victim_targeting.to_obj(ns_info=ns_info) + if self.kill_chain_phases: + return_obj.Kill_Chain_Phases = self.kill_chain_phases.to_obj(ns_info=ns_info) if self.handling: return_obj.Handling = self.handling.to_obj(ns_info=ns_info) if self.related_packages: @@ -162,6 +185,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.victim_targeting = VictimTargeting.from_obj(obj.Victim_Targeting) return_obj.handling = Marking.from_obj(obj.Handling) return_obj.intended_effects = _IntendedEffects.from_obj(obj.Intended_Effect) + return_obj.kill_chain_phases = KillChainPhasesReference.from_obj(obj.Kill_Chain_Phases) return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) return return_obj @@ -188,6 +212,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.victim_targeting = VictimTargeting.from_dict(get('victim_targeting')) return_obj.handling = Marking.from_dict(get('handling')) return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) + return_obj.kill_chain_phases = KillChainPhasesReference.from_dict(get('kill_chain_phases')) return return_obj From c2ca678cf3a13e39a36643b6f7a56e2955279f13 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Wed, 13 May 2015 22:08:52 -0400 Subject: [PATCH 094/438] * Moved `handling` property to BaseCoreComponent (from STIX component classes). * Added docs. --- stix/base.py | 23 ++++++++++++ stix/campaign/__init__.py | 51 ++++++++++++++++++++++---- stix/coa/__init__.py | 64 +++++++++++++++++++++++++-------- stix/core/stix_header.py | 2 +- stix/exploit_target/__init__.py | 17 +-------- stix/incident/__init__.py | 30 ++++++++-------- stix/indicator/indicator.py | 16 +-------- stix/threat_actor/__init__.py | 22 ++++++++---- stix/ttp/__init__.py | 30 ++++++++-------- 9 files changed, 169 insertions(+), 86 deletions(-) diff --git a/stix/base.py b/stix/base.py index 1aa7dc69..279c5dd9 100644 --- a/stix/base.py +++ b/stix/base.py @@ -567,6 +567,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.short_description = short_description self.version = None self.information_source = None + self.handling = None if timestamp: self.timestamp = timestamp @@ -828,9 +829,24 @@ def information_source(self, value): from stix.common import InformationSource self._set_var(InformationSource, try_cast=False, information_source=value) + @property + def handling(self): + return self._handling + + @handling.setter + def handling(self, value): + """The :class:`.Marking` section of this component. This section + contains data marking information. + + """ + from stix.data_marking import Marking + self._set_var(Marking, try_cast=False, handling=value) + + @classmethod def from_obj(cls, obj, return_obj=None): from stix.common import StructuredTextList, InformationSource + from stix.data_marking import Marking if not return_obj: raise ValueError("Must provide a return_obj argument") @@ -852,6 +868,8 @@ def from_obj(cls, obj, return_obj=None): StructuredTextList.from_obj(getattr(obj, 'Short_Description', None)) return_obj.information_source = \ InformationSource.from_obj(getattr(obj, 'Information_Source', None)) + return_obj.handling = \ + Marking.from_obj(getattr(obj, 'Handling', None)) return return_obj @@ -877,12 +895,15 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) if self.information_source: return_obj.Information_Source = self.information_source.to_obj(ns_info=ns_info) + if self.handling: + return_obj.Handling = self.handling.to_obj(ns_info=ns_info) return return_obj @classmethod def from_dict(cls, d, return_obj=None): from stix.common import StructuredTextList, InformationSource + from stix.data_marking import Marking if not return_obj: raise ValueError("Must provide a return_obj argument") @@ -899,6 +920,8 @@ def from_dict(cls, d, return_obj=None): StructuredTextList.from_dict(get('short_description')) return_obj.information_source = \ InformationSource.from_dict(get('information_source')) + return_obj.handling = \ + Marking.from_dict(get('handling')) return return_obj diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 8c528f19..52ce9824 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -9,7 +9,6 @@ RelatedPackageRefs, RelatedThreatActor, RelatedTTP ) from stix.common import vocabs -from stix.data_marking import Marking import stix.bindings.campaign as campaign_binding @@ -72,6 +71,22 @@ class Names(stix.EntityList): class Campaign(stix.BaseCoreComponent): + """Implementation of the STIX Campaign. + + Args: + id_ (optional): An identifier. If ``None``, a value will be generated + via ``stix.utils.create_id()``. If set, this will unset the + ``idref`` property. + idref (optional): An identifier reference. If set this will unset the + ``id_`` property. + timestamp (optional): A timestamp value. Can be an instance of + ``datetime.datetime`` or ``str``. + description: A description of the purpose or intent of this object. + short_description: A short description of the intent + or purpose of this object. + title: The title of this object. + + """ _binding = campaign_binding _binding_class = _binding.CampaignType _namespace = "http://stix.mitre.org/Campaign-1" @@ -101,15 +116,25 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.associated_campaigns = AssociatedCampaigns() self.confidence = None self.activity = _Activities() - self.handling = None self.related_packages = RelatedPackageRefs() @property def intended_effects(self): + """A collection of :class:`.Statement` objects. This behaves like a + ``MutableSequence`` type. + + """ return self._intended_effects @intended_effects.setter def intended_effects(self, value): + """Adds a :class:`.Statement` object to the :attr:`intended_effects` + collection. + + If `value` is not an instance of :class:`.Statement`, an attempt will + be made to convert it to one. + + """ self._intended_effects = _IntendedEffects(value) def add_intended_effect(self, value): @@ -117,6 +142,10 @@ def add_intended_effect(self, value): @property def activity(self): + """A collection of :class:`.Activity` objects. This behaves like a + ``MutableSequence`` type. + + """ return self._activity @activity.setter @@ -124,10 +153,20 @@ def activity(self, value): self._activity = _Activities(value) def add_activity(self, value): + """Adds an :class:`.Activity` object to the :attr:`activity` + collection. + + """ self.activity.append(value) @property def status(self): + """The status of the Campaign. This is a :class:`VocabString` field. + + If set to a string, an attempt will be made to convert it to a + :class:`.CampaignStatus` object. + + """ return self._status @status.setter @@ -136,6 +175,10 @@ def status(self, value): @property def attribution(self): + """A collection of :class:`.Attribution` objects. This behaves like a + ``MutableSequence`` type. + + """ return self._attribution @attribution.setter @@ -168,8 +211,6 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Confidence = self.confidence.to_obj(ns_info=ns_info) if self.activity: return_obj.Activity = self.activity.to_obj(ns_info=ns_info) - if self.handling: - return_obj.Handling = self.handling.to_obj(ns_info=ns_info) if self.related_packages: return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) @@ -200,7 +241,6 @@ def from_obj(cls, obj, return_obj=None): AssociatedCampaigns.from_obj(obj.Associated_Campaigns) return_obj.confidence = Confidence.from_obj(obj.Confidence) return_obj.activity = _Activities.from_obj(obj.Activity) - return_obj.handling = Marking.from_obj(obj.Handling) return_obj.related_packages = \ RelatedPackageRefs.from_obj(obj.Related_Packages) @@ -236,7 +276,6 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.confidence = \ Confidence.from_dict(get('confidence')) return_obj.activity = _Activities.from_dict(get('activity')) - return_obj.handling = Marking.from_dict(get('handling')) return_obj.related_packages = \ RelatedPackageRefs.from_dict(get('related_packages')) diff --git a/stix/coa/__init__.py b/stix/coa/__init__.py index c2740796..235a218f 100644 --- a/stix/coa/__init__.py +++ b/stix/coa/__init__.py @@ -6,7 +6,6 @@ # internal import stix -from stix.data_marking import Marking from stix.common import vocabs, related, VocabString, Statement import stix.bindings.course_of_action as coa_binding @@ -29,6 +28,22 @@ class RelatedCOAs(related.GenericRelationshipList): class CourseOfAction(stix.BaseCoreComponent): + """Implementation of the STIX Course of Action. + + Args: + id_ (optional): An identifier. If ``None``, a value will be generated + via ``stix.utils.create_id()``. If set, this will unset the + ``idref`` property. + idref (optional): An identifier reference. If set this will unset the + ``id_`` property. + timestamp (optional): A timestamp value. Can be an instance of + ``datetime.datetime`` or ``str``. + description: A description of the purpose or intent of this object. + short_description: A short description of the intent + or purpose of this object. + title: The title of this object. + + """ _binding = coa_binding _binding_class = coa_binding.CourseOfActionType _namespace = "http://stix.mitre.org/CourseOfAction-1" @@ -56,12 +71,15 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.impact = None self.cost = None self.efficacy = None - self.handling = None self.related_coas = RelatedCOAs() self.related_packages = related.RelatedPackageRefs() @property def stage(self): + """A :class:`.VocabString` property. If set to a string, an attempt + will be made to convert it to an instance of :class:`.Stage`. + + """ return self._stage @stage.setter @@ -70,6 +88,10 @@ def stage(self, value): @property def type_(self): + """A :class:`.VocabString` property. If set to a string, an attempt + will be made to convert it to an instance of :class:`.COAType`. + + """ return self._type @type_.setter @@ -78,6 +100,9 @@ def type_(self, value): @property def objective(self): + """A :class:`.Objective` field. + + """ return self._objective @objective.setter @@ -86,6 +111,12 @@ def objective(self, value): @property def impact(self): + """The impact of this COA. This is a :class:`.Statement` property. + + If set to a string, an attempt will be made to convert it into a + :class:`.Statement` object. + + """ return self._impact @impact.setter @@ -94,6 +125,12 @@ def impact(self, value): @property def cost(self): + """The cost of this COA. This is a :class:`.Statement` property. + + If set to a string, an attempt will be made to convert it into a + :class:`.Statement` object. + + """ return self._cost @cost.setter @@ -102,22 +139,25 @@ def cost(self, value): @property def efficacy(self): + """The efficacy of this COA. This is a :class:`.Statement` property. + + If set to a string, an attempt will be made to convert it into a + :class:`.Statement` object. + + """ return self._efficacy @efficacy.setter def efficacy(self, value): self._set_var(Statement, efficacy=value) - @property - def handling(self): - return self._handling - - @handling.setter - def handling(self, value): - self._set_var(Marking, try_cast=False, handling=value) - @property def structured_coa(self): + """A structured Course of Action extension point. This can be + set to implementations of this extension point, such as + :class:`.GenericStructuredCOA`. + + """ return self._structured_coa @structured_coa.setter @@ -144,8 +184,6 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Cost = self.cost.to_obj(ns_info=ns_info) if self.efficacy: return_obj.Efficacy = self.efficacy.to_obj(ns_info=ns_info) - if self.handling: - return_obj.Handling = self.handling.to_obj(ns_info=ns_info) if self.related_coas: return_obj.Related_COAs = self.related_coas.to_obj(ns_info=ns_info) if self.related_packages: @@ -175,7 +213,6 @@ def from_obj(cls, obj, return_obj=None): return_obj.impact = Statement.from_obj(obj.Impact) return_obj.cost = Statement.from_obj(obj.Cost) return_obj.efficacy = Statement.from_obj(obj.Efficacy) - return_obj.handling = Marking.from_obj(obj.Handling) return_obj.related_coas = \ RelatedCOAs.from_obj(obj.Related_COAs) return_obj.related_packages = \ @@ -206,7 +243,6 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.impact = Statement.from_dict(get('impact')) return_obj.cost = Statement.from_dict(get('cost')) return_obj.efficacy = Statement.from_dict(get('efficacy')) - return_obj.handling = Marking.from_dict(get('handling')) return_obj.related_coas = \ RelatedCOAs.from_dict(get('related_coas')) return_obj.related_packages = \ diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index d5d22924..bf0db5cc 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -193,7 +193,7 @@ def handling(self, value): @property def package_intents(self): """**DEPRECATED**. A collection of :class:`.VocabString` controlled - vocabulary objects defining the intent of the STIX PAckage. + vocabulary objects defining the intent of the STIX Package. """ return self._package_intents diff --git a/stix/exploit_target/__init__.py b/stix/exploit_target/__init__.py index 863bd33d..48acf01a 100644 --- a/stix/exploit_target/__init__.py +++ b/stix/exploit_target/__init__.py @@ -8,7 +8,6 @@ GenericRelationshipList, RelatedCOA, RelatedExploitTarget, RelatedPackageRefs ) -from stix.data_marking import Marking # relative from .vulnerability import Vulnerability, _Vulnerabilities # noqa @@ -17,7 +16,7 @@ class ExploitTarget(stix.BaseCoreComponent): - """Implementation of STIX ``ExploitTarget``. + """Implementation of STIX Exploit Target. Args: id_ (optional): An identifier. If ``None``, a value will be generated @@ -51,22 +50,12 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, short_description=short_description ) - self.handling = None self.potential_coas = PotentialCOAs() self.related_exploit_targets = RelatedExploitTargets() self.vulnerabilities = None self.weaknesses = None self.configuration = None self.related_packages = RelatedPackageRefs() - - @property - def handling(self): - - return self._handling - - @handling.setter - def handling(self, value): - self._set_var(Marking, try_cast=False, handling=value) @property def vulnerabilities(self): @@ -188,8 +177,6 @@ def to_obj(self, return_obj=None, ns_info=None): super(ExploitTarget, self).to_obj(return_obj=return_obj, ns_info=ns_info) - if self.handling: - return_obj.Handling = self.handling.to_obj(ns_info=ns_info) if self.potential_coas: return_obj.Potential_COAs = self.potential_coas.to_obj(ns_info=ns_info) if self.related_exploit_targets: @@ -216,7 +203,6 @@ def from_obj(cls, obj, return_obj=None): super(ExploitTarget, cls).from_obj(obj, return_obj=return_obj) if isinstance(obj, cls._binding_class): - return_obj.handling = Marking.from_obj(obj.Handling) return_obj.potential_coas = PotentialCOAs.from_obj(obj.Potential_COAs) return_obj.related_exploit_targets = RelatedExploitTargets.from_obj(obj.Related_Exploit_Targets) return_obj.vulnerabilities = _Vulnerabilities.from_obj(obj.Vulnerability) @@ -240,7 +226,6 @@ def from_dict(cls, dict_repr, return_obj=None): super(ExploitTarget, cls).from_dict(dict_repr, return_obj=return_obj) get = dict_repr.get - return_obj.handling = Marking.from_dict(get('handling')) return_obj.potential_coas = PotentialCOAs.from_dict(get('potential_coas')) return_obj.related_exploit_targets = RelatedExploitTargets.from_dict(get('related_exploit_targets')) return_obj.vulnerabilities = _Vulnerabilities.from_dict(get('vulnerabilities')) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index d44491f7..b866a054 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -11,7 +11,6 @@ GenericRelationshipList, RelatedIndicator, RelatedThreatActor, RelatedTTP, RelatedObservable, RelatedIncident, RelatedPackageRefs ) -from stix.data_marking import Marking # relative from .affected_asset import AffectedAsset @@ -24,6 +23,22 @@ class Incident(stix.BaseCoreComponent): + """Implementation of the STIX Incident. + + Args: + id_ (optional): An identifier. If ``None``, a value will be generated + via ``stix.utils.create_id()``. If set, this will unset the + ``idref`` property. + idref (optional): An identifier reference. If set this will unset the + ``id_`` property. + timestamp (optional): A timestamp value. Can be an instance of + ``datetime.datetime`` or ``str``. + description: A description of the purpose or intent of this object. + short_description: A short description of the intent + or purpose of this object. + title: The title of this object. + + """ _binding = incident_binding _binding_class = _binding.IncidentType _namespace = "http://stix.mitre.org/Incident-1" @@ -63,7 +78,6 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, description self.confidence = None self.coa_taken = None self.coa_requested = None - self.handling = None self.history = History() @@ -83,14 +97,6 @@ def time(self): def time(self, value): self._set_var(Time, try_cast=False, time=value) - @property - def handling(self): - return self._handling - - @handling.setter - def handling(self, value): - self._set_var(Marking, try_cast=False, handling=value) - @property def intended_effects(self): return self._intended_effects @@ -372,8 +378,6 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.COA_Requested = self.coa_requested.to_obj(ns_info=ns_info) if self.status: return_obj.Status = self.status.to_obj(ns_info=ns_info) - if self.handling: - return_obj.Handling = self.handling.to_obj(ns_info=ns_info) if self.history: return_obj.History = self.history.to_obj(ns_info=ns_info) if self.related_packages: @@ -407,7 +411,6 @@ def from_obj(cls, obj, return_obj=None): return_obj.leveraged_ttps = LeveragedTTPs.from_obj(obj.Leveraged_TTPs) return_obj.related_incidents = RelatedIncidents.from_obj(obj.Related_Incidents) return_obj.status = VocabString.from_obj(obj.Status) - return_obj.handling = Marking.from_obj(obj.Handling) return_obj.history = History.from_obj(obj.History) return_obj.responders = _InformationSources.from_obj(obj.Responder) return_obj.coordinators = _InformationSources.from_obj(obj.Coordinator) @@ -454,7 +457,6 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.coa_taken = _COAsTaken.from_dict(get('coa_taken')) return_obj.coa_requested = _COAsRequested.from_dict(get('coa_requested')) return_obj.status = VocabString.from_dict(get('status')) - return_obj.handling = Marking.from_dict(get('handling')) return_obj.history = History.from_dict(get('history')) return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index bbab5074..17d54c6a 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -16,7 +16,6 @@ GenericRelationshipList, RelatedCOA, RelatedIndicator, RelatedCampaignRef, RelatedPackageRefs ) -from stix.data_marking import Marking from stix.common.vocabs import IndicatorType from stix.common.kill_chains import KillChainPhasesReference import stix.bindings.indicator as indicator_binding @@ -156,7 +155,7 @@ def __init__(self, related_indicators=None, scope=None): class Indicator(stix.BaseCoreComponent): - """Implementation of the STIX ``IndicatorType``. + """Implementation of the STIX Indicator. Args: id_ (optional): An identifier. If ``None``, a value will be generated @@ -201,7 +200,6 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.suggested_coas = SuggestedCOAs() self.sightings = Sightings() self.composite_indicator_expression = None - self.handling = None self.kill_chain_phases = KillChainPhasesReference() self.valid_time_positions = _ValidTimePositions() self.related_indicators = None @@ -552,14 +550,6 @@ def add_test_mechanism(self, tm): """ self.test_mechanisms.append(tm) - @property - def handling(self): - return self._handling - - @handling.setter - def handling(self, value): - self._set_var(Marking, handling=value) - @property def related_indicators(self): return self._related_indicators @@ -905,8 +895,6 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Sightings = self.sightings.to_obj(ns_info=ns_info) if self.composite_indicator_expression: return_obj.Composite_Indicator_Expression = self.composite_indicator_expression.to_obj(ns_info=ns_info) - if self.handling: - return_obj.Handling = self.handling.to_obj(ns_info=ns_info) if self.kill_chain_phases: return_obj.Kill_Chain_Phases = self.kill_chain_phases.to_obj(ns_info=ns_info) if self.related_indicators: @@ -939,7 +927,6 @@ def from_obj(cls, obj, return_obj=None): return_obj.confidence = Confidence.from_obj(obj.Confidence) return_obj.sightings = Sightings.from_obj(obj.Sightings) return_obj.composite_indicator_expression = CompositeIndicatorExpression.from_obj(obj.Composite_Indicator_Expression) - return_obj.handling = Marking.from_obj(obj.Handling) return_obj.kill_chain_phases = KillChainPhasesReference.from_obj(obj.Kill_Chain_Phases) return_obj.related_indicators = RelatedIndicators.from_obj(obj.Related_Indicators) return_obj.likely_impact = Statement.from_obj(obj.Likely_Impact) @@ -988,7 +975,6 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.suggested_coas = SuggestedCOAs.from_dict(get('suggested_coas')) return_obj.sightings = Sightings.from_dict(get('sightings')) return_obj.composite_indicator_expression = CompositeIndicatorExpression.from_dict(get('composite_indicator_expression')) - return_obj.handling = Marking.from_dict(get('handling')) return_obj.kill_chain_phases = KillChainPhasesReference.from_dict(get('kill_chain_phases')) return_obj.related_indicators = RelatedIndicators.from_dict(get('related_indicators')) return_obj.likely_impact = Statement.from_dict(get('likely_impact')) diff --git a/stix/threat_actor/__init__.py b/stix/threat_actor/__init__.py index a0747679..5aac80a0 100644 --- a/stix/threat_actor/__init__.py +++ b/stix/threat_actor/__init__.py @@ -2,7 +2,6 @@ # See LICENSE.txt for complete terms. import stix -from stix.data_marking import Marking import stix.bindings.threat_actor as threat_actor_binding from stix.common import vocabs, Confidence, Identity, Statement from stix.common.related import ( @@ -39,6 +38,22 @@ class AssociatedCampaigns(GenericRelationshipList): class ThreatActor(stix.BaseCoreComponent): + """Implementation of the STIX Threat Actor. + + Args: + id_ (optional): An identifier. If ``None``, a value will be generated + via ``stix.utils.create_id()``. If set, this will unset the + ``idref`` property. + idref (optional): An identifier reference. If set this will unset the + ``id_`` property. + timestamp (optional): A timestamp value. Can be an instance of + ``datetime.datetime`` or ``str``. + description: A description of the purpose or intent of this object. + short_description: A short description of the intent + or purpose of this object. + title: The title of this object. + + """ _binding = threat_actor_binding _binding_class = threat_actor_binding.ThreatActorType _namespace = 'http://stix.mitre.org/ThreatActor-1' @@ -64,7 +79,6 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.sophistications = None self.intended_effects = None self.planning_and_operational_supports = None - self.handling = None self.confidence = None self.observed_ttps = ObservedTTPs() self.associated_campaigns = AssociatedCampaigns() @@ -159,8 +173,6 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Associated_Campaigns = self.associated_campaigns.to_obj(ns_info=ns_info) if self.associated_actors: return_obj.Associated_Actors = self.associated_actors.to_obj(ns_info=ns_info) - if self.handling: - return_obj.Handling = self.handling.to_obj(ns_info=ns_info) if self.confidence: return_obj.Confidence = self.confidence.to_obj(ns_info=ns_info) if self.related_packages: @@ -188,7 +200,6 @@ def from_obj(cls, obj, return_obj=None): return_obj.observed_ttps = ObservedTTPs.from_obj(obj.Observed_TTPs) return_obj.associated_campaigns = AssociatedCampaigns.from_obj(obj.Associated_Campaigns) return_obj.associated_actors = AssociatedActors.from_obj(obj.Associated_Actors) - return_obj.handling = Marking.from_obj(obj.Handling) return_obj.confidence = Confidence.from_obj(obj.Confidence) return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) @@ -218,7 +229,6 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.observed_ttps = ObservedTTPs.from_dict(get('observed_ttps')) return_obj.associated_campaigns = AssociatedCampaigns.from_dict(get('associated_campaigns')) return_obj.associated_actors = AssociatedActors.from_dict(get('associated_actors')) - return_obj.handling = Marking.from_dict(get('handling')) return_obj.confidence = Confidence.from_dict(get('confidence')) return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index afd7d766..ba9b8cf8 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -6,7 +6,6 @@ import stix.bindings.ttp as ttp_binding from stix.common import vocabs, Statement from stix.common.kill_chains import KillChainPhasesReference -from stix.data_marking import Marking from stix.common.related import RelatedPackageRefs # relative @@ -16,6 +15,22 @@ class TTP(stix.BaseCoreComponent): + """Implementation of the STIX TTP. + + Args: + id_ (optional): An identifier. If ``None``, a value will be generated + via ``stix.utils.create_id()``. If set, this will unset the + ``idref`` property. + idref (optional): An identifier reference. If set this will unset the + ``id_`` property. + timestamp (optional): A timestamp value. Can be an instance of + ``datetime.datetime`` or ``str``. + description: A description of the purpose or intent of this object. + short_description: A short description of the intent + or purpose of this object. + title: The title of this object. + + """ _binding = ttp_binding _binding_class = _binding.TTPType _namespace = "http://stix.mitre.org/TTP-1" @@ -40,7 +55,6 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.intended_effects = None self.resources = None self.victim_targeting = None - self.handling = None self.exploit_targets = ExploitTargets() self.related_packages = None self.kill_chain_phases = None @@ -102,14 +116,6 @@ def victim_targeting(self): def victim_targeting(self, value): self._set_var(VictimTargeting, try_cast=False, victim_targeting=value) - @property - def handling(self): - return self._handling - - @handling.setter - def handling(self, value): - self._set_var(Marking, try_cast=False, handling=value) - @property def kill_chain_phases(self): return self._kill_chain_phases @@ -160,8 +166,6 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Victim_Targeting = self.victim_targeting.to_obj(ns_info=ns_info) if self.kill_chain_phases: return_obj.Kill_Chain_Phases = self.kill_chain_phases.to_obj(ns_info=ns_info) - if self.handling: - return_obj.Handling = self.handling.to_obj(ns_info=ns_info) if self.related_packages: return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) @@ -183,7 +187,6 @@ def from_obj(cls, obj, return_obj=None): return_obj.exploit_targets = ExploitTargets.from_obj(obj.Exploit_Targets) return_obj.resources = Resource.from_obj(obj.Resources) return_obj.victim_targeting = VictimTargeting.from_obj(obj.Victim_Targeting) - return_obj.handling = Marking.from_obj(obj.Handling) return_obj.intended_effects = _IntendedEffects.from_obj(obj.Intended_Effect) return_obj.kill_chain_phases = KillChainPhasesReference.from_obj(obj.Kill_Chain_Phases) return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) @@ -210,7 +213,6 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.intended_effects = _IntendedEffects.from_dict(get('intended_effects')) return_obj.resources = Resource.from_dict(get('resources')) return_obj.victim_targeting = VictimTargeting.from_dict(get('victim_targeting')) - return_obj.handling = Marking.from_dict(get('handling')) return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) return_obj.kill_chain_phases = KillChainPhasesReference.from_dict(get('kill_chain_phases')) From 98501aa32eb61e5dfba936e279d401a43c319981 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Wed, 13 May 2015 22:09:41 -0400 Subject: [PATCH 095/438] Added docs. --- docs/api/campaign/campaign.rst | 32 ++++++++++++---------- docs/api/coa/coa.rst | 6 +++- docs/api/exploit_target/exploit_target.rst | 16 +++++++---- docs/api/incident/incident.rst | 12 +++++++- docs/api/indicator/indicator.rst | 18 ++++++++---- docs/api/threat_actor/threat_actor.rst | 22 +++++++++------ docs/api/ttp/ttp.rst | 9 ++++-- 7 files changed, 78 insertions(+), 37 deletions(-) diff --git a/docs/api/campaign/campaign.rst b/docs/api/campaign/campaign.rst index e53dce1d..9b9129ad 100644 --- a/docs/api/campaign/campaign.rst +++ b/docs/api/campaign/campaign.rst @@ -7,29 +7,33 @@ Classes ------- .. autoclass:: Campaign - :show-inheritance: - :members: + :show-inheritance: + :members: activity, add_activity, add_description, add_intended_effect, + add_short_description, attribution, description, descriptions, find, id_, + idref, information_source, intended_effects, short_description, + short_descriptions, status, timestamp, title, to_dict, to_json, to_obj, + version, walk .. autoclass:: AssociatedCampaigns - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: Attribution - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: Names - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: RelatedIncidents - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: RelatedIndicators - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: RelatedTTPs - :show-inheritance: - :members: + :show-inheritance: + :members: diff --git a/docs/api/coa/coa.rst b/docs/api/coa/coa.rst index eaa56491..d2d1f5f4 100644 --- a/docs/api/coa/coa.rst +++ b/docs/api/coa/coa.rst @@ -8,7 +8,11 @@ Classes .. autoclass:: CourseOfAction :show-inheritance: - :members: + :members: add_description, add_short_description, cost, description, + descriptions, efficacy, find, handling, id_, idref, impact, + information_source, objective, short_description, short_descriptions, + stage, structured_coa, timestamp, title, to_dict, to_json, to_obj, type_, + version, walk .. autoclass:: RelatedCOAs :show-inheritance: diff --git a/docs/api/exploit_target/exploit_target.rst b/docs/api/exploit_target/exploit_target.rst index 33dd9f58..11d7d0a4 100644 --- a/docs/api/exploit_target/exploit_target.rst +++ b/docs/api/exploit_target/exploit_target.rst @@ -19,13 +19,17 @@ Classes ------- .. autoclass:: ExploitTarget - :show-inheritance: - :members: + :show-inheritance: + :members: add_configuration, add_description, add_short_description, + add_vulnerability, add_weakness, configuration, description, descriptions, + find, handling, id_, idref, information_source, short_description, + short_descriptions, timestamp, title, to_dict, to_json, to_obj, version, + vulnerabilities, walk, weaknesses .. autoclass:: PotentialCOAs - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: RelatedExploitTargets - :show-inheritance: - :members: + :show-inheritance: + :members: diff --git a/docs/api/incident/incident.rst b/docs/api/incident/incident.rst index 09498782..0e0bc34f 100644 --- a/docs/api/incident/incident.rst +++ b/docs/api/incident/incident.rst @@ -8,7 +8,17 @@ Classes .. autoclass:: Incident :show-inheritance: - :members: + :members: add_affected_asset, add_category, add_coa_requested, add_coa_taken, + add_coordinator, add_description, add_discovery_method, add_external_id, + add_intended_effect, add_related_indicator, add_related_observable, + add_related_package, add_responder, add_short_description, add_victim, + affected_assets, categories, coa_requested, coa_taken, confidence, + coordinators, description, descriptions, discovery_methods, external_ids, + find, handling, id_, idref, impact_assessment, information_source, + intended_effects, related_indicators, related_observables, related_packages, + reporter, responders, security_compromise, short_description, + short_descriptions, status, time, timestamp, title, to_dict, to_json, + to_obj, version, victims, walk .. autoclass:: AttributedThreatActors :show-inheritance: diff --git a/docs/api/indicator/indicator.rst b/docs/api/indicator/indicator.rst index 96318f89..fa8e2a2f 100644 --- a/docs/api/indicator/indicator.rst +++ b/docs/api/indicator/indicator.rst @@ -23,11 +23,19 @@ Classes .. autoclass:: Indicator :show-inheritance: - :members: to_obj, from_obj, to_dict, from_dict, producer, observable, - observables, add_observable, alternative_id, add_alternative_id, - valid_time_positions, add_valid_time_position, indicator_types, - add_indicator_type, confidence, add_indicated_ttp, - add_test_mechanism, add_related_indicator + :members: add_alternative_id, add_description, add_indicated_ttp, + add_indicator_type, add_kill_chain_phase, add_object, add_observable, + add_related_campaign, add_related_indicator, add_related_package, + add_short_description, add_test_mechanism, add_valid_time_position, + alternative_id, confidence, description, descriptions, find, + get_produced_time, get_received_time, handling, id_, idref, + indicated_ttps, indicator_types, information_source, kill_chain_phases, + likely_impact, negate, observable, observable_composition_operator, + observables, producer, related_campaigns, related_indicators, + related_packages, set_produced_time, set_producer_identity, + set_received_time, short_description, short_descriptions, + test_mechanisms, timestamp, title, to_dict, to_json, to_obj, to_xml, + valid_time_positions, version, walk .. autoclass:: CompositeIndicatorExpression diff --git a/docs/api/threat_actor/threat_actor.rst b/docs/api/threat_actor/threat_actor.rst index 2a4157da..ea520945 100644 --- a/docs/api/threat_actor/threat_actor.rst +++ b/docs/api/threat_actor/threat_actor.rst @@ -7,17 +7,23 @@ Classes ------- .. autoclass:: ThreatActor - :show-inheritance: - :members: + :show-inheritance: + :members: add_description, add_intended_effect, add_motivation, + add_planning_and_operational_support, add_short_description, + add_sophistication, add_type, description, descriptions, find, id_, + identity, idref, information_source, intended_effects, motivations, + planning_and_operational_supports, short_description, short_descriptions, + sophistications, timestamp, title, to_dict, to_json, to_obj, types, + version, walk .. autoclass:: AssociatedActors - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: AssociatedCampaigns - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: ObservedTTPs - :show-inheritance: - :members: + :show-inheritance: + :members: diff --git a/docs/api/ttp/ttp.rst b/docs/api/ttp/ttp.rst index e20217f6..273adeb7 100644 --- a/docs/api/ttp/ttp.rst +++ b/docs/api/ttp/ttp.rst @@ -7,5 +7,10 @@ Classes ------- .. autoclass:: TTP - :show-inheritance: - :members: + :show-inheritance: + :members: add_description, add_intended_effect, add_kill_chain_phase, + add_related_package, add_short_description, behavior, description, + descriptions, exploit_targets, find, handling, id_, idref, information_source, + intended_effects, kill_chain_phases, related_packages, related_ttps, + resources, short_description, short_descriptions, timestamp, title, + to_dict, to_json, to_obj, version, victim_targeting, walk From 90fb7728ccb9b7eb3499fb10ec7539e149730ace Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Wed, 13 May 2015 22:11:35 -0400 Subject: [PATCH 096/438] Updated data-model URLs in rst files. --- docs/api/exploit_target/exploit_target.rst | 2 +- docs/api/indicator/indicator.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/exploit_target/exploit_target.rst b/docs/api/exploit_target/exploit_target.rst index 11d7d0a4..012548e6 100644 --- a/docs/api/exploit_target/exploit_target.rst +++ b/docs/api/exploit_target/exploit_target.rst @@ -12,7 +12,7 @@ This denotes the specific vulnerability, weakness, or software configuration tha Documentation Resources ~~~~~~~~~~~~~~~~~~~~~~~ -* `ExploitTarget Data Model `_ +* `ExploitTarget Data Model `_ * `ExploitTarget Idioms `_ Classes diff --git a/docs/api/indicator/indicator.rst b/docs/api/indicator/indicator.rst index fa8e2a2f..1b8a992c 100644 --- a/docs/api/indicator/indicator.rst +++ b/docs/api/indicator/indicator.rst @@ -14,7 +14,7 @@ acted on, etc. Documentation Resources ~~~~~~~~~~~~~~~~~~~~~~~ -* `Indicator Data Model `_ +* `Indicator Data Model `_ * `Indicator Idioms `_ From d167928e6d03ad18a2c1913a348a19e214f2a55a Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 08:19:56 -0400 Subject: [PATCH 097/438] Updated docstrings on ExploitTarget --- stix/exploit_target/__init__.py | 63 +++++++++++++++------------------ 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/stix/exploit_target/__init__.py b/stix/exploit_target/__init__.py index 48acf01a..123b0169 100644 --- a/stix/exploit_target/__init__.py +++ b/stix/exploit_target/__init__.py @@ -59,18 +59,17 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, @property def vulnerabilities(self): - """A list of ``Vulnerability`` objects + """A collection of :class:`.Vulnerability` objects. This behaves like + a ``MutableSequence`` type. Default Value: ``None`` Returns: - A list of - :class:`stix.exploit_target.vulnerability` + A list of :class:`.Vulnerability` Raises: ValueError: If set to a value that is not ``None`` and not an - instance of - :class:`stix.exploit_target.vulnerability` + instance of :class:`.Vulnerability` """ @@ -80,74 +79,69 @@ def vulnerabilities(self): def vulnerabilities(self, value): self._vulnerabilities = _Vulnerabilities(value) - def add_vulnerability(self, v): - """Adds a vulnerability to the ``vulnerabilies`` list property. + def add_vulnerability(self, value): + """Adds a vulnerability to the :attr:`vulnerabilities` list property. Note: If ``None`` is passed in no value is added Args: - v: A Vulnerability value. + value: A :class:`.Vulnerability` object.. - Raises: ValueError if the ``v`` param is of type - :class:`stix.exploit_target.vulnerability` - + Raises: + ValueError: if the `value` param is of type :class:`.Vulnerability` """ - self.vulnerabilities.append(v) + self.vulnerabilities.append(value) @property def weaknesses(self): - """A list of ``Weakness`` objects + """A collection of :class:`.Weakness` objects. This behaves like + a ``MutableSequence`` type. Default Value: ``None`` Returns: - A list of - :class:`stix.exploit_target.weakness` + A list of :class:`.Weakness` objects. Raises: ValueError: If set to a value that is not ``None`` and not an - instance of - :class:`stix.exploit_target.weakness` + instance of :class:`.Weakness` """ - return self._weaknesses @weaknesses.setter def weaknesses(self, value): self._weaknesses = _Weaknesses(value) - def add_weakness(self, v): - """Adds a weakness to the ``weaknesses`` list property. + def add_weakness(self, value): + """Adds a weakness to the :attr:`weaknesses` list property. Note: If ``None`` is passed in no value is added Args: - v: A weakness value. + value: A :class:`.Weakness` object. - Raises: ValueError if the ``v`` param is of type :class:`stix.exploit_target.weakness` - + Raises: ValueError if the `value` param is of type :class:`.Weakness` """ - self.weaknesses.append(v) + self.weaknesses.append(value) @property def configuration(self): - """A list of ``Configuration`` objects + """A list of :class:`.Configuration` objects. This behaves like + a ``MutableSequence`` type. Default Value: ``None`` Returns: - A list of - :class:`stix.exploit_target.configuration` + A list of :class:`.Configuration` objects. Raises: ValueError: If set to a value that is not ``None`` and not an - instance of - :class:`stix.exploit_target.configuration` + instance of :class:`.Configuration`. """ @@ -157,19 +151,20 @@ def configuration(self): def configuration(self, value): self._configuration = _Configurations(value) - def add_configuration(self, v): - """Adds a configuration to the ``configurations`` list property. + def add_configuration(self, value): + """Adds a configuration to the :attr:`configurations` list property. Note: If ``None`` is passed in no value is added Args: - v: A configuration value. + value: A configuration value. - Raises: ValueError if the ``v`` param is of type :class:`stix.exploit_target.configuration` + Raises: + ValueError: If the `value` param is of type :class:`.Configuration` """ - self.configuration.append(v) + self.configuration.append(value) def to_obj(self, return_obj=None, ns_info=None): if not return_obj: From 12d3912c8154cf26ef0c15e156f79d4f4632e04a Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 09:10:42 -0400 Subject: [PATCH 098/438] Added high-level overview docs to each of the top-level component classes. --- docs/api/campaign/campaign.rst | 14 ++++++++++++++ docs/api/coa/coa.rst | 18 +++++++++++++++++- docs/api/exploit_target/exploit_target.rst | 11 +++++++---- docs/api/incident/incident.rst | 16 +++++++++++++++- docs/api/report/report.rst | 14 ++++++++++++++ docs/api/threat_actor/threat_actor.rst | 16 ++++++++++++++++ docs/api/ttp/ttp.rst | 15 ++++++++++++++- 7 files changed, 97 insertions(+), 7 deletions(-) diff --git a/docs/api/campaign/campaign.rst b/docs/api/campaign/campaign.rst index 9b9129ad..1c125a3d 100644 --- a/docs/api/campaign/campaign.rst +++ b/docs/api/campaign/campaign.rst @@ -3,6 +3,20 @@ .. module:: stix.campaign +Overview +-------- + +The :mod:`stix.campaign` module implements :class:`.Campaign`. + +Campaigns are instances of ThreatActors pursuing an intent, as observed through +sets of Incidents and/or TTP, potentially across organizations. + + +Documentation Resources +~~~~~~~~~~~~~~~~~~~~~~~ + +* `Campaign Data Model `_ + Classes ------- diff --git a/docs/api/coa/coa.rst b/docs/api/coa/coa.rst index d2d1f5f4..84fa0a40 100644 --- a/docs/api/coa/coa.rst +++ b/docs/api/coa/coa.rst @@ -1,8 +1,24 @@ :mod:`stix.coa` Module -================================== +====================== .. module:: stix.coa +Overview +-------- + +The :mod:`stix.coa` module implements :class:`.CourseOfAction`. + +CoursesOfAction are specific measures to be taken to address threat whether +they are corrective or preventative to address ExploitTargets, or responsive to +counter or mitigate the potential impacts of Incidents + + +Documentation Resources +~~~~~~~~~~~~~~~~~~~~~~~ + +* `Course Of Action Data Model `_ + + Classes ------- diff --git a/docs/api/exploit_target/exploit_target.rst b/docs/api/exploit_target/exploit_target.rst index 012548e6..7d88044e 100644 --- a/docs/api/exploit_target/exploit_target.rst +++ b/docs/api/exploit_target/exploit_target.rst @@ -5,15 +5,18 @@ Overview -------- -The :mod:`stix.exploit_target` module implements ``ExploitTarget``. -This denotes the specific vulnerability, weakness, or software configuration that creates a security risk. + +The :mod:`stix.exploit_target` module implements :class:`.ExploitTarget`. + +This denotes the specific vulnerability, weakness, or software configuration +that creates a security risk. Documentation Resources ~~~~~~~~~~~~~~~~~~~~~~~ -* `ExploitTarget Data Model `_ -* `ExploitTarget Idioms `_ +* `Exploit Target Data Model `_ +* `Exploit Target Idioms `_ Classes ------- diff --git a/docs/api/incident/incident.rst b/docs/api/incident/incident.rst index 0e0bc34f..f290773f 100644 --- a/docs/api/incident/incident.rst +++ b/docs/api/incident/incident.rst @@ -1,8 +1,22 @@ :mod:`stix.incident` Module -================================== +=========================== .. module:: stix.incident +Overview +-------- + +The :mod:`stix.incident` module implements :class:`.Incident`. + +Incidents are discrete instances of Indicators affecting an organization along +with information discovered or decided during an incident response investigation. + + +Documentation Resources +~~~~~~~~~~~~~~~~~~~~~~~ + +* `Incident Data Model `_ + Classes ------- diff --git a/docs/api/report/report.rst b/docs/api/report/report.rst index a60bfcaf..20ea49b8 100644 --- a/docs/api/report/report.rst +++ b/docs/api/report/report.rst @@ -3,6 +3,20 @@ .. module:: stix.report +Overview +-------- + +The :mod:`stix.report` module implements :class:`.Report`. + +A Report defines a contextual wrapper for a grouping of STIX content. + + +Documentation Resources +~~~~~~~~~~~~~~~~~~~~~~~ + +* `Report Data Model `_ + + Classes ------- diff --git a/docs/api/threat_actor/threat_actor.rst b/docs/api/threat_actor/threat_actor.rst index ea520945..1fb2d2f7 100644 --- a/docs/api/threat_actor/threat_actor.rst +++ b/docs/api/threat_actor/threat_actor.rst @@ -3,6 +3,22 @@ .. module:: stix.threat_actor +Overview +-------- + +The :mod:`stix.threat_actor` module implements :class:`.ThreatActor`. + +ThreatActors are characterizations of malicious actors (or adversaries) +representing a cyber attack threat including presumed intent and historically +observed behavior. + + +Documentation Resources +~~~~~~~~~~~~~~~~~~~~~~~ + +* `Threat Actor Data Model `_ + + Classes ------- diff --git a/docs/api/ttp/ttp.rst b/docs/api/ttp/ttp.rst index 273adeb7..7aef4767 100644 --- a/docs/api/ttp/ttp.rst +++ b/docs/api/ttp/ttp.rst @@ -1,8 +1,21 @@ :mod:`stix.ttp` Module -================================== +====================== .. module:: stix.ttp +Overview +-------- + +The :mod:`stix.ttp` module implements :class:`.TTP`. + +TTPs are representations of the behavior or modus operandi of cyber adversaries. + + +Documentation Resources +~~~~~~~~~~~~~~~~~~~~~~~ + +* `TTP Data Model `_ + Classes ------- From aeb3d18542e62dc72675c42a8e9b2b5b8fd1292f Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 09:13:24 -0400 Subject: [PATCH 099/438] Added high-level docs to STIX Package. --- docs/api/core/stix_package.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/api/core/stix_package.rst b/docs/api/core/stix_package.rst index ccf79934..6e20e849 100644 --- a/docs/api/core/stix_package.rst +++ b/docs/api/core/stix_package.rst @@ -3,6 +3,22 @@ .. module:: stix.core.stix_package +Overview +-------- + +The :mod:`stix.core.stix_package` module implements :class:`.STIXPackage`. + +STIXType defines a bundle of information characterized in the Structured Threat +Information eXpression (STIX) language. + + +Documentation Resources +~~~~~~~~~~~~~~~~~~~~~~~ + +* `STIX Package Data Model `_ + + + Classes ------- From 7b3a64b3dc3d95b06552f7d46eaa1bb132ba0b2b Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 09:41:45 -0400 Subject: [PATCH 100/438] Added docs to Incident class. --- docs/api/incident/coa.rst | 4 ++ stix/incident/__init__.py | 124 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/docs/api/incident/coa.rst b/docs/api/incident/coa.rst index f8a0a5bc..1a1e9834 100644 --- a/docs/api/incident/coa.rst +++ b/docs/api/incident/coa.rst @@ -10,6 +10,10 @@ Classes :show-inheritance: :members: +.. autoclass:: COARequested + :show-inheritance: + :members: + .. autoclass:: COATime :show-inheritance: :members: diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index b866a054..3a186790 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -83,6 +83,10 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, description @property def status(self): + """A :class:`.VocabString` property. If set to a string, an attempt + will be made to convert it to an instance of :class:`.IncidentStatus`. + + """ return self._status @status.setter @@ -91,6 +95,9 @@ def status(self, value): @property def time(self): + """Time section of the Incident. This is a :class:`.time.Time` field. + + """ return self._time @time.setter @@ -99,6 +106,15 @@ def time(self, value): @property def intended_effects(self): + """The impact of this intended effects of this Incident. This is a + collection of :class:`.Statement` objects and behaves like a + ``MutableSequence`` type. + + If set to a string, an attempt will be made to convert it into a + :class:`.Statement` object with its value set to an instance of + :class:`.IntendedEffect`. + + """ return self._intended_effects @intended_effects.setter @@ -106,10 +122,21 @@ def intended_effects(self, value): self._intended_effects = _IntendedEffects(value) def add_intended_effect(self, value): + """Adds a :class:`.Statement` object to the :attr:`intended_effects` + collection. + + If `value` is a string, an attempt will be made to convert it into an + instance of :class:`.Statement`. + + """ self.intended_effects.append(value) @property def victims(self): + """A collection of victim :class:`.Identity` objects. This behaves like + a ``MutableSequence`` type. + + """ return self._victims @victims.setter @@ -117,10 +144,18 @@ def victims(self, value): self._victims = _Victims(value) def add_victim(self, victim): + """Adds a :class:`.IdentityType` value to the :attr:`victims` + collection. + + """ self._victims.append(victim) @property def categories(self): + """A collection of :class:`.VocabString` objects. This behaves + like a ``MutableSequence`` type. + + """ return self._categories @categories.setter @@ -128,10 +163,21 @@ def categories(self, value): self._categories = IncidentCategories(value) def add_category(self, category): + """Adds a :class:`.VocabString` object to the :attr:`categories` + collection. + + If `category` is a string, an attempt will be made to convert it into + an instance of :class:`.IncidentCategory`. + + """ self.categories.append(category) @property def affected_assets(self): + """A collection of :class:`.AffectedAsset` objects. This behaves like + a ``MutableSequence`` type. + + """ return self._affected_assets @affected_assets.setter @@ -139,10 +185,18 @@ def affected_assets(self, value): self._affected_assets = AffectedAssets(value) def add_affected_asset(self, v): + """Adds a :class:`.AffectedAsset` object to the :attr:`affected_assets` + collection. + + """ self.affected_assets.append(v) @property def discovery_methods(self): + """A :class:`.VocabString` collection. This behaves like a + ``MutableSequence`` type. + + """ return self._discovery_methods @discovery_methods.setter @@ -150,10 +204,20 @@ def discovery_methods(self, value): self._discovery_methods = DiscoveryMethods(value) def add_discovery_method(self, value): + """Adds a :class:`.VocabString` object to the :attr:`discovery_methods` + collection. + + If `value` is a string, an attempt will be made to convert it to an + instance of :class:`.DiscoveryMethod`. + + """ self.discovery_methods.append(value) @property def reporter(self): + """A :class:`.InformationSource` field. + + """ return self._reporter @reporter.setter @@ -162,6 +226,12 @@ def reporter(self, value): @property def responders(self): + """A class of :class:`.InformationSource` objects which contain + information about incident responders. + + This behaves like a ``MutableSequence`` type. + + """ return self._responders @responders.setter @@ -169,10 +239,18 @@ def responders(self, value): self._responders = _InformationSources(value) def add_responder(self, value): + """Adds a :class:`.InformationSource` object to the :attr:`responders` + collection. + + """ self.responders.append(value) @property def coordinators(self): + """A class of :class:`.InformationSource` objects. This behaves like a + ``MutableSequence`` type. + + """ return self._coordinators @coordinators.setter @@ -180,6 +258,10 @@ def coordinators(self, value): self._coordinators = _InformationSources(value) def add_coordinator(self, value): + """Adds a :class:`.InformationSource` object to the :attr:`coordinators` + collection. + + """ self.coordinators.append(value) @property @@ -188,13 +270,24 @@ def external_ids(self): @external_ids.setter def external_ids(self, value): + """A collection of :class:`.ExternalID` objects for capturing + incident tracker identification information. + + """ self._external_ids = _ExternalIDs(value) def add_external_id(self, value): + """Adds a :class:`.ExternalID` object to the :attr:`external_ids` + collection. + + """ self.external_ids.append(value) @property def impact_assessment(self): + """A class :class:`.ImpactAssessment` field. + + """ return self._impact_assessment @impact_assessment.setter @@ -203,6 +296,10 @@ def impact_assessment(self, value): @property def security_compromise(self): + """A :class:`.VocabString` field. If set to a string, an attempt will + be made to convert it into an instance of :class:`.SecurityCompromise`. + + """ return self._security_compromise @security_compromise.setter @@ -211,6 +308,9 @@ def security_compromise(self, value): @property def confidence(self): + """A :class:`.Confidence` field. + + """ return self._confidence @confidence.setter @@ -219,6 +319,12 @@ def confidence(self, value): @property def coa_taken(self): + """A collection of :class:`.COATaken` objects which characterize + courses of action taken during the incident. + + This behaves like a ``MutableSequence`` type. + + """ return self._coa_taken @coa_taken.setter @@ -226,10 +332,20 @@ def coa_taken(self, value): self._coa_taken = _COAsTaken(value) def add_coa_taken(self, value): + """Adds a :class:`.COATaken` object to the :attr:`coas_taken` + collection. + + """ self.coa_taken.append(value) @property def coa_requested(self): + """A collection of :class:`.COARequested` objects which characterize + courses of action requested for response to this incident. + + This behaves like a ``MutableSequence`` type. + + """ return self._coa_requested @coa_requested.setter @@ -237,10 +353,18 @@ def coa_requested(self, value): self._coa_requested = _COAsRequested(value) def add_coa_requested(self, value): + """Adds a :class:`.COARequested` object to the :attr:`coas_requested` + collection. + + """ self.coa_requested.append(value) @property def related_indicators(self): + """A collection of :class:`.RelatedIndicator` objects characterizing + indicators related to this incident. + + """ return self._related_indicators @related_indicators.setter From b41a62c83b5ef3e0ee48f6e3520408db98f3ce98 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 10:10:57 -0400 Subject: [PATCH 101/438] Added docs to Incident class --- stix/incident/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index 3a186790..c13184b3 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -372,7 +372,7 @@ def related_indicators(self, value): self._set_var(RelatedIndicators, related_indicators=value) def add_related_indicator(self, value): - """Adds an Related Indicator to the ``related_indicators`` list + """Adds an Related Indicator to the :attr:`related_indicators` list property of this :class:`Incident`. The `indicator` parameter must be an instance of From 0044cac90c57b4afca06be502d04417da6fd012a Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 10:11:10 -0400 Subject: [PATCH 102/438] Added docs to ThreatActor class --- stix/threat_actor/__init__.py | 67 +++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/stix/threat_actor/__init__.py b/stix/threat_actor/__init__.py index 5aac80a0..63e77f95 100644 --- a/stix/threat_actor/__init__.py +++ b/stix/threat_actor/__init__.py @@ -87,6 +87,10 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, @property def identity(self): + """A :class:`.Identity` field characterizing information about the + threat actor. + + """ return self._identity @identity.setter @@ -95,6 +99,12 @@ def identity(self, value): @property def types(self): + """A collection of :class:`.VocabString` objects. Default is + :class:`.ThreatActorType`. + + This behaves like a ``MutableSequence`` type. + + """ return self._types @types.setter @@ -102,10 +112,22 @@ def types(self, value): self._types = _Types(value) def add_type(self, value): + """Adds a :class:`.VocabString` object to the :attr:`types` collection. + + If set to a string, an attempt will be made to convert it into an + instance of :class:`.ThreatActorType`. + + """ self.types.append(value) @property def motivations(self): + """A collection of :class:`.VocabString` objects. Default is + :class:`.Motivation`. + + This behaves like a ``MutableSequence`` type. + + """ return self._motivations @motivations.setter @@ -113,10 +135,20 @@ def motivations(self, value): self._motivations = _Motivations(value) def add_motivation(self, value): + """Adds a :class:`.Motivation` object to the :attr:`motivations` + collection. + + """ self.motivations.append(value) @property def sophistications(self): + """A collection of :class:`.VocabString` objects. Default is + :class:`.ThreatActorSophistication`. + + This behaves like a ``MutableSequence`` type. + + """ return self._sophistications @sophistications.setter @@ -124,10 +156,25 @@ def sophistications(self, value): self._sophistications = _Sophistications(value) def add_sophistication(self, value): + """Adds a :class:`.VocabString` object to the :attr:`sophistications` + collection. + + If `value` is a string, an attempt will be made to convert it to an + instance of :class:`.ThreatActorSophistication`. + + """ self._sophistications.append(value) @property def intended_effects(self): + """A collection of :class:`.Statement` objects. This behaves like a + ``MutableSequence`` type. + + If set to a string, an attempt will be made to convert it into a + :class:`.Statement` object with its value set to an instance of + :class:`.IntendedEffect`. + + """ return self._intended_effects @intended_effects.setter @@ -135,10 +182,23 @@ def intended_effects(self, value): self._intended_effects = _IntendedEffects(value) def add_intended_effect(self, value): + """Adds a :class:`.Statement` object to the :attr:`intended_effects` + collection. + + If `value` is a string, an attempt will be made to convert it into an + instance of :class:`.Statement`. + + """ self.intended_effects.append(value) @property def planning_and_operational_supports(self): + """A collection of :class:`.VocabString` objects. Default is + :class:`.PlanningAndOperationalSupport`. + + This behaves like a ``MutableSequence`` type. + + """ return self._planning_and_operational_supports @planning_and_operational_supports.setter @@ -146,6 +206,13 @@ def planning_and_operational_supports(self, value): self._planning_and_operational_supports = _PlanningAndOperationalSupports(value) def add_planning_and_operational_support(self, value): + """Adds a :class:`.VocabString` object to the + :attr:`planning_and_operational_supports` collection. + + If `value` is a string, an attempt will be made to convert it to an + instance of :class:`.PlanningAndOperationalSupport`. + + """ self.planning_and_operational_supports.append(value) def to_obj(self, return_obj=None, ns_info=None): From c417d733b44f6ba3ac5cfd301da5e1734f2ad820 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 10:11:26 -0400 Subject: [PATCH 103/438] Added docs to TTP class --- stix/ttp/__init__.py | 100 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 5 deletions(-) diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index ba9b8cf8..9534a446 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -61,6 +61,9 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, @property def behavior(self): + """A :class:`.Behavior` field. + + """ return self._behavior @behavior.setter @@ -69,6 +72,10 @@ def behavior(self, value): @property def related_ttps(self): + """A collection of :class:`.RelatedTTP` objects. This behaves like a + ``MutableSequence`` Type. + + """ return self._related_ttps @related_ttps.setter @@ -78,8 +85,44 @@ def related_ttps(self, value): else: self._related_ttps = RelatedTTPs(value) + def add_related_ttp(self, value): + """Adds an Related TTP to the :attr:`related_ttps` list + property of this :class:`TTP`. + + The `TTP` parameter must be an instance of + :class:`.RelatedTTP` or :class:`TTP`. + + If the `TTP` parameter is ``None``, no item wil be added to the + ``related_ttps`` list property. + + Calling this method is the same as calling ``append()`` on the + ``related_ttps`` property. + + See Also: + The :class:`RelatedTTPs` documentation. + + Note: + If the `TTP` parameter is not an instance of + :class:`.RelatedTTP` an attempt will be + made to convert it to one. + + Args: + TTP: An instance of :class:`TTP` or + :class:`.RelatedTTP`. + + Raises: + ValueError: If the `TTP` parameter cannot be converted into + an instance of :class:`.RelatedTTP` + + """ + self.related_ttps.append(value) + @property def exploit_targets(self): + """A collection of :class:`.ExploitTarget` objects. This behaves like + a ``MutableSequence`` type. + + """ return self._exploit_targets @exploit_targets.setter @@ -89,8 +132,23 @@ def exploit_targets(self, value): else: self._exploit_targets = ExploitTargets(value) + def add_exploit_target(self, value): + """Adds a :class:`.ExploitTarget` object to the :attr:`exploit_targets` + collection. + + """ + self.exploit_targets.append(value) + @property def intended_effects(self): + """A collection of :class:`.Statement` objects. This behaves like a + ``MutableSequence`` type. + + If set to a string, an attempt will be made to convert it into a + :class:`.Statement` object with its value set to an instance of + :class:`.IntendedEffect`. + + """ return self._intended_effects @intended_effects.setter @@ -98,10 +156,21 @@ def intended_effects(self, value): self._intended_effects = _IntendedEffects(value) def add_intended_effect(self, value): + """Adds a :class:`.Statement` object to the :attr:`intended_effects` + collection. + + If `value` is a string, an attempt will be made to convert it into an + instance of :class:`.Statement`. + + """ self.intended_effects.append(value) @property def resources(self): + """A collection of :class:`.Resource` objects. This behaves like a + ``MutableSequence`` type. + + """ return self._resources @resources.setter @@ -110,6 +179,10 @@ def resources(self, value): @property def victim_targeting(self): + """A collection of :class:`.VictimTargeting` objects. This behaves like + a ``MutableSequence`` type. + + """ return self._victim_targeting @victim_targeting.setter @@ -118,6 +191,10 @@ def victim_targeting(self, value): @property def kill_chain_phases(self): + """A collection of :class:`.KillChainPhaseReference` objects. This + behaves like a ``MutableSequence`` type. + + """ return self._kill_chain_phases @kill_chain_phases.setter @@ -125,18 +202,23 @@ def kill_chain_phases(self, value): self._kill_chain_phases = KillChainPhasesReference(value) def add_kill_chain_phase(self, value): - """Add a new Kill Chain Phase reference to this Indicator. + """Adds a :class:`.KillChainPhaseReference` to the + :attr:`kill_chain_phases` collection. Args: - value: a :class:`stix.common.kill_chains.KillChainPhase` or a `str` - representing the phase_id of. Note that you if you are defining - a custom Kill Chain, you need to add it to the STIX package - separately. + value: A :class:`.KillChainPhase`, :class:`.KillChainPhaseReference` + or a ``str`` representing the phase_id of. Note that you if you + are defining a custom Kill Chain, you need to add it to the + STIX package separately. """ self.kill_chain_phases.append(value) @property def related_packages(self): + """**DEPRECATED**: A collection of :class:`.RelatedPackageRef` + objects. This behaves like a ``MutableSequence``. + + """ return self._related_packages @related_packages.setter @@ -144,6 +226,14 @@ def related_packages(self, value): self._related_packages = RelatedPackageRefs(value) def add_related_package(self, value): + """Adds a :class:`.RelatedPackageRef` object to the + :attr:`related_packages` collection. + + Args: + value: A :class:`.RelatedPackageRef` or a :class:`.STIXPackage` + object. + + """ self.related_packages.append(value) def to_obj(self, return_obj=None, ns_info=None): From 642e9e5220517b2f60db11bfcc85ed10442e6f5f Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 10:30:19 -0400 Subject: [PATCH 104/438] Updated Indicator docs --- docs/api/indicator/indicator.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/indicator/indicator.rst b/docs/api/indicator/indicator.rst index 1b8a992c..0b299213 100644 --- a/docs/api/indicator/indicator.rst +++ b/docs/api/indicator/indicator.rst @@ -34,7 +34,7 @@ Classes observables, producer, related_campaigns, related_indicators, related_packages, set_produced_time, set_producer_identity, set_received_time, short_description, short_descriptions, - test_mechanisms, timestamp, title, to_dict, to_json, to_obj, to_xml, + test_mechanisms, timestamp, title, to_dict, to_json, to_obj, valid_time_positions, version, walk From d98f38e744c0b4feea826cc21423bd4bf4a021d3 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 10:30:33 -0400 Subject: [PATCH 105/438] Updated STIXPackage docs. --- docs/api/core/stix_package.rst | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/api/core/stix_package.rst b/docs/api/core/stix_package.rst index 6e20e849..6a0f469c 100644 --- a/docs/api/core/stix_package.rst +++ b/docs/api/core/stix_package.rst @@ -18,14 +18,20 @@ Documentation Resources * `STIX Package Data Model `_ - Classes ------- .. autoclass:: STIXPackage - :show-inheritance: - :members: + :show-inheritance: + :members: add_course_of_action, add_related_package, add_incident, + stix_header, add_indicator, add, version, indicators, exploit_targets, + id_, add_exploit_target, add_report, timestamp, add_threat_actor, + campaigns, add_observable, to_obj, related_packages, idref, + courses_of_action, reports, ttps, incidents, to_dict, observables, + add_ttp, threat_actors, add_campaign, walk, to_obj, to_xml, find, + to_json, to_dict + .. autoclass:: RelatedPackages - :show-inheritance: - :members: + :show-inheritance: + :members: From 9f57f0f197d6b3b93432a31c941db2354c50e284 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 10:30:45 -0400 Subject: [PATCH 106/438] Fixed indentation in kill chain docs. --- docs/api/common/kill_chains.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/api/common/kill_chains.rst b/docs/api/common/kill_chains.rst index cb7a8892..98d5cdaa 100755 --- a/docs/api/common/kill_chains.rst +++ b/docs/api/common/kill_chains.rst @@ -7,24 +7,24 @@ Classes ------- .. autoclass:: KillChain - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: KillChains - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: KillChainPhase - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: KillChainPhaseReference - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: KillChainPhasesReference - :show-inheritance: - :members: + :show-inheritance: + :members: Lockheed Martin Kill Chain -------------------------- From 71913100c2836949b6026b7c15d628dc2e9eeb32 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 11:00:16 -0400 Subject: [PATCH 107/438] Updated stix utils docs. --- docs/api/index.rst | 1 + docs/api/utils/utils.rst | 23 +++++++++++++++++++++++ stix/utils/__init__.py | 23 +++++++++++++++++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100755 docs/api/utils/utils.rst diff --git a/docs/api/index.rst b/docs/api/index.rst index 1acb8343..ee26d8a3 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -168,4 +168,5 @@ Modules located in the `stix.utils`_ package :titlesonly: :glob: + utils/utils utils/* diff --git a/docs/api/utils/utils.rst b/docs/api/utils/utils.rst new file mode 100755 index 00000000..5d5a817a --- /dev/null +++ b/docs/api/utils/utils.rst @@ -0,0 +1,23 @@ +:mod:`stix.utils` Module +============================== + +.. module:: stix.utils + +Functions +--------- + + +.. autofunction:: is_cdata + +.. autofunction:: strip_cdata + +.. autofunction:: cdata + +.. autofunction:: raise_warnings + +.. autofunction:: silence_warnings + +.. autofunction:: xml_bool + + + diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index d5f5cd5b..faaec557 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -40,6 +40,11 @@ def raise_warnings(func): """Function decorator that causes all Python warnings to be raised as exceptions in the wrapped function. + Example: + >>> @raise_warnings + >>> def foo(): + >>> warnings.warn("this will raise an exception") + """ @functools.wraps(func) def inner(*args, **kwargs): @@ -53,6 +58,11 @@ def silence_warnings(func): """Function decorator that silences/ignores all Python warnings in the wrapped function. + Example: + >>> @silence_warnings + >>> def foo(): + >>> warnings.warn("this will not appear") + """ @functools.wraps(func) def inner(*args, **kwargs): @@ -63,6 +73,15 @@ def inner(*args, **kwargs): def is_cdata(text): + """Returns ``True`` if `text` contains a CDATA block. + + Example: + >>> is_cdata("") + True + >>> is_cdata("NOPE") + False + + """ if not text: return False @@ -92,7 +111,7 @@ def strip_cdata(text): def cdata(text): - """Wraps the input `text` in a block. + """Wraps the input `text` in a ```` block. If the text contains CDATA sections already, they are stripped and replaced by the application of an outer-most CDATA block. @@ -101,7 +120,7 @@ def cdata(text): text: A string to wrap in a CDATA block. Returns: - The `text` value wrapped in + The `text` value wrapped in ```` """ if not text: From bcb788e43a8364819e3abe8b5517a7b954ab26eb Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 11:04:25 -0400 Subject: [PATCH 108/438] Updated utils.dates docs. --- docs/api/utils/dates.rst | 6 ++++++ stix/utils/dates.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/api/utils/dates.rst b/docs/api/utils/dates.rst index 3e1454b8..811a4fd9 100644 --- a/docs/api/utils/dates.rst +++ b/docs/api/utils/dates.rst @@ -9,3 +9,9 @@ Functions .. autofunction:: parse_value .. autofunction:: serialize_value + +.. autofunction:: parse_date + +.. autofunction:: serialize_value + +.. autofunction:: now diff --git a/stix/utils/dates.py b/stix/utils/dates.py index 55fc4cf9..19802e8f 100644 --- a/stix/utils/dates.py +++ b/stix/utils/dates.py @@ -83,5 +83,5 @@ def serialize_date(value): def now(): - """Returns the current UTC datetime.datetime.""" + """Returns the current UTC ``datetime.datetime`` timestamp.""" return datetime.datetime.now(tz=dateutil.tz.tzutc()) From 06b818b8ca0294c73e2e76d02445bffc555d8188 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 13:15:06 -0400 Subject: [PATCH 109/438] updated README to include 1.2 components. --- README.rst | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/README.rst b/README.rst index 97329b69..fa18e658 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ python-stix =========== -A python library for parsing, manipulating, and generating STIX v1.1.1 content. +A python library for parsing, manipulating, and generating STIX v1.2 content. :Source: https://github.com/STIXProject/python-stix :Documentation: http://stix.readthedocs.org @@ -67,36 +67,38 @@ Layout The python-stix package layout is as follows: -* ``stix/`` : root level package +* ``stix/`` : root level package. -* ``examples/`` : example python scripts that leverage the python-stix library +* ``examples/`` : example python scripts that leverage the python-stix library. * ``stix/utils/`` : utility classes and modules used internally by the python-stix - library + library. * ``stix/bindings/`` : generateDS generated xml-to-python bindings (leveraged for - parsing and output of STIX XML content) + parsing and output of STIX XML content). -* ``stix/campaign/`` : APIs for STIX Campaign constructs +* ``stix/campaign/`` : APIs for STIX Campaign constructs. -* ``stix/coa/`` : APIs for STIX Course Of Action constructs +* ``stix/coa/`` : APIs for STIX Course Of Action constructs. -* ``stix/core/`` : APIs for core STIX constructs (e.g., STIX Header, STIX Package) +* ``stix/core/`` : APIs for core STIX constructs (e.g., STIX Header, STIX Package). * ``stix/common/`` : APIs for common STIX constructs (e.g., Structured Text, - Information Source) + Information Source). -* ``stix/exploit_target/`` : APIs for STIX Exploit Target constructs +* ``stix/exploit_target/`` : APIs for STIX Exploit Target constructs. -* ``stix/incident/`` : APIs for common Incident constructs +* ``stix/incident/`` : APIs for common Incident constructs. -* ``stix/indicator/`` : APIs for STIX Indicator constructs +* ``stix/indicator/`` : APIs for STIX Indicator constructs. -* ``stix/extensions/`` : APIs for STIX extensions (e.g., CIQ Identity) +* ``stix/extensions/`` : APIs for STIX extensions (e.g., CIQ Identity). -* ``stix/threat_actor/`` : APIs for STIX Threat Actor constructs +* ``stix/report/``: APIs for STIX Report constructs. -* ``stix/ttp/`` : APIs for STIX TTP constructs +* ``stix/threat_actor/`` : APIs for STIX Threat Actor constructs. + +* ``stix/ttp/`` : APIs for STIX TTP constructs. Please refer to examples for concrete examples of how to interact with the -python-stix library +python-stix library. From 961e3c8f8340abdbd5cb5e3b3c5e4f8c57ffb60e Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 13:15:39 -0400 Subject: [PATCH 110/438] Updated API coverage. --- docs/api/common/structured_text.rst | 12 ++++++------ docs/api/coverage.rst | 27 ++++++++++++++------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/docs/api/common/structured_text.rst b/docs/api/common/structured_text.rst index 3ef0bb20..be40c4ba 100644 --- a/docs/api/common/structured_text.rst +++ b/docs/api/common/structured_text.rst @@ -7,13 +7,13 @@ Classes ------- .. autoclass:: StructuredText - :show-inheritance: - :members: to_obj, from_obj, to_dict, from_dict, ordinality, - __str__, __unicode__ + :show-inheritance: + :members: to_obj, from_obj, to_dict, from_dict, ordinality, + __str__, __unicode__ .. autoclass:: StructuredTextList - :show-inheritance: - :members: __getitem__, __delitem__, __iter__, add, update, - insert, remove, reset, sorted, next_ordinality, to_obj, to_dict + :show-inheritance: + :members: __getitem__, __delitem__, __iter__, add, update, + insert, remove, reset, sorted, next_ordinality, to_obj, to_dict diff --git a/docs/api/coverage.rst b/docs/api/coverage.rst index 86bb0959..ecac2a25 100644 --- a/docs/api/coverage.rst +++ b/docs/api/coverage.rst @@ -62,22 +62,22 @@ CIQ Address × None CAPEC 2.7 × None | **Identity Extensions** -CIQ Identity ✓ Full :class:`stix.extensions.identity.ciq_identity_3_0.CIQIdentity3_0Instance` +CIQ Identity ⚠ Partial :class:`stix.extensions.identity.ciq_identity_3_0.CIQIdentity3_0Instance` | -**Malware Extensions** +**Malware Extensions** MAEC ✓ Full :class:`stix.extensions.malware.maec_4_1_malware.MAECInstance` | -**Marking Extensions** +**Marking Extensions** Simple Marking ✓ Full :class:`stix.extensions.marking.simple_marking.SimpleMarkingStructure` TLP ✓ Full :class:`stix.extensions.marking.tlp.TLPMarkingStructure` Terms of Use ✓ Full :class:`stix.extensions.marking.terms_of_use_marking.TermsOfUseMarkingStructure` | -**Structured COA Extensions** -Generic Structured COA × None +**Structured COA Extensions** +Generic Structured COA ✓ Full :class:`stix.extensions.structured_coa.generic_structured_coa.GenericStructuredCOA` | -**Test Mechanism Extensions** +**Test Mechanism Extensions** Generic Test Mechanism ✓ Full :class:`stix.extensions.test_mechanism.generic_test_mechanism.GenericTestMechanism` -OVAL × None +OVAL × None OpenIOC ✓ Full :class:`stix.extensions.test_mechanism.open_ioc_2010_test_mechanism.OpenIOCTestMechanism` SNORT ✓ Full :class:`stix.extensions.test_mechanism.snort_test_mechanism.SnortTestMechanism` YARA ✓ Full :class:`stix.extensions.test_mechanism.yara_test_mechanism.YaraTestMechanism` @@ -95,19 +95,20 @@ STIX Construct API Coverage AssetTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.AssetType` AttackerInfrastructureTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.AttackerInfrastructureType` AttackerToolTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.AttackerToolType` -AvailabilityLossTypeVocab-1.0 × None *(replaced by version 1.1.1)* +AvailabilityLossTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.AttackToolType_1_0` AvailabilityLossTypeVocab-1.1.1 ✓ Full :class:`stix.common.vocabs.AvailabilityLossType` COAStageVocab-1.0 ✓ Full :class:`stix.common.vocabs.COAStage` CampaignStatusVocab-1.0 ✓ Full :class:`stix.common.vocabs.CampaignStatus` CourseOfActionTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.CourseOfActionType` -DiscoveryMethodVocab-1.0 ✓ Full :class:`stix.common.vocabs.DiscoveryMethod` +DiscoveryMethodVocab-1.0 ✓ Full :class:`stix.common.vocabs.DiscoveryMethod_1_0` +DiscoveryMethodVocab-2.0 ✓ Full :class:`stix.common.vocabs.DiscoveryMethod` HighMediumLowVocab-1.0 ✓ Full :class:`stix.common.vocabs.HighMediumLow` ImpactQualificationVocab-1.0 ✓ Full :class:`stix.common.vocabs.ImpactQualification` ImpactRatingVocab-1.0 ✓ Full :class:`stix.common.vocabs.ImpactRating` IncidentCategoryVocab-1.0 ✓ Full :class:`stix.common.vocabs.IncidentCategory` IncidentEffectVocab-1.0 ✓ Full :class:`stix.common.vocabs.IncidentEffect` IncidentStatusVocab-1.0 ✓ Full :class:`stix.common.vocabs.IncidentStatus` -IndicatorTypeVocab-1.0 × None *(replaced by version 1.1)* +IndicatorTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.IndicatorType_1_0` IndicatorTypeVocab-1.1 ✓ Full :class:`stix.common.vocabs.IndicatorType` InformationSourceRoleVocab-1.0 ✓ Full :class:`stix.common.vocabs.InformationSourceRole` InformationTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.InformationType` @@ -117,12 +118,12 @@ LossDurationVocab-1.0 ✓ Full LossPropertyVocab-1.0 ✓ Full :class:`stix.common.vocabs.LossProperty` MalwareTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.MalwareType` ManagementClassVocab-1.0 ✓ Full :class:`stix.common.vocabs.ManagementClass` -MotivationVocab-1.0 × None *(replaced by version 1.0.1)* -MotivationVocab-1.0.1 × None *(replaced by version 1.1)* +MotivationVocab-1.0 ✓ Full :class:`stix.common.vocabs.Motivation_1_0` +MotivationVocab-1.0.1 ✓ Full :class:`stix.common.vocabs.Motivation_1_0_1` MotivationVocab-1.1 ✓ Full :class:`stix.common.vocabs.Motivation` OwnershipClassVocab-1.0 ✓ Full :class:`stix.common.vocabs.OwnershipClass` PackageIntentVocab-1.0 ✓ Full :class:`stix.common.vocabs.PackageIntent` -PlanningAndOperationalSupportVocab-1.0 × None *(replaced by version 1.0.1)* +PlanningAndOperationalSupportVocab-1.0 ✓ Full :class:`stix.common.vocabs.PlanningAndOperationalSupport_1_0` PlanningAndOperationalSupportVocab-1.0.1 ✓ Full :class:`stix.common.vocabs.PlanningAndOperationalSupport` SecurityCompromiseVocab-1.0 ✓ Full :class:`stix.common.vocabs.SecurityCompromise` SystemTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.SystemType` From aca9a9c49a8e162228c00e29d52fc4f78bf5c6fe Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 13:15:57 -0400 Subject: [PATCH 111/438] Added from_xml to STIXPackage docs. --- docs/api/core/stix_package.rst | 2 +- docs/api/utils/idgen.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/core/stix_package.rst b/docs/api/core/stix_package.rst index 6a0f469c..e4580d54 100644 --- a/docs/api/core/stix_package.rst +++ b/docs/api/core/stix_package.rst @@ -29,7 +29,7 @@ Classes campaigns, add_observable, to_obj, related_packages, idref, courses_of_action, reports, ttps, incidents, to_dict, observables, add_ttp, threat_actors, add_campaign, walk, to_obj, to_xml, find, - to_json, to_dict + to_json, to_dict, from_xml .. autoclass:: RelatedPackages diff --git a/docs/api/utils/idgen.rst b/docs/api/utils/idgen.rst index 717926b9..99fbedc6 100644 --- a/docs/api/utils/idgen.rst +++ b/docs/api/utils/idgen.rst @@ -1,5 +1,5 @@ :mod:`stix.utils.idgen` Module -================================== +============================== .. module:: stix.utils.idgen From 4ddd642a6358b415159e9925abf090d9156a46f1 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 13:16:46 -0400 Subject: [PATCH 112/438] Moved Controlled Vocabulary and ID Namespace docs outside of Examples. --- docs/examples/index.rst | 374 +--------------------- docs/index.rst | 7 +- docs/overview/controlled_vocabularies.rst | 298 +++++++++++++++++ docs/overview/id_namespaces.rst | 41 +++ docs/overview/index.rst | 14 + 5 files changed, 368 insertions(+), 366 deletions(-) create mode 100644 docs/overview/controlled_vocabularies.rst create mode 100644 docs/overview/id_namespaces.rst create mode 100644 docs/overview/index.rst diff --git a/docs/examples/index.rst b/docs/examples/index.rst index b8d4464a..f7f1292b 100755 --- a/docs/examples/index.rst +++ b/docs/examples/index.rst @@ -6,13 +6,6 @@ This page includes some basic examples of creating and parsing STIX content. There are a couple things we do in these examples for purposes of demonstration that shouldn't be done in production code: -* When calling ``to_xml()``, we use ``include_namespaces=False``. This is to - make the example output easier to read, but means the resulting output - cannot be successfully parsed. The XML parser doesn't know what namespaces - to use if they aren't included. In production code, you should explicitly - set ``include_namespaces`` to ``True`` or omit it entirely (``True`` is the - default). - * In some examples, we use ``set_id_method(IDGenerator.METHOD_INT)`` to make IDs for STIX constructs easier to read and cross-reference within the XML document. In production code, you should omit this statement, which causes @@ -25,7 +18,8 @@ documentation for more great examples of how to use **python-stix**. Creating a STIX Package ----------------------- -.. testcode:: + +.. code-block:: python from stix.core import STIXPackage, STIXHeader from stix.utils import IDGenerator, set_id_method @@ -37,376 +31,30 @@ Creating a STIX Package stix_header.description = "Getting Started!" stix_package.stix_header = stix_header - print stix_package.to_xml(include_namespaces=False) + print stix_package.to_xml() Which outputs: -.. testoutput:: +.. code-block:: xml - + Getting Started! -ID Namespaces -------------- -By default, **python-stix** sets the default ID namespace to -``http://example.com`` with an alias of ``example``. This results in STIX -id declarations that look like -``id="example:Package-2813128d-f45e-41f7-b10a-20a5656e3785"``. - -To change this, use the ``stix.utils.set_id_namespace()`` method which takes -a dictionary as a parameter. - -.. testcode:: - - from stix.core import STIXPackage - from stix.utils import set_id_namespace - - NAMESPACE = {"http://MY-NAMESPACE.com" : "myNS"} - set_id_namespace(NAMESPACE) # new ids will be prefixed by "myNS" - - stix_package = STIXPackage() # id will be created automatically - print stix_package.to_xml() - -Which outputs: - -.. testoutput:: - - - -Success! The ``xmlns:myNS="http://MY-NAMESPACE.com"`` matches our ``NAMESPACE`` -dictionary and the ``id`` attribute includes the ``myNS`` namespace alias. - -Working With CybOX -~~~~~~~~~~~~~~~~~~ -If you are creating CybOX entities such as ``Observables``, you'll want to set -the ID namespace for ``python-cybox`` as well. - -Note that **python-stix** and ``python-cybox`` treat namespaces slightly -differently (for now anyway). Where **python-stix** uses Python dictionaries, -``python-cybox`` uses the ``cybox.utils.Namespace`` class to represent a -namespace. - -.. testcode:: - - from cybox.utils import set_id_namespace, Namespace - from cybox.core import Observable - - NAMESPACE = Namespace("http://MY-NAMESPACE.com", "myNS") - set_id_namespace(NAMESPACE) - - obs = Observable() - print obs.to_xml() - -Which outputs: - -.. testoutput:: - - - - -Success (again)! The ``xmlns:myNS="http://MY-NAMESPACE.com"`` matches our -``Namespace`` object and the ``id`` attribute includes the ``myNS`` namespace -alias. - Controlled Vocabularies: VocabString ------------------------------------ -Many fields in STIX leverage the ``stixCommon:ControlledVocabularyStringType``, -which acts as a base type for controlled vocabulary implementations. The STIX -language defines a set of default controlled vocabularies which are found in -the ``stix_default_vocabs.xsd`` XML Schema file. - -The **python-stix** library contains a ``stix.common.vocabs`` module, which -defines the ``VocabString`` class implementation of the schema -``ControlledVocabularyStringType`` as well as ``VocabString`` implementations -which correspond to default controlled vocabularies. - -For example, the ``stix_default_vocabularies.xsd`` schema defines a controlled -vocabulary for STIX Package Intents: ``PackageIntentVocab-1.0``. The -``stix.common.vocabs`` module contains an analogous ``PackageIntent`` class, -which acts as a derivation of ``VocabString``. - -Each ``VocabString`` implementation contains: - -* A static list of class-level term attributes, each beginning with ``TERM_` - (e.g., ``TERM_INDICATORS``) - -* A tuple containing all allowed vocabulary terms: ``ALLOWED_VALUES``, which is - use for input validation - -* Methods found on ``stix.Entity``, such as ``to_xml()``, ``to_dict()``, - ``from_dict()``, etc. - - -Interacting With VocabString Fields -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The following sections define ways of interacting with VocabString fields. - -Default Vocabulary Terms -######################## -The STIX Language often suggested a default controlled vocabulary type for a -given controlled vocabulary field. Each controlled vocabulary contains an -enumeration of allowed terms. - -Each ``VocabString`` implementation found in the ``stix.common.vocabs`` module -contains static class-level attributes for each vocabulary term. When setting -controlled vocabulary field values, it is recommended that users take advantage -of these class-level attributes. - -The following demonstrates setting the ``Package_Intent`` field with a default -vocabulary term. Note that the ``STIXHeader.package_intents`` property returns -a list. As such, we use the ``append()`` method to add terms. Other STIX -controlled vocabulary fields may only allow one value rather than a list of -values. - -.. testcode:: - - from stix.core import STIXHeader - from stix.common.vocabs import PackageIntent - - header = STIXHeader() - header.package_intents.append(PackageIntent.TERM_INDICATORS) - - print header.to_xml(include_namespaces=False) - -Which outputs: - -.. testoutput:: - - - Indicators - - -Non-Default Vocabulary Terms -############################ -Though it is suggested, STIX content authors are not required to use the default -controlled vocabulary for a given field. As such, **python-stix** allows users -to pass in non-default values for controlled vocabulary fields. - -To set a controlled vocabulary to a non-default vocabulary term, pass a -``VocabString`` instance into a controlled vocabulary field. - -A raw ``VocabString`` field will contain no ``xsi:type`` information or -``ALLOWED_VALUES`` members, which removes the input and schema validation -requirements. - -.. testcode:: - from stix.core import STIXHeader - from stix.common.vocabs import VocabString, PackageIntent +This section has moved! Head over to :doc:`/overview/controlled_vocabularies` +for the documentation. - header = STIXHeader() - non_default_term = VocabString("NON-DEFAULT VOCABULARY TERM") - header.package_intents.append(non_default_term) - print header.to_xml(include_namespaces=False) - -Which outputs: - -.. testoutput:: - - - NON-DEFAULT VOCABULARY TERM - - -Notice that the ```` field does not have an ``xsi:type`` -attribute. As such, this field can contain any string value and is not bound -by a controlled vocabulary enumeration of terms. - - -Working With Custom Controlled Vocabularies -########################################### - -STIX allows content authors and developers to extend the -``ControlledVocabularyStringType`` schema type for the definition of new -controlled vocabularies. The **python-stix** library allows developers to -create and register Python types which mirror the custom XML Schema vocabulary -types. - -XSD Example -""""""""""" - -The following XML Schema example shows the definition of a a new custom -controlled vocabulary schema type. Instances of this schema type could be -used wherever a ``ControlledVocabularyStringType`` instance is expected -(e.g., the ``STIX_Header/Package_Intent`` field). - -.. code-block:: xml - - Filename: customVocabs.xsd - - - - - - - - - - - - - - - - - - - - - - -XML Instance Sample -""""""""""""""""""" - -The following STIX XML instance document shows a potential use of this field. -Note the ``xsi:type=customVocabs:CustomVocab-1.0`` on the ``Package_Intent`` -field. - -.. code-block:: xml - - Filename: customVocabs.xml - - - - FOO - - - -Python Code -""""""""""" - -To parse content which uses custom controlled vocabularies, Python developers -don't have to do anything special--you just call ``STIXPackage.from_xml()`` on -the input and all the namespaces, ``xsi:types``, etc. are attached to each -instance of ``VocabString``. When serializing the document, the input namespaces -and ``xsi:type`` attributes are retained! - -However, to `create` new content which utilizes a schema defined and enforced -custom controlled vocabulary, developers must create a :class:`.VocabString` -implementation which mirrors the schema definition. - -For our ``CustomVocab-1.0`` schema type, the Python would look like this: - -.. code-block:: python - - from stix.common import vocabs - - # Create a custom vocabulary type - class CustomVocab(vocabs.VocabString): - _namespace = 'http://customvocabs.com/vocabs-1' - _XSI_TYPE = 'customVocabs:CustomVocab-1.0' - _ALLOWED_VALUES = ('FOO', 'BAR') - - # Register the type as a VocabString - vocabs.add_vocab(CustomVocab) - -As you can see, we can express a lot of the same information found in the -XML Schema definition, just with a lot less typing! - -* ``_namespace``: The ``targetNamespace`` for our custom vocabulary - -* ``_XSI_TYPE``: The ``xsi:type`` attribute value to write out for instances - of this vocabulary. -* ``_ALLOWED_VALUES``: A ``tuple`` of allowable values for this vocabulary. - -.. note:: - - The call to ``add_vocab()`` registers the class and its ``xsi:type`` as a - ``VocabString`` implementation so **python-stix** will know to build - instances of ``CustomVocab`` when parsed content contains - ``CustomVocab-1.0`` content. You must call ``add_vocab()`` to register - your class prior to parsing content if you want the parser to build - instances of your custom vocabulary class! - -.. code-block:: python - - # builtin - from StringIO import StringIO - - # python-stix modules - from stix.core import STIXPackage - from stix.common import vocabs - - XML = \ - """ - - - FOO - - - """ - - # Create a VocabString class for our CustomVocab-1.0 vocabulary which - class CustomVocab(vocabs.VocabString): - _namespace = 'http://customvocabs.com/vocabs-1' - _XSI_TYPE = 'customVocabs:CustomVocab-1.0' - _ALLOWED_VALUES = ('FOO', 'BAR') - - # Register our Custom Vocabulary class so parsing builds instances of - # CustomVocab - vocabs.add_vocab(CustomVocab) - - # Parse the input document - sio = StringIO(XML) - package = STIXPackage.from_xml(sio) - - # Retrieve the first (and only) Package_Intent entry - package_intent = package.stix_header.package_intents[0] - - # Print information about the input Package_Intent - print type(package_intent), package_intent.xsi_type, package_intent +ID Namespaces +------------- - # Add another Package Intent - bar = CustomVocab('BAR') - package.stix_header.add_package_intent(bar) +This section has moved! Head over to :doc:`/overview/id_namespaces` for the +documentation. - # This will include the 'BAR' CustomVocab entry - print package.to_xml() diff --git a/docs/index.rst b/docs/index.rst index ee6a4de1..00420d88 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,9 +5,9 @@ The **python-stix** library provides an API for developing and consuming *Struct .. note:: - These docs provide standard reference for this Python library. For documentation on *idiomatic* usage and *common patterns*, as well as various STIX-related information and utilities, please visit the `STIXProject at GitHub`_. - - .. _STIXProject at GitHub: http://stixproject.github.io/ + These docs provide standard reference for this Python library. For documentation on *idiomatic* usage and *common patterns*, as well as various STIX-related information and utilities, please visit the `STIXProject at GitHub`_. + + .. _STIXProject at GitHub: http://stixproject.github.io/ .. _STIX website: http://stix.mitre.org @@ -55,6 +55,7 @@ Contents installation getting_started + overview/index examples/index api_vs_bindings/index diff --git a/docs/overview/controlled_vocabularies.rst b/docs/overview/controlled_vocabularies.rst new file mode 100644 index 00000000..1c355238 --- /dev/null +++ b/docs/overview/controlled_vocabularies.rst @@ -0,0 +1,298 @@ +Controlled Vocabularies +======================= + +Many fields in STIX leverage the ``stixCommon:ControlledVocabularyStringType``, +which acts as a base type for controlled vocabulary implementations. The STIX +language defines a set of default controlled vocabularies which are found in +the ``stix_default_vocabs.xsd`` XML Schema file. + +The **python-stix** library contains a :mod:`stix.common.vocabs` module, which +defines the :class:`.VocabString` class implementation of the schema +``ControlledVocabularyStringType`` as well as :class:`.VocabString` +implementations which correspond to default controlled vocabularies. + +For example, the ``stix_default_vocabularies.xsd`` schema defines a controlled +vocabulary for STIX Package Intents: ``PackageIntentVocab-1.0``. The +:mod:`.stix.common.vocabs` module contains an analogous :class:`.PackageIntent` +class, which acts as a derivation of :class:`.VocabString`. + +Each :class:`.VocabString` implementation contains: + +* A static list of class-level term attributes, each beginning with ``TERM_` + (e.g., ``TERM_INDICATORS``) + +* A tuple containing all allowed vocabulary terms: ``_ALLOWED_VALUES``, which is + use for input validation. This is generated via the :meth:`.vocabs.register_vocab` + class decorator. + +* Methods found on :class:`stix.Entity`, such as ``to_xml()``, ``to_dict()``, + ``from_dict()``, etc. + + +Interacting With VocabString Fields +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The following sections define ways of interacting with VocabString fields. + +Default Vocabulary Terms +######################## + +The STIX Language often suggested a default controlled vocabulary type for a +given controlled vocabulary field. Each controlled vocabulary contains an +enumeration of allowed terms. + +Each :class:`.VocabString` implementation found in the :mod:`stix.common.vocabs` +module contains static class-level attributes for each vocabulary term. When +setting controlled vocabulary field values, it is recommended that users take +advantage of these class-level attributes. + +The following demonstrates setting the ``Package_Intent`` field with a default +vocabulary term. Note that the :attr:`.STIXHeader.package_intents` property returns +a list. As such, we use the ``append()`` method to add terms. Other STIX +controlled vocabulary fields may only allow one value rather than a list of +values. + +.. code-block:: python + + from stix.core import STIXHeader + from stix.common.vocabs import PackageIntent + + header = STIXHeader() + header.package_intents.append(PackageIntent.TERM_INDICATORS) + + print header.to_xml() + +Which outputs: + +.. code-block:: xml + + + Indicators + + +Non-Default Vocabulary Terms +############################ + +Though it is suggested, STIX content authors are not required to use the default +controlled vocabulary for a given field. As such, **python-stix** allows users +to pass in non-default values for controlled vocabulary fields. + +To set a controlled vocabulary to a non-default vocabulary term, pass a +:class:`.VocabString` instance into a controlled vocabulary field. + +A raw :class:`.VocabString` field will contain no ``xsi:type`` information or +``_ALLOWED_VALUES`` members, which removes the input and schema validation +requirements. + +.. code-block:: python + + from stix.core import STIXHeader + from stix.common.vocabs import VocabString, PackageIntent + + header = STIXHeader() + non_default_term = VocabString("NON-DEFAULT VOCABULARY TERM") + header.package_intents.append(non_default_term) + + print header.to_xml() + +Which outputs: + +.. code-block:: xml + + + NON-DEFAULT VOCABULARY TERM + + +Notice that the ```` field does not have an ``xsi:type`` +attribute. As such, this field can contain any string value and is not bound +by a controlled vocabulary enumeration of terms. + + +Working With Custom Controlled Vocabularies +########################################### + +STIX allows content authors and developers to extend the +``ControlledVocabularyStringType`` schema type for the definition of new +controlled vocabularies. The **python-stix** library allows developers to +create and register Python types which mirror the custom XML Schema vocabulary +types. + +XSD Example +""""""""""" + +The following XML Schema example shows the definition of a a new custom +controlled vocabulary schema type. Instances of this schema type could be +used wherever a ``ControlledVocabularyStringType`` instance is expected +(e.g., the ``STIX_Header/Package_Intent`` field). + +.. code-block:: xml + + Filename: customVocabs.xsd + + + + + + + + + + + + + + + + + + + + + + +XML Instance Sample +""""""""""""""""""" + +The following STIX XML instance document shows a potential use of this field. +Note the ``xsi:type=customVocabs:CustomVocab-1.0`` on the ``Package_Intent`` +field. + +.. code-block:: xml + + Filename: customVocabs.xml + + + + FOO + + + +Python Code +""""""""""" + +To parse content which uses custom controlled vocabularies, Python developers +don't have to do anything special--you just call :meth:`.STIXPackage.from_xml()` on +the input and all the namespaces, ``xsi:types``, etc. are attached to each +instance of :class:`.VocabString`. When serializing the document, the input namespaces +and ``xsi:type`` attributes are retained! + +However, to `create` new content which utilizes a schema defined and enforced +custom controlled vocabulary, developers must create a :class:`.VocabString` +implementation which mirrors the schema definition. + +For our ``CustomVocab-1.0`` schema type, the Python would look like this: + +.. code-block:: python + + from stix.common import vocabs + + # Create a custom vocabulary type + @vocabs.register_vocab + class CustomVocab(vocabs.VocabString): + _namespace = 'http://customvocabs.com/vocabs-1' + _XSI_TYPE = 'customVocabs:CustomVocab-1.0' + + # Valid terms + TERM_FOO = 'FOO' + TERM_BAR = 'BAR' + +As you can see, we can express a lot of the same information found in the +XML Schema definition, but in Python! + +* ``_namespace``: The ``targetNamespace`` for our custom vocabulary + +* ``_XSI_TYPE``: The ``xsi:type`` attribute value to write out for instances + of this vocabulary. + +* ``TERM_FOO|BAR``: Allowable terms for the vocabulary. These terms are + collected for input validation. + +.. note:: + + The ``@register_vocab`` class decorator registers the class and its + ``xsi:type`` as a :class:`.VocabString` implementation so **python-stix** will + know to build instances of ``CustomVocab`` when parsed content contains + ``CustomVocab-1.0`` content. + + This also inspects the class attributes for any that begin with + ``TERM_`` and collects their values for the purpose of input validation. + +.. warning:: + + Before **python-stix** 1.2.0.0, users registered custom :class:`.VocabString` + implementations via the :meth:`stix.common.vocabs.add_vocab` method. This + method still exists but is considered **DEPRECATED** in favor of the + :meth:`stix.common.vocabs.register_vocab` class decorator. + +.. code-block:: python + + # builtin + from StringIO import StringIO + + # python-stix modules + from stix.core import STIXPackage + from stix.common import vocabs + + XML = \ + """ + + + FOO + + + """ + + # Create a VocabString class for our CustomVocab-1.0 vocabulary which + class CustomVocab(vocabs.VocabString): + _namespace = 'http://customvocabs.com/vocabs-1' + _XSI_TYPE = 'customVocabs:CustomVocab-1.0' + _ALLOWED_VALUES = ('FOO', 'BAR') + + # Register our Custom Vocabulary class so parsing builds instances of + # CustomVocab + vocabs.add_vocab(CustomVocab) + + # Parse the input document + sio = StringIO(XML) + package = STIXPackage.from_xml(sio) + + # Retrieve the first (and only) Package_Intent entry + package_intent = package.stix_header.package_intents[0] + + # Print information about the input Package_Intent + print type(package_intent), package_intent.xsi_type, package_intent + + # Add another Package Intent + bar = CustomVocab('BAR') + package.stix_header.add_package_intent(bar) + + # This will include the 'BAR' CustomVocab entry + print package.to_xml() + diff --git a/docs/overview/id_namespaces.rst b/docs/overview/id_namespaces.rst new file mode 100644 index 00000000..fa316eb7 --- /dev/null +++ b/docs/overview/id_namespaces.rst @@ -0,0 +1,41 @@ +ID Namespaces +============= + +By default, **python-stix** sets the default ID namespace to +``http://example.com`` with an alias of ``example``. This results in STIX +id declarations that look like +``id="example:Package-2813128d-f45e-41f7-b10a-20a5656e3785"``. + +To change this, use the :meth:`stix.utils.idgen.set_id_namespace` method which takes +a dictionary as a parameter. + +.. code-block:: python + + from stix.core import STIXPackage + from stix.utils import set_id_namespace + + NAMESPACE = {"http://MY-NAMESPACE.com" : "myNS"} + set_id_namespace(NAMESPACE) # new ids will be prefixed by "myNS" + + stix_package = STIXPackage() # id will be created automatically + print stix_package.to_xml() + +Which outputs: + +.. code-block:: xml + + + +Success! The ``xmlns:myNS="http://MY-NAMESPACE.com"`` matches our ``NAMESPACE`` +dictionary and the ``id`` attribute includes the ``myNS`` namespace alias. + +Working With CybOX +~~~~~~~~~~~~~~~~~~ +When setting the ID namespace in **python-stix**, the ID namespace will also be +set in **python-cybox**. diff --git a/docs/overview/index.rst b/docs/overview/index.rst new file mode 100644 index 00000000..199bdf11 --- /dev/null +++ b/docs/overview/index.rst @@ -0,0 +1,14 @@ +Overview +======== + +This page provides a quick overview needed to understand the inner workings +of the **python-stix** library. If you prefer a more hands-on approach, browse +the :doc:`/examples/index`. + +.. toctree:: + :maxdepth: 2 + :titlesonly: + :glob: + + id_namespaces + controlled_vocabularies From ed52040154fbbb67106075501746463058e2e2ea Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 13:17:05 -0400 Subject: [PATCH 113/438] Updated register_vocab docstrings. --- stix/common/vocabs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index ef3ceb40..b729240d 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -165,7 +165,7 @@ def add_vocab(cls): def register_vocab(cls): - """Register a VocabString subclass. + """Class decorator that registers a VocabString subclass. Also, calculate all the permitted values for class being decorated by adding an ``_ALLOWED_VALUES`` tuple of all the values of class members From 897bf11aaeb0b564e067409f8c258e55847ff5a6 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 13:25:42 -0400 Subject: [PATCH 114/438] Added 1.2 to version compatibility table. --- docs/index.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/index.rst b/docs/index.rst index 00420d88..7befc8d0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,12 +22,15 @@ version of STIX. ============ =================== STIX Version python-stix Version ============ =================== +1.2 1.2.0.0 (`PyPI`__) (`GitHub`__) 1.1.1 1.1.1.5 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) ============ =================== +__ https://pypi.python.org/pypi/stix/1.2.0.0 +__ https://github.com/STIXProject/python-stix/tree/v1.2.0.0 __ https://pypi.python.org/pypi/stix/1.1.1.5 __ https://github.com/STIXProject/python-stix/tree/v1.1.1.5 __ https://pypi.python.org/pypi/stix/1.1.0.6 From 864ef2fcc4762616b3541cafdbfe5caed99b418e Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 14 May 2015 16:31:44 -0400 Subject: [PATCH 115/438] Added is_sequence utility unit tests. --- stix/test/utils/utils_test.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 stix/test/utils/utils_test.py diff --git a/stix/test/utils/utils_test.py b/stix/test/utils/utils_test.py new file mode 100644 index 00000000..a42e21c1 --- /dev/null +++ b/stix/test/utils/utils_test.py @@ -0,0 +1,19 @@ +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +# stdlib +import unittest + +# internal +from stix import utils + + +class UtilsTests(unittest.TestCase): + def test_is_sequence(self): + self.assertTrue(utils.is_sequence([1,2,3])) + self.assertTrue(utils.is_sequence((1,2,3))) + self.assertTrue(utils.is_sequence(set([1,2,3]))) + self.assertTrue(utils.is_sequence({1:1})) + + # Make sure that strings are not sequences. + self.assertEqual(False, utils.is_sequence("abc")) From 0053e76d24232b292707c15acdbd5a371f6435c7 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 07:22:16 -0400 Subject: [PATCH 116/438] Updated controlled vocabulary documentation. --- docs/overview/controlled_vocabularies.rst | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/overview/controlled_vocabularies.rst b/docs/overview/controlled_vocabularies.rst index 1c355238..4b2cdcce 100644 --- a/docs/overview/controlled_vocabularies.rst +++ b/docs/overview/controlled_vocabularies.rst @@ -248,7 +248,7 @@ XML Schema definition, but in Python! # python-stix modules from stix.core import STIXPackage - from stix.common import vocabs + from stix.common.vocabs import VocabString, register_vocab XML = \ """ @@ -270,14 +270,12 @@ XML Schema definition, but in Python! """ # Create a VocabString class for our CustomVocab-1.0 vocabulary which - class CustomVocab(vocabs.VocabString): + @register_vocab + class CustomVocab(VocabString): _namespace = 'http://customvocabs.com/vocabs-1' - _XSI_TYPE = 'customVocabs:CustomVocab-1.0' - _ALLOWED_VALUES = ('FOO', 'BAR') - - # Register our Custom Vocabulary class so parsing builds instances of - # CustomVocab - vocabs.add_vocab(CustomVocab) + _XSI_TYPE = 'customVocabs:CustomVocab-1.0' + TERM_FOO = 'FOO' + TERM_BAR = 'BAR' # Parse the input document sio = StringIO(XML) From 93360a940ff69a0271879bfae92abe9e23bab32e Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 07:27:08 -0400 Subject: [PATCH 117/438] Added missing 1.1.1.5 CHANGES.txt entries. --- CHANGES.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 1f6d6478..e8e55225 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,12 @@ +Version 1.1.1.5 +2015-04-29 +- #200 Refactored ns_dict behavior in to_xml() to allow custom namespace mappings +- #254 Added information_source to MarkingSpecification class. +- #188 Added nationalities to CIQ Identity extension. +- #246 Added coa_requested to Incident class. +- #248 Set include_schemalocs to False by default in to_xml() +- #249 Removed "Work In Progress" label from RTD documentation. + Version 1.1.1.4 2015-03-19 - #44 Added StructuredCOA support. This completes the COA structure. From 65f22a635f75dd2ee6cde0ba69591a2d8d6d0ba4 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 07:36:52 -0400 Subject: [PATCH 118/438] Updated CHANGES.txt for python-stix 1.2.0.0 --- CHANGES.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index e8e55225..ed71ee28 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,15 @@ +Version 1.2.0.0 +2015-05-15 +- Support for parsing and creating STIX 1.2 content. +- Added VocabString implementations for deprecated default STIX controlled + vocabularies. +- Refactored internal class resolution for xsi:types. +- #262 Added support for STIX Report content +- #261 Added deprecation warnings when setting fields that have been + deprecated in STIX 1.2. +- #260 Added Versioning controlled vocabulary. +- #253 Added support for Kill Chain Phases and Related Pacakges on TTP + Version 1.1.1.5 2015-04-29 - #200 Refactored ns_dict behavior in to_xml() to allow custom namespace mappings From c1fce5163319e39a688848772f5a2a077f0c3c38 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 07:57:39 -0400 Subject: [PATCH 119/438] Added STIXPackage.version unit test. --- stix/test/core/stix_package_test.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index 02d1d1a1..2ec508b8 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -187,6 +187,22 @@ def test_related_package_idref_deprecation(self): package = core.STIXPackage() package.add_related_package(core.STIXPackage(idref='foo')) + def test_version(self): + """Tests that setting the version property of a STIXPackage does + not affect the serialized versions. + + """ + p = core.STIXPackage() + p.version = "1.0" # old version + + s = p.to_xml() + sio = StringIO.StringIO(s) + + # Reparse the package + p = core.STIXPackage.from_xml(sio) + + self.assertEqual(p.version, core.STIXPackage._version) + if __name__ == "__main__": unittest.main() From 35b11a7de63fc4c320d7d64d2f86a2ce236106f7 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 07:58:15 -0400 Subject: [PATCH 120/438] STIXPackage.timestamp is deprecated. Don't set it by default. --- stix/core/stix_package.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 30c2ec7d..f91d82b7 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -85,11 +85,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, self.ttps = ttps self.related_packages = related_packages self.reports = reports - - if timestamp: - self.timestamp = timestamp - else: - self.timestamp = utils.dates.now() if not idref else None + self.timestamp = timestamp @property def id_(self): From 1b1ba1686b41a89ea9981122a3e96f1ed9cba3f3 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 08:01:57 -0400 Subject: [PATCH 121/438] Updated STIXPackage class docstring to mention deprecation of idref and timestamp. --- stix/core/stix_package.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index f91d82b7..2eaf50b7 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -42,9 +42,9 @@ class STIXPackage(stix.Entity): id_ (optional): An identifier. If ``None``, a value will be generated via ``stix.utils.create_id()``. If set, this will unset the ``idref`` property. - idref (optional): An identifier reference. If set this will unset the - ``id_`` property. - timestamp (optional): A timestamp value. Can be an instance of + idref: **DEPRECATED** An identifier reference. If set this will unset + the ``id_`` property. + timestamp: **DEPRECATED**A timestamp value. Can be an instance of ``datetime.datetime`` or ``str``. header: A Report :class:`.Header` object. campaigns: A collection of :class:`.Campaign` objects. From 7843c3f58555ebc45ffe061391c8c2bf5b2b5fd6 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 08:15:43 -0400 Subject: [PATCH 122/438] Added whitespace. --- stix/core/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/stix/core/__init__.py b/stix/core/__init__.py index f5870750..b6519141 100644 --- a/stix/core/__init__.py +++ b/stix/core/__init__.py @@ -48,6 +48,7 @@ def _is_valid(self, value): idref_deprecated(value) return stix.EntityList._is_valid(self, value) + class ExploitTargets(stix.EntityList): _binding = stix_common_binding _namespace = 'http://stix.mitre.org/common-1' From 71017d86435eca7817f88dd801acea86f0dcc62d Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 08:33:49 -0400 Subject: [PATCH 123/438] Tweaked walk() method to use hasattr() rather than getattr() with a default value. --- stix/utils/__init__.py | 1 - stix/utils/walk.py | 12 +++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index faaec557..b1904357 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -6,7 +6,6 @@ import keyword import functools - # external import cybox import lxml.etree diff --git a/stix/utils/walk.py b/stix/utils/walk.py index 6965a20f..344ac77c 100644 --- a/stix/utils/walk.py +++ b/stix/utils/walk.py @@ -25,9 +25,15 @@ def _is_skippable(owner, varname, varobj): def _iter_vars(obj): - instance_vars = getattr(obj, "__dict__", {}).iteritems() - typed_fields = getattr(obj, "_fields", {}).iteritems() - return itertools.chain(instance_vars, typed_fields) + vars = [] + + if hasattr(obj, "__dict__"): + vars.append(obj.__dict__.iteritems()) + + if hasattr(obj, "_fields"): + vars.append(obj._fields.iteritems()) + + return itertools.chain.from_iterable(vars) def iterwalk(obj): From afe31481f6b2aa05ff9f43f69e9e3c404cf81156 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 09:41:22 -0400 Subject: [PATCH 124/438] Bumped STIX version and removed timestamp from examples. --- docs/examples/index.rst | 2 +- docs/overview/controlled_vocabularies.rst | 2 -- docs/overview/id_namespaces.rst | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/examples/index.rst b/docs/examples/index.rst index f7f1292b..1ff8e757 100755 --- a/docs/examples/index.rst +++ b/docs/examples/index.rst @@ -37,7 +37,7 @@ Which outputs: .. code-block:: xml - + Getting Started! diff --git a/docs/overview/controlled_vocabularies.rst b/docs/overview/controlled_vocabularies.rst index 4b2cdcce..e0f18733 100644 --- a/docs/overview/controlled_vocabularies.rst +++ b/docs/overview/controlled_vocabularies.rst @@ -177,7 +177,6 @@ field. http://stix.mitre.org/stix-1 /path/to/stix_core.xsd http://customvocabs.com/vocabs-1 /path/to/customVocabs.xsd" id="stixExample:STIXPackage-33fe3b22-0201-47cf-85d0-97c02164528d" - timestamp="2014-05-08T09:00:00.000000Z" version="1.2"> FOO @@ -261,7 +260,6 @@ XML Schema definition, but in Python! http://stix.mitre.org/stix-1 /path/to/stix_core.xsd http://customvocabs.com/vocabs-1 /path/to/customVocabs.xsd" id="example:STIXPackage-33fe3b22-0201-47cf-85d0-97c02164528d" - timestamp="2014-05-08T09:00:00.000000Z" version="1.2"> FOO diff --git a/docs/overview/id_namespaces.rst b/docs/overview/id_namespaces.rst index fa316eb7..ec7329a5 100644 --- a/docs/overview/id_namespaces.rst +++ b/docs/overview/id_namespaces.rst @@ -30,7 +30,7 @@ Which outputs: xmlns:stixVocabs="http://stix.mitre.org/default_vocabularies-1" xmlns:stix="http://stix.mitre.org/stix-1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - id="myNS:Package-b2039368-9476-4a5b-8c1d-0ef5d1b37e06" version="1.1.1" timestamp="2014-08-12T18:15:33.603457+00:00"/> + id="myNS:Package-b2039368-9476-4a5b-8c1d-0ef5d1b37e06" version="1.2"/> Success! The ``xmlns:myNS="http://MY-NAMESPACE.com"`` matches our ``NAMESPACE`` dictionary and the ``id`` attribute includes the ``myNS`` namespace alias. From cd844e2b507ba4f5e5ba99213993b75f8c611806 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 09:43:05 -0400 Subject: [PATCH 125/438] Renamed vars to attrs so as not to conflict with builtin name. --- stix/utils/walk.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stix/utils/walk.py b/stix/utils/walk.py index 344ac77c..99b84836 100644 --- a/stix/utils/walk.py +++ b/stix/utils/walk.py @@ -25,15 +25,15 @@ def _is_skippable(owner, varname, varobj): def _iter_vars(obj): - vars = [] + attrs = [] if hasattr(obj, "__dict__"): - vars.append(obj.__dict__.iteritems()) + attrs.append(obj.__dict__.iteritems()) if hasattr(obj, "_fields"): - vars.append(obj._fields.iteritems()) + attrs.append(obj._fields.iteritems()) - return itertools.chain.from_iterable(vars) + return itertools.chain.from_iterable(attrs) def iterwalk(obj): From edee94d9cd597adf2ef0bca0a0f5282ea481f117 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 10:28:20 -0400 Subject: [PATCH 126/438] Added missing GenericStructuredCOA docs. --- docs/api/extensions/structured_coa/generic.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100755 docs/api/extensions/structured_coa/generic.rst diff --git a/docs/api/extensions/structured_coa/generic.rst b/docs/api/extensions/structured_coa/generic.rst new file mode 100755 index 00000000..688864a7 --- /dev/null +++ b/docs/api/extensions/structured_coa/generic.rst @@ -0,0 +1,11 @@ +:mod:`stix.extensions.structured_coa.generic_structured_coa` Module +=================================================================== + +.. module:: stix.extensions.structured_coa.generic_structured_coa + +Classes +------- + +.. autoclass:: GenericStructuredCOA + :show-inheritance: + :members: From f8d726ec025c3475e50953127141126266bdcc39 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 12:21:37 -0400 Subject: [PATCH 127/438] * Refactored TypedCollection to include an abstract method. * Removed TypedSequence. * StructuredTextList extends from TypedCollection and collections.Sequence. --- stix/__init__.py | 6 ++---- stix/base.py | 25 +++++++++++++++++-------- stix/common/structured_text.py | 12 ++++++++---- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index f7c7f08e..703708cc 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -2,10 +2,8 @@ # See LICENSE.txt for complete terms. # Make sure base gets imported before common. -from .base import ( # noqa - Entity, EntityList, TypedCollection, TypedList, TypedSequence, - BaseCoreComponent -) +from .base import (Entity, EntityList, TypedCollection, TypedList, # noqa + BaseCoreComponent) #: Mapping of xsi:types to implementation/extension classes _EXTENSION_MAP = {} diff --git a/stix/base.py b/stix/base.py index 279c5dd9..53e5ab15 100644 --- a/stix/base.py +++ b/stix/base.py @@ -425,11 +425,25 @@ def from_dict(cls, dict_repr, return_obj=None, contained_type=None, return return_obj + class TypedCollection(object): + """Abstract base class for non-STIX collections of entities. + + See also: + TypedList + + """ _contained_type = _override - def __init__(self): + def __init__(self, *args): self._inner = [] + self._initialize_inner(*args) + + def _initialize_inner(self, *args): + """Must be overridden by subclass. + + """ + raise NotImplementedError() def __len__(self): return len(self._inner) @@ -473,8 +487,6 @@ def from_obj(cls, obj_list, contained_type=None): if not obj_list: return None - return_obj = cls() - if not contained_type: contained_type = cls._contained_type @@ -513,14 +525,11 @@ def dict_from_object(cls, entity_obj): return cls.from_obj(entity_obj).to_dict() -class TypedSequence(TypedCollection, collections.Sequence): - pass - - class TypedList(TypedCollection, collections.MutableSequence): def __init__(self, *args): - TypedCollection.__init__(self) + TypedCollection.__init__(self, *args) + def _initialize_inner(self, *args): # Check if it was initialized with args=None if not any(args): return diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index a4d7e4cc..c1257751 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -3,6 +3,7 @@ import itertools import contextlib +import collections import stix import stix.utils as utils @@ -179,7 +180,7 @@ def _unset_default(text): text.ordinality = ordinality -class StructuredTextList(stix.TypedSequence): +class StructuredTextList(stix.TypedCollection, collections.Sequence): """A sequence type used to store StructureText objects. Args: @@ -190,8 +191,9 @@ class StructuredTextList(stix.TypedSequence): _contained_type = StructuredText def __init__(self, *args): - super(StructuredTextList, self).__init__() + stix.TypedCollection.__init__(self, *args) + def _initialize_inner(self, *args): # Check if it was initialized with args=None if not any(args): return @@ -292,10 +294,12 @@ def __delitem__(self, key): self._inner.remove(self[key]) def __reversed__(self): - """The collections.Sequence class defines this in an incompatible way. + """Yields the :class:`StructuredText` collection in descending order + of their ordinalities. """ - raise NotImplementedError() + for text in reversed(self.sorted): + yield text def add(self, value): """Adds the :class:`.StructuredText` `value` to the collection. From e506a7b6933f971d34e4be3391cfd12e589fbe3e Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 12:23:00 -0400 Subject: [PATCH 128/438] Removed unused import. --- stix/report/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/stix/report/__init__.py b/stix/report/__init__.py index 89333f65..026ff571 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -7,7 +7,6 @@ # internal import stix import stix.utils as utils -import stix.utils.parser as parser # components from stix.campaign import Campaign From c28723b033f3a9d752e3ff417898c3fb5cae571f Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 12:23:12 -0400 Subject: [PATCH 129/438] Fixed comment format. --- stix/core/stix_package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 2eaf50b7..d4c8132a 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -44,7 +44,7 @@ class STIXPackage(stix.Entity): ``idref`` property. idref: **DEPRECATED** An identifier reference. If set this will unset the ``id_`` property. - timestamp: **DEPRECATED**A timestamp value. Can be an instance of + timestamp: **DEPRECATED** A timestamp value. Can be an instance of ``datetime.datetime`` or ``str``. header: A Report :class:`.Header` object. campaigns: A collection of :class:`.Campaign` objects. From 5ef5368a5982a5ca2e34b309b869490e2fab244b Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 12:23:50 -0400 Subject: [PATCH 130/438] Renamed param to avoid collision with builtin. --- stix/utils/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index b1904357..ed3450cd 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -372,16 +372,16 @@ def cast_var(item, klass, arg=None): return klass(**kwarg) # klass(value='foobar') -def remove_entries(map, keys): - """Removes all the `keys` from `map`. +def remove_entries(d, keys): + """Removes all the `keys` from the dictionary `d`. Args: - map: A dictionary. + d: A dictionary. keys: An iterable collection of dictionary keys to remove. """ for key in keys: - map.pop(key, None) + d.pop(key, None) # Namespace flattening From c4bf54bf3de3a04b49a1d46c3b14b4022b895b40 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 13:20:33 -0400 Subject: [PATCH 131/438] Added VocabString terms to docs. Added version-specific vocabstring entries. --- docs/api/common/vocabs.rst | 323 +++++++++++++++++++++++++++++-------- 1 file changed, 259 insertions(+), 64 deletions(-) diff --git a/docs/api/common/vocabs.rst b/docs/api/common/vocabs.rst index 6af0120f..a8d645ac 100644 --- a/docs/api/common/vocabs.rst +++ b/docs/api/common/vocabs.rst @@ -6,133 +6,328 @@ Classes ------- +.. autoclass:: AssetType_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: AttackerInfrastructureType_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: AttackerToolType_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: AvailabilityLossType_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: AvailabilityLossType_1_1_1 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: COAStage_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: CampaignStatus_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: CourseOfActionType_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: DiscoveryMethod_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: DiscoveryMethod_2_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: HighMediumLow_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: ImpactQualification_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: ImpactRating_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: IncidentCategory_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: IncidentEffect_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: IncidentStatus_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: IndicatorType_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: IndicatorType_1_1 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: InformationSourceRole_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: InformationType_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: IntendedEffect_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: LocationClass_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: LossDuration_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: LossProperty_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: MalwareType_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: ManagementClass_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: Motivation_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: Motivation_1_0_1 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: Motivation_1_1 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: OwnershipClass_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: PackageIntent_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: PlanningAndOperationalSupport_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: PlanningAndOperationalSupport_1_0_1 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: ReportIntent_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: SecurityCompromise_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: SystemType_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: ThreatActorSophistication_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: ThreatActorType_1_0 + :undoc-members: + :members: + :show-inheritance: + +.. autoclass:: Versioning_1_0 + :undoc-members: + :members: + :show-inheritance: + .. autoclass:: VocabString - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: AssetType - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: AttackerInfrastructureType - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: AttackerToolType - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: AvailabilityLossType - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: CampaignStatus - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: COAStage - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: CourseOfActionType - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: DiscoveryMethod - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: HighMediumLow - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: ImpactQualification - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: ImpactRating - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: IncidentCategory - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: IncidentEffect - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: IncidentStatus - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: IndicatorType - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: InformationSourceRole - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: InformationType - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: IntendedEffect - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: LocationClass - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: LossDuration - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: LossProperty - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: MalwareType - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: ManagementClass - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: Motivation - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: OwnershipClass - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: PackageIntent - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: PlanningAndOperationalSupport - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: SecurityCompromise - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: SystemType - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: ThreatActorSophistication - :show-inheritance: - :members: + :show-inheritance: + :members: .. autoclass:: ThreatActorType - :show-inheritance: - :members: + :show-inheritance: + :members: Functions --------- From b2a35d0194f122ea6d1cd1c105e0d7e8b539e140 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 13:25:33 -0400 Subject: [PATCH 132/438] Updated vocab section of the coverage docs to point to correct VocabString impls. --- docs/api/coverage.rst | 64 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/docs/api/coverage.rst b/docs/api/coverage.rst index ecac2a25..02051446 100644 --- a/docs/api/coverage.rst +++ b/docs/api/coverage.rst @@ -92,41 +92,41 @@ STIX Vocabularies ========================================= ======================================== ======================================================== STIX Construct API Coverage Documentation ========================================= ======================================== ======================================================== -AssetTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.AssetType` -AttackerInfrastructureTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.AttackerInfrastructureType` -AttackerToolTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.AttackerToolType` -AvailabilityLossTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.AttackToolType_1_0` -AvailabilityLossTypeVocab-1.1.1 ✓ Full :class:`stix.common.vocabs.AvailabilityLossType` -COAStageVocab-1.0 ✓ Full :class:`stix.common.vocabs.COAStage` -CampaignStatusVocab-1.0 ✓ Full :class:`stix.common.vocabs.CampaignStatus` -CourseOfActionTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.CourseOfActionType` +AssetTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.AssetType_1_0` +AttackerInfrastructureTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.AttackerInfrastructureType_1_0` +AttackerToolTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.AttackerToolType_1_0` +AvailabilityLossTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.AvailabilityLossType_1_0` +AvailabilityLossTypeVocab-1.1.1 ✓ Full :class:`stix.common.vocabs.AvailabilityLossType_1_1_1` +COAStageVocab-1.0 ✓ Full :class:`stix.common.vocabs.COAStage_1_0` +CampaignStatusVocab-1.0 ✓ Full :class:`stix.common.vocabs.CampaignStatus_1_0` +CourseOfActionTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.CourseOfActionType_1_0` DiscoveryMethodVocab-1.0 ✓ Full :class:`stix.common.vocabs.DiscoveryMethod_1_0` -DiscoveryMethodVocab-2.0 ✓ Full :class:`stix.common.vocabs.DiscoveryMethod` -HighMediumLowVocab-1.0 ✓ Full :class:`stix.common.vocabs.HighMediumLow` -ImpactQualificationVocab-1.0 ✓ Full :class:`stix.common.vocabs.ImpactQualification` -ImpactRatingVocab-1.0 ✓ Full :class:`stix.common.vocabs.ImpactRating` -IncidentCategoryVocab-1.0 ✓ Full :class:`stix.common.vocabs.IncidentCategory` -IncidentEffectVocab-1.0 ✓ Full :class:`stix.common.vocabs.IncidentEffect` -IncidentStatusVocab-1.0 ✓ Full :class:`stix.common.vocabs.IncidentStatus` +DiscoveryMethodVocab-2.0 ✓ Full :class:`stix.common.vocabs.DiscoveryMethod_2_0` +HighMediumLowVocab-1.0 ✓ Full :class:`stix.common.vocabs.HighMediumLow_1_0` +ImpactQualificationVocab-1.0 ✓ Full :class:`stix.common.vocabs.ImpactQualification_1_0` +ImpactRatingVocab-1.0 ✓ Full :class:`stix.common.vocabs.ImpactRating_1_0` +IncidentCategoryVocab-1.0 ✓ Full :class:`stix.common.vocabs.IncidentCategory_1_0` +IncidentEffectVocab-1.0 ✓ Full :class:`stix.common.vocabs.IncidentEffect_1_0` +IncidentStatusVocab-1.0 ✓ Full :class:`stix.common.vocabs.IncidentStatus_1_0` IndicatorTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.IndicatorType_1_0` -IndicatorTypeVocab-1.1 ✓ Full :class:`stix.common.vocabs.IndicatorType` -InformationSourceRoleVocab-1.0 ✓ Full :class:`stix.common.vocabs.InformationSourceRole` -InformationTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.InformationType` -IntendedEffectVocab-1.0 ✓ Full :class:`stix.common.vocabs.IntendedEffect` -LocationClassVocab-1.0 ✓ Full :class:`stix.common.vocabs.LocationClass` -LossDurationVocab-1.0 ✓ Full :class:`stix.common.vocabs.LossDuration` -LossPropertyVocab-1.0 ✓ Full :class:`stix.common.vocabs.LossProperty` -MalwareTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.MalwareType` -ManagementClassVocab-1.0 ✓ Full :class:`stix.common.vocabs.ManagementClass` +IndicatorTypeVocab-1.1 ✓ Full :class:`stix.common.vocabs.IndicatorType_1_1` +InformationSourceRoleVocab-1.0 ✓ Full :class:`stix.common.vocabs.InformationSourceRole_1_0` +InformationTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.InformationType_1_0` +IntendedEffectVocab-1.0 ✓ Full :class:`stix.common.vocabs.IntendedEffect_1_0` +LocationClassVocab-1.0 ✓ Full :class:`stix.common.vocabs.LocationClass_1_0` +LossDurationVocab-1.0 ✓ Full :class:`stix.common.vocabs.LossDuration_1_0` +LossPropertyVocab-1.0 ✓ Full :class:`stix.common.vocabs.LossProperty_1_0` +MalwareTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.MalwareType_1_0` +ManagementClassVocab-1.0 ✓ Full :class:`stix.common.vocabs.ManagementClass_1_0` MotivationVocab-1.0 ✓ Full :class:`stix.common.vocabs.Motivation_1_0` MotivationVocab-1.0.1 ✓ Full :class:`stix.common.vocabs.Motivation_1_0_1` -MotivationVocab-1.1 ✓ Full :class:`stix.common.vocabs.Motivation` -OwnershipClassVocab-1.0 ✓ Full :class:`stix.common.vocabs.OwnershipClass` -PackageIntentVocab-1.0 ✓ Full :class:`stix.common.vocabs.PackageIntent` +MotivationVocab-1.1 ✓ Full :class:`stix.common.vocabs.Motivation_1_1` +OwnershipClassVocab-1.0 ✓ Full :class:`stix.common.vocabs.OwnershipClass_1_0` +PackageIntentVocab-1.0 ✓ Full :class:`stix.common.vocabs.PackageIntent_1_0` PlanningAndOperationalSupportVocab-1.0 ✓ Full :class:`stix.common.vocabs.PlanningAndOperationalSupport_1_0` -PlanningAndOperationalSupportVocab-1.0.1 ✓ Full :class:`stix.common.vocabs.PlanningAndOperationalSupport` -SecurityCompromiseVocab-1.0 ✓ Full :class:`stix.common.vocabs.SecurityCompromise` -SystemTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.SystemType` -ThreatActorSophisticationVocab-1.0 ✓ Full :class:`stix.common.vocabs.ThreatActorSophistication` -ThreatActorTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.ThreatActorType` +PlanningAndOperationalSupportVocab-1.0.1 ✓ Full :class:`stix.common.vocabs.PlanningAndOperationalSupport_1_0_1` +SecurityCompromiseVocab-1.0 ✓ Full :class:`stix.common.vocabs.SecurityCompromise_1_0` +SystemTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.SystemType_1_0` +ThreatActorSophisticationVocab-1.0 ✓ Full :class:`stix.common.vocabs.ThreatActorSophistication_1_0` +ThreatActorTypeVocab-1.0 ✓ Full :class:`stix.common.vocabs.ThreatActorType_1_0` ========================================= ======================================== ======================================================== From e99bb3153a648c9f9669cc244561be4ff356c815 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 15:46:01 -0400 Subject: [PATCH 133/438] Fixed TOU marking schemalocation --- stix/utils/nsparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index 0574f0a5..47096b5f 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -404,7 +404,7 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): 'http://data-marking.mitre.org/Marking-1': 'http://stix.mitre.org/XMLSchema/data_marking/1.2/data_marking.xsd', 'http://data-marking.mitre.org/extensions/MarkingStructure#Simple-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/simple/1.2/simple_marking.xsd', 'http://data-marking.mitre.org/extensions/MarkingStructure#TLP-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/tlp/1.2/tlp_marking.xsd', - 'http://data-marking.mitre.org/extensions/MarkingStructure#Terms_Of_Use-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/terms_of_use/1.0.1/terms_of_use_marking.xsd', + 'http://data-marking.mitre.org/extensions/MarkingStructure#Terms_Of_Use-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/terms_of_use/1.1/terms_of_use_marking.xsd', 'http://stix.mitre.org/Campaign-1': 'http://stix.mitre.org/XMLSchema/campaign/1.2/campaign.xsd', 'http://stix.mitre.org/CourseOfAction-1': 'http://stix.mitre.org/XMLSchema/course_of_action/1.2/course_of_action.xsd', 'http://stix.mitre.org/ExploitTarget-1': 'http://stix.mitre.org/XMLSchema/exploit_target/1.2/exploit_target.xsd', From 603e39da20ac034d31815184a6a4b2d0869576db Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 17:18:42 -0400 Subject: [PATCH 134/438] Bumped version to 1.2.0.0 --- stix/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/version.py b/stix/version.py index 69c52d59..3de175ea 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.0.dev0" +__version__ = "1.2.0.0" From b6dd48caf2a3861a6a4c17314df5f8df4e13f75e Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 15 May 2015 17:19:13 -0400 Subject: [PATCH 135/438] Bumped version to 1.2.0.1.dev0 --- stix/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/version.py b/stix/version.py index 3de175ea..eb0c11b3 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.0" +__version__ = "1.2.0.1.dev0" From 2f9ace9c73e92b1aedf2c50c78355f6b869448f6 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 21 May 2015 08:21:24 -0400 Subject: [PATCH 136/438] Changed __dict__ access to vars() calls. --- stix/common/vocabs.py | 2 +- stix/utils/__init__.py | 2 +- stix/utils/walk.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index b729240d..bc421ace 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -149,7 +149,7 @@ def from_dict(cls, vocab_dict, return_obj=None): def _get_terms(vocab_class): """Helper function used by register_vocab.""" - for k, v in vocab_class.__dict__.items(): + for k, v in vars(vocab_class).items(): if k.startswith("TERM_"): yield v diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index ed3450cd..f9e5a97e 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -251,7 +251,7 @@ def iter_vars(obj): def check(name): return name not in ('__input_namespaces__', '__input_schemalocations__') - instance_vars = obj.__dict__.iteritems() + instance_vars = vars(obj).iteritems() return ((attr_name(name), val) for name, val in instance_vars if check(name)) diff --git a/stix/utils/walk.py b/stix/utils/walk.py index 99b84836..fe1261ea 100644 --- a/stix/utils/walk.py +++ b/stix/utils/walk.py @@ -28,7 +28,7 @@ def _iter_vars(obj): attrs = [] if hasattr(obj, "__dict__"): - attrs.append(obj.__dict__.iteritems()) + attrs.append(vars(obj).iteritems()) if hasattr(obj, "_fields"): attrs.append(obj._fields.iteritems()) From 4ecd394bd4afb15cdda0945ae7fef2e4cd956df6 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 22 May 2015 15:32:35 -0400 Subject: [PATCH 137/438] Added mixbox github dep to tox.ini --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index 59c9179a..6d98a8aa 100644 --- a/tox.ini +++ b/tox.ini @@ -8,6 +8,7 @@ commands = # sphinx-build -b doctest docs docs/_build/doctest sphinx-build -b html docs docs/_build/html deps = + https://github.com/CybOXProject/mixbox/archive/master.zip -rrequirements.txt # We call this "lxml23" instead of "rhel6", since RHEL6 ships with LXML 2.2.3. @@ -22,3 +23,4 @@ deps = cybox maec nose + https://github.com/CybOXProject/mixbox/archive/master.zip \ No newline at end of file From 35590a160274a1d0fe53a06c009652eee81ce606 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 22 May 2015 15:33:06 -0400 Subject: [PATCH 138/438] Added mixbox dep to setup.py --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6ad803b2..0dc8e23a 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,8 @@ def get_version(): install_requires = [ 'lxml>=2.3', 'python-dateutil', - 'cybox>=2.1.0.11,<2.1.1.0' + 'cybox>=2.1.0.11,<2.1.1.0', + 'mixbox' ] From 6515c2e86b958c1acfec243505acb7006e1772a5 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 22 May 2015 15:43:34 -0400 Subject: [PATCH 139/438] Added idref to MalwareInstance, AttackPattern, Infrastructure and Exploit. --- stix/ttp/attack_pattern.py | 59 +++++++++++++++++++++++++++++++++++- stix/ttp/exploit.py | 57 ++++++++++++++++++++++++++++++++-- stix/ttp/infrastructure.py | 53 +++++++++++++++++++++++++++++++- stix/ttp/malware_instance.py | 59 ++++++++++++++++++++++++++++++++++-- 4 files changed, 222 insertions(+), 6 deletions(-) diff --git a/stix/ttp/attack_pattern.py b/stix/ttp/attack_pattern.py index 2b2dbaf6..442bfcc0 100644 --- a/stix/ttp/attack_pattern.py +++ b/stix/ttp/attack_pattern.py @@ -1,8 +1,11 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# internal import stix from stix.common import StructuredTextList + +# bindings import stix.bindings.ttp as ttp_binding @@ -11,13 +14,64 @@ class AttackPattern(stix.Entity): _binding_class = _binding.AttackPatternType _namespace = "http://stix.mitre.org/TTP-1" - def __init__(self, id_=None, title=None, description=None, short_description=None): + def __init__(self, id_=None, idref=None, title=None, description=None, short_description=None): self.id_ = id_ + self.idref = idref self.capec_id = None self.title = title self.description = description self.short_description = short_description + @property + def id_(self): + """The ``id_`` property serves as an identifier. + + Default Value: ``None`` + + Note: + Both the ``id_`` and ``idref`` properties cannot be set at the + same time. **Setting one will unset the other!** + + Returns: + A string id. + + """ + return self._id + + @id_.setter + def id_(self, value): + if not value: + self._id = None + else: + self._id = value + self.idref = None + + @property + def idref(self): + """The ``idref`` property must be set to the ``id_`` value of another + object instance of the same type. An idref does not need to resolve to + a local object instance. + + Default Value: ``None``. + + Note: + Both the ``id_`` and ``idref`` properties cannot be set at the + same time. **Setting one will unset the other!** + + Returns: + The value of the ``idref`` property + + """ + return self._idref + + @idref.setter + def idref(self, value): + if not value: + self._idref = None + else: + self._idref = value + self.id_ = None # unset id_ if idref is present + @property def title(self): return self._title @@ -150,6 +204,7 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj = self._binding_class() return_obj.id = self.id_ + return_obj.idref = self.idref return_obj.capec_id = self.capec_id return_obj.Title = self.title @@ -168,6 +223,7 @@ def from_obj(cls, obj, return_obj=None): return_obj = cls() return_obj.id_ = obj.id + return_obj.idref = obj.idref return_obj.capec_id = obj.capec_id return_obj.title = obj.Title return_obj.descriptions = StructuredTextList.from_obj(obj.Description) @@ -186,6 +242,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj = cls() return_obj.id_ = dict_repr.get('id') + return_obj.idref = dict_repr.get('idref') return_obj.capec_id = dict_repr.get('capec_id') return_obj.title = dict_repr.get('title') return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) diff --git a/stix/ttp/exploit.py b/stix/ttp/exploit.py index 664b6eaf..73ba449e 100644 --- a/stix/ttp/exploit.py +++ b/stix/ttp/exploit.py @@ -1,9 +1,11 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# internal import stix -import stix.utils from stix.common import StructuredTextList + +# bindings import stix.bindings.ttp as ttp_binding @@ -12,12 +14,63 @@ class Exploit(stix.Entity): _binding_class = _binding.ExploitType _namespace = "http://stix.mitre.org/TTP-1" - def __init__(self, id_=None, title=None, description=None, short_description=None): + def __init__(self, id_=None, idref=None, title=None, description=None, short_description=None): self.id_ = id_ + self.idref = idref self.title = title self.description = description self.short_description = short_description + @property + def id_(self): + """The ``id_`` property serves as an identifier. + + Default Value: ``None`` + + Note: + Both the ``id_`` and ``idref`` properties cannot be set at the + same time. **Setting one will unset the other!** + + Returns: + A string id. + + """ + return self._id + + @id_.setter + def id_(self, value): + if not value: + self._id = None + else: + self._id = value + self.idref = None + + @property + def idref(self): + """The ``idref`` property must be set to the ``id_`` value of another + object instance of the same type. An idref does not need to resolve to + a local object instance. + + Default Value: ``None``. + + Note: + Both the ``id_`` and ``idref`` properties cannot be set at the + same time. **Setting one will unset the other!** + + Returns: + The value of the ``idref`` property + + """ + return self._idref + + @idref.setter + def idref(self, value): + if not value: + self._idref = None + else: + self._idref = value + self.id_ = None # unset id_ if idref is present + @property def title(self): return self._title diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index 355e6cf1..76381dda 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -16,14 +16,65 @@ class Infrastructure(stix.Entity): _binding_class = _binding.InfrastructureType _namespace = "http://stix.mitre.org/TTP-1" - def __init__(self, id_=None, title=None, description=None, short_description=None): + def __init__(self, id_=None, idref=None, title=None, description=None, short_description=None): self.id_ = id_ + self.idref = idref self.title = title self.description = description self.short_description = short_description self.types = None self.observable_characterization = None + @property + def id_(self): + """The ``id_`` property serves as an identifier. + + Default Value: ``None`` + + Note: + Both the ``id_`` and ``idref`` properties cannot be set at the + same time. **Setting one will unset the other!** + + Returns: + A string id. + + """ + return self._id + + @id_.setter + def id_(self, value): + if not value: + self._id = None + else: + self._id = value + self.idref = None + + @property + def idref(self): + """The ``idref`` property must be set to the ``id_`` value of another + object instance of the same type. An idref does not need to resolve to + a local object instance. + + Default Value: ``None``. + + Note: + Both the ``id_`` and ``idref`` properties cannot be set at the + same time. **Setting one will unset the other!** + + Returns: + The value of the ``idref`` property + + """ + return self._idref + + @idref.setter + def idref(self, value): + if not value: + self._idref = None + else: + self._idref = value + self.id_ = None # unset id_ if idref is present + @property def title(self): return self._title diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index 9239d748..8bac8ac9 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -1,9 +1,13 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# internal import stix import stix.utils as utils -from stix.common import vocabs, StructuredTextList, VocabString +from stix.common import vocabs +from stix.common import StructuredTextList, VocabString + +# bindings import stix.bindings.ttp as ttp_binding @@ -12,14 +16,65 @@ class MalwareInstance(stix.Entity): _binding_class = _binding.MalwareInstanceType _namespace = "http://stix.mitre.org/TTP-1" - def __init__(self, id_=None, title=None, description=None, short_description=None): + def __init__(self, id_=None, idref=None, title=None, description=None, short_description=None): self.id_ = id_ + self.idref = idref self.title = title self.description = description self.short_description = short_description self.names = None self.types = None + @property + def id_(self): + """The ``id_`` property serves as an identifier. + + Default Value: ``None`` + + Note: + Both the ``id_`` and ``idref`` properties cannot be set at the + same time. **Setting one will unset the other!** + + Returns: + A string id. + + """ + return self._id + + @id_.setter + def id_(self, value): + if not value: + self._id = None + else: + self._id = value + self.idref = None + + @property + def idref(self): + """The ``idref`` property must be set to the ``id_`` value of another + object instance of the same type. An idref does not need to resolve to + a local object instance. + + Default Value: ``None``. + + Note: + Both the ``id_`` and ``idref`` properties cannot be set at the + same time. **Setting one will unset the other!** + + Returns: + The value of the ``idref`` property + + """ + return self._idref + + @idref.setter + def idref(self, value): + if not value: + self._idref = None + else: + self._idref = value + self.id_ = None # unset id_ if idref is present + @property def title(self): return self._title From 0d2fba8ee594b846ade99d8dd4476ecb547bfbf6 Mon Sep 17 00:00:00 2001 From: Ben Schmoker Date: Thu, 28 May 2015 09:27:24 -0400 Subject: [PATCH 140/438] blow away that header #deprecated --- examples/sample.xml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/sample.xml b/examples/sample.xml index 4e260dbc..add37949 100755 --- a/examples/sample.xml +++ b/examples/sample.xml @@ -17,10 +17,7 @@ id="example:STIXPackage-33fe3b22-0201-47cf-85d0-97c02164528d" timestamp="2014-05-08T09:00:00.000000Z" version="1.2"> - - Example watchlist that contains IP information. - Indicators - Watchlist - + IP Watchlist From 67adb111cdbc707a55a296132509b4f3610a5788 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Fri, 29 May 2015 13:58:38 -0500 Subject: [PATCH 141/438] Bump sphinx version to 1.3.1 to match Read The Docs. --- docs/conf.py | 2 +- setup.py | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 3ece72c7..c4c7dc0b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -13,7 +13,7 @@ 'sphinx.ext.ifconfig', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode', - 'sphinxcontrib.napoleon', + 'sphinx.ext.napoleon', ] intersphinx_mapping = { diff --git a/setup.py b/setup.py index 6ad803b2..f700a7f1 100644 --- a/setup.py +++ b/setup.py @@ -25,11 +25,8 @@ def get_version(): extras_require = { 'docs': [ - 'Sphinx==1.2.1', - # TODO: remove when updating to Sphinx 1.3, since napoleon will be - # included as sphinx.ext.napoleon - 'sphinxcontrib-napoleon==0.2.4', - 'sphinx_rtd_theme==0.1.7', + 'Sphinx==1.3.1', + 'sphinx_rtd_theme==0.1.8', ], 'test': [ 'nose==1.3.0', From b8840bbe66d70bd4046108741498cef61eda67ec Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 1 Jun 2015 08:06:45 -0400 Subject: [PATCH 142/438] Added Cached mixin to classes which can be referenced via idref. --- stix/base.py | 5 ++++- stix/coa/structured_coa.py | 6 +++++- stix/common/identity.py | 6 ++++-- stix/core/stix_package.py | 3 ++- stix/data_marking.py | 12 ++++++++++-- .../structured_coa/generic_structured_coa.py | 3 +++ stix/indicator/test_mechanism.py | 8 +++++++- stix/report/__init__.py | 3 ++- stix/test/ttp_test.py | 10 ++++++++++ stix/ttp/attack_pattern.py | 5 ++++- stix/ttp/exploit.py | 5 ++++- stix/ttp/infrastructure.py | 3 ++- stix/ttp/malware_instance.py | 5 ++++- 13 files changed, 61 insertions(+), 13 deletions(-) diff --git a/stix/base.py b/stix/base.py index 53e5ab15..8b349ff5 100644 --- a/stix/base.py +++ b/stix/base.py @@ -7,6 +7,9 @@ import itertools import StringIO +# external +from mixbox.cache import Cached + # internal from . import bindings, utils @@ -562,7 +565,7 @@ def insert(self, idx, value): self._inner.insert(idx, value) -class BaseCoreComponent(Entity): +class BaseCoreComponent(Cached, Entity): _ALL_VERSIONS = () _ID_PREFIX = None diff --git a/stix/coa/structured_coa.py b/stix/coa/structured_coa.py index e77a1f72..2621e7cb 100644 --- a/stix/coa/structured_coa.py +++ b/stix/coa/structured_coa.py @@ -1,11 +1,15 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox.cache import Cached + +# internal import stix from stix.bindings import course_of_action as coa_binding -class _BaseStructuredCOA(stix.Entity): +class _BaseStructuredCOA(Cached, stix.Entity): _namespace = "http://stix.mitre.org/CourseOfAction-1" _binding = coa_binding _binding_class = coa_binding.StructuredCOAType diff --git a/stix/common/identity.py b/stix/common/identity.py index c66a487d..11f8b93f 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -1,13 +1,15 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -from __future__ import absolute_import +# external +from mixbox.cache import Cached +# internal import stix import stix.bindings.stix_common as common_binding -class Identity(stix.Entity): +class Identity(Cached, stix.Entity): _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index d4c8132a..ed074b60 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox.cache import Cached from cybox.core import Observable, Observables # base @@ -35,7 +36,7 @@ import stix.bindings.stix_core as stix_core_binding -class STIXPackage(stix.Entity): +class STIXPackage(Cached, stix.Entity): """A STIX Package object. Args: diff --git a/stix/data_marking.py b/stix/data_marking.py index 4caba8a8..ce077f9b 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -1,8 +1,14 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox.cache import Cached + +# internal import stix from stix.common import InformationSource + +# bindings import stix.bindings.data_marking as stix_data_marking_binding @@ -70,12 +76,14 @@ def from_list(cls, markings_list, return_obj=None): from_dict = from_list -class MarkingSpecification(stix.Entity): +class MarkingSpecification(Cached, stix.Entity): _binding = stix_data_marking_binding _binding_class = stix_data_marking_binding.MarkingSpecificationType _namespace = 'http://data-marking.mitre.org/Marking-1' def __init__(self, controlled_structure=None, marking_structures=None): + super(MarkingSpecification, self).__init__() + self.id_ = None self.idref = None self.version = None @@ -159,7 +167,7 @@ def from_dict(cls, d, return_obj=None): return return_obj -class MarkingStructure(stix.Entity): +class MarkingStructure(Cached, stix.Entity): _binding = stix_data_marking_binding _binding_class = stix_data_marking_binding.MarkingStructureType _namespace = 'http://data-marking.mitre.org/Marking-1' diff --git a/stix/extensions/structured_coa/generic_structured_coa.py b/stix/extensions/structured_coa/generic_structured_coa.py index b9350a09..ecd74afd 100644 --- a/stix/extensions/structured_coa/generic_structured_coa.py +++ b/stix/extensions/structured_coa/generic_structured_coa.py @@ -1,9 +1,12 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# internal import stix from stix.common import EncodedCDATA, StructuredTextList, VocabString from stix.coa.structured_coa import _BaseStructuredCOA + +# bindings import stix.bindings.extensions.structured_coa.generic as generic_structured_coa_binding diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index bc255f5a..b5b39f38 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -1,12 +1,18 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox.cache import Cached + +# internal import stix from stix.common import InformationSource, Statement + +# bindings import stix.bindings.indicator as indicator_binding -class _BaseTestMechanism(stix.Entity): +class _BaseTestMechanism(Cached, stix.Entity): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = indicator_binding.TestMechanismType() diff --git a/stix/report/__init__.py b/stix/report/__init__.py index 026ff571..90ae5db6 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox.cache import Cached from cybox.core import Observable, Observables # internal @@ -29,7 +30,7 @@ import stix.bindings.report as report_binding -class Report(stix.Entity): +class Report(Cached, stix.Entity): """A STIX Report Object. Args: diff --git a/stix/test/ttp_test.py b/stix/test/ttp_test.py index a95544d8..04f11903 100644 --- a/stix/test/ttp_test.py +++ b/stix/test/ttp_test.py @@ -119,6 +119,16 @@ class AttackPatternTests(EntityTestCase, unittest.TestCase): 'capec_id': '12345' } + def idref_test(self): + ap = attack_pattern.AttackPattern() + ap.id_ = 'foo' + + self.assertEqual(ap.id_, 'foo') + + ap.idref = 'bar' + self.assertEqual(ap.idref, 'bar') + self.assertEqual(ap.id_, None) + class AttackPatternsTests(EntityTestCase, unittest.TestCase): klass = behavior.AttackPatterns diff --git a/stix/ttp/attack_pattern.py b/stix/ttp/attack_pattern.py index 442bfcc0..43014d0c 100644 --- a/stix/ttp/attack_pattern.py +++ b/stix/ttp/attack_pattern.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox.cache import Cached + # internal import stix from stix.common import StructuredTextList @@ -9,7 +12,7 @@ import stix.bindings.ttp as ttp_binding -class AttackPattern(stix.Entity): +class AttackPattern(Cached, stix.Entity): _binding = ttp_binding _binding_class = _binding.AttackPatternType _namespace = "http://stix.mitre.org/TTP-1" diff --git a/stix/ttp/exploit.py b/stix/ttp/exploit.py index 73ba449e..3018efbf 100644 --- a/stix/ttp/exploit.py +++ b/stix/ttp/exploit.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox.cache import Cached + # internal import stix from stix.common import StructuredTextList @@ -9,7 +12,7 @@ import stix.bindings.ttp as ttp_binding -class Exploit(stix.Entity): +class Exploit(Cached, stix.Entity): _binding = ttp_binding _binding_class = _binding.ExploitType _namespace = "http://stix.mitre.org/TTP-1" diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index 76381dda..b5502868 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox.cache import Cached from cybox.core import Observables # internal @@ -11,7 +12,7 @@ import stix.bindings.ttp as ttp_binding -class Infrastructure(stix.Entity): +class Infrastructure(Cached, stix.Entity): _binding = ttp_binding _binding_class = _binding.InfrastructureType _namespace = "http://stix.mitre.org/TTP-1" diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index 8bac8ac9..ab4497e0 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox.cache import Cached + # internal import stix import stix.utils as utils @@ -11,7 +14,7 @@ import stix.bindings.ttp as ttp_binding -class MalwareInstance(stix.Entity): +class MalwareInstance(Cached, stix.Entity): _binding = ttp_binding _binding_class = _binding.MalwareInstanceType _namespace = "http://stix.mitre.org/TTP-1" From c6544c0d8d98bc420bb2c27f3044f40fd26cb693 Mon Sep 17 00:00:00 2001 From: Ben Schmoker Date: Tue, 2 Jun 2015 17:00:10 -0400 Subject: [PATCH 143/438] Update vocabs.py --- stix/common/vocabs.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index bc421ace..031fba52 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -648,6 +648,18 @@ class ImpactRating_1_0(VocabString): TERM_NONE = "None" TERM_UNKNOWN = "Unknown" +@register_vocab +class DeceptionChain(VocabString): + _namespace = 'http://stix.mitre.org/default_vocabularies-1' + _XSI_TYPE = 'stixVocabs:SystemTypeVocab-1.0' + _VOCAB_VERSION = '1.0' + + TERM_PURPOSE = "Purpose" + TERM_PURPOSE = "Purpose" + TERM_PURPOSE = "Purpose" + TERM_PURPOSE = "Purpose" + TERM_PURPOSE = "Purpose" + @register_vocab class AssetType_1_0(VocabString): From 49736313984f0be42df26185a829ab2f93c18f1e Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 2 Jun 2015 21:02:37 +0000 Subject: [PATCH 144/438] Revert "Update vocabs.py" This reverts commit c6544c0d8d98bc420bb2c27f3044f40fd26cb693. --- stix/common/vocabs.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index 031fba52..bc421ace 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -648,18 +648,6 @@ class ImpactRating_1_0(VocabString): TERM_NONE = "None" TERM_UNKNOWN = "Unknown" -@register_vocab -class DeceptionChain(VocabString): - _namespace = 'http://stix.mitre.org/default_vocabularies-1' - _XSI_TYPE = 'stixVocabs:SystemTypeVocab-1.0' - _VOCAB_VERSION = '1.0' - - TERM_PURPOSE = "Purpose" - TERM_PURPOSE = "Purpose" - TERM_PURPOSE = "Purpose" - TERM_PURPOSE = "Purpose" - TERM_PURPOSE = "Purpose" - @register_vocab class AssetType_1_0(VocabString): From 05342c66a5e3291838b373ff88586062df3036c4 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Wed, 3 Jun 2015 11:23:13 -0400 Subject: [PATCH 145/438] Modified VocabString class resolution to return a VocabString class if xsi:type lookups failed. Fixes #266. --- stix/common/vocabs.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index bc421ace..ab23e097 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -56,14 +56,17 @@ def __eq__(self, other): def is_plain(self): """Whether the VocabString can be represented as a single value.""" return ( - self._XSI_TYPE is None and + self.xsi_type is None and self.vocab_name is None and self.vocab_reference is None ) @staticmethod def lookup_class(xsi_type): - return stix.lookup_extension(xsi_type, default=VocabString) + try: + return stix.lookup_extension(xsi_type, default=VocabString) + except ValueError: + return VocabString def to_obj(self, return_obj=None, ns_info=None): super(VocabString, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -105,7 +108,7 @@ def from_obj(cls, vocab_obj, return_obj=None): return None if not return_obj: - klass = stix.lookup_extension(vocab_obj.xsi_type, default=cls) + klass = cls.lookup_class(vocab_obj.xsi_type) return klass.from_obj(vocab_obj, return_obj=klass()) # xsi_type should be set automatically by the class's constructor. @@ -127,7 +130,7 @@ def from_dict(cls, vocab_dict, return_obj=None): if not return_obj: if isinstance(vocab_dict, dict): get = vocab_dict.get - klass = stix.lookup_extension(get('xsi:type'), default=cls) + klass = cls.lookup_class(get('xsi:type')) return klass.from_dict(vocab_dict, return_obj=klass()) else: return_obj = cls() From 1b4de9c931d8925401dab597ca4ac6f78bb03760 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Wed, 3 Jun 2015 11:53:07 -0500 Subject: [PATCH 146/438] Update to use mixbox.xml and mixbox.binding_utils. --- stix/base.py | 5 +- stix/bindings/__init__.py | 407 +----------------- stix/bindings/campaign.py | 5 +- stix/bindings/course_of_action.py | 5 +- stix/bindings/data_marking.py | 7 +- stix/bindings/exploit_target.py | 5 +- .../extensions/address/ciq_address_3_0.py | 5 +- .../extensions/attack_pattern/capec_2_7.py | 5 +- .../extensions/identity/ciq_identity_3_0.py | 5 +- stix/bindings/extensions/malware/maec_4_1.py | 7 +- .../extensions/marking/simple_marking.py | 5 +- .../marking/terms_of_use_marking.py | 5 +- stix/bindings/extensions/marking/tlp.py | 5 +- .../extensions/structured_coa/generic.py | 5 +- .../extensions/test_mechanism/generic.py | 5 +- .../test_mechanism/open_ioc_2010.py | 5 +- .../extensions/test_mechanism/oval_5_10.py | 5 +- .../extensions/test_mechanism/snort.py | 5 +- .../extensions/test_mechanism/yara.py | 5 +- .../extensions/vulnerability/cvrf_1_1.py | 5 +- stix/bindings/incident.py | 5 +- stix/bindings/indicator.py | 5 +- stix/bindings/report.py | 4 +- stix/bindings/stix_common.py | 4 +- stix/bindings/stix_core.py | 7 +- stix/bindings/threat_actor.py | 5 +- stix/bindings/ttp.py | 5 +- stix/extensions/malware/maec_4_1_malware.py | 12 +- .../open_ioc_2010_test_mechanism.py | 10 +- stix/test/__init__.py | 6 +- stix/test/encoding_test.py | 87 +--- .../malware/maec_4_1_malware_test.py | 12 +- .../test_mechanisms/openioc_test.py | 7 +- stix/utils/__init__.py | 18 +- stix/utils/parser.py | 87 +--- stix/xmlconst.py | 10 - 36 files changed, 148 insertions(+), 642 deletions(-) diff --git a/stix/base.py b/stix/base.py index 8b349ff5..468ea3b1 100644 --- a/stix/base.py +++ b/stix/base.py @@ -9,9 +9,10 @@ # external from mixbox.cache import Cached +from mixbox.binding_utils import save_encoding # internal -from . import bindings, utils +from . import utils def _override(*args, **kwargs): @@ -185,7 +186,7 @@ def to_xml(self, include_namespaces=True, include_schemalocs=False, if not pretty: namespace_def = namespace_def.replace('\n\t', ' ') - with bindings.save_encoding(encoding): + with save_encoding(encoding): sio = StringIO.StringIO() obj.export( sio.write, # output buffer diff --git a/stix/bindings/__init__.py b/stix/bindings/__init__.py index 61483315..3376c9b5 100644 --- a/stix/bindings/__init__.py +++ b/stix/bindings/__init__.py @@ -1,397 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -import re -import base64 import collections -import contextlib -from xml.sax import saxutils -from datetime import datetime, tzinfo, timedelta from lxml import etree as etree_ -import cybox.bindings as cybox_bindings - -from stix import xmlconst - -try: - import maec.bindings as maec_bindings - _MAEC_INSTALLED = True -except ImportError: - _MAEC_INSTALLED = False - - -CDATA_START = "" - -ExternalEncoding = 'utf-8' -Tag_pattern_ = re.compile(r'({.*})?(.*)') - -# These are only used internally -_tzoff_pattern = re.compile(r'(\+|-)((0\d|1[0-3]):[0-5]\d|14:00)$') -_Tag_strip_pattern_ = re.compile(r'\{.*\}') - - -@contextlib.contextmanager -def save_encoding(encoding='utf-8'): - global ExternalEncoding - - try: - # Save original binding encoding attribute value - orig_stix_encoding = ExternalEncoding - orig_cybox_encoding = cybox_bindings.ExternalEncoding - - # Set binding encoding attribute value to `encoding` - ExternalEncoding = encoding - cybox_bindings.ExternalEncoding = encoding - - # Set MAEC binding encoding attribute to `encoding` if python-maec - # is installed. - if _MAEC_INSTALLED: - orig_maec_encoding = maec_bindings.ExternalEncoding - maec_bindings.ExternalEncoding = encoding - - # Return to caller - yield - - finally: - # Reset the binding encoding attribute values to original values - ExternalEncoding = orig_stix_encoding - cybox_bindings.ExternalEncoding = orig_cybox_encoding - - if _MAEC_INSTALLED: - maec_bindings.ExternalEncoding = orig_maec_encoding - - -def parsexml_(*args, **kwargs): - from stix.utils.parser import get_xml_parser - - if 'parser' not in kwargs: - # Use the lxml ElementTree compatible parser so that, e.g., - # we ignore comments. - kwargs['parser'] = get_xml_parser() - return etree_.parse(*args, **kwargs) - - -class _FixedOffsetTZ(tzinfo): - - def __init__(self, offset, name): - self.__offset = timedelta(minutes=offset) - self.__name = name - - def utcoffset(self, dt): - return self.__offset - - def tzname(self, dt): - return self.__name - - def dst(self, dt): - return None - - __reduce__ = object.__reduce__ - - -class GeneratedsSuper(object): - - def gds_format_string(self, input_data, input_name=''): - return input_data - - def gds_validate_string(self, input_data, node, input_name=''): - return input_data - - def gds_format_base64(self, input_data, input_name=''): - return base64.b64encode(input_data) - - def gds_validate_base64(self, input_data, node, input_name=''): - return input_data - - def gds_format_integer(self, input_data, input_name=''): - return '%d' % input_data - - def gds_validate_integer(self, input_data, node, input_name=''): - return input_data - - def gds_format_integer_list(self, input_data, input_name=''): - return '%s' % input_data - - def gds_validate_integer_list(self, input_data, node, input_name=''): - values = input_data.split() - for value in values: - try: - fvalue = float(value) - except (TypeError, ValueError), exp: - raise_parse_error(node, 'Requires sequence of integers') - return input_data - - def gds_format_float(self, input_data, input_name=''): - return '%f' % input_data - - def gds_validate_float(self, input_data, node, input_name=''): - return input_data - - def gds_format_float_list(self, input_data, input_name=''): - return '%s' % input_data - - def gds_validate_float_list(self, input_data, node, input_name=''): - values = input_data.split() - for value in values: - try: - fvalue = float(value) - except (TypeError, ValueError), exp: - raise_parse_error(node, 'Requires sequence of floats') - return input_data - - def gds_format_double(self, input_data, input_name=''): - return '%e' % input_data - - def gds_validate_double(self, input_data, node, input_name=''): - return input_data - - def gds_format_double_list(self, input_data, input_name=''): - return '%s' % input_data - - def gds_validate_double_list(self, input_data, node, input_name=''): - values = input_data.split() - for value in values: - try: - fvalue = float(value) - except (TypeError, ValueError), exp: - raise_parse_error(node, 'Requires sequence of doubles') - return input_data - - def gds_format_boolean(self, input_data, input_name=''): - return ('%s' % input_data).lower() - - def gds_validate_boolean(self, input_data, node, input_name=''): - return input_data - - def gds_format_boolean_list(self, input_data, input_name=''): - return '%s' % input_data - - def gds_validate_boolean_list(self, input_data, node, input_name=''): - values = input_data.split() - for value in values: - if value not in ('true', '1', 'false', '0'): - msg = ('Requires sequence of booleans ' - '("true", "1", "false", "0")') - raise_parse_error(node, msg) - return input_data - - def gds_validate_datetime(self, input_data, node, input_name=''): - return input_data - - def gds_format_datetime(self, input_data, input_name=''): - if isinstance(input_data, basestring): - return input_data - if input_data.microsecond == 0: - _svalue = input_data.strftime('%Y-%m-%dT%H:%M:%S') - else: - _svalue = input_data.strftime('%Y-%m-%dT%H:%M:%S.%f') - if input_data.tzinfo is not None: - tzoff = input_data.tzinfo.utcoffset(input_data) - if tzoff is not None: - total_seconds = tzoff.seconds + (86400 * tzoff.days) - if total_seconds == 0: - _svalue += 'Z' - else: - if total_seconds < 0: - _svalue += '-' - total_seconds *= -1 - else: - _svalue += '+' - hours = total_seconds // 3600 - minutes = (total_seconds - (hours * 3600)) // 60 - _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) - return _svalue - - def gds_parse_datetime(self, input_data, node, input_name=''): - tz = None - if input_data[-1] == 'Z': - tz = _FixedOffsetTZ(0, 'GMT') - input_data = input_data[:-1] - else: - results = _tzoff_pattern.search(input_data) - if results is not None: - tzoff_parts = results.group(2).split(':') - tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) - if results.group(1) == '-': - tzoff *= -1 - tz = _FixedOffsetTZ(tzoff, results.group(0)) - input_data = input_data[:-6] - if len(input_data.split('.')) > 1: - dt = datetime.strptime(input_data, '%Y-%m-%dT%H:%M:%S.%f') - else: - dt = datetime.strptime(input_data, '%Y-%m-%dT%H:%M:%S') - return dt.replace(tzinfo=tz) - - def gds_validate_date(self, input_data, node, input_name=''): - return input_data - - def gds_format_date(self, input_data, input_name=''): - if isinstance(input_data, basestring): - return input_data - _svalue = input_data.strftime('%Y-%m-%d') - if input_data.tzinfo is not None: - tzoff = input_data.tzinfo.utcoffset(input_data) - if tzoff is not None: - total_seconds = tzoff.seconds + (86400 * tzoff.days) - if total_seconds == 0: - _svalue += 'Z' - else: - if total_seconds < 0: - _svalue += '-' - total_seconds *= -1 - else: - _svalue += '+' - hours = total_seconds // 3600 - minutes = (total_seconds - (hours * 3600)) // 60 - _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) - return _svalue - - def gds_parse_date(self, input_data, node, input_name=''): - tz = None - if input_data[-1] == 'Z': - tz = _FixedOffsetTZ(0, 'GMT') - input_data = input_data[:-1] - else: - results = _tzoff_pattern.search(input_data) - if results is not None: - tzoff_parts = results.group(2).split(':') - tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) - if results.group(1) == '-': - tzoff *= -1 - tz = _FixedOffsetTZ(tzoff, results.group(0)) - input_data = input_data[:-6] - return datetime.strptime(input_data, '%Y-%m-%d').replace(tzinfo=tz) - - def gds_str_lower(self, instring): - return instring.lower() - - def get_path_(self, node): - path_list = [] - self.get_path_list_(node, path_list) - path_list.reverse() - path = '/'.join(path_list) - return path - - def get_path_list_(self, node, path_list): - if node is None: - return - tag = _Tag_strip_pattern_.sub('', node.tag) - if tag: - path_list.append(tag) - self.get_path_list_(node.getparent(), path_list) - - def get_class_obj_(self, node, default_class=None): - class_obj1 = default_class - if 'xsi' in node.nsmap: - classname = node.get('{%s}type' % node.nsmap['xsi']) - if classname is not None: - names = classname.split(':') - if len(names) == 2: - classname = names[1] - class_obj2 = globals().get(classname) - if class_obj2 is not None: - class_obj1 = class_obj2 - return class_obj1 - - def gds_build_any(self, node, type_name=None): - return None - - -def showIndent(lwrite, level, pretty_print=True): - if pretty_print: - lwrite(' ' * level) - - -def quote_xml(text): - if text is None: - return u'' - - # Convert `text` to unicode string. This is mainly a catch-all for non - # string/unicode types like bool and int. - try: - text = unicode(text) - except UnicodeDecodeError: - text = text.decode(ExternalEncoding) - - # If it's a CDATA block, return the text as is. - if text.startswith(CDATA_START): - return text - - # If it's not a CDATA block, escape the XML and return the character - # encoded string. - return saxutils.escape(text) - - -def quote_attrib(text): - if text is None: - return u'""' - - # Convert `text` to unicode string. This is mainly a catch-all for non - # string/unicode types like bool and int. - try: - text = unicode(text) - except UnicodeDecodeError: - text = text.decode(ExternalEncoding) - - # Return the escaped the value of text. - # Note: This wraps the escaped text in quotation marks. - return saxutils.quoteattr(text) - - -def quote_python(inStr): - s1 = inStr - if s1.find("'") == -1: - if s1.find('\n') == -1: - return "'%s'" % s1 - else: - return "'''%s'''" % s1 - else: - if s1.find('"') != -1: - s1 = s1.replace('"', '\\"') - if s1.find('\n') == -1: - return '"%s"' % s1 - else: - return '"""%s"""' % s1 - - -def get_all_text_(node): - if node.text is not None: - text = node.text - else: - text = '' - for child in node: - if child.tail is not None: - text += child.tail - return text - - -def find_attr_value_(attr_name, node): - attrs = node.attrib - attr_parts = attr_name.split(':') - value = None - if len(attr_parts) == 1: - value = attrs.get(attr_name) - elif len(attr_parts) == 2: - prefix, name = attr_parts - namespace = node.nsmap.get(prefix) - if namespace is not None: - value = attrs.get('{%s}%s' % (namespace, name, )) - return value - - -class GDSParseError(Exception): - pass - -def raise_parse_error(node, msg): - msg = '%s (element %s/line %d)' % (msg, node.tag, node.sourceline) - raise GDSParseError(msg) - - -def _cast(typ, value): - if typ is None or value is None: - return value - return typ(value) +import mixbox.xml TypeInfo = collections.namedtuple("TypeInfo", ('ns', 'typename')) @@ -410,7 +23,7 @@ def get_type_info(node): KeyError: If `node` does not have an ``xsi:type`` attribute. """ - xsi_type = node.attrib[xmlconst.TAG_XSI_TYPE] + xsi_type = node.attrib[mixbox.xml.TAG_XSI_TYPE] typeinfo = xsi_type.split(":") if len(typeinfo) == 2: @@ -482,29 +95,15 @@ def has_xsi_type(node): """Returns ``True`` if `node` does not have an xsi:type attribute. """ - return xmlconst.TAG_XSI_TYPE in node.attrib + return mixbox.xml.TAG_XSI_TYPE in node.attrib __all__ = [ - 'CDATA_END', - 'CDATA_START', - 'ExternalEncoding', - 'GeneratedsSuper', - 'Tag_pattern_', 'TypeInfo', - '_cast', 'add_extension', 'etree_', - 'find_attr_value_', - 'get_all_text_', 'get_type_info', 'has_xsi_type', 'lookup_extension', - 'parsexml_', - 'quote_attrib', - 'quote_python', - 'quote_xml', - 'raise_parse_error', 'register_extension', - 'showIndent' ] diff --git a/stix/bindings/campaign.py b/stix/bindings/campaign.py index 4969dc93..a6083434 100644 --- a/stix/bindings/campaign.py +++ b/stix/bindings/campaign.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.stix_common as stix_common_binding import stix.bindings.data_marking as data_marking_binding diff --git a/stix/bindings/course_of_action.py b/stix/bindings/course_of_action.py index 1c5a1158..b6ef8862 100644 --- a/stix/bindings/course_of_action.py +++ b/stix/bindings/course_of_action.py @@ -9,8 +9,11 @@ # import sys -from stix.bindings import * + import cybox.bindings.cybox_core as cybox_core_binding +from mixbox.binding_utils import * + +from stix.bindings import lookup_extension, register_extension import stix.bindings.stix_common as stix_common_binding import stix.bindings.data_marking as data_marking_binding diff --git a/stix/bindings/data_marking.py b/stix/bindings/data_marking.py index 240bfbaa..9fbc42cc 100644 --- a/stix/bindings/data_marking.py +++ b/stix/bindings/data_marking.py @@ -7,11 +7,12 @@ # # Generated Thu Apr 11 15:06:22 2013 by generateDS.py version 2.9a. # -# stdlib + import sys -# internal -from stix.bindings import * +from mixbox.binding_utils import * + +from stix.bindings import lookup_extension from . import stix_common as stix_common_binding XML_NS = "http://data-marking.mitre.org/Marking-1" diff --git a/stix/bindings/exploit_target.py b/stix/bindings/exploit_target.py index f72c97ed..c4856181 100644 --- a/stix/bindings/exploit_target.py +++ b/stix/bindings/exploit_target.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import lookup_extension, register_extension import stix.bindings.stix_common as stix_common_binding import stix.bindings.data_marking as data_marking_binding diff --git a/stix/bindings/extensions/address/ciq_address_3_0.py b/stix/bindings/extensions/address/ciq_address_3_0.py index 5ae3a492..cd1e24de 100644 --- a/stix/bindings/extensions/address/ciq_address_3_0.py +++ b/stix/bindings/extensions/address/ciq_address_3_0.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.stix_common as stix_common_binding XML_NS = "http://stix.mitre.org/extensions/Address#CIQAddress3.0-1" diff --git a/stix/bindings/extensions/attack_pattern/capec_2_7.py b/stix/bindings/extensions/attack_pattern/capec_2_7.py index 8cb36966..6cc3aa0c 100644 --- a/stix/bindings/extensions/attack_pattern/capec_2_7.py +++ b/stix/bindings/extensions/attack_pattern/capec_2_7.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.ttp as ttp_binding XML_NS = "http://stix.mitre.org/extensions/AP#CAPEC2.7-1" diff --git a/stix/bindings/extensions/identity/ciq_identity_3_0.py b/stix/bindings/extensions/identity/ciq_identity_3_0.py index a6a1fca5..3c37c4b1 100644 --- a/stix/bindings/extensions/identity/ciq_identity_3_0.py +++ b/stix/bindings/extensions/identity/ciq_identity_3_0.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.stix_common as stix_common_binding XML_NS = "http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1" diff --git a/stix/bindings/extensions/malware/maec_4_1.py b/stix/bindings/extensions/malware/maec_4_1.py index 44aefc15..552beed1 100644 --- a/stix/bindings/extensions/malware/maec_4_1.py +++ b/stix/bindings/extensions/malware/maec_4_1.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.ttp as ttp_binding try: @@ -191,4 +194,4 @@ def main(): __all__ = [ "MAEC4_1InstanceType" - ] \ No newline at end of file + ] diff --git a/stix/bindings/extensions/marking/simple_marking.py b/stix/bindings/extensions/marking/simple_marking.py index ac9e5099..839ae146 100644 --- a/stix/bindings/extensions/marking/simple_marking.py +++ b/stix/bindings/extensions/marking/simple_marking.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.data_marking as data_marking_binding XML_NS = "http://data-marking.mitre.org/extensions/MarkingStructure#Simple-1" diff --git a/stix/bindings/extensions/marking/terms_of_use_marking.py b/stix/bindings/extensions/marking/terms_of_use_marking.py index 097fcea4..d9d99551 100644 --- a/stix/bindings/extensions/marking/terms_of_use_marking.py +++ b/stix/bindings/extensions/marking/terms_of_use_marking.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.data_marking as data_marking_binding XML_NS = "http://data-marking.mitre.org/extensions/MarkingStructure#Terms_Of_Use-1" diff --git a/stix/bindings/extensions/marking/tlp.py b/stix/bindings/extensions/marking/tlp.py index e84c85ed..fecade54 100644 --- a/stix/bindings/extensions/marking/tlp.py +++ b/stix/bindings/extensions/marking/tlp.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.data_marking as data_marking_binding XML_NS = "http://data-marking.mitre.org/extensions/MarkingStructure#TLP-1" diff --git a/stix/bindings/extensions/structured_coa/generic.py b/stix/bindings/extensions/structured_coa/generic.py index 19401b50..3ba383dd 100644 --- a/stix/bindings/extensions/structured_coa/generic.py +++ b/stix/bindings/extensions/structured_coa/generic.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension from stix.bindings.course_of_action import StructuredCOAType import stix.bindings.stix_common as stix_common_binding diff --git a/stix/bindings/extensions/test_mechanism/generic.py b/stix/bindings/extensions/test_mechanism/generic.py index 2f01d4f4..ca06cac1 100644 --- a/stix/bindings/extensions/test_mechanism/generic.py +++ b/stix/bindings/extensions/test_mechanism/generic.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.indicator as indicator_binding import stix.bindings.stix_common as stix_common_binding diff --git a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py index 29773b5f..6e1559ec 100644 --- a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py +++ b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.indicator as indicator_binding XML_NS = "http://stix.mitre.org/extensions/TestMechanism#OpenIOC2010-1" diff --git a/stix/bindings/extensions/test_mechanism/oval_5_10.py b/stix/bindings/extensions/test_mechanism/oval_5_10.py index 7938df10..565432d2 100644 --- a/stix/bindings/extensions/test_mechanism/oval_5_10.py +++ b/stix/bindings/extensions/test_mechanism/oval_5_10.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.indicator as indicator_binding XML_NS = "http://stix.mitre.org/extensions/TestMechanism#OVAL5.10-1" diff --git a/stix/bindings/extensions/test_mechanism/snort.py b/stix/bindings/extensions/test_mechanism/snort.py index 0553bdbb..53908ddf 100644 --- a/stix/bindings/extensions/test_mechanism/snort.py +++ b/stix/bindings/extensions/test_mechanism/snort.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.indicator as indicator_binding import stix.bindings.stix_common as stix_common_binding diff --git a/stix/bindings/extensions/test_mechanism/yara.py b/stix/bindings/extensions/test_mechanism/yara.py index f479faf5..458c9945 100644 --- a/stix/bindings/extensions/test_mechanism/yara.py +++ b/stix/bindings/extensions/test_mechanism/yara.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.indicator as indicator_binding import stix.bindings.stix_common as stix_common_binding diff --git a/stix/bindings/extensions/vulnerability/cvrf_1_1.py b/stix/bindings/extensions/vulnerability/cvrf_1_1.py index ed4e357e..49bc751b 100644 --- a/stix/bindings/extensions/vulnerability/cvrf_1_1.py +++ b/stix/bindings/extensions/vulnerability/cvrf_1_1.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import register_extension import stix.bindings.exploit_target as exploit_target_binding XML_NS = "http://stix.mitre.org/extensions/Vulnerability#CVRF-1" diff --git a/stix/bindings/incident.py b/stix/bindings/incident.py index eeb165e5..8e177282 100644 --- a/stix/bindings/incident.py +++ b/stix/bindings/incident.py @@ -8,9 +8,12 @@ # Generated Thu Apr 11 15:06:24 2013 by generateDS.py version 2.9a. # import sys -from stix.bindings import * + import cybox.bindings.cybox_core as cybox_core_binding import cybox.bindings.cybox_common as cybox_common_binding +from mixbox.binding_utils import * + +from stix.bindings import lookup_extension, register_extension import stix.bindings.stix_common as stix_common_binding import stix.bindings.data_marking as data_marking_binding diff --git a/stix/bindings/indicator.py b/stix/bindings/indicator.py index b14ded68..d6c8b810 100644 --- a/stix/bindings/indicator.py +++ b/stix/bindings/indicator.py @@ -9,8 +9,11 @@ # import sys -from stix.bindings import * + import cybox.bindings.cybox_core as cybox_core_binding +from mixbox.binding_utils import * + +from stix.bindings import lookup_extension, register_extension import stix.bindings.stix_common as stix_common_binding import stix.bindings.data_marking as data_marking_binding diff --git a/stix/bindings/report.py b/stix/bindings/report.py index c12b2ef3..9e3fbcc4 100644 --- a/stix/bindings/report.py +++ b/stix/bindings/report.py @@ -8,8 +8,10 @@ # Generated Mon Apr 27 08:13:59 2015 by generateDS.py version 2.9a. # -from stix.bindings import * from cybox.bindings import cybox_core +from mixbox.binding_utils import * + +from stix.bindings import lookup_extension, register_extension import stix.bindings.stix_common as common_binding import stix.bindings.data_marking as data_marking_binding diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index eacf55a3..257fd74e 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -9,10 +9,12 @@ # import sys -from stix.bindings import * +from mixbox.binding_utils import * import cybox.bindings.cybox_common as cybox_common_binding import cybox.bindings.cybox_core as cybox_core_binding +from stix.bindings import get_type_info, lookup_extension + XML_NS = "http://stix.mitre.org/common-1" # diff --git a/stix/bindings/stix_core.py b/stix/bindings/stix_core.py index 9de68033..0d2d779e 100644 --- a/stix/bindings/stix_core.py +++ b/stix/bindings/stix_core.py @@ -9,10 +9,13 @@ # import sys -from stix.bindings import * + +import cybox.bindings.cybox_core as cybox_core_binding +from mixbox.binding_utils import * + +from stix.bindings import lookup_extension import stix.bindings.stix_common as stix_common_binding import stix.bindings.data_marking as data_marking_binding -import cybox.bindings.cybox_core as cybox_core_binding XML_NS = "http://stix.mitre.org/stix-1" diff --git a/stix/bindings/threat_actor.py b/stix/bindings/threat_actor.py index 2252ec42..35be13d7 100644 --- a/stix/bindings/threat_actor.py +++ b/stix/bindings/threat_actor.py @@ -9,7 +9,10 @@ # import sys -from stix.bindings import * + +from mixbox.binding_utils import * + +from stix.bindings import lookup_extension, register_extension import stix.bindings.stix_common as stix_common_binding import stix.bindings.data_marking as data_marking_binding diff --git a/stix/bindings/ttp.py b/stix/bindings/ttp.py index 44d3e1cd..f67ecc0a 100644 --- a/stix/bindings/ttp.py +++ b/stix/bindings/ttp.py @@ -8,8 +8,11 @@ # import sys -from stix.bindings import * + import cybox.bindings.cybox_core as cybox_core_binding +from mixbox.binding_utils import * + +from stix.bindings import lookup_extension, register_extension import stix.bindings.stix_common as stix_common_binding import stix.bindings.data_marking as data_marking_binding diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index 32b5398f..4bf7b044 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -7,11 +7,11 @@ # external from lxml import etree +import mixbox.xml # internal import stix import stix.utils as utils -import stix.utils.parser as parser import stix.ttp.malware_instance from stix.ttp.malware_instance import MalwareInstance import stix.bindings.extensions.malware.maec_4_1 as ext_binding @@ -107,9 +107,9 @@ def maec(self, value): self._maec = None elif _MAEC_INSTALLED and is_maec(value): self._maec = value - elif utils.is_element(value) or utils.is_etree(value): - tree = parser.get_etree(value) - root = parser.get_etree_root(tree) + elif mixbox.xml.is_element(value) or mixbox.xml.is_etree(value): + tree = mixbox.xml.get_etree(value) + root = mixbox.xml.get_etree_root(tree) self._parse_etree(root) self._maec = root else: @@ -143,7 +143,7 @@ def _cast_maec(self, node): def _collect_schemalocs(self, node): try: - schemaloc = parser.get_schemaloc_pairs(node) + schemaloc = mixbox.xml.get_schemaloc_pairs(node) self.__input_schemalocations__ = dict(schemaloc) except KeyError: self.__input_schemalocations__ = {} @@ -205,7 +205,7 @@ def from_dict(cls, d, return_obj=None): if isinstance(maec, dict): return_obj.maec = cls._maec_from_dict(maec) else: - parser = stix.utils.parser.get_xml_parser() + parser = mixbox.xml.get_xml_parser() return_obj.maec = etree.parse(StringIO(maec), parser=parser) return return_obj diff --git a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py index d6b1492f..f7ae9eff 100644 --- a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py +++ b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py @@ -6,10 +6,10 @@ # external from lxml import etree +import mixbox.xml # internal import stix -import stix.utils.parser as parser from stix.indicator.test_mechanism import _BaseTestMechanism import stix.bindings.extensions.test_mechanism.open_ioc_2010 as open_ioc_tm_binding @@ -39,8 +39,8 @@ def ioc(self, value): self._ioc = None return - tree = parser.get_etree(value) - root = parser.get_etree_root(tree) + tree = mixbox.xml.get_etree(value) + root = mixbox.xml.get_etree_root(tree) if root.tag != self._TAG_IOC: self._cast_ioc(root) @@ -51,7 +51,7 @@ def ioc(self, value): def _collect_schemalocs(self, node): try: - schemaloc = parser.get_schemaloc_pairs(node) + schemaloc = mixbox.xml.get_schemaloc_pairs(node) self.__input_schemalocations__ = dict(schemaloc) except KeyError: self.__input_schemalocations__ = {} @@ -99,7 +99,7 @@ def from_dict(cls, d, return_obj=None): super(OpenIOCTestMechanism, cls).from_dict(d, return_obj) if 'ioc' in d: - parser = stix.utils.parser.get_xml_parser() + parser = mixbox.xml.get_xml_parser() return_obj.ioc = etree.parse(StringIO(d['ioc']), parser=parser) return return_obj diff --git a/stix/test/__init__.py b/stix/test/__init__.py index eb009e21..97b43d12 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -8,8 +8,8 @@ import warnings import cybox.utils +from mixbox.binding_utils import ExternalEncoding -import stix.bindings as bindings from stix.utils import NamespaceInfo, silence_warnings @@ -102,10 +102,10 @@ def round_trip(o, output=False, list_=False): try: # 6. Bindings Object -> XML String - xml_string = o2.to_xml(encoding=bindings.ExternalEncoding) + xml_string = o2.to_xml(encoding=ExternalEncoding) if not isinstance(xml_string, unicode): - xml_string = xml_string.decode(bindings.ExternalEncoding) + xml_string = xml_string.decode(ExternalEncoding) except KeyError as ex: print str(ex) diff --git a/stix/test/encoding_test.py b/stix/test/encoding_test.py index 8d9a466d..0ff7c7a2 100644 --- a/stix/test/encoding_test.py +++ b/stix/test/encoding_test.py @@ -7,6 +7,7 @@ import unittest from StringIO import StringIO +from mixbox import binding_utils from stix.core import STIXHeader, STIXPackage from stix.campaign import Campaign @@ -18,7 +19,6 @@ from stix.common import StructuredText from stix.incident import affected_asset from stix.utils import silence_warnings -import stix.bindings as bindings from stix.test import round_trip @@ -42,12 +42,12 @@ class EncodingTests(unittest.TestCase): @classmethod def setUpClass(cls): - cls.orig_encoding = bindings.ExternalEncoding - bindings.ExternalEncoding = 'utf-16' + cls.orig_encoding = binding_utils.ExternalEncoding + binding_utils.ExternalEncoding = 'utf-16' @classmethod def tearDownClass(cls): - bindings.ExternalEncoding = cls.orig_encoding + binding_utils.ExternalEncoding = cls.orig_encoding def _test_equal(self, obj1, obj2): self.assertEqual(obj1.title, obj2.title) @@ -122,85 +122,6 @@ def test_campaign(self): c2 = round_trip(c) self._test_equal(c, c2) - def test_quote_xml(self): - s = bindings.quote_xml(UNICODE_STR) - self.assertEqual(s, UNICODE_STR) - - def test_quote_attrib(self): - """Tests that the stix.bindings.quote_attrib method works properly - on unicode inputs. - - Note: - The quote_attrib method (more specifically, saxutils.quoteattr()) - adds quotation marks around the input data, so we need to strip - the leading and trailing chars to test effectively - """ - s = bindings.quote_attrib(UNICODE_STR) - s = s[1:-1] - self.assertEqual(s, UNICODE_STR) - - def test_quote_attrib_int(self): - i = 65536 - s = bindings.quote_attrib(i) - self.assertEqual(u'"65536"', s) - - def test_quote_attrib_bool(self): - b = True - s = bindings.quote_attrib(b) - self.assertEqual(u'"True"', s) - - def test_quote_xml_int(self): - i = 65536 - s = bindings.quote_xml(i) - self.assertEqual(unicode(i), s) - - def test_quote_xml_bool(self): - b = True - s = bindings.quote_xml(b) - self.assertEqual(unicode(b), s) - - def test_quote_xml_encoded(self): - encoding = bindings.ExternalEncoding - encoded = UNICODE_STR.encode(encoding) - quoted = bindings.quote_xml(encoded) - self.assertEqual(UNICODE_STR, quoted) - - def test_quote_attrib_encoded(self): - encoding = bindings.ExternalEncoding - encoded = UNICODE_STR.encode(encoding) - quoted = bindings.quote_attrib(encoded)[1:-1] - self.assertEqual(UNICODE_STR, quoted) - - def test_quote_xml_zero(self): - i = 0 - s = bindings.quote_xml(i) - self.assertEqual(unicode(i), s) - - def test_quote_attrib_zero(self): - i = 0 - s = bindings.quote_attrib(i) - self.assertEqual(u'"0"', s) - - def test_quote_xml_none(self): - i = None - s = bindings.quote_xml(i) - self.assertEqual(u'', s) - - def test_quote_attrib_none(self): - i = None - s = bindings.quote_attrib(i) - self.assertEqual(u'""', s) - - def test_quote_attrib_empty(self): - i = '' - s = bindings.quote_attrib(i) - self.assertEqual(u'""', s) - - def test_quote_xml_empty(self): - i = '' - s = bindings.quote_xml(i) - self.assertEqual(u'', s) - @silence_warnings def test_to_xml_utf16_encoded(self): encoding = 'utf-16' diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index 2aeea093..40db6948 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -1,11 +1,13 @@ import unittest from StringIO import StringIO + from lxml import etree +import mixbox.xml -import stix.utils.parser from stix.test import EntityTestCase from stix.extensions.malware.maec_4_1_malware import MAECInstance + class PythonMAECTests(EntityTestCase, unittest.TestCase): klass = MAECInstance @@ -70,7 +72,7 @@ class PythonMAECEtreeTests(unittest.TestCase): def _test_xml(self, obj): xml = obj.to_xml() - parser = stix.utils.parser.get_xml_parser() + parser = mixbox.xml.get_xml_parser() tree = etree.parse(StringIO(xml), parser=parser) root = tree.getroot() @@ -83,7 +85,7 @@ def _test_xml(self, obj): def test_etree(self): - parser = stix.utils.parser.get_xml_parser() + parser = mixbox.xml.get_xml_parser() tree = etree.parse(StringIO(self.XML), parser=parser) ext = MAECInstance() @@ -92,7 +94,7 @@ def test_etree(self): def test_etree_dict(self): - parser = stix.utils.parser.get_xml_parser() + parser = mixbox.xml.get_xml_parser() tree = etree.parse(StringIO(self.XML), parser=parser) ext = MAECInstance() ext.maec = tree @@ -103,4 +105,4 @@ def test_etree_dict(self): if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() diff --git a/stix/test/extensions/test_mechanisms/openioc_test.py b/stix/test/extensions/test_mechanisms/openioc_test.py index 36fc19dc..ffa1ef40 100644 --- a/stix/test/extensions/test_mechanisms/openioc_test.py +++ b/stix/test/extensions/test_mechanisms/openioc_test.py @@ -5,6 +5,7 @@ import StringIO import lxml +import mixbox.xml from stix import utils from stix.test import EntityTestCase @@ -124,7 +125,7 @@ def tearDown(self): def _test_xml(self, obj): xml = obj.to_xml() - parser = utils.parser.get_xml_parser() + parser = mixbox.xml.get_xml_parser() tree = lxml.etree.parse(StringIO.StringIO(xml), parser=parser) root = tree.getroot() @@ -136,7 +137,7 @@ def _test_xml(self, obj): self.assertEqual(nodes[0].text, self.DESCRIPTION) def test_etree(self): - parser = utils.parser.get_xml_parser() + parser = mixbox.xml.get_xml_parser() tree = lxml.etree.parse(StringIO.StringIO(self.XML), parser=parser) ext = OpenIOCTestMechanism() @@ -144,7 +145,7 @@ def test_etree(self): self._test_xml(ext) def test_etree_dict(self): - parser = utils.parser.get_xml_parser() + parser = mixbox.xml.get_xml_parser() tree = lxml.etree.parse(StringIO.StringIO(self.XML), parser=parser) ext = OpenIOCTestMechanism() ext.ioc = tree diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index f9e5a97e..7a7b5283 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -9,10 +9,10 @@ # external import cybox import lxml.etree +import mixbox.xml # internal import stix -import stix.xmlconst as xmlconst # relative from . import dates @@ -275,16 +275,6 @@ def is_bool(obj): return isinstance(obj, bool) -def is_element(obj): - """Returns ``True`` if `obj` is an lxml ``Element``.""" - return isinstance(obj, lxml.etree._Element) # noqa - - -def is_etree(obj): - """Returns ``True`` if `obj` is an lxml ``ElementTree``.""" - return isinstance(obj, lxml.etree._ElementTree) # noqa - - def has_value(var): """Returns ``True`` if `var` is not ``None`` and not empty.""" if var is None: @@ -326,7 +316,7 @@ def dict_iter(items): d[key] = dates.serialize_value(field) elif is_date(field): d[key] = dates.serialize_date(field) - elif is_element(field) or is_etree(field): + elif mixbox.xml.is_element(field) or mixbox.xml.is_etree(field): d[key] = lxml.etree.tostring(field) elif is_sequence(field): d[key] = dict_iter(field) @@ -345,10 +335,10 @@ def xml_bool(value): if value is None: return None - if value in xmlconst.FALSE: + if value in mixbox.xml.FALSE: return False - if value in xmlconst.TRUE: + if value in mixbox.xml.TRUE: return True error = "Unable to determine the xml boolean value of '{0}'".format(value) diff --git a/stix/utils/parser.py b/stix/utils/parser.py index a777c034..62c80fbb 100644 --- a/stix/utils/parser.py +++ b/stix/utils/parser.py @@ -1,18 +1,13 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# stdlib from distutils.version import StrictVersion -# external -from lxml import etree +import mixbox.xml -# internal import stix import stix.xmlconst as xmlconst - -# relative -from . import ignored, is_etree, is_element +from . import ignored class UnknownVersionError(Exception): @@ -46,72 +41,8 @@ def __init__(self, message, expected=None, found=None): UnsupportedRootElement = UnsupportedRootElementError -def get_xml_parser(encoding=None): - """Returns an ``etree.ETCompatXMLParser`` instance.""" - parser = etree.ETCompatXMLParser( - huge_tree=True, - remove_comments=True, - strip_cdata=False, - remove_blank_text=True, - resolve_entities=False, - encoding=encoding - ) - - return parser - - -def get_etree(doc, encoding=None): - if is_etree(doc): - return doc - elif is_element(doc): - return etree.ElementTree(doc) - else: - parser = get_xml_parser(encoding=encoding) - return etree.parse(doc, parser=parser) - - -def get_etree_root(doc, encoding=None): - """Returns an instance of lxml.etree._Element for the given `doc` input. - - Args: - doc: The input XML document. Can be an instance of - ``lxml.etree._Element``, ``lxml.etree._ElementTree``, a file-like - object, or a string filename. - encoding: The character encoding of `doc`. If ``None``, an attempt - will be made to determine the character encoding by the XML - parser. - - Returns: - An ``lxml.etree._Element`` instance for `doc`. - - Raises: - IOError: If `doc` cannot be found. - lxml.ParseError: If `doc` is a malformed XML document. - - """ - tree = get_etree(doc, encoding) - root = tree.getroot() - - return root - - -def get_schemaloc_pairs(node): - """Parses the xsi:schemaLocation attribute on `node`. - - Returns: - A list of (ns, schemaLocation) tuples for the node. - - Raises: - KeyError: If `node` does not have an xsi:schemaLocation attribute. - - """ - schemalocs = node.attrib[xmlconst.TAG_SCHEMALOCATION] - l = schemalocs.split() - return zip(l[::2], l[1::2]) - - def get_document_version(doc): - root = get_etree_root(doc) + root = mixbox.xml.get_etree_root(doc) if 'version' in root.attrib: return root.attrib['version'] @@ -123,7 +54,7 @@ def get_document_version(doc): def root_tag(doc): - root = get_etree_root(doc) + root = mixbox.xml.get_etree_root(doc) return root.tag @@ -173,7 +104,7 @@ def _check_root(self, tree): ) def _apply_input_namespaces(self, tree, entity): - root = get_etree_root(tree) + root = mixbox.xml.get_etree_root(tree) entity.__input_namespaces__ = dict(root.nsmap.iteritems()) def _apply_input_schemalocations(self, tree, entity): @@ -184,10 +115,10 @@ def _apply_input_schemalocations(self, tree, entity): entity: The entity to attach the schemlocation dictionary to """ - root = get_etree_root(tree) + root = mixbox.xml.get_etree_root(tree) with ignored(KeyError): - pairs = get_schemaloc_pairs(root) + pairs = mixbox.xml.get_schemaloc_pairs(root) entity.__input_schemalocations__ = dict(pairs) def parse_xml_to_obj(self, xml_file, check_version=True, check_root=True, @@ -210,7 +141,7 @@ def parse_xml_to_obj(self, xml_file, check_version=True, check_root=True, contains an invalid root element. """ - root = get_etree_root(xml_file, encoding=encoding) + root = mixbox.xml.get_etree_root(xml_file, encoding=encoding) if check_version: self._check_version(root) @@ -246,7 +177,7 @@ def parse_xml(self, xml_file, check_version=True, check_root=True, contains an invalid root element. """ - root = get_etree_root(xml_file, encoding=encoding) + root = mixbox.xml.get_etree_root(xml_file, encoding=encoding) stix_package_obj = self.parse_xml_to_obj( xml_file=root, diff --git a/stix/xmlconst.py b/stix/xmlconst.py index e508eeb2..4acf3d25 100644 --- a/stix/xmlconst.py +++ b/stix/xmlconst.py @@ -1,15 +1,5 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# XML NAMESPACES -NS_XSI = "http://www.w3.org/2001/XMLSchema-instance" - -# XML TAGS -TAG_XSI_TYPE = "{%s}type" % NS_XSI -TAG_SCHEMALOCATION = "{%s}schemaLocation" % NS_XSI - # STIX TAGS TAG_STIX_PACKAGE = "{http://stix.mitre.org/stix-1}STIX_Package" - -FALSE = (False, 'false', 0, '0') -TRUE = (True, 'true', 1, '1') From 4dd9c5da10034599293ff2f96e29135217335693 Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 18 Jun 2015 13:04:45 -0400 Subject: [PATCH 147/438] WIP add typedfields to base.py --- stix/__init__.py | 10 +- stix/base.py | 284 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 211 insertions(+), 83 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index 703708cc..68527b6c 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -122,11 +122,9 @@ def register_extension(cls): add_extension(cls) return cls - from . import common # noqa from .version import __version__ # noqa - def supported_stix_version(): """Returns a tuple of STIX version strings that this version of python-stix supports (i.e., can parse). @@ -134,3 +132,11 @@ def supported_stix_version(): """ return ('1.1.1', '1.2') +# because common depends on base, we can only set the TypeFields types on +# BaseCoreComponent to common classes after both common and base are imported +#BaseCoreComponent.description.type_ = common.StructuredText +#common.StructuredText +BaseCoreComponent.information_source.type_ = common.InformationSource + +import data_marking +BaseCoreComponent.handling.type_ = data_marking.Marking \ No newline at end of file diff --git a/stix/base.py b/stix/base.py index 53e5ab15..71c85e43 100644 --- a/stix/base.py +++ b/stix/base.py @@ -6,6 +6,7 @@ import collections import itertools import StringIO +from cybox import TypedField # internal from . import bindings, utils @@ -15,11 +16,25 @@ def _override(*args, **kwargs): raise NotImplementedError() +class AttributeField(TypedField): + pass + +class ElementField(TypedField): + pass + +class IdField(AttributeField): + pass + + class Entity(object): """Base class for all classes in the STIX API.""" _namespace = None _XSI_TYPE = None + def __init__(self): + pass + #self._fields = {} + def _collect_ns_info(self, ns_info=None): if not ns_info: return @@ -62,6 +77,17 @@ def _set_var(self, klass, try_cast=True, arg=None, **kwargs): error = error.format(name, klass, type(item)) raise TypeError(error) + @classmethod + def _get_vars(cls): + import inspect + var_list = [] + for (name, obj) in inspect.getmembers(cls, inspect.isdatadescriptor): + print name + " " + str(type(obj)) + " " + str(obj.__class__) + if isinstance(obj, TypedField): + var_list.append(obj) + + return var_list + def _set_vocab(self, klass=None, **kwargs): """Sets a controlled vocabulary property value. @@ -89,20 +115,93 @@ def _set_vocab(self, klass=None, **kwargs): else: self._set_var(klass, **kwargs) + @classmethod + def istypeof(cls, obj): + """Check if `cls` is the type of `obj` + + In the normal case, as implemented here, a simple isinstance check is + used. However, there are more complex checks possible. For instance, + EmailAddress.istypeof(obj) checks if obj is an Address object with + a category of Address.CAT_EMAIL + """ + return isinstance(obj, cls) + def to_obj(self, return_obj=None, ns_info=None): - """Converts an `Entity` into a binding object. + """Convert to a GenerateDS binding object. - Note: - This needs to be overridden by derived classes. + Subclasses can override this function. + Returns: + An instance of this Entity's ``_binding_class`` with properties + set from this Entity. """ + + def _objectify(value, return_obj, ns_info): + """Make `value` suitable for a binding object. + + If `value` is an Entity, call to_obj() on it. Otherwise, return it + unmodified. + """ + if isinstance(value, Entity): + return value.to_obj(return_obj=return_obj, ns_info=ns_info) + else: + return value + self._collect_ns_info(ns_info) - return return_obj + + entity_obj = self._binding_class() + + vars = {} + for klass in self.__class__.__mro__: + if klass is Entity: + break + vars.update(klass.__dict__.iteritems()) + + print "vars", vars + print "self", self.__dict__ + + for name, field in vars.iteritems(): + if isinstance(field, TypedField): + val = getattr(self, field.attr_name) + + if field.multiple: + if val: + val = [_objectify(x, return_obj, ns_info) for x in val] + else: + val = [] + else: + val = _objectify(val, return_obj, ns_info) + + setattr(entity_obj, field.name, val) + + self._finalize_obj(entity_obj) + return entity_obj + + def _finalize_obj(self, entity_obj): + """Subclasses can define additional items in the binding object. + + `entity_obj` should be modified in place. + """ + pass @classmethod - def from_obj(cls, obj, return_obj=None): + def from_obj(cls, cls_obj=None): """Create an object from a binding object""" - raise NotImplementedError() + if not cls_obj: + return None + + entity = cls() + + for field in cls._get_vars(): + val = getattr(cls_obj, field.name) + if field.type_: + if field.multiple and val is not None: + val = [field.type_.from_obj(x) for x in val] + else: + val = field.type_.from_obj(val) + setattr(entity, field.attr_name, val) + + return entity def to_xml(self, include_namespaces=True, include_schemalocs=False, ns_dict=None, schemaloc_dict=None, pretty=True, @@ -228,16 +327,97 @@ def to_dict(self): """Converts a STIX :class:`Entity` implementation into a Python dictionary. This may be overridden by derived classes. + Returns: + Python dict with keys set from this Entity. """ - return utils.to_dict(self) + def _dictify(value): + """Make `value` suitable for a dictionary. + + If `value` is an Entity, call to_dict() on it. Otherwise, return it + unmodified. + """ + if isinstance(value, Entity): + return value.to_dict() + else: + return value + + entity_dict = {} + vars = {} + for klass in self.__class__.__mro__: + if klass is Entity: + break + vars.update(klass.__dict__.iteritems()) + + hasAnyTypedField = False + for name, field in vars.iteritems(): + if isinstance(field, TypedField): + hasAnyTypedField = True + + val = getattr(self, field.attr_name) + + if field.multiple: + if val: + val = [_dictify(x) for x in val] + else: + val = [] + else: + val = _dictify(val) + + # Only add non-None objects or non-empty lists + if val is not None and val != []: + entity_dict[field.key_name] = val + + # doesn't quite work, possibly because of inherited TypedFields? + #if not hasAnyTypedField: + # return utils.to_dict(self) + + self._finalize_dict(entity_dict) + + return entity_dict + + def _finalize_dict(self, entity_dict): + """Subclasses can define additional items in the dictionary. + + `entity_dict` should be modified in place. + """ + pass @classmethod - def from_dict(cls, d, return_obj=None): - """Convert from dict representation to object representation. - This should be overriden by a subclass + def from_dict(cls, cls_dict=None): + """Convert from dict representation to object representation.""" + if cls_dict is None: + return None - """ - raise NotImplementedError() + entity = cls() + + # Shortcut if an actual dict is not provided: + if not isinstance(cls_dict, dict): + value = cls_dict + # Call the class's constructor + try: + return cls(value) + except TypeError: + raise TypeError("Could not instantiate a %s from a %s: %s" % + (cls, type(value), value)) + + for field in cls._get_vars(): + val = cls_dict.get(field.key_name) + if field.type_: + if issubclass(field.type_, EntityList): + val = field.type_.from_list(val) + elif field.multiple: + if val is not None: + val = [field.type_.from_dict(x) for x in val] + else: + val = [] + else: + val = field.type_.from_dict(val) + else: + if field.multiple and not val: + val = [] + setattr(entity, field.attr_name, val) + + return entity @classmethod def object_from_dict(cls, entity_dict): @@ -561,14 +741,21 @@ def insert(self, idx, value): value = self._fix_value(value) self._inner.insert(idx, value) - class BaseCoreComponent(Entity): _ALL_VERSIONS = () _ID_PREFIX = None + title = ElementField("Title") + id_ = IdField("id") + idref = IdField("idref") + version = AttributeField("version") + information_source = ElementField("Information_Source") + handling = ElementField("Handling", multiple=True) + def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): - + super(BaseCoreComponent, self).__init__() + self._fields = {} self.id_ = id_ or utils.create_id(self._ID_PREFIX) self.idref = idref self.title = title @@ -634,27 +821,8 @@ def idref(self, value): self._idref = value self.id_ = None # unset id_ if idref is present - @property - def version(self): - """The schematic version of this component. This property - will always return ``None`` unless it is set to a value different than - ``self.__class__._version``. - - Note: - This property refers to the version of the schema component - type and should not be used for the purpose of content versioning. - - Default Value: ``None`` - - Returns: - The value of the ``version`` property if set to a value different - than ``self.__class__._version`` - - """ - return self._version - - @version.setter - def version(self, value): + # TODO: add this as a callback_hook to version TypedField + def check_version(self, value): if not value: self._version = None else: @@ -689,14 +857,6 @@ def timestamp(self): def timestamp(self, value): self._timestamp = utils.dates.parse_value(value) - @property - def title(self): - return self._title - - @title.setter - def title(self, value): - self._title = value - @property def description(self): """A single description about the contents or purpose of this object. @@ -815,42 +975,6 @@ def add_short_description(self, description): """ self.short_descriptions.add(description) - @property - def information_source(self): - """Contains information about the source of this object. - - Default Value: ``None`` - - Returns: - An instance of - :class:`.InformationSource` - - Raises: - ValueError: If set to a value that is not ``None`` and not an - instance of - :class:`.InformationSource` - - """ - return self._information_source - - @information_source.setter - def information_source(self, value): - from stix.common import InformationSource - self._set_var(InformationSource, try_cast=False, information_source=value) - - @property - def handling(self): - return self._handling - - @handling.setter - def handling(self, value): - """The :class:`.Marking` section of this component. This section - contains data marking information. - - """ - from stix.data_marking import Marking - self._set_var(Marking, try_cast=False, handling=value) - @classmethod def from_obj(cls, obj, return_obj=None): @@ -936,5 +1060,3 @@ def from_dict(cls, d, return_obj=None): def to_dict(self): return super(BaseCoreComponent, self).to_dict() - - From a2c74a7429b82ebf572f48e8794fb356df84f29e Mon Sep 17 00:00:00 2001 From: Greg Back Date: Fri, 19 Jun 2015 13:59:15 -0500 Subject: [PATCH 148/438] Update requirements to use development versions of cybox and maec. --- setup.py | 6 +++--- tox.ini | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/setup.py b/setup.py index 57b821d6..e79340d3 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ def get_version(): 'test': [ 'nose==1.3.0', 'tox==1.6.1', - 'maec>=4.1.0.12,<4.1.1.0' + 'maec>=4.1.0.13.dev0,<4.1.1.0', ], } @@ -39,8 +39,8 @@ def get_version(): install_requires = [ 'lxml>=2.3', 'python-dateutil', - 'cybox>=2.1.0.11,<2.1.1.0', - 'mixbox' + 'cybox>=2.1.0.12.dev0,<2.1.1.0', + 'mixbox', ] diff --git a/tox.ini b/tox.ini index 6d98a8aa..042a7b3a 100644 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,6 @@ commands = # sphinx-build -b doctest docs docs/_build/doctest sphinx-build -b html docs docs/_build/html deps = - https://github.com/CybOXProject/mixbox/archive/master.zip -rrequirements.txt # We call this "lxml23" instead of "rhel6", since RHEL6 ships with LXML 2.2.3. @@ -20,7 +19,7 @@ commands = deps = lxml==2.3 python-dateutil==1.4.1 - cybox - maec + mixbox + cybox>=2.1.0.12.dev0 + maec>=4.1.0.13.dev0 nose - https://github.com/CybOXProject/mixbox/archive/master.zip \ No newline at end of file From 46580f6c18cfb204b10c52c2f6e4268812c2ec1c Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 25 Jun 2015 12:33:38 -0400 Subject: [PATCH 149/438] WIP switch to mixbox TypedFields; add more TypedFields --- stix/__init__.py | 7 +-- stix/base.py | 82 +++++++------------------------ stix/common/activity.py | 2 + stix/common/identity.py | 58 ++++++---------------- stix/common/information_source.py | 21 ++++---- stix/common/structured_text.py | 4 ++ stix/indicator/indicator.py | 4 +- 7 files changed, 56 insertions(+), 122 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index 68527b6c..25d05965 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -134,9 +134,4 @@ def supported_stix_version(): # because common depends on base, we can only set the TypeFields types on # BaseCoreComponent to common classes after both common and base are imported -#BaseCoreComponent.description.type_ = common.StructuredText -#common.StructuredText -BaseCoreComponent.information_source.type_ = common.InformationSource - -import data_marking -BaseCoreComponent.handling.type_ = data_marking.Marking \ No newline at end of file +BaseCoreComponent.initClassFields() diff --git a/stix/base.py b/stix/base.py index 71c85e43..41f37346 100644 --- a/stix/base.py +++ b/stix/base.py @@ -6,7 +6,7 @@ import collections import itertools import StringIO -from cybox import TypedField +from mixbox import fields, entities # internal from . import bindings, utils @@ -16,10 +16,10 @@ def _override(*args, **kwargs): raise NotImplementedError() -class AttributeField(TypedField): +class AttributeField(fields.TypedField): pass -class ElementField(TypedField): +class ElementField(fields.TypedField): pass class IdField(AttributeField): @@ -32,8 +32,7 @@ class Entity(object): _XSI_TYPE = None def __init__(self): - pass - #self._fields = {} + self._fields = {} def _collect_ns_info(self, ns_info=None): if not ns_info: @@ -83,7 +82,7 @@ def _get_vars(cls): var_list = [] for (name, obj) in inspect.getmembers(cls, inspect.isdatadescriptor): print name + " " + str(type(obj)) + " " + str(obj.__class__) - if isinstance(obj, TypedField): + if isinstance(obj, fields.TypedField): var_list.append(obj) return var_list @@ -161,7 +160,7 @@ def _objectify(value, return_obj, ns_info): print "self", self.__dict__ for name, field in vars.iteritems(): - if isinstance(field, TypedField): + if isinstance(field, fields.TypedField): val = getattr(self, field.attr_name) if field.multiple: @@ -341,8 +340,8 @@ def _dictify(value): else: return value - entity_dict = {} - vars = {} + entity_dict = { } + vars = { } for klass in self.__class__.__mro__: if klass is Entity: break @@ -350,7 +349,7 @@ def _dictify(value): hasAnyTypedField = False for name, field in vars.iteritems(): - if isinstance(field, TypedField): + if isinstance(field, fields.TypedField): hasAnyTypedField = True val = getattr(self, field.attr_name) @@ -750,12 +749,20 @@ class BaseCoreComponent(Entity): idref = IdField("idref") version = AttributeField("version") information_source = ElementField("Information_Source") - handling = ElementField("Handling", multiple=True) + #description = ElementField("Description") + handling = ElementField("Handling") + + @classmethod + def initClassFields(cls): + import data_marking + import common + BaseCoreComponent.handling.type_ = data_marking.Marking + #BaseCoreComponent.description.type_ = common.StructuredText + BaseCoreComponent.information_source.type_ = common.InformationSource def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): super(BaseCoreComponent, self).__init__() - self._fields = {} self.id_ = id_ or utils.create_id(self._ID_PREFIX) self.idref = idref self.title = title @@ -770,57 +777,6 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, else: self.timestamp = utils.dates.now() if not idref else None - @property - def id_(self): - """The ``id_`` property serves as an identifier. This is - automatically set during ``__init__()``. - - Default Value: ``None`` - - Note: - Both the ``id_`` and ``idref`` properties cannot be set at the - same time. **Setting one will unset the other!** - - Returns: - A string id. - - """ - return self._id - - @id_.setter - def id_(self, value): - if not value: - self._id = None - else: - self._id = value - self.idref = None - - @property - def idref(self): - """The ``idref`` property must be set to the ``id_`` value of another - object instance of the same type. An idref does not need to resolve to - a local object instance. - - Default Value: ``None``. - - Note: - Both the ``id_`` and ``idref`` properties cannot be set at the - same time. **Setting one will unset the other!** - - Returns: - The value of the ``idref`` property - - """ - return self._idref - - @idref.setter - def idref(self, value): - if not value: - self._idref = None - else: - self._idref = value - self.id_ = None # unset id_ if idref is present - # TODO: add this as a callback_hook to version TypedField def check_version(self, value): if not value: diff --git a/stix/common/activity.py b/stix/common/activity.py index ed4e23aa..c410fcf1 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -3,6 +3,7 @@ import stix import stix.bindings.stix_common as common_binding +import stix.utils from .datetimewithprecision import DateTimeWithPrecision from .structured_text import StructuredTextList @@ -108,6 +109,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_dict(self): + return stix.utils.to_dict(self) return super(Activity, self).to_dict() @classmethod diff --git a/stix/common/identity.py b/stix/common/identity.py index c66a487d..5c47478c 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -5,58 +5,31 @@ import stix import stix.bindings.stix_common as common_binding - +from stix.base import ElementField, IdField +from stix.bindings.stix_common import IdentityType class Identity(stix.Entity): _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' + _binding_class = IdentityType + + id_ = IdField("id") + idref = IdField("idref") + name = ElementField("Name") + related_identities = ElementField("Related_Identities") + + @classmethod + def initializeClassFields(cls): + cls.related_identities.type = RelatedIdentities def __init__(self, id_=None, idref=None, name=None, related_identities=None): + super(Identity, self).__init__() + self.id_ = id_ self.idref = idref self.name = name self.related_identities = related_identities - @property - def id_(self): - return self._id - - @id_.setter - def id_(self, value): - if not value: - self._id = None - else: - self._id = value - self.idref = None - - @property - def idref(self): - return self._idref - - @idref.setter - def idref(self, value): - if not value: - self._idref = None - else: - self._idref = value - self.id_ = None # unset id_ if idref is present - - @property - def name(self): - return self._name - - @name.setter - def name(self, value): - self._name = value if value else None - - @property - def related_identities(self): - return self._related_identities - - @related_identities.setter - def related_identities(self, value): - self._related_identities = RelatedIdentities(value) - def to_obj(self, return_obj=None, ns_info=None): super(Identity, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -137,7 +110,8 @@ class RelatedIdentities(stix.EntityList): _contained_type = RelatedIdentity _inner_name = "identities" - +# this must come after RelatedIdentities definition +Identity.initializeClassFields() # Backwards compatibility add_extension = stix.add_extension diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 44d9dfef..a35b5f19 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -15,14 +15,17 @@ from . import vocabs, VocabString from .identity import Identity from .structured_text import StructuredTextList - +from stix.base import ElementField class InformationSource(stix.Entity): _binding = stix_common_binding _binding_class = stix_common_binding.InformationSourceType _namespace = 'http://stix.mitre.org/common-1' + identity = ElementField("Identity", Identity) + def __init__(self, description=None, identity=None, time=None, tools=None, contributing_sources=None, references=None): + self._fields = {} self.description = description self.identity = identity self.contributing_sources = contributing_sources @@ -120,14 +123,6 @@ def add_description(self, description): """ self.descriptions.add(description) - @property - def identity(self): - return self._identity - - @identity.setter - def identity(self, value): - self._set_var(Identity, try_cast=False, identity=value) - @property def time(self): return self._time @@ -224,7 +219,13 @@ def from_dict(cls, dict_repr, return_obj=None): return return_obj def to_dict(self): - return super(InformationSource, self).to_dict() + #for i in range(10): print i + print "TO DICT INFORMATION_SOURCE CALLED" + print self.description + ret = super(InformationSource, self).to_dict() + print ret + print utils.to_dict(self) + return ret class ContributingSources(stix.EntityList): _namespace = "http://stix.mitre.org/common-1" diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index c1257751..6db1fa16 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -9,6 +9,8 @@ import stix.utils as utils import stix.bindings.stix_common as stix_common_binding +from stix.base import AttributeField, ElementField + #: Default ordinality value for StructuredText. DEFAULT_ORDINALITY = 1 @@ -27,6 +29,8 @@ class StructuredText(stix.Entity): _binding_class = _binding.StructuredTextType _namespace = 'http://stix.mitre.org/common-1' + #ordinality = AttributeField("ordinality") + def __init__(self, value=None, ordinality=None): self.id_ = None self.value = value diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 17d54c6a..44c67467 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -944,7 +944,9 @@ def from_obj(cls, obj, return_obj=None): def to_dict(self): keys = ('observables', 'observable_composition_operator', 'negate') - d = utils.to_dict(self, skip=keys) + #d = utils.to_dict(self, skip=keys) + + d = super(Indicator, self).to_dict() if self.negate: d['negate'] = True From ac163900d41fc72f15e52db75f24714456e338a3 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Wed, 1 Jul 2015 13:48:43 -0500 Subject: [PATCH 150/438] Update to use latest version of cybox and maec namespaces. --- stix/utils/__init__.py | 25 +++++++++++++------------ stix/utils/idgen.py | 4 +++- stix/utils/nsparser.py | 22 +++++++++++----------- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index 7a7b5283..1c2016c4 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -1,17 +1,15 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# stdlib import contextlib -import keyword import functools +import keyword -# external -import cybox import lxml.etree + +from mixbox.entities import Entity, EntityList import mixbox.xml -# internal import stix # relative @@ -138,24 +136,27 @@ def is_stix(entity): def is_cybox(entity): - """Returns true if `entity` is an instance of :class:`cybox.Entity`.""" - return isinstance(entity, cybox.Entity) + """Returns true if `entity` is an instance of + :class:`mixbox.entities.Entity`. + """ + # TODO: once all entities subclass from mixbox.entities.Entity, how do we + # do this? + return isinstance(entity, Entity) def is_entity(entity): """Returns true if `entity` is an instance of :class:`.Entity` or - :class:`cybox.Entity`. - + :class:`mixbox.Entity`. """ - return isinstance(entity, (cybox.Entity, stix.Entity)) + return isinstance(entity, (Entity, stix.Entity)) def is_entitylist(entity): """Returns true if `entity` is an instance of :class:`.EntityList` - or :class:`cybox.EntityList`. + or :class:`mixbox.entities.EntityList`. """ - return isinstance(entity, (cybox.EntityList, stix.EntityList)) + return isinstance(entity, (EntityList, stix.EntityList)) def is_typedlist(entity): diff --git a/stix/utils/idgen.py b/stix/utils/idgen.py index ecb661db..cf3c915e 100644 --- a/stix/utils/idgen.py +++ b/stix/utils/idgen.py @@ -3,6 +3,8 @@ import uuid import contextlib + +from mixbox.namespaces import Namespace import cybox.utils @@ -93,7 +95,7 @@ def _set_cybox_namespace(namespace): uri = namespace.iterkeys().next() prefix = namespace.itervalues().next() - ns = cybox.utils.Namespace(uri, prefix) + ns = Namespace(uri, prefix, '') cybox.utils.set_id_namespace(ns) diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index 47096b5f..872874c4 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -1,16 +1,16 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# stdlib import collections -import warnings import itertools +import warnings + +from mixbox.entities import Entity -# external import cybox import cybox.core import cybox.common -import cybox.utils +from cybox.utils.nsparser import CYBOX_NAMESPACES # internal import stix @@ -71,9 +71,9 @@ def update(self, ns_info): def _parse_collected_classes(self): collected = self._collected_classes - entity_klasses = (stix.Entity, cybox.Entity) + entity_klasses = (stix.Entity, Entity) - # Generator which yields all stix.Entity and cybox.Entity subclasses + # Generator which yields all stix.Entity and mixbox.Entity subclasses # that were collected. entity_subclasses = ( klass for klass in collected if issubclass(klass, entity_klasses) @@ -431,7 +431,7 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): #: Schema locations for namespaces defined by the CybOX language CYBOX_NS_TO_SCHEMALOCATION = dict( - (ns, loc) for ns, _, loc in cybox.utils.nsparser.NS_LIST if loc + (x.name, x.schema_location) for x in CYBOX_NAMESPACES if x.schema_location ) #: Schema locations for namespaces not defined by STIX, but hosted on the STIX website @@ -489,7 +489,7 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): #: Mapping of CybOX namespaces to default aliases DEFAULT_CYBOX_NAMESPACES = dict( - (ns, alias) for (ns, alias, _) in cybox.utils.nsparser.NS_LIST + (x.name, x.prefix) for x in CYBOX_NAMESPACES ) @@ -522,10 +522,10 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): # python-maec support code with ignored(ImportError): - from maec.utils.nsparser import NS_LIST + from maec.utils.nsparser import MAEC_NAMESPACES ns_to_prefix = dict( - (ns, prefix) for (ns, prefix, _) in NS_LIST + (x.name, x.prefix) for x in MAEC_NAMESPACES ) del ns_to_prefix['http://maec.mitre.org/default_vocabularies-1'] @@ -535,7 +535,7 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): ) ns_to_schemalocation = dict( - (ns, schemaloc) for ns, _, schemaloc in NS_LIST if schemaloc + (x.name, x.schema_location) for x in MAEC_NAMESPACES if x.schema_location ) DEFAULT_STIX_NAMESPACES.update(ns_to_prefix) From 17b74c596c9dc246edb7a95562c45cc8433e0ff0 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Wed, 1 Jul 2015 15:11:11 -0500 Subject: [PATCH 151/438] Use idgen from mixbox. --- stix/base.py | 6 +- stix/campaign/__init__.py | 2 +- stix/coa/__init__.py | 2 +- stix/core/stix_package.py | 7 +- stix/exploit_target/__init__.py | 2 +- stix/incident/__init__.py | 2 +- stix/indicator/indicator.py | 2 +- stix/report/__init__.py | 7 +- .../test_mechanisms/openioc_test.py | 10 +- stix/threat_actor/__init__.py | 2 +- stix/ttp/__init__.py | 2 +- stix/utils/__init__.py | 1 - stix/utils/idgen.py | 138 ------------------ stix/utils/nsparser.py | 14 +- 14 files changed, 32 insertions(+), 165 deletions(-) delete mode 100644 stix/utils/idgen.py diff --git a/stix/base.py b/stix/base.py index 468ea3b1..f9ef7ebc 100644 --- a/stix/base.py +++ b/stix/base.py @@ -7,9 +7,9 @@ import itertools import StringIO -# external -from mixbox.cache import Cached +from mixbox import idgen from mixbox.binding_utils import save_encoding +from mixbox.cache import Cached # internal from . import utils @@ -573,7 +573,7 @@ class BaseCoreComponent(Cached, Entity): def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): - self.id_ = id_ or utils.create_id(self._ID_PREFIX) + self.id_ = id_ or idgen.create_id(self._ID_PREFIX) self.idref = idref self.title = title self.description = description diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 52ce9824..451f15ca 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -75,7 +75,7 @@ class Campaign(stix.BaseCoreComponent): Args: id_ (optional): An identifier. If ``None``, a value will be generated - via ``stix.utils.create_id()``. If set, this will unset the + via ``mixbox.idgen.create_id()``. If set, this will unset the ``idref`` property. idref (optional): An identifier reference. If set this will unset the ``id_`` property. diff --git a/stix/coa/__init__.py b/stix/coa/__init__.py index 235a218f..2469d53e 100644 --- a/stix/coa/__init__.py +++ b/stix/coa/__init__.py @@ -32,7 +32,7 @@ class CourseOfAction(stix.BaseCoreComponent): Args: id_ (optional): An identifier. If ``None``, a value will be generated - via ``stix.utils.create_id()``. If set, this will unset the + via ``mixbox.idgen.create_id()``. If set, this will unset the ``idref`` property. idref (optional): An identifier reference. If set this will unset the ``id_`` property. diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index ed074b60..74ce2fa9 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -1,8 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# external +from mixbox import idgen from mixbox.cache import Cached + from cybox.core import Observable, Observables # base @@ -41,7 +42,7 @@ class STIXPackage(Cached, stix.Entity): Args: id_ (optional): An identifier. If ``None``, a value will be generated - via ``stix.utils.create_id()``. If set, this will unset the + via ``mixbox.idgen.create_id()``. If set, this will unset the ``idref`` property. idref: **DEPRECATED** An identifier reference. If set this will unset the ``id_`` property. @@ -72,7 +73,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, ttps=None, campaigns=None, related_packages=None, reports=None): - self.id_ = id_ or stix.utils.create_id("Package") + self.id_ = id_ or idgen.create_id("Package") self.idref = idref self.version = STIXPackage._version self.stix_header = stix_header diff --git a/stix/exploit_target/__init__.py b/stix/exploit_target/__init__.py index 123b0169..bd884578 100644 --- a/stix/exploit_target/__init__.py +++ b/stix/exploit_target/__init__.py @@ -20,7 +20,7 @@ class ExploitTarget(stix.BaseCoreComponent): Args: id_ (optional): An identifier. If ``None``, a value will be generated - via ``stix.utils.create_id()``. If set, this will unset the + via ``mixbox.idgen.create_id()``. If set, this will unset the ``idref`` property. idref (optional): An identifier reference. If set this will unset the ``id_`` property. diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index c13184b3..a814a962 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -27,7 +27,7 @@ class Incident(stix.BaseCoreComponent): Args: id_ (optional): An identifier. If ``None``, a value will be generated - via ``stix.utils.create_id()``. If set, this will unset the + via ``mixbox.idgen.create_id()``. If set, this will unset the ``idref`` property. idref (optional): An identifier reference. If set this will unset the ``id_`` property. diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 17d54c6a..c9c0dd42 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -159,7 +159,7 @@ class Indicator(stix.BaseCoreComponent): Args: id_ (optional): An identifier. If ``None``, a value will be generated - via ``stix.utils.create_id()``. If set, this will unset the + via ``mixbox.idgen.create_id()``. If set, this will unset the ``idref`` property. idref (optional): An identifier reference. If set this will unset the ``id_`` property. diff --git a/stix/report/__init__.py b/stix/report/__init__.py index 90ae5db6..aa6406ac 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -1,8 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# external +from mixbox import idgen from mixbox.cache import Cached + from cybox.core import Observable, Observables # internal @@ -35,7 +36,7 @@ class Report(Cached, stix.Entity): Args: id_ (optional): An identifier. If ``None``, a value will be generated - via ``stix.utils.create_id()``. If set, this will unset the + via ``mixbox.idgen.create_id()``. If set, this will unset the ``idref`` property. idref (optional): An identifier reference. If set this will unset the ``id_`` property. @@ -62,7 +63,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, header=None, observables=None, incidents=None, threat_actors=None, ttps=None, campaigns=None, related_reports=None): - self.id_ = id_ or stix.utils.create_id("Report") + self.id_ = id_ or idgen.create_id("Report") self.idref = idref self.version = self._version self.header = header diff --git a/stix/test/extensions/test_mechanisms/openioc_test.py b/stix/test/extensions/test_mechanisms/openioc_test.py index ffa1ef40..0002dbe0 100644 --- a/stix/test/extensions/test_mechanisms/openioc_test.py +++ b/stix/test/extensions/test_mechanisms/openioc_test.py @@ -5,9 +5,11 @@ import StringIO import lxml + +from mixbox import idgen +from mixbox.namespaces import Namespace import mixbox.xml -from stix import utils from stix.test import EntityTestCase from stix.extensions.test_mechanism.open_ioc_2010_test_mechanism import OpenIOCTestMechanism @@ -118,10 +120,12 @@ class OpenIOCEtreeTests(unittest.TestCase): ) def setUp(self): - utils.set_id_namespace({"http://schemas.mandiant.com/2010/ioc": "mandiant-openioc"}) + ioc_ns = Namespace("http://schemas.mandiant.com/2010/ioc", + "mandiant-openioc", '') + idgen.set_id_namespace(ioc_ns) def tearDown(self): - utils.set_id_namespace(utils.EXAMPLE_NAMESPACE) + idgen.set_id_namespace(idgen.EXAMPLE_NAMESPACE) def _test_xml(self, obj): xml = obj.to_xml() diff --git a/stix/threat_actor/__init__.py b/stix/threat_actor/__init__.py index 63e77f95..95e12674 100644 --- a/stix/threat_actor/__init__.py +++ b/stix/threat_actor/__init__.py @@ -42,7 +42,7 @@ class ThreatActor(stix.BaseCoreComponent): Args: id_ (optional): An identifier. If ``None``, a value will be generated - via ``stix.utils.create_id()``. If set, this will unset the + via ``mixbox.idgen.create_id()``. If set, this will unset the ``idref`` property. idref (optional): An identifier reference. If set this will unset the ``id_`` property. diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index 9534a446..c6bfc2c3 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -19,7 +19,7 @@ class TTP(stix.BaseCoreComponent): Args: id_ (optional): An identifier. If ``None``, a value will be generated - via ``stix.utils.create_id()``. If set, this will unset the + via ``mixbox.idgen.create_id()``. If set, this will unset the ``idref`` property. idref (optional): An identifier reference. If set this will unset the ``id_`` property. diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index 1c2016c4..8f2276a6 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -378,6 +378,5 @@ def remove_entries(d, keys): # Namespace flattening from .nsparser import * # noqa from .dates import * # noqa -from .idgen import * # noqa from .nsparser import * # noqa from .walk import * # noqa diff --git a/stix/utils/idgen.py b/stix/utils/idgen.py deleted file mode 100644 index cf3c915e..00000000 --- a/stix/utils/idgen.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. -# See LICENSE.txt for complete terms. - -import uuid -import contextlib - -from mixbox.namespaces import Namespace -import cybox.utils - - -#: Default "example" namespace used for identifiers when no other namespace is -#: defined. -EXAMPLE_NAMESPACE = {'http://example.com': 'example'} - - -class InvalidMethodError(ValueError): - def __init__(self, method): - ValueError.__init__(self, "invalid method: %s" % method) - - -class IDGenerator(object): - """Utility class for generating STIX ids""" - METHOD_UUID = 1 - METHOD_INT = 2 - - METHODS = (METHOD_UUID, METHOD_INT,) - - def __init__(self, namespace=None, method=METHOD_UUID): - self.namespace = namespace or EXAMPLE_NAMESPACE - self.method = method - self.next_int = 1 - - @property - def namespace(self): - return self._namespace - - @namespace.setter - def namespace(self, value): - if not isinstance(value, dict): - raise ValueError("Must be a dictionary: ex {'http://example.com' : 'example'}") - - if len(value) != 1: - raise ValueError("Provided dictionary must have at most one entry") - - self._namespace = value - - @property - def method(self): - return self._method - - @method.setter - def method(self, value): - if value not in IDGenerator.METHODS: - raise InvalidMethodError("invalid method: %s" % value) - self._method = value - - def create_id(self, prefix="guid"): - """Create an ID. - - Note that if `prefix` is not provided, it will be `quid`, even if the - `method` is `METHOD_INT`. - """ - if self.method == IDGenerator.METHOD_UUID: - id_ = str(uuid.uuid4()) - elif self.method == IDGenerator.METHOD_INT: - id_ = self.next_int - self.next_int += 1 - else: - raise InvalidMethodError(self.method) - - ns_prefix = next(self.namespace.itervalues()) - return "%s:%s-%s" % (ns_prefix, prefix, id_) - - -#: Singleton instance within this module. It is lazily instantiated, so simply -#: importing the utils module will not create the object. -__generator = None - - -def _get_generator(): - """Return the `stix.utils` module's generator object. - - Only under rare circumstances should this function be called by external - code. More likely, external code should initialize its own IDGenerator or - use the `set_id_namespace`, `set_id_method`, or `create_id` functions of - the `stix.utils` module. - """ - global __generator - if not __generator: - __generator = IDGenerator() - return __generator - - -def _set_cybox_namespace(namespace): - uri = namespace.iterkeys().next() - prefix = namespace.itervalues().next() - - ns = Namespace(uri, prefix, '') - cybox.utils.set_id_namespace(ns) - - -def set_id_namespace(namespace): - """ Set the namespace for the module-level ID Generator""" - _get_generator().namespace = namespace - _set_cybox_namespace(namespace) - - -def set_id_method(method): - """ Set the method for the module-level ID Generator""" - _get_generator().method = method - - -def get_id_namespace(): - """Return the namespace associated with generated ids""" - return next(_get_generator().namespace.iterkeys()) - - -def get_id_namespace_alias(): - """Returns the namespace alias assoicated with generated ids""" - return next(_get_generator().namespace.itervalues()) - - -def create_id(prefix=None): - """ Create an ID using the module-level ID Generator""" - if not prefix: - return _get_generator().create_id() - else: - return _get_generator().create_id(prefix) - - -@contextlib.contextmanager -def temp_id_namespace(namespace): - try: - saved_id_namespace = {get_id_namespace(): get_id_namespace_alias()} - set_id_namespace(namespace) - yield - finally: - set_id_namespace(saved_id_namespace) diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index 872874c4..2804482f 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -5,6 +5,7 @@ import itertools import warnings +from mixbox import idgen from mixbox.entities import Entity import cybox @@ -16,7 +17,7 @@ import stix # relative -from . import ignored, idgen +from . import ignored from .walk import iterwalk @@ -122,20 +123,19 @@ def _fix_example_namespace(self): 'http://example.com' by removing the former. """ - ex_api_ns = idgen.EXAMPLE_NAMESPACE.keys()[0] - ex_prefix = 'example' # Example ns prefix - id_alias = idgen.get_id_namespace_alias() + example_prefix = 'example' # Example ns prefix + idgen_prefix = idgen.get_id_namespace_prefix() # If the ID namespace alias doesn't match the example alias, return. - if id_alias != ex_prefix: + if idgen_prefix != example_prefix: return # If the example namespace prefix isn't in the parsed namespace # prefixes, return. - if ex_prefix not in self._input_namespaces: + if example_prefix not in self._input_namespaces: return - self._input_namespaces[ex_prefix] = ex_api_ns + self._input_namespaces[example_prefix] = idgen.EXAMPLE_NAMESPACE.name def _check_namespaces(self, ns_dict): """Check that all the prefixes in `ns_dict` are mapped to only From 007f2fbde34e4323ebe684fd35e909f1fcdfc6cf Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Wed, 1 Jul 2015 17:47:31 -0400 Subject: [PATCH 152/438] Fixes for issue #252, adding additional fields to Incident --- stix/incident/__init__.py | 31 +++++++++++++++++++++++++++++++ stix/test/incident_test.py | 2 ++ 2 files changed, 33 insertions(+) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index c13184b3..0804ecf2 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -79,6 +79,8 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, description self.coa_taken = None self.coa_requested = None self.history = History() + self.contacts = None + self.url = None @property @@ -454,6 +456,27 @@ def related_packages(self, value): def add_related_package(self, value): self.related_packages.append(value) + @property + def contacts(self): + return self.contacts + + @contacts.setter + def contacts(self, contacts_list): + self.contacts = contacts_list + + def add_contact(self, contact): + if self.contacts is None: + self.contacts = _InformationSources() + self.contacts.append(contact) + + @property + def url(self): + return self.url + + @url.setter + def url(self, value): + self.url = value + def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() @@ -506,6 +529,10 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.History = self.history.to_obj(ns_info=ns_info) if self.related_packages: return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) + if self.contacts: + return_obj.Contact = self.contacts.to_obj(ns_info=ns_info) + if self.url: + return_obj.URL = self.url return return_obj @@ -543,6 +570,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.impact_assessment = ImpactAssessment.from_obj(obj.Impact_Assessment) return_obj.security_compromise = VocabString.from_obj(obj.Security_Compromise) return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) + return_obj.contacts = _InformationSources.from_obj(obj.Contact) + return_obj.url = obj.URL return return_obj @@ -583,6 +612,8 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.status = VocabString.from_dict(get('status')) return_obj.history = History.from_dict(get('history')) return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) + return_obj.contacts = _InformationSources.from_dict(get('contacts')) + return_obj.url = get('url') return return_obj diff --git a/stix/test/incident_test.py b/stix/test/incident_test.py index c4e26440..4ba9a3a8 100644 --- a/stix/test/incident_test.py +++ b/stix/test/incident_test.py @@ -468,6 +468,8 @@ class IncidentTest(EntityTestCase, unittest.TestCase): 'discovery_methods': DiscoveryMethodsTests._full_dict, 'confidence': confidence_test.ConfidenceTests._full_dict, 'related_packages': related_test.RelatedPackageRefsTests._full_dict, + 'contacts': InformationSourcesTest._full_dict, + 'url': 'http://www.example.com/' } def test_parse_category(self): From c6ea95c74ef926582cd9090029be1fb237a432e7 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Thu, 2 Jul 2015 09:45:51 -0500 Subject: [PATCH 153/438] Remove idgen documentation since it no longer is a stix module. --- docs/api/utils/idgen.rst | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 docs/api/utils/idgen.rst diff --git a/docs/api/utils/idgen.rst b/docs/api/utils/idgen.rst deleted file mode 100644 index 99fbedc6..00000000 --- a/docs/api/utils/idgen.rst +++ /dev/null @@ -1,37 +0,0 @@ -:mod:`stix.utils.idgen` Module -============================== - -.. module:: stix.utils.idgen - -Classes -------- - -.. autoclass:: IDGenerator - :show-inheritance: - :members: - -.. autoclass:: InvalidMethodError - :show-inheritance: - :members: - -Functions ---------- - -.. autofunction:: _get_generator - -.. autofunction:: set_id_namespace - -.. autofunction:: set_id_method - -.. autofunction:: get_id_namespace - -.. autofunction:: get_id_namespace_alias - -.. autofunction:: create_id - -Constants ---------- - -.. autodata:: __generator - -.. autodata:: EXAMPLE_NAMESPACE From 99f5369b2578152b6df47343de7ac27250634f5e Mon Sep 17 00:00:00 2001 From: Greg Back Date: Thu, 2 Jul 2015 09:46:15 -0500 Subject: [PATCH 154/438] Bump required dependency versions. --- setup.py | 6 +++--- tox.ini | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index e79340d3..b5c1bcdc 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ def get_version(): 'test': [ 'nose==1.3.0', 'tox==1.6.1', - 'maec>=4.1.0.13.dev0,<4.1.1.0', + 'maec>=4.1.0.13.dev1,<4.1.1.0', ], } @@ -39,8 +39,8 @@ def get_version(): install_requires = [ 'lxml>=2.3', 'python-dateutil', - 'cybox>=2.1.0.12.dev0,<2.1.1.0', - 'mixbox', + 'cybox>=2.1.0.12.dev1,<2.1.1.0', + 'mixbox>=0.0.8', ] diff --git a/tox.ini b/tox.ini index 042a7b3a..249050d7 100644 --- a/tox.ini +++ b/tox.ini @@ -19,7 +19,7 @@ commands = deps = lxml==2.3 python-dateutil==1.4.1 - mixbox - cybox>=2.1.0.12.dev0 - maec>=4.1.0.13.dev0 + mixbox>=0.0.8 + cybox>=2.1.0.12.dev1 + maec>=4.1.0.13.dev1 nose From c3521424f35e45b5993c8bf1e4d0eb2764dd76c7 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Thu, 2 Jul 2015 09:49:11 -0500 Subject: [PATCH 155/438] Bump version to 1.2.0.1.dev1 --- stix/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/version.py b/stix/version.py index eb0c11b3..e7f685eb 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.1.dev0" +__version__ = "1.2.0.1.dev1" From 184a3ac6be18b0dea1c5a996d4b9f2ec28fbfe3f Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Wed, 1 Jul 2015 17:47:31 -0400 Subject: [PATCH 156/438] Fixes for issue #252, adding additional fields to Incident --- stix/incident/__init__.py | 31 +++++++++++++++++++++++++++++++ stix/test/incident_test.py | 2 ++ 2 files changed, 33 insertions(+) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index a814a962..dc503a4e 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -79,6 +79,8 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, description self.coa_taken = None self.coa_requested = None self.history = History() + self.contacts = None + self.url = None @property @@ -454,6 +456,27 @@ def related_packages(self, value): def add_related_package(self, value): self.related_packages.append(value) + @property + def contacts(self): + return self.contacts + + @contacts.setter + def contacts(self, contacts_list): + self.contacts = contacts_list + + def add_contact(self, contact): + if self.contacts is None: + self.contacts = _InformationSources() + self.contacts.append(contact) + + @property + def url(self): + return self.url + + @url.setter + def url(self, value): + self.url = value + def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() @@ -506,6 +529,10 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.History = self.history.to_obj(ns_info=ns_info) if self.related_packages: return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) + if self.contacts: + return_obj.Contact = self.contacts.to_obj(ns_info=ns_info) + if self.url: + return_obj.URL = self.url return return_obj @@ -543,6 +570,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.impact_assessment = ImpactAssessment.from_obj(obj.Impact_Assessment) return_obj.security_compromise = VocabString.from_obj(obj.Security_Compromise) return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) + return_obj.contacts = _InformationSources.from_obj(obj.Contact) + return_obj.url = obj.URL return return_obj @@ -583,6 +612,8 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.status = VocabString.from_dict(get('status')) return_obj.history = History.from_dict(get('history')) return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) + return_obj.contacts = _InformationSources.from_dict(get('contacts')) + return_obj.url = get('url') return return_obj diff --git a/stix/test/incident_test.py b/stix/test/incident_test.py index c4e26440..4ba9a3a8 100644 --- a/stix/test/incident_test.py +++ b/stix/test/incident_test.py @@ -468,6 +468,8 @@ class IncidentTest(EntityTestCase, unittest.TestCase): 'discovery_methods': DiscoveryMethodsTests._full_dict, 'confidence': confidence_test.ConfidenceTests._full_dict, 'related_packages': related_test.RelatedPackageRefsTests._full_dict, + 'contacts': InformationSourcesTest._full_dict, + 'url': 'http://www.example.com/' } def test_parse_category(self): From 338105cb24906d670b57b2cee3da8f96ab116f06 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Thu, 2 Jul 2015 18:18:42 -0400 Subject: [PATCH 157/438] Fixed incident attr names 'url' and 'contacts' to not conflict with property names, by adding a leading underscore. This prevents infinite recursion inside the property getter/setter implementations. --- stix/incident/__init__.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index dc503a4e..7f9abdb5 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -79,8 +79,8 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, description self.coa_taken = None self.coa_requested = None self.history = History() - self.contacts = None - self.url = None + self._contacts = None + self._url = None @property @@ -458,24 +458,24 @@ def add_related_package(self, value): @property def contacts(self): - return self.contacts + return self._contacts @contacts.setter def contacts(self, contacts_list): - self.contacts = contacts_list + self._contacts = contacts_list def add_contact(self, contact): - if self.contacts is None: - self.contacts = _InformationSources() - self.contacts.append(contact) + if self._contacts is None: + self._contacts = _InformationSources() + self._contacts.append(contact) @property def url(self): - return self.url + return self._url @url.setter def url(self, value): - self.url = value + self._url = value def to_obj(self, return_obj=None, ns_info=None): if not return_obj: From 736a163c1729d412d6d7fa7aa074729b723c9038 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Sun, 5 Jul 2015 22:11:25 -0400 Subject: [PATCH 158/438] Incident's contacts setter now works with any iterable. --- stix/incident/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index 7f9abdb5..9c0d94bd 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -462,7 +462,7 @@ def contacts(self): @contacts.setter def contacts(self, contacts_list): - self._contacts = contacts_list + self._contacts = _InformationSources(contacts_list) def add_contact(self, contact): if self._contacts is None: From daf800ececa6833980e3108128c85de37b707189 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Tue, 7 Jul 2015 11:45:29 -0400 Subject: [PATCH 159/438] Made STIXPackage's version property read-only. This induced changes in other methods which tried to set it via the property descriptor. Now those methods just set self._version directly. Also removed a test case for setting STIXPackage versions. It is irrelevant if version is read-only. --- stix/core/stix_package.py | 15 +++------------ stix/test/core/stix_package_test.py | 16 ---------------- 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 74ce2fa9..79061ef5 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -75,7 +75,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, self.id_ = id_ or idgen.create_id("Package") self.idref = idref - self.version = STIXPackage._version + self._version = STIXPackage._version self.stix_header = stix_header self.campaigns = campaigns self.courses_of_action = courses_of_action @@ -149,15 +149,6 @@ def version(self): """ return self._version - @version.setter - def version(self, value): - if not value: - self._version = None - else: - utils.check_version(self._ALL_VERSIONS, value) - self._version = value - - @property def stix_header(self): """The :class:`.STIXHeader` section of the STIX Package. @@ -462,7 +453,7 @@ def from_obj(cls, obj, return_obj=None): # Don't overwrite this unless passed in. if obj.version: - return_obj.version = obj.version + return_obj._version = obj.version return return_obj @@ -475,7 +466,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.id_ = get('id') return_obj.idref = get('idref') return_obj.timestamp = get('timestamp') - return_obj.version = get('version', cls._version) + return_obj._version = get('version', cls._version) return_obj.stix_header = STIXHeader.from_dict(get('stix_header')) return_obj.campaigns = Campaigns.from_dict(get('campaigns')) return_obj.courses_of_action = CoursesOfAction.from_dict(get('courses_of_action')) diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index 2ec508b8..02d1d1a1 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -187,22 +187,6 @@ def test_related_package_idref_deprecation(self): package = core.STIXPackage() package.add_related_package(core.STIXPackage(idref='foo')) - def test_version(self): - """Tests that setting the version property of a STIXPackage does - not affect the serialized versions. - - """ - p = core.STIXPackage() - p.version = "1.0" # old version - - s = p.to_xml() - sio = StringIO.StringIO(s) - - # Reparse the package - p = core.STIXPackage.from_xml(sio) - - self.assertEqual(p.version, core.STIXPackage._version) - if __name__ == "__main__": unittest.main() From 2bb26f4f3f9f16ec2e8f0098da0907585667e567 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Wed, 15 Jul 2015 11:39:45 -0500 Subject: [PATCH 160/438] Add tests for STIX entity parser. --- stix/test/utils/parser_test.py | 77 ++++++++++++++++++++++++++++++++++ stix/utils/__init__.py | 2 +- 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 stix/test/utils/parser_test.py diff --git a/stix/test/utils/parser_test.py b/stix/test/utils/parser_test.py new file mode 100644 index 00000000..e54d5fb9 --- /dev/null +++ b/stix/test/utils/parser_test.py @@ -0,0 +1,77 @@ +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +from StringIO import StringIO +import unittest + +from stix.utils import (EntityParser, UnknownVersionError, + UnsupportedRootElementError, UnsupportedVersionError) + + +class ParserTests(unittest.TestCase): + + def test_valid(self): + valid = """ + + + """ + + parser = EntityParser() + package = parser.parse_xml(StringIO(valid)) + + self.assertEqual("example:Package-1", package.id_) + + def test_wrong_root_element(self): + wrong_root = """ + + + """ + + parser = EntityParser() + self.assertRaises(UnsupportedRootElementError, + parser.parse_xml, StringIO(wrong_root)) + + package = parser.parse_xml(StringIO(wrong_root), + check_root=False) + + self.assertEqual("example:Package-1", package.id_) + self.assertEqual("1.2", package.version) + + def test_wrong_version(self): + wrong_version = """ + + + """ + + parser = EntityParser() + self.assertRaises(UnsupportedVersionError, + parser.parse_xml, StringIO(wrong_version)) + + package = parser.parse_xml(StringIO(wrong_version), + check_version=False) + + self.assertEqual("example:Package-1", package.id_) + self.assertEqual("17.8.9", package.version) + + def test_missing_version(self): + missing_version = """ + + + """ + + parser = EntityParser() + self.assertRaises(UnknownVersionError, + parser.parse_xml, StringIO(missing_version)) + + package = parser.parse_xml(StringIO(missing_version), + check_version=False) + + self.assertEqual("example:Package-1", package.id_) + + +if __name__ == "__main__": + unittest.main() diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index 8f2276a6..869c030b 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -378,5 +378,5 @@ def remove_entries(d, keys): # Namespace flattening from .nsparser import * # noqa from .dates import * # noqa -from .nsparser import * # noqa +from .parser import * # noqa from .walk import * # noqa From a7dce805f93546a044d9bc935bc2367bafd6d230 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Wed, 15 Jul 2015 14:23:07 -0500 Subject: [PATCH 161/438] Use mixbox parser. --- stix/utils/parser.py | 195 ++++--------------------------------------- 1 file changed, 14 insertions(+), 181 deletions(-) diff --git a/stix/utils/parser.py b/stix/utils/parser.py index 62c80fbb..9001b676 100644 --- a/stix/utils/parser.py +++ b/stix/utils/parser.py @@ -1,195 +1,28 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -from distutils.version import StrictVersion - -import mixbox.xml - import stix -import stix.xmlconst as xmlconst -from . import ignored - - -class UnknownVersionError(Exception): - """Raised when a parsed STIX document contains no version information.""" - pass - - -class UnsupportedVersionError(Exception): - """Raised when a parsed STIX document contains a version that is - not supported by this verison of python-stix. - - """ - def __init__(self, message, expected=None, found=None): - super(UnsupportedVersionError, self).__init__(message) - self.expected = expected - self.found = found - - -class UnsupportedRootElementError(Exception): - """Raised when an input STIX document does not contain a supported root- - level element. - - """ - def __init__(self, message, expected=None, found=None): - super(UnsupportedRootElementError, self).__init__(message) - self.expected = expected - self.found = found +from stix.xmlconst import TAG_STIX_PACKAGE +import mixbox.parser +# Import these from mixbox for backward compatibility +from mixbox.parser import (UnknownVersionError, UnsupportedVersionError, + UnsupportedRootElementError) # Alias for backwards compatibility UnsupportedRootElement = UnsupportedRootElementError -def get_document_version(doc): - root = mixbox.xml.get_etree_root(doc) - - if 'version' in root.attrib: - return root.attrib['version'] - - raise UnknownVersionError( - "Unable to determine the version if the input STIX document: no " - "version attribute found on the root element." - ) - - -def root_tag(doc): - root = mixbox.xml.get_etree_root(doc) - return root.tag - - -def is_stix(doc): - root = root_tag(doc) - return root == xmlconst.TAG_STIX_PACKAGE - - -class EntityParser(object): - def __init__(self): - pass - - def _check_version(self, tree): - """Returns true of the instance document @tree is a version supported - by python-stix. - - """ - document_version = get_document_version(tree) - supported = stix.supported_stix_version() - - sv_doc_version = StrictVersion(document_version) - sv_api_versions = [StrictVersion(x) for x in supported] - - if sv_doc_version in sv_api_versions: - return - - error = ( - "Your python-stix library supports STIX versions: %s. Document " - "version was %s" % (supported, document_version) - ) - - raise UnsupportedVersionError( - message=error, - expected=supported, - found=document_version - ) - - def _check_root(self, tree): - if is_stix(tree): - return - - error = "Document root element must be an instance of STIX_Package" - raise UnsupportedRootElement( - message=error, - expected=xmlconst.TAG_STIX_PACKAGE, - found=root_tag(tree), - ) - - def _apply_input_namespaces(self, tree, entity): - root = mixbox.xml.get_etree_root(tree) - entity.__input_namespaces__ = dict(root.nsmap.iteritems()) - - def _apply_input_schemalocations(self, tree, entity): - """Attaches an __input_schemalocations__ dictionary to the input entity. - - Args: - tree: The input etree instance - entity: The entity to attach the schemlocation dictionary to - - """ - root = mixbox.xml.get_etree_root(tree) - - with ignored(KeyError): - pairs = mixbox.xml.get_schemaloc_pairs(root) - entity.__input_schemalocations__ = dict(pairs) - - def parse_xml_to_obj(self, xml_file, check_version=True, check_root=True, - encoding=None): - """Creates a STIX binding object from the supplied xml file. - - Args: - xml_file: A filename/path or a file-like object representing a STIX - instance document - check_version: Inspect the version before parsing. - check_root: Inspect the root element before parsing. - encoding: The character encoding of the input `xml_file`. - - Raises: - .UnknownVersionError: If `check_version` is ``True`` and `xml_file` - does not contain STIX version information. - .UnsupportedVersionError: If `check_version` is ``False`` and - `xml_file` contains an unsupported STIX version. - .UnsupportedRootElement: If `check_root` is ``True`` and `xml_file` - contains an invalid root element. - - """ - root = mixbox.xml.get_etree_root(xml_file, encoding=encoding) - - if check_version: - self._check_version(root) - - if check_root: - self._check_root(root) - - import stix.bindings.stix_core as stix_core_binding - stix_package_obj = stix_core_binding.STIXType().factory() - stix_package_obj.build(root) - - return stix_package_obj - - def parse_xml(self, xml_file, check_version=True, check_root=True, - encoding=None): - """Creates a python-stix STIXPackage object from the supplied xml_file. - - Args: - xml_file: A filename/path or a file-like object representing a STIX - instance document - check_version: Inspect the version before parsing. - check_root: Inspect the root element before parsing. - encoding: The character encoding of the input `xml_file`. If - ``None``, an attempt will be made to determine the input - character encoding. +class EntityParser(mixbox.parser.EntityParser): - Raises: - .UnknownVersionError: If `check_version` is ``True`` and `xml_file` - does not contain STIX version information. - .UnsupportedVersionError: If `check_version` is ``False`` and - `xml_file` contains an unsupported STIX version. - .UnsupportedRootElement: If `check_root` is ``True`` and `xml_file` - contains an invalid root element. + def supported_tags(self): + return [TAG_STIX_PACKAGE] - """ - root = mixbox.xml.get_etree_root(xml_file, encoding=encoding) + def get_version(self, root): + return root.attrib.get('version') - stix_package_obj = self.parse_xml_to_obj( - xml_file=root, - check_version=check_version, - check_root=check_root, - encoding=encoding - ) - - from stix.core import STIXPackage # resolve circular dependencies - stix_package = STIXPackage().from_obj(stix_package_obj) + def supported_versions(self, tag=TAG_STIX_PACKAGE): + return stix.supported_stix_version() - self._apply_input_namespaces(root, stix_package) - self._apply_input_schemalocations(root, stix_package) - - return stix_package + def get_entity_class(self, tag=TAG_STIX_PACKAGE): + return stix.core.STIXPackage From 8618b0f77cbabceb332e53f0c9020ab89316869d Mon Sep 17 00:00:00 2001 From: Greg Back Date: Wed, 15 Jul 2015 14:23:14 -0500 Subject: [PATCH 162/438] Bump required version of mixbox. --- setup.py | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index b5c1bcdc..3e3fdb9a 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ def get_version(): 'lxml>=2.3', 'python-dateutil', 'cybox>=2.1.0.12.dev1,<2.1.1.0', - 'mixbox>=0.0.8', + 'mixbox>=0.0.10', ] diff --git a/tox.ini b/tox.ini index 249050d7..250fe85d 100644 --- a/tox.ini +++ b/tox.ini @@ -19,7 +19,7 @@ commands = deps = lxml==2.3 python-dateutil==1.4.1 - mixbox>=0.0.8 + mixbox>=0.0.10 cybox>=2.1.0.12.dev1 maec>=4.1.0.13.dev1 nose From acfbd64617453dce89baf8c4fecbb94320b2c697 Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 30 Jul 2015 15:06:42 -0400 Subject: [PATCH 163/438] WIP: more TypedFields work --- stix/base.py | 44 +++++-- stix/campaign/__init__.py | 38 ++---- stix/common/information_source.py | 110 +++--------------- stix/common/related.py | 6 + stix/common/structured_text.py | 57 +++++---- .../structured_coa/generic_structured_coa.py | 4 +- stix/test/__init__.py | 6 +- stix/test/common/related_test.py | 13 ++- 8 files changed, 107 insertions(+), 171 deletions(-) diff --git a/stix/base.py b/stix/base.py index 41f37346..246579be 100644 --- a/stix/base.py +++ b/stix/base.py @@ -81,7 +81,7 @@ def _get_vars(cls): import inspect var_list = [] for (name, obj) in inspect.getmembers(cls, inspect.isdatadescriptor): - print name + " " + str(type(obj)) + " " + str(obj.__class__) + #print name + " " + str(type(obj)) + " " + str(obj.__class__) if isinstance(obj, fields.TypedField): var_list.append(obj) @@ -141,9 +141,9 @@ def _objectify(value, return_obj, ns_info): If `value` is an Entity, call to_obj() on it. Otherwise, return it unmodified. """ - if isinstance(value, Entity): + try: return value.to_obj(return_obj=return_obj, ns_info=ns_info) - else: + except: return value self._collect_ns_info(ns_info) @@ -156,8 +156,8 @@ def _objectify(value, return_obj, ns_info): break vars.update(klass.__dict__.iteritems()) - print "vars", vars - print "self", self.__dict__ + #print "vars", vars + #print "self", self.__dict__ for name, field in vars.iteritems(): if isinstance(field, fields.TypedField): @@ -184,12 +184,15 @@ def _finalize_obj(self, entity_obj): pass @classmethod - def from_obj(cls, cls_obj=None): + def from_obj(cls, cls_obj=None, return_obj=None): """Create an object from a binding object""" if not cls_obj: return None - entity = cls() + if return_obj is None: + entity = cls() + else: + entity = return_obj for field in cls._get_vars(): val = getattr(cls_obj, field.name) @@ -335,9 +338,9 @@ def _dictify(value): If `value` is an Entity, call to_dict() on it. Otherwise, return it unmodified. """ - if isinstance(value, Entity): + try: return value.to_dict() - else: + except: return value entity_dict = { } @@ -382,12 +385,15 @@ def _finalize_dict(self, entity_dict): pass @classmethod - def from_dict(cls, cls_dict=None): + def from_dict(cls, cls_dict=None, return_obj=None): """Convert from dict representation to object representation.""" if cls_dict is None: return None - entity = cls() + if return_obj is None: + entity = cls() + else: + entity = return_obj # Shortcut if an actual dict is not provided: if not isinstance(cls_dict, dict): @@ -566,6 +572,7 @@ def from_obj(cls, obj, return_obj=None, contained_type=None, @classmethod def from_list(cls, list_repr, return_obj=None, contained_type=None): + from stix.common.related import GenericRelationshipList if not utils.is_sequence(list_repr): return None @@ -575,6 +582,18 @@ def from_list(cls, list_repr, return_obj=None, contained_type=None): if not contained_type: contained_type = cls._contained_type + print list_repr.__class__, isinstance(list_repr, GenericRelationshipList) + + # GenericRelationshipList is not actually a list; it's dict with a list member + if issubclass(cls, GenericRelationshipList): + return cls.from_dict(list_repr, return_obj) + + try: + list_repr = list_repr[getattr(cls, '_inner_name')] + except: + pass + + return_obj.extend(contained_type.from_dict(x) for x in list_repr) return return_obj @@ -931,7 +950,7 @@ def add_short_description(self, description): """ self.short_descriptions.add(description) - +""" @classmethod def from_obj(cls, obj, return_obj=None): from stix.common import StructuredTextList, InformationSource @@ -1016,3 +1035,4 @@ def from_dict(cls, d, return_obj=None): def to_dict(self): return super(BaseCoreComponent, self).to_dict() +""" diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 52ce9824..8925d163 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -10,7 +10,8 @@ ) from stix.common import vocabs import stix.bindings.campaign as campaign_binding - +from stix.common.structured_text import StructuredTextList, StructuredTextListField +from stix.base import ElementField, AttributeField class AssociatedCampaigns(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" @@ -94,6 +95,12 @@ class Campaign(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'campaign' + descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") + activity = ElementField("Activity", multiple=True) + associated_campaigns = ElementField("Associated_Campaigns", AssociatedCampaigns) + attribution = ElementField("Attribution", multiple=True) + #confidence = ElementField("Confidence") + def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): @@ -112,10 +119,9 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.related_ttps = RelatedTTPs() self.related_incidents = RelatedIncidents() self.related_indicators = RelatedIndicators() - self.attribution = _AttributionList() - self.associated_campaigns = AssociatedCampaigns() + #self.attribution = _AttributionList() self.confidence = None - self.activity = _Activities() + #self.activity = _Activities() self.related_packages = RelatedPackageRefs() @property @@ -140,17 +146,7 @@ def intended_effects(self, value): def add_intended_effect(self, value): self.intended_effects.append(value) - @property - def activity(self): - """A collection of :class:`.Activity` objects. This behaves like a - ``MutableSequence`` type. - - """ - return self._activity - @activity.setter - def activity(self, value): - self._activity = _Activities(value) def add_activity(self, value): """Adds an :class:`.Activity` object to the :attr:`activity` @@ -173,19 +169,9 @@ def status(self): def status(self, value): self._set_vocab(vocabs.CampaignStatus, status=value) - @property - def attribution(self): - """A collection of :class:`.Attribution` objects. This behaves like a - ``MutableSequence`` type. - """ - return self._attribution - @attribution.setter - def attribution(self, value): - self._attribution = _AttributionList(value) - - def to_obj(self, return_obj=None, ns_info=None): +""" def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() @@ -280,7 +266,7 @@ def from_dict(cls, dict_repr, return_obj=None): RelatedPackageRefs.from_dict(get('related_packages')) return return_obj - +""" # Not Actual STIX Types! class _AttributionList(stix.TypedList): diff --git a/stix/common/information_source.py b/stix/common/information_source.py index a35b5f19..01515015 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -14,8 +14,9 @@ # relative from . import vocabs, VocabString from .identity import Identity -from .structured_text import StructuredTextList +from .structured_text import StructuredTextList, StructuredTextListField from stix.base import ElementField +from mixbox.entities import Entity class InformationSource(stix.Entity): _binding = stix_common_binding @@ -23,25 +24,25 @@ class InformationSource(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' identity = ElementField("Identity", Identity) + descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") + contributing_sources = ElementField("Contributing_Sources") + time = ElementField("Time", cybox.common.Time) + + @classmethod + def initClassFields(cls): + cls.contributing_sources.type_ = ContributingSources def __init__(self, description=None, identity=None, time=None, tools=None, contributing_sources=None, references=None): - self._fields = {} - self.description = description + super(InformationSource, self).__init__() + #self._fields = {} self.identity = identity + self.description = description self.contributing_sources = contributing_sources self.time = time self.tools = tools self.references = references self.roles = None - @property - def contributing_sources(self): - return self._contributing_sources - - @contributing_sources.setter - def contributing_sources(self, value): - self._contributing_sources = ContributingSources(value) - def add_contributing_source(self, value): self.contributing_sources.append(value) @@ -67,53 +68,6 @@ def add_reference(self, value): # TODO: Check if it's a valid URI? self.references.append(value) - @property - def description(self): - """A single description about the contents or purpose of this object. - - Default Value: ``None`` - - Note: - If this object has more than one description set, this will return - the description with the lowest ordinality value. - - Returns: - An instance of - :class:`.StructuredText` - - """ - return next(iter(self.descriptions), None) - - @description.setter - def description(self, value): - self.descriptions = value - - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) def add_description(self, description): """Adds a description to the ``descriptions`` collection. @@ -123,14 +77,6 @@ def add_description(self, description): """ self.descriptions.add(description) - @property - def time(self): - return self._time - - @time.setter - def time(self, value): - self._set_var(cybox.common.Time, try_cast=False, time=value) - @property def tools(self): return self._tools @@ -197,35 +143,6 @@ def from_obj(cls, obj, return_obj=None): return return_obj - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - # To resolve circular dependency - # TODO: Improve how this extension is handled. - - if not dict_repr: - return None - if not return_obj: - return_obj = cls() - - get = dict_repr.get - return_obj.description = StructuredTextList.from_dict(get('description')) - return_obj.references = get('references') - return_obj.contributing_sources = ContributingSources.from_dict(get('contributing_sources')) - return_obj.identity = Identity.from_dict(get('identity')) - return_obj.time = cybox.common.Time.from_dict(get('time')) - return_obj.tools = cybox.common.ToolInformationList.from_list(get('tools')) - return_obj.roles = _Roles.from_dict(get('roles')) - - return return_obj - - def to_dict(self): - #for i in range(10): print i - print "TO DICT INFORMATION_SOURCE CALLED" - print self.description - ret = super(InformationSource, self).to_dict() - print ret - print utils.to_dict(self) - return ret class ContributingSources(stix.EntityList): _namespace = "http://stix.mitre.org/common-1" @@ -242,3 +159,6 @@ class _Roles(stix.TypedList): def _fix_value(self, value): return vocabs.InformationSourceRole(value) + +# finally, initialize field types that would be circular dependencies +InformationSource.initClassFields() diff --git a/stix/common/related.py b/stix/common/related.py index 24f08f85..52ca5860 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -91,6 +91,8 @@ def from_dict(cls, dict_repr, return_obj=None): if not return_obj: return_obj = cls() + print "DICT", dict_repr + return_obj.confidence = Confidence.from_dict(dict_repr.get('confidence')) return_obj.information_source = InformationSource.from_dict(dict_repr.get('information_source')) return_obj.relationship = VocabString.from_dict(dict_repr.get('relationship')) @@ -204,6 +206,10 @@ def __nonzero__(self): super(GenericRelationshipList, self).__nonzero__() or bool(self.scope) ) + + #def __iter__(self): + # print "ITER", self._inner_name, len(self) + # return getattr(self, self._inner_name) @property def scope(self): diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 6db1fa16..fef4a332 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -8,13 +8,24 @@ import stix import stix.utils as utils import stix.bindings.stix_common as stix_common_binding - +from mixbox.fields import TypedField from stix.base import AttributeField, ElementField #: Default ordinality value for StructuredText. DEFAULT_ORDINALITY = 1 +class StructuredTextListField(ElementField): + + @TypedField.attr_name.getter + def attr_name(self): + return "descriptions" + + @TypedField.key_name.getter + def key_name(self): + return "description" + + class StructuredText(stix.Entity): """Used for storing descriptive text elements. @@ -29,40 +40,17 @@ class StructuredText(stix.Entity): _binding_class = _binding.StructuredTextType _namespace = 'http://stix.mitre.org/common-1' - #ordinality = AttributeField("ordinality") - + ordinality = AttributeField("ordinality") + value = AttributeField("value") + structuring_format = AttributeField("structuring_format") + def __init__(self, value=None, ordinality=None): + self._fields = {} self.id_ = None self.value = value self.structuring_format = None self.ordinality = ordinality - @property - def ordinality(self): - return self._ordinality - - @ordinality.setter - def ordinality(self, value): - """An integer ordinality for this text item. This must be greater than - 1. - - This is used for displaying :class:`.StructuredTextList` items and - provides an order to display text items to a parser. - - """ - if value is None: - self._ordinality = None - return - - value = int(value) - - if value > 0: - self._ordinality = value - return - - error = "Value must be an integer > 0. Received {0}".format(value) - raise ValueError(error) - def to_obj(self, return_obj=None, ns_info=None): """Converts this object into a binding object. @@ -208,6 +196,17 @@ def _initialize_inner(self, *args): else: self.add(arg) + @classmethod + def istypeof(cls, obj): + """Check if `cls` is the type of `obj` + + In the normal case, as implemented here, a simple isinstance check is + used. However, there are more complex checks possible. For instance, + EmailAddress.istypeof(obj) checks if obj is an Address object with + a category of Address.CAT_EMAIL + """ + return isinstance(obj, cls) + def with_id(self, id): """Returns a :class:`.StructuredText` object with a matching `id` or ``None`` if not found. diff --git a/stix/extensions/structured_coa/generic_structured_coa.py b/stix/extensions/structured_coa/generic_structured_coa.py index b9350a09..d9161522 100644 --- a/stix/extensions/structured_coa/generic_structured_coa.py +++ b/stix/extensions/structured_coa/generic_structured_coa.py @@ -5,7 +5,7 @@ from stix.common import EncodedCDATA, StructuredTextList, VocabString from stix.coa.structured_coa import _BaseStructuredCOA import stix.bindings.extensions.structured_coa.generic as generic_structured_coa_binding - +from stix.base import ElementField @stix.register_extension class GenericStructuredCOA(_BaseStructuredCOA): @@ -14,6 +14,8 @@ class GenericStructuredCOA(_BaseStructuredCOA): _binding_class = _binding.GenericStructuredCOAType _XSI_TYPE = "genericStructuredCOA:GenericStructuredCOAType" + specification = ElementField("Specification", EncodedCDATA) + def __init__(self, id_=None, idref=None): super(GenericStructuredCOA, self).__init__(id_=id_, idref=idref) self.reference_location = None diff --git a/stix/test/__init__.py b/stix/test/__init__.py index eb009e21..13106967 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -45,9 +45,11 @@ def inner(*args, **kwargs): def round_trip_dict(cls, dict_): - obj = cls.object_from_dict(dict_) - dict2 = cls.dict_from_object(obj) + #obj = cls.object_from_dict(dict_) + #dict2 = cls.dict_from_object(obj) + api_obj = cls.from_dict(dict_) + dict2 = cls.to_dict(api_obj) return dict2 def round_trip(o, output=False, list_=False): diff --git a/stix/test/common/related_test.py b/stix/test/common/related_test.py index e41a4b66..d34beb64 100644 --- a/stix/test/common/related_test.py +++ b/stix/test/common/related_test.py @@ -229,15 +229,15 @@ class RelatedCOATests(EntityTestCase, unittest.TestCase): class RelatedTTPTests(EntityTestCase, unittest.TestCase): klass = RelatedTTP _full_dict = { - 'confidence': {'value': {'value': "Medium", 'xsi:type':'stixVocabs:HighMediumLowVocab-1.0'}}, + #'confidence': {'value': {'value': "Medium", 'xsi:type':'stixVocabs:HighMediumLowVocab-1.0'}}, 'information_source': { 'description': "Source of the relationship", }, - 'relationship': "Associated", - 'ttp': { - 'id': 'example:bar-1', - 'title': 'Test' - } + #'relationship': "Associated", +# 'ttp': { +# 'id': 'example:bar-1', +# 'title': 'Test' +# } } class RelatedIdentityTests(EntityTestCase, unittest.TestCase): @@ -339,3 +339,4 @@ class RelatedCampaignRefTests(EntityTestCase, unittest.TestCase): if __name__ == "__main__": unittest.main() + From 18fd8910fb0914dcee2da7101d576db7b29f0a83 Mon Sep 17 00:00:00 2001 From: emmanvg Date: Mon, 3 Aug 2015 09:56:08 -0400 Subject: [PATCH 164/438] Strong bindings for data markings *Added strong binding support for data markings *Emit signal from MarkingSpecification class --- stix/bindings/campaign.py | 7 +++++ stix/bindings/course_of_action.py | 4 +++ stix/bindings/data_marking.py | 3 ++ stix/bindings/exploit_target.py | 8 ++++++ stix/bindings/incident.py | 29 +++++++++++++++++++ stix/bindings/indicator.py | 11 ++++++++ stix/bindings/report.py | 9 ++++++ stix/bindings/stix_common.py | 47 +++++++++++++++++++++++++++++++ stix/bindings/stix_core.py | 11 ++++++++ stix/bindings/threat_actor.py | 4 +++ stix/bindings/ttp.py | 15 ++++++++++ stix/data_marking.py | 2 ++ 12 files changed, 150 insertions(+) diff --git a/stix/bindings/campaign.py b/stix/bindings/campaign.py index a6083434..44eabc94 100644 --- a/stix/bindings/campaign.py +++ b/stix/bindings/campaign.py @@ -74,6 +74,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='NamesTy for Name_ in self.Name: Name_.export(lwrite, level, nsmap, namespace_, name_='Name', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -142,6 +143,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Associa for Associated_Campaign_ in self.Associated_Campaign: Associated_Campaign_.export(lwrite, level, nsmap, namespace_, name_='Associated_Campaign', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -211,6 +213,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_Indicator_ in self.Related_Indicator: Related_Indicator_.export(lwrite, level, nsmap, namespace_, name_='Related_Indicator', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -280,6 +283,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_Incident_ in self.Related_Incident: Related_Incident_.export(lwrite, level, nsmap, namespace_, name_='Related_Incident', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -349,6 +353,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_TTP_ in self.Related_TTP: Related_TTP_.export(lwrite, level, nsmap, namespace_, name_='Related_TTP', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -420,6 +425,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Attribu for Attributed_Threat_Actor_ in self.Attributed_Threat_Actor: Attributed_Threat_Actor_.export(lwrite, level, nsmap, namespace_, name_='Attributed_Threat_Actor', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -624,6 +630,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Campaig if self.Related_Packages is not None: self.Related_Packages.export(lwrite, level, nsmap, namespace_, name_='Related_Packages', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/course_of_action.py b/stix/bindings/course_of_action.py index b6ef8862..e5c8cd0c 100644 --- a/stix/bindings/course_of_action.py +++ b/stix/bindings/course_of_action.py @@ -99,6 +99,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='coa:', def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='StructuredCOAType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -189,6 +190,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Objecti if self.Applicability_Confidence is not None: self.Applicability_Confidence.export(lwrite, level, nsmap, namespace_, name_='Applicability_Confidence', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -382,6 +384,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CourseO if self.Related_Packages is not None: self.Related_Packages.export(lwrite, level, nsmap, namespace_, name_='Related_Packages', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -513,6 +516,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_COA_ in self.Related_COA: Related_COA_.export(lwrite, level, nsmap, namespace_, name_='Related_COA', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/data_marking.py b/stix/bindings/data_marking.py index 9fbc42cc..643a83e2 100644 --- a/stix/bindings/data_marking.py +++ b/stix/bindings/data_marking.py @@ -75,6 +75,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Marking for Marking_ in self.Marking: Marking_.export(lwrite, level, nsmap, namespace_, name_='Marking', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -197,6 +198,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='marking def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='MarkingStructureType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -308,6 +310,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Marking if self.Information_Source is not None: self.Information_Source.export(lwrite, level, nsmap, namespace_, name_='Information_Source', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/exploit_target.py b/stix/bindings/exploit_target.py index c4856181..e7727b67 100644 --- a/stix/bindings/exploit_target.py +++ b/stix/bindings/exploit_target.py @@ -171,6 +171,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Vulnera if self.References is not None: self.References.export(lwrite, level, nsmap, namespace_, name_='References', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -319,6 +320,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Configu showIndent(lwrite, level, pretty_print) lwrite('<%s:CCE_ID>%s%s' % (nsmap[namespace_], quote_xml(self.CCE_ID), nsmap[namespace_], eol_)) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -395,6 +397,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Affecte for Affected_Software_ in self.Affected_Software: Affected_Software_.export(lwrite, level, nsmap, namespace_, name_='Affected_Software', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -464,6 +467,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_Exploit_Target_ in self.Related_Exploit_Target: Related_Exploit_Target_.export(lwrite, level, nsmap, namespace_, name_='Related_Exploit_Target', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -538,6 +542,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Weaknes showIndent(lwrite, level, pretty_print) lwrite('<%s:CWE_ID>%s%s' % (nsmap[namespace_], quote_xml(self.CWE_ID), nsmap[namespace_], eol_)) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -650,6 +655,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CVSSVec if self.Environmental_Vector is not None: lwrite('<%s:Environmental_Vector>%s%s' % (nsmap[namespace_], quote_xml(self.Environmental_Vector), nsmap[namespace_], eol_)) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -742,6 +748,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Potenti for Potential_COA_ in self.Potential_COA: Potential_COA_.export(lwrite, level, nsmap, namespace_, name_='Potential_COA', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -916,6 +923,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Exploit if self.Related_Packages is not None: self.Related_Packages.export(lwrite, level, nsmap, namespace_, name_='Related_Packages', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/incident.py b/stix/bindings/incident.py index 8e177282..e7f609d6 100644 --- a/stix/bindings/incident.py +++ b/stix/bindings/incident.py @@ -98,6 +98,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Propert if self.Non_Public_Data_Compromised is not None: self.Non_Public_Data_Compromised.export(lwrite, level, nsmap, namespace_, name_='Non_Public_Data_Compromised', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -234,6 +235,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Affecte if self.Structured_Description is not None: self.Structured_Description.export(lwrite, level, "%s:" % (nsmap[namespace_]), name_='Structured_Description', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -359,6 +361,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ImpactA if self.External_Impact_Assessment_Model is not None: self.External_Impact_Assessment_Model.export(lwrite, level, nsmap, namespace_, name_='External_Impact_Assessment_Model', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -461,6 +464,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='inciden def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ExternalImpactAssessmentModelType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -544,6 +548,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='COATake if self.Course_Of_Action is not None: self.Course_Of_Action.export(lwrite, level, nsmap, namespace_, name_='Course_Of_Action', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -639,6 +644,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='inciden def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='JournalEntryType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) self.valueOf_ = get_all_text_(node) @@ -714,6 +720,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='inciden def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='COARequestedType', fromsubclass_=False, pretty_print=True): super(COARequestedType, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -781,6 +788,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Contrib for Contributor_ in self.Contributor: Contributor_.export(lwrite, level, "%s:" % (nsmap[namespace_]), name_='Contributor', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -847,6 +855,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='COATime if self.End is not None: self.End.export(lwrite, level, nsmap, namespace_, name_='End', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -916,6 +925,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='inciden def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='LossEstimationType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -986,6 +996,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TotalLo if self.Actual_Total_Loss_Estimation is not None: self.Actual_Total_Loss_Estimation.export(lwrite, level, nsmap, namespace_, name_='Actual_Total_Loss_Estimation', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1068,6 +1079,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Indirec if self.Legal_And_Regulatory_Costs is not None: self.Legal_And_Regulatory_Costs.export(lwrite, level, nsmap, namespace_, name_='Legal_And_Regulatory_Costs', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1152,6 +1164,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='DirectI if self.Response_And_Recovery_Costs is not None: self.Response_And_Recovery_Costs.export(lwrite, level, nsmap, namespace_, name_='Response_And_Recovery_Costs', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1225,6 +1238,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='NatureO for Property_Affected_ in self.Property_Affected: Property_Affected_.export(lwrite, level, nsmap, namespace_, name_='Property_Affected', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1291,6 +1305,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='History if self.Journal_Entry is not None: self.Journal_Entry.export(lwrite, level, nsmap, namespace_, name_='Journal_Entry', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1360,6 +1375,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='History for History_Item_ in self.History_Item: History_Item_.export(lwrite, level, nsmap, namespace_, name_='History_Item', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1425,6 +1441,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Affecte for Affected_Asset_ in self.Affected_Asset: Affected_Asset_.export(lwrite, level, nsmap, namespace_, name_='Affected_Asset', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1533,6 +1550,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TimeTyp if self.Incident_Closed is not None: self.Incident_Closed.export(lwrite, level, nsmap, namespace_, name_='Incident_Closed', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1632,6 +1650,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Categor for Category_ in self.Category: Category_.export(lwrite, level, nsmap, namespace_, name_='Category', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1699,6 +1718,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Effects for Effect_ in self.Effect: Effect_.export(lwrite, level, nsmap, namespace_, name_='Effect', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1769,6 +1789,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Attribu for Threat_Actor_ in self.Threat_Actor: Threat_Actor_.export(lwrite, level, nsmap, namespace_, name_='Threat_Actor', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1838,6 +1859,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_Indicator_ in self.Related_Indicator: Related_Indicator_.export(lwrite, level, nsmap, namespace_, name_='Related_Indicator', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1907,6 +1929,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_Observable_ in self.Related_Observable: Related_Observable_.export(lwrite, level, nsmap, namespace_, name_='Related_Observable', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1976,6 +1999,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Leverag for Leveraged_TTP_ in self.Leveraged_TTP: Leveraged_TTP_.export(lwrite, level, nsmap, namespace_, name_='Leveraged_TTP', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2045,6 +2069,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_Incident_ in self.Related_Incident: Related_Incident_.export(lwrite, level, nsmap, namespace_, name_='Related_Incident', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2121,6 +2146,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='AssetTy super(AssetTypeType, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) self.valueOf_ = get_all_text_(node) @@ -2441,6 +2467,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Inciden if self.Related_Packages is not None: self.Related_Packages.export(lwrite, level, nsmap, namespace_, name_='Related_Packages', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2627,6 +2654,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='NonPubl super(NonPublicDataCompromisedType, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2695,6 +2723,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='inciden def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ExternalIDType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) self.valueOf_ = get_all_text_(node) diff --git a/stix/bindings/indicator.py b/stix/bindings/indicator.py index d6c8b810..dcebb35d 100644 --- a/stix/bindings/indicator.py +++ b/stix/bindings/indicator.py @@ -77,6 +77,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ValidTi if self.End_Time is not None: self.End_Time.export(lwrite, level, nsmap, namespace_, name_='End_Time', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -155,6 +156,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Composi for Indicator_ in self.Indicator: Indicator_.export(lwrite, level, nsmap, namespace_, name_='Indicator', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -290,6 +292,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TestMec if self.Producer is not None: self.Producer.export(lwrite, level, nsmap, namespace_, name_='Producer', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -378,6 +381,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Sightin for Sighting_ in self.Sighting: Sighting_.export(lwrite, level, nsmap, namespace_, name_='Sighting', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -494,6 +498,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Sightin if self.Related_Observables is not None: self.Related_Observables.export(lwrite, level, nsmap, namespace_, name_='Related_Observables', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -590,6 +595,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_Observable_ in self.Related_Observable: Related_Observable_.export(lwrite, level, nsmap, namespace_, name_='Related_Observable', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -656,6 +662,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TestMec for Test_Mechanism_ in self.get_Test_Mechanism(): Test_Mechanism_.export(lwrite, level, nsmap, namespace_, name_='Test_Mechanism', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -725,6 +732,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Suggest for Suggested_COA_ in self.Suggested_COA: Suggested_COA_.export(lwrite, level, nsmap, namespace_, name_='Suggested_COA', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -794,6 +802,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_Indicator_ in self.Related_Indicator: Related_Indicator_.export(lwrite, level, nsmap, namespace_, name_='Related_Indicator', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1041,6 +1050,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Indicat if self.Producer is not None: self.Producer.export(lwrite, level, nsmap, namespace_, name_='Producer', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1198,6 +1208,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_Campaign_ in self.Related_Campaign: Related_Campaign_.export(lwrite, level, nsmap, namespace_, name_='Related_Campaign', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/report.py b/stix/bindings/report.py index 9e3fbcc4..5f151830 100644 --- a/stix/bindings/report.py +++ b/stix/bindings/report.py @@ -115,6 +115,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='HeaderT if self.Information_Source is not None: self.Information_Source.export(lwrite, level, nsmap, namespace_, name_='Information_Source', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -201,6 +202,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Indicat for Indicator_ in self.Indicator: Indicator_.export(lwrite, level, nsmap, namespace_, name_='Indicator', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -273,6 +275,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TTPsTyp if self.Kill_Chains is not None: self.Kill_Chains.export(lwrite, level, nsmap, namespace_, name_='Kill_Chains', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -343,6 +346,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Inciden for Incident_ in self.Incident: Incident_.export(lwrite, level, nsmap, namespace_, name_='Incident', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -409,6 +413,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Courses for Course_Of_Action_ in self.Course_Of_Action: Course_Of_Action_.export(lwrite, level, nsmap, namespace_, name_='Course_Of_Action', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -475,6 +480,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Campaig for Campaign_ in self.Campaign: Campaign_.export(lwrite, level, nsmap, namespace_, name_='Campaign', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -541,6 +547,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ThreatA for Threat_Actor_ in self.Threat_Actor: Threat_Actor_.export(lwrite, level, nsmap, namespace_, name_='Threat_Actor', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -679,6 +686,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ReportT if self.Related_Reports is not None: self.Related_Reports.export(lwrite, level, nsmap, namespace_, name_='Related_Reports', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -789,6 +797,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_Report_ in self.Related_Report: Related_Report_.export(lwrite, level, nsmap, namespace_, name_='Related_Report', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index 257fd74e..b9a00e12 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -89,6 +89,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Generic if self.Relationship is not None: self.Relationship.export(lwrite, level, nsmap, namespace_, name_='Relationship', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -172,6 +173,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='DateTimeWithPrecisionType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) self.valueOf_ = get_all_text_(node) @@ -240,6 +242,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Profile showIndent(lwrite, level, pretty_print) lwrite('<%s:Profile>%s%s' % (nsmap[namespace_],quote_xml(Profile_), nsmap[namespace_], eol_)) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -315,6 +318,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='RelatedPackageRefType', fromsubclass_=False, pretty_print=True): super(RelatedPackageRefType, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -392,6 +396,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Package_Reference_ in self.Package_Reference: Package_Reference_.export(lwrite, level, nsmap, namespace_, name_='Package_Reference', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -480,6 +485,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ToolInf for Short_Description in self.Short_Description: Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -596,6 +602,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Informa if self.References is not None: self.References.export(lwrite, level, nsmap, namespace_, name_='References', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -717,6 +724,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Confide if self.Confidence_Assertion_Chain is not None: self.Confidence_Assertion_Chain.export(lwrite, level, nsmap, namespace_, name_='Confidence_Assertion_Chain', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -811,6 +819,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Activit for Description in self.Description: Description.export(lwrite, level, nsmap, namespace_, name_='Description', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -880,6 +889,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='KillCha for Kill_Chain_ in self.Kill_Chain: Kill_Chain_.export(lwrite, level, nsmap, namespace_, name_='Kill_Chain', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -981,6 +991,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='KillCha for Kill_Chain_Phase_ in self.Kill_Chain_Phase: Kill_Chain_Phase_.export(lwrite, level, nsmap, namespace_, name_='Kill_Chain_Phase', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1081,6 +1092,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='KillChainPhaseType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1161,6 +1173,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='KillCha for Kill_Chain_Phase_ in self.Kill_Chain_Phase: Kill_Chain_Phase_.export(lwrite, level, nsmap, namespace_, name_='Kill_Chain_Phase', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1229,6 +1242,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='KillCha super(KillChainPhaseReferenceType, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1326,6 +1340,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Identit if self.Related_Identities is not None: self.Related_Identities.export(lwrite, level, nsmap, namespace_, name_='Related_Identities', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1405,6 +1420,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='GenericRelationshipListType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1470,6 +1486,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related if self.Campaign is not None: self.Campaign.export(lwrite, level, nsmap, namespace_, name_='Campaign', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1536,6 +1553,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related if self.Course_Of_Action is not None: self.Course_Of_Action.export(lwrite, level, nsmap, namespace_, name_='Course_Of_Action', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1602,6 +1620,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related if self.Exploit_Target is not None: self.Exploit_Target.export(lwrite, level, nsmap, namespace_, name_='Exploit_Target', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1667,6 +1686,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related if self.Incident is not None: self.Incident.export(lwrite, level, nsmap, namespace_, name_='Incident', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1733,6 +1753,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related if self.Indicator is not None: self.Indicator.export(lwrite, level, nsmap, namespace_, name_='Indicator', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1799,6 +1820,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related if self.Observable is not None: self.Observable.export(lwrite, level, "%s:" % (nsmap[namespace_]), name_='Observable', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1864,6 +1886,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related if self.Threat_Actor is not None: self.Threat_Actor.export(lwrite, level, nsmap, namespace_, name_='Threat_Actor', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1930,6 +1953,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related if self.TTP is not None: self.TTP.export(lwrite, level, nsmap, namespace_, name_='TTP', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1996,6 +2020,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related if self.Identity is not None: self.Identity.export(lwrite, level, nsmap, namespace_, name_='Identity', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2079,6 +2104,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='IndicatorBaseType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2180,6 +2206,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='IncidentBaseType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2281,6 +2308,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TTPBaseType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2383,6 +2411,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ExploitTargetBaseType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2484,6 +2513,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CourseOfActionBaseType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2560,6 +2590,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related if self.Campaign is not None: self.Campaign.export(lwrite, level, nsmap, namespace_, name_='Campaign', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2640,6 +2671,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Campaig if self.Names is not None: self.Names.export(lwrite, level, nsmap, namespace_, name_='Names', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2715,6 +2747,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='NamesTy for Name_ in self.Name: Name_.export(lwrite, level, nsmap, namespace_, name_='Name', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2805,6 +2838,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CampaignBaseType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2907,6 +2941,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ThreatActorBaseType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -2984,6 +3019,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Exploit for Exploit_Target_ in self.Exploit_Target: Exploit_Target_.export(lwrite, level, nsmap, namespace_, name_='Exploit_Target', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -3047,6 +3083,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='AddressAbstractType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -3109,6 +3146,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Contrib for Source_ in self.Source: Source_.export(lwrite, level, nsmap, namespace_, name_='Source', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -3175,6 +3213,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Referen showIndent(lwrite, level, pretty_print) lwrite('<%s:Reference>%s%s' % (nsmap[namespace_], quote_xml(Reference_), nsmap[namespace_], eol_)) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -3240,6 +3279,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_Identity_ in self.Related_Identity: Related_Identity_.export(lwrite, level, nsmap, namespace_, name_='Related_Identity', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -3305,6 +3345,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Confide for Confidence_Assertion_ in self.Confidence_Assertion: Confidence_Assertion_.export(lwrite, level, nsmap, namespace_, name_='Confidence_Assertion', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -3409,6 +3450,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Stateme if self.Confidence is not None: self.Confidence.export(lwrite, level, nsmap, namespace_, name_='Confidence', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -3516,6 +3558,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='StructuredTextType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) self.valueOf_ = get_all_text_(node) @@ -3598,6 +3641,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='EncodedCDATAType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) self.valueOf_ = get_all_text_(node) @@ -3681,6 +3725,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='stixCom def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ControlledVocabularyStringType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) self.valueOf_ = get_all_text_(node) @@ -3802,6 +3847,7 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_='report: def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ReportBaseType', fromsubclass_=False, pretty_print=True): pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -3881,6 +3927,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related if self.Report is not None: self.Report.export(lwrite, level, nsmap, namespace_, name_='Report', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/stix_core.py b/stix/bindings/stix_core.py index 0d2d779e..d8499f9f 100644 --- a/stix/bindings/stix_core.py +++ b/stix/bindings/stix_core.py @@ -162,6 +162,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='STIXTyp if self.Related_Packages is not None: self.Related_Packages.export(lwrite, level, nsmap, namespace_, name_='Related_Packages', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.nsmap = node.nsmap self.buildAttributes(node, node.attrib, already_processed) @@ -290,6 +291,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_Package_ in self.Related_Package: Related_Package_.export(lwrite, level, nsmap, namespace_, name_='Related_Package', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -355,6 +357,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related if self.Package is not None: self.Package.export(lwrite, level, nsmap, namespace_, name_='Package', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -471,6 +474,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='STIXHea if self.Information_Source is not None: self.Information_Source.export(lwrite, level, nsmap, namespace_, name_='Information_Source', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -560,6 +564,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Indicat for Indicator_ in self.Indicator: Indicator_.export(lwrite, level, nsmap, namespace_, name_='Indicator', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -633,6 +638,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TTPsTyp if self.Kill_Chains is not None: self.Kill_Chains.export(lwrite, level, nsmap, namespace_, name_='Kill_Chains', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -704,6 +710,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Inciden for Incident_ in self.Incident: Incident_.export(lwrite, level, nsmap, namespace_, name_='Incident', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -771,6 +778,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Courses for Course_Of_Action_ in self.Course_Of_Action: Course_Of_Action_.export(lwrite, level, nsmap, namespace_, name_='Course_Of_Action', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -837,6 +845,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Campaig for Campaign_ in self.Campaign: Campaign_.export(lwrite, level, nsmap, namespace_, name_='Campaign', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -903,6 +912,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ThreatA for Threat_Actor_ in self.Threat_Actor: Threat_Actor_.export(lwrite, level, nsmap, namespace_, name_='Threat_Actor', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -971,6 +981,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Reports Report_.export(lwrite, level, nsmap, namespace_, name_='Report', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/threat_actor.py b/stix/bindings/threat_actor.py index 35be13d7..a4986761 100644 --- a/stix/bindings/threat_actor.py +++ b/stix/bindings/threat_actor.py @@ -77,6 +77,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Observe for Observed_TTP_ in self.Observed_TTP: Observed_TTP_.export(lwrite, level, nsmap, namespace_, name_='Observed_TTP', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -146,6 +147,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Associa for Associated_Campaign_ in self.Associated_Campaign: Associated_Campaign_.export(lwrite, level, nsmap, namespace_, name_='Associated_Campaign', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -215,6 +217,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Associa for Associated_Actor_ in self.Associated_Actor: Associated_Actor_.export(lwrite, level, nsmap, namespace_, name_='Associated_Actor', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -427,6 +430,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ThreatA if self.Related_Packages is not None: self.Related_Packages.export(lwrite, level, nsmap, namespace_, name_='Related_Packages', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/ttp.py b/stix/bindings/ttp.py index f67ecc0a..b83aa343 100644 --- a/stix/bindings/ttp.py +++ b/stix/bindings/ttp.py @@ -125,6 +125,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='AttackP for Short_Description in self.Short_Description: Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -278,6 +279,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Malware for Short_Description in self.Short_Description: Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -407,6 +409,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Exploit for Short_Description in self.Short_Description: Short_Description.export(lwrite, level, nsmap, namespace_, name_='Short_Description', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -540,6 +543,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Infrast if self.Observable_Characterization is not None: self.Observable_Characterization.export(lwrite, level, "%s:" % (nsmap[namespace_]), name_='Observable_Characterization', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -629,6 +633,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='ToolsTy for Tool_ in self.Tool: Tool_.export(lwrite, level, nsmap, namespace_, name_='Tool', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -694,6 +699,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Exploit for Exploit_ in self.Exploit: Exploit_.export(lwrite, level, nsmap, namespace_, name_='Exploit', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -759,6 +765,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Malware for Malware_Instance_ in self.Malware_Instance: Malware_Instance_.export(lwrite, level, nsmap, namespace_, name_='Malware_Instance', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -825,6 +832,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='AttackP for Attack_Pattern_ in self.Attack_Pattern: Attack_Pattern_.export(lwrite, level, nsmap, namespace_, name_='Attack_Pattern', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -898,6 +906,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Resourc if self.Personas is not None: self.Personas.export(lwrite, level, nsmap, namespace_, name_='Personas', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -971,6 +980,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Persona for Persona_ in self.Persona: Persona_.export(lwrite, level, nsmap, namespace_, name_='Persona', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1044,6 +1054,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Behavio if self.Exploits is not None: self.Exploits.export(lwrite, level, nsmap, namespace_, name_='Exploits', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1141,6 +1152,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='VictimT self.Targeted_Technical_Details.export(lwrite, level, "%s:" % (nsmap[namespace_]), name_='Targeted_Technical_Details', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1222,6 +1234,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Related for Related_TTP_ in self.Related_TTP: Related_TTP_.export(lwrite, level, nsmap, namespace_, name_='Related_TTP', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1403,6 +1416,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TTPType if self.Related_Packages is not None: self.Related_Packages.export(lwrite, level, nsmap, namespace_, name_='Related_Packages', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: @@ -1529,6 +1543,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Exploit for Exploit_Target_ in self.Exploit_Target: Exploit_Target_.export(lwrite, level, nsmap, namespace_, name_='Exploit_Target', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/data_marking.py b/stix/data_marking.py index ce077f9b..73bacf67 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox import signals from mixbox.cache import Cached # internal @@ -143,6 +144,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.marking_structures = _MarkingStructures.from_obj(obj.Marking_Structure) return_obj.information_source = InformationSource.from_obj(obj.Information_Source) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod From ce15384339ff69edd644b2d70072b8dc92e6e769 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 4 Aug 2015 10:09:00 -0400 Subject: [PATCH 165/438] Updated cybox dependency version. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3e3fdb9a..c5ea9ad3 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ def get_version(): install_requires = [ 'lxml>=2.3', 'python-dateutil', - 'cybox>=2.1.0.12.dev1,<2.1.1.0', + 'cybox>=2.1.0.13.dev0,<2.1.1.0', 'mixbox>=0.0.10', ] From 98932a35ad0d9911d9eb8ea8ba22f290af4aa9c0 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 4 Aug 2015 10:09:12 -0400 Subject: [PATCH 166/438] Bumped version to 1.2.0.1.dev2 --- stix/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/version.py b/stix/version.py index e7f685eb..87535902 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.1.dev1" +__version__ = "1.2.0.1.dev2" From 9a979f770973c7e3ce94029aca2ef774a393b8c0 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 6 Aug 2015 19:09:22 -0400 Subject: [PATCH 167/438] Added signal.emit() call to Indicator.from_obj() --- stix/indicator/indicator.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index c9c0dd42..8d8e3cd4 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox import signals from cybox.core import Observable, ObservableComposition from cybox.common import Time @@ -939,7 +940,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.observable = Observable.from_obj(obj.Observable) return_obj.related_campaigns = RelatedCampaignRefs.from_obj(obj.Related_Campaigns) return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) - + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): From 6529db910236154568254e6a0081c86783f196de Mon Sep 17 00:00:00 2001 From: apsillers Date: Mon, 10 Aug 2015 10:41:41 -0400 Subject: [PATCH 168/438] More TypedField changes (Confidence, InformationSource, related.py) --- stix/base.py | 74 ++---------------- stix/campaign/__init__.py | 5 +- stix/common/confidence.py | 124 ++++-------------------------- stix/common/information_source.py | 44 ++++++----- stix/common/related.py | 1 + 5 files changed, 52 insertions(+), 196 deletions(-) diff --git a/stix/base.py b/stix/base.py index 246579be..7fbb974f 100644 --- a/stix/base.py +++ b/stix/base.py @@ -25,7 +25,6 @@ class ElementField(fields.TypedField): class IdField(AttributeField): pass - class Entity(object): """Base class for all classes in the STIX API.""" _namespace = None @@ -767,17 +766,21 @@ class BaseCoreComponent(Entity): id_ = IdField("id") idref = IdField("idref") version = AttributeField("version") + timestamp = AttributeField("timestamp") information_source = ElementField("Information_Source") - #description = ElementField("Description") + descriptions = None + short_descriptions = None handling = ElementField("Handling") @classmethod def initClassFields(cls): import data_marking import common - BaseCoreComponent.handling.type_ = data_marking.Marking - #BaseCoreComponent.description.type_ = common.StructuredText - BaseCoreComponent.information_source.type_ = common.InformationSource + from stix.common.structured_text import StructuredTextList, StructuredTextListField + cls.handling.type_ = data_marking.Marking + cls.information_source.type_ = common.InformationSource + cls.descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") + cls.short_descriptions = StructuredTextListField("Short_Description", StructuredTextList, key_name="short_description") def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): @@ -852,37 +855,6 @@ def description(self): def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - from stix.common import StructuredTextList - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. @@ -912,36 +884,6 @@ def short_description(self): def short_description(self, value): self.short_descriptions = value - @property - def short_descriptions(self): - """A :class:`.StructuredTextList` object, containing short descriptions - about the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - short descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of :class:`.StructuredTextList` - - """ - return self._short_description - - @short_descriptions.setter - def short_descriptions(self, value): - from stix.common import StructuredTextList - self._short_description = StructuredTextList(value) - def add_short_description(self, description): """Adds a description to the ``short_descriptions`` collection. diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 8925d163..df988466 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -95,11 +95,12 @@ class Campaign(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'campaign' - descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") + #descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") activity = ElementField("Activity", multiple=True) associated_campaigns = ElementField("Associated_Campaigns", AssociatedCampaigns) attribution = ElementField("Attribution", multiple=True) - #confidence = ElementField("Confidence") + confidence = ElementField("Confidence", Confidence) + references = ElementField("Reference", multiple=True) def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 5fffea24..45690382 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -8,15 +8,22 @@ import stix.bindings.stix_common as common_binding from . import vocabs, VocabString -from .structured_text import StructuredTextList - +from .structured_text import StructuredTextList, StructuredTextListField +from stix.base import ElementField, AttributeField class Confidence(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' _binding = common_binding _binding_class = common_binding.ConfidenceType + value = ElementField("value") + descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") + timestamp = AttributeField("timestamp") + timestamp_precision = AttributeField("timestamp_precision") + source = ElementField("source") + def __init__(self, value=None, timestamp=None, description=None, source=None): + self._fields = {} self.timestamp = timestamp or utils.dates.now() self.timestamp_precision = "second" self.value = value @@ -24,7 +31,13 @@ def __init__(self, value=None, timestamp=None, description=None, source=None): self.source = source # TODO: support confidence_assertion_chain # self.confidence_assertion_chain = None - + + # called in stix.common.related + @classmethod + def initClassFields(cls): + from .information_source import InformationSource + cls.source.type_ = InformationSource + @property def timestamp(self): return self._timestamp @@ -33,23 +46,6 @@ def timestamp(self): def timestamp(self, value): self._timestamp = utils.dates.parse_value(value) - @property - def value(self): - return self._value - - @value.setter - def value(self, value): - self._set_vocab(vocabs.HighMediumLow, value=value) - - @property - def source(self): - return self._source - - @source.setter - def source(self, value): - from .information_source import InformationSource - self._set_var(InformationSource, try_cast=False, source=value) - @property def description(self): """A single description about the contents or purpose of this object. @@ -71,33 +67,6 @@ def description(self): def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. @@ -115,67 +84,6 @@ def add_description(self, description): # if value: # raise NotImplementedError() - def to_obj(self, return_obj=None, ns_info=None): - super(Confidence, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - obj = self._binding_class() - obj.timestamp = utils.dates.serialize_value(self.timestamp) - obj.timestamp_precision = self.timestamp_precision - - if self.value: - obj.Value = self.value.to_obj(ns_info=ns_info) - if self.descriptions: - obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.source: - obj.Source = self.source.to_obj(ns_info=ns_info) - - return obj - - def to_dict(self): - skip = ('timestamp_precision',) - d = utils.to_dict(self, skip=skip) - - if self.timestamp_precision != 'second': - d['timestamp_precision'] = self.timestamp_precision - - return d - - @classmethod - def from_obj(cls, obj, return_obj=None): - from .information_source import InformationSource - - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.timestamp = obj.timestamp - return_obj.timestamp_precision = obj.timestamp_precision - return_obj.value = VocabString.from_obj(obj.Value) - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.source = InformationSource.from_obj(obj.Source) - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - from .information_source import InformationSource - - if not d: - return None - - if not return_obj: - return_obj = cls() - - return_obj.timestamp = d.get('timestamp') - return_obj.timestamp_precision = d.get('timestamp_precision', 'second') - return_obj.value = VocabString.from_dict(d.get('value')) - return_obj.descriptions = StructuredTextList.from_dict(d.get('description')) - return_obj.source = InformationSource.from_dict(d.get('source')) - - return return_obj - # class ConfidenceAssertionChain(stix.Entity): # _namespace = 'http://stix.mitre.org/common-2' diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 01515015..de32c022 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -17,6 +17,7 @@ from .structured_text import StructuredTextList, StructuredTextListField from stix.base import ElementField from mixbox.entities import Entity +from cybox.common.tools import ToolInformationList class InformationSource(stix.Entity): _binding = stix_common_binding @@ -27,6 +28,8 @@ class InformationSource(stix.Entity): descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") contributing_sources = ElementField("Contributing_Sources") time = ElementField("Time", cybox.common.Time) + roles = ElementField("Role", multiple=True) + tools = ElementField("Tools", ToolInformationList) @classmethod def initClassFields(cls): @@ -41,7 +44,7 @@ def __init__(self, description=None, identity=None, time=None, tools=None, contr self.time = time self.tools = tools self.references = references - self.roles = None + #self.roles = None def add_contributing_source(self, value): self.contributing_sources.append(value) @@ -77,25 +80,26 @@ def add_description(self, description): """ self.descriptions.add(description) - @property - def tools(self): - return self._tools + #@property + #def tools(self): + # return self._tools - @tools.setter - def tools(self, value): - self._set_var(cybox.common.ToolInformationList, try_cast=False, tools=value) + #@tools.setter + #def tools(self, value): + # self._set_var(cybox.common.ToolInformationList, try_cast=False, tools=value) - @property - def roles(self): - return self._roles + #@property + #def roles(self): + # return self._roles - @roles.setter - def roles(self, value): - self._roles = _Roles(value) + #@roles.setter + #def roles(self, value): + # self._roles = _Roles(value) def add_role(self, value): self.roles.append(value) - + +""" def to_obj(self, return_obj=None, ns_info=None): super(InformationSource, self).to_obj( return_obj=return_obj, @@ -142,7 +146,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.tools = cybox.common.ToolInformationList.from_obj(obj.Tools) return return_obj - +""" class ContributingSources(stix.EntityList): _namespace = "http://stix.mitre.org/common-1" @@ -154,11 +158,11 @@ class ContributingSources(stix.EntityList): # NOT AN ACTUAL STIX TYPE! -class _Roles(stix.TypedList): - _contained_type = VocabString - - def _fix_value(self, value): - return vocabs.InformationSourceRole(value) +#class _Roles(stix.TypedList): +# _contained_type = VocabString +# +# def _fix_value(self, value): +# return vocabs.InformationSourceRole(value) # finally, initialize field types that would be circular dependencies InformationSource.initClassFields() diff --git a/stix/common/related.py b/stix/common/related.py index 52ca5860..a8456120 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -19,6 +19,7 @@ from .information_source import InformationSource from .confidence import Confidence +Confidence.initClassFields() class GenericRelationship(stix.Entity): _namespace = "http://stix.mitre.org/common-1" From 341a82ed4a9260e6e3c3a10b8121c2c930b18214 Mon Sep 17 00:00:00 2001 From: apsillers Date: Tue, 11 Aug 2015 14:14:12 -0400 Subject: [PATCH 169/438] WIP: Add more TypedFields, fix more description(s) issues (in progress) --- stix/base.py | 15 ++++++++++- stix/campaign/__init__.py | 44 +++++++++++-------------------- stix/common/confidence.py | 4 +-- stix/common/information_source.py | 34 +++++++++++++----------- stix/common/structured_text.py | 4 ++- 5 files changed, 53 insertions(+), 48 deletions(-) diff --git a/stix/base.py b/stix/base.py index 7fbb974f..69503965 100644 --- a/stix/base.py +++ b/stix/base.py @@ -141,13 +141,17 @@ def _objectify(value, return_obj, ns_info): unmodified. """ try: + #print "objifying", value.to_obj return value.to_obj(return_obj=return_obj, ns_info=ns_info) - except: + except AttributeError: + if type(value) == dict: + print value return value self._collect_ns_info(ns_info) entity_obj = self._binding_class() + print "entity", entity_obj vars = {} for klass in self.__class__.__mro__: @@ -159,6 +163,7 @@ def _objectify(value, return_obj, ns_info): #print "self", self.__dict__ for name, field in vars.iteritems(): + print name, field.__class__ if isinstance(field, fields.TypedField): val = getattr(self, field.attr_name) @@ -169,6 +174,7 @@ def _objectify(value, return_obj, ns_info): val = [] else: val = _objectify(val, return_obj, ns_info) + #print "USING THE ABOVE FIELD", val setattr(entity_obj, field.name, val) @@ -674,6 +680,7 @@ def _fix_value(self, value): return new_value def to_obj(self, ns_info=None): + print "TypedCollection to_obj called" return [x.to_obj(ns_info=ns_info) for x in self] def to_list(self): @@ -861,6 +868,9 @@ def add_description(self, description): This is the same as calling "foo.descriptions.add(bar)". """ + if self.descriptions is None: + from stix.common.structured_text import StructuredTextList + self.descriptions = StructuredTextList() self.descriptions.add(description) @property @@ -890,6 +900,9 @@ def add_short_description(self, description): This is the same as calling "foo.short_descriptions.add(bar)". """ + if self.short_descriptions is None: + from stix.common.structured_text import StructuredTextList + self.short_descriptions = StructuredTextList self.short_descriptions.add(description) """ diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index df988466..867952c3 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -101,6 +101,12 @@ class Campaign(stix.BaseCoreComponent): attribution = ElementField("Attribution", multiple=True) confidence = ElementField("Confidence", Confidence) references = ElementField("Reference", multiple=True) + status = ElementField("Status", VocabString) + intended_effects = ElementField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") + names = ElementField("Names", Names) + related_incidents = ElementField("Related_Incidents", RelatedIncidents) + related_indicators = ElementField("Related_Indicators", RelatedIndicators) + related_packages = ElementField("Related_Packages", RelatedPackageRefs) def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): @@ -125,24 +131,6 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, #self.activity = _Activities() self.related_packages = RelatedPackageRefs() - @property - def intended_effects(self): - """A collection of :class:`.Statement` objects. This behaves like a - ``MutableSequence`` type. - - """ - return self._intended_effects - - @intended_effects.setter - def intended_effects(self, value): - """Adds a :class:`.Statement` object to the :attr:`intended_effects` - collection. - - If `value` is not an instance of :class:`.Statement`, an attempt will - be made to convert it to one. - - """ - self._intended_effects = _IntendedEffects(value) def add_intended_effect(self, value): self.intended_effects.append(value) @@ -156,19 +144,19 @@ def add_activity(self, value): """ self.activity.append(value) - @property - def status(self): - """The status of the Campaign. This is a :class:`VocabString` field. + #@property + #def status(self): + # """The status of the Campaign. This is a :class:`VocabString` field. - If set to a string, an attempt will be made to convert it to a - :class:`.CampaignStatus` object. + # If set to a string, an attempt will be made to convert it to a + # :class:`.CampaignStatus` object. - """ - return self._status + # """ + # return self._status - @status.setter - def status(self, value): - self._set_vocab(vocabs.CampaignStatus, status=value) + #@status.setter + #def status(self, value): + # self._set_vocab(vocabs.CampaignStatus, status=value) diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 45690382..a68ccc81 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -16,11 +16,11 @@ class Confidence(stix.Entity): _binding = common_binding _binding_class = common_binding.ConfidenceType - value = ElementField("value") + value = ElementField("Value", VocabString) descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") timestamp = AttributeField("timestamp") timestamp_precision = AttributeField("timestamp_precision") - source = ElementField("source") + source = ElementField("Source") def __init__(self, value=None, timestamp=None, description=None, source=None): self._fields = {} diff --git a/stix/common/information_source.py b/stix/common/information_source.py index de32c022..14e78848 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -28,8 +28,10 @@ class InformationSource(stix.Entity): descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") contributing_sources = ElementField("Contributing_Sources") time = ElementField("Time", cybox.common.Time) - roles = ElementField("Role", multiple=True) - tools = ElementField("Tools", ToolInformationList) + roles = ElementField("Role", VocabString, multiple=True, key_name="roles") + + tools = ElementField("Tools", ToolInformationList) #TODO: shows up, but broken + references = ElementField("References") #TODO: list-setting behavior does not match @classmethod def initClassFields(cls): @@ -49,21 +51,21 @@ def __init__(self, description=None, identity=None, time=None, tools=None, contr def add_contributing_source(self, value): self.contributing_sources.append(value) - @property - def references(self): - return self._references + #@property + #def references(self): + # return self._references - @references.setter - def references(self, value): - self._references = [] - - if not value: - return - elif utils.is_sequence(value): - for v in value: - self.add_reference(v) - else: - self.add_reference(value) + #@references.setter + #def references(self, value): + # self._references = [] + + # if not value: + # return + # elif utils.is_sequence(value): + # for v in value: + # self.add_reference(v) + # else: + # self.add_reference(value) def add_reference(self, value): if not value: diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index fef4a332..150dccd1 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -392,13 +392,15 @@ def remove(self, value): """ self._inner.remove(value) - def to_obj(self, ns_info=None): + def to_obj(self, return_obj=None, ns_info=None): """Returns a binding object list for the StructuredTextList. If the list has a length of 1, and its member has an ordinality of 1, the ordinality will be unset. """ + print "STList to_obj called" + if not self: return [] From 9aceaaf9f48e4b42dd21569082d5c5ba8483ef82 Mon Sep 17 00:00:00 2001 From: apsillers Date: Wed, 12 Aug 2015 21:00:03 -0400 Subject: [PATCH 170/438] WIP: Change `description` setters to wrap input in StructuredTextList; Change TypedCollection to return an empty collection on `None` input --- stix/base.py | 38 ++++++++++++++++++++----------- stix/campaign/__init__.py | 29 +++++++++++++++++++++++ stix/common/confidence.py | 25 ++++++++++++++++---- stix/common/information_source.py | 20 ++++++++++++++++ 4 files changed, 94 insertions(+), 18 deletions(-) diff --git a/stix/base.py b/stix/base.py index 69503965..595391ea 100644 --- a/stix/base.py +++ b/stix/base.py @@ -11,7 +11,6 @@ # internal from . import bindings, utils - def _override(*args, **kwargs): raise NotImplementedError() @@ -147,11 +146,19 @@ def _objectify(value, return_obj, ns_info): if type(value) == dict: print value return value + + import common + if isinstance(self, common.Confidence): + print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + print self, self.descriptions, self._fields self._collect_ns_info(ns_info) entity_obj = self._binding_class() - print "entity", entity_obj + print "entity", entity_obj, self vars = {} for klass in self.__class__.__mro__: @@ -163,8 +170,15 @@ def _objectify(value, return_obj, ns_info): #print "self", self.__dict__ for name, field in vars.iteritems(): - print name, field.__class__ if isinstance(field, fields.TypedField): + print name, field.__class__, field.attr_name + import common + if field.attr_name == "descriptions" and isinstance(self, common.Confidence): + print "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" + print "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" + print "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" + print "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" + print getattr(self, field.attr_name), self.descriptions val = getattr(self, field.attr_name) if field.multiple: @@ -173,9 +187,11 @@ def _objectify(value, return_obj, ns_info): else: val = [] else: + print "objectifying", val val = _objectify(val, return_obj, ns_info) - #print "USING THE ABOVE FIELD", val + print "objectified", val + print "setting on binding", field.name, val setattr(entity_obj, field.name, val) self._finalize_obj(entity_obj) @@ -704,7 +720,7 @@ def from_obj(cls, obj_list, contained_type=None): def from_list(cls, list_repr, contained_type=None): if not list_repr: - return None + return cls() if isinstance(list_repr, dict) or not utils.is_sequence(list_repr): list_repr = [list_repr] @@ -860,7 +876,8 @@ def description(self): @description.setter def description(self, value): - self.descriptions = value + from stix.common.structured_text import StructuredTextList + self.descriptions = StructuredTextList(value) def add_description(self, description): """Adds a description to the ``descriptions`` collection. @@ -868,9 +885,6 @@ def add_description(self, description): This is the same as calling "foo.descriptions.add(bar)". """ - if self.descriptions is None: - from stix.common.structured_text import StructuredTextList - self.descriptions = StructuredTextList() self.descriptions.add(description) @property @@ -892,7 +906,8 @@ def short_description(self): @short_description.setter def short_description(self, value): - self.short_descriptions = value + from stix.common.structured_text import StructuredTextList + self.short_descriptions = StructuredTextList(value) def add_short_description(self, description): """Adds a description to the ``short_descriptions`` collection. @@ -900,9 +915,6 @@ def add_short_description(self, description): This is the same as calling "foo.short_descriptions.add(bar)". """ - if self.short_descriptions is None: - from stix.common.structured_text import StructuredTextList - self.short_descriptions = StructuredTextList self.short_descriptions.add(description) """ diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 867952c3..22f20ec2 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -144,6 +144,35 @@ def add_activity(self, value): """ self.activity.append(value) + @property + def description(self): + """A single description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If this object has more than one description set, this will return + the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + + """ + return next(iter(self.descriptions), None) + + @description.setter + def description(self, value): + from stix.common.structured_text import StructuredTextList + self.descriptions = StructuredTextList(value) + + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + + """ + self.descriptions.add(description) + #@property #def status(self): # """The status of the Campaign. This is a :class:`VocabString` field. diff --git a/stix/common/confidence.py b/stix/common/confidence.py index a68ccc81..84467b0e 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -23,12 +23,24 @@ class Confidence(stix.Entity): source = ElementField("Source") def __init__(self, value=None, timestamp=None, description=None, source=None): - self._fields = {} + import random + self._fields = { 'a': random.random() } self.timestamp = timestamp or utils.dates.now() self.timestamp_precision = "second" self.value = value self.description = description self.source = source + print "#######################################################" + print "#######################################################" + print "#######################################################" + print "#######################################################" + print "#######################################################" + print "#######################################################" + print "#######################################################" + print "#######################################################" + print "#######################################################" + print self, self.descriptions, self._fields + pass # TODO: support confidence_assertion_chain # self.confidence_assertion_chain = None @@ -57,15 +69,18 @@ def description(self): the description with the lowest ordinality value. Returns: - An instance of - :class:`.StructuredText` + An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions), None) + return next(iter(self.descriptions), "None") @description.setter def description(self, value): - self.descriptions = value + from stix.common.structured_text import StructuredTextList + if value is None: + self.descriptions = StructuredTextList() + else: + self.descriptions = StructuredTextList(value) def add_description(self, description): """Adds a description to the ``descriptions`` collection. diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 14e78848..f1557a86 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -73,6 +73,26 @@ def add_reference(self, value): # TODO: Check if it's a valid URI? self.references.append(value) + @property + def description(self): + """A single description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If this object has more than one description set, this will return + the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + + """ + return next(iter(self.descriptions), None) + + @description.setter + def description(self, value): + from stix.common.structured_text import StructuredTextList + self.descriptions = StructuredTextList(value) def add_description(self, description): """Adds a description to the ``descriptions`` collection. From 36d8c92a55636194dd8ce5f9a6945c5daa9af279 Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 13 Aug 2015 18:26:40 -0400 Subject: [PATCH 171/438] WIP: experimental replacement for GenericRelationshipList; Activity; clear away debugging --- stix/base.py | 31 ++++-------- stix/campaign/__init__.py | 21 +++++--- stix/common/activity.py | 87 +++------------------------------- stix/common/confidence.py | 14 +----- stix/common/related.py | 25 +++++++++- stix/common/structured_text.py | 2 +- 6 files changed, 54 insertions(+), 126 deletions(-) diff --git a/stix/base.py b/stix/base.py index 595391ea..28b58aaf 100644 --- a/stix/base.py +++ b/stix/base.py @@ -144,21 +144,13 @@ def _objectify(value, return_obj, ns_info): return value.to_obj(return_obj=return_obj, ns_info=ns_info) except AttributeError: if type(value) == dict: - print value + print "dict doesn't have to_obj", return_obj, value return value - - import common - if isinstance(self, common.Confidence): - print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" - print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" - print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" - print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" - print self, self.descriptions, self._fields self._collect_ns_info(ns_info) entity_obj = self._binding_class() - print "entity", entity_obj, self + #print "entity", entity_obj, self vars = {} for klass in self.__class__.__mro__: @@ -171,14 +163,7 @@ def _objectify(value, return_obj, ns_info): for name, field in vars.iteritems(): if isinstance(field, fields.TypedField): - print name, field.__class__, field.attr_name - import common - if field.attr_name == "descriptions" and isinstance(self, common.Confidence): - print "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" - print "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" - print "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" - print "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" - print getattr(self, field.attr_name), self.descriptions + #print name, field.__class__, field.attr_name val = getattr(self, field.attr_name) if field.multiple: @@ -187,11 +172,11 @@ def _objectify(value, return_obj, ns_info): else: val = [] else: - print "objectifying", val + #print "objectifying", val val = _objectify(val, return_obj, ns_info) - print "objectified", val + #print "objectified", val - print "setting on binding", field.name, val + #print "setting on binding", field.name, val setattr(entity_obj, field.name, val) self._finalize_obj(entity_obj) @@ -603,7 +588,7 @@ def from_list(cls, list_repr, return_obj=None, contained_type=None): if not contained_type: contained_type = cls._contained_type - print list_repr.__class__, isinstance(list_repr, GenericRelationshipList) + #print list_repr.__class__, isinstance(list_repr, GenericRelationshipList) # GenericRelationshipList is not actually a list; it's dict with a list member if issubclass(cls, GenericRelationshipList): @@ -696,7 +681,7 @@ def _fix_value(self, value): return new_value def to_obj(self, ns_info=None): - print "TypedCollection to_obj called" + #print "TypedCollection to_obj called" return [x.to_obj(ns_info=ns_info) for x in self] def to_list(self): diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 22f20ec2..446fb281 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -22,14 +22,21 @@ class AssociatedCampaigns(GenericRelationshipList): _inner_name = "campaigns" -class Attribution(GenericRelationshipList): +class Attribution(stix.Entity): + threat_actors = ElementField("Attributed_Threat_Actor", RelatedThreatActor, multiple=True, key_name="threat_actors") + scope = AttributeField("scope") + + def __init__(self, scope=None, *args): + self._fields = {} + super(Attribution, self).__init__(*args) + _namespace = "http://stix.mitre.org/Campaign-1" _binding = campaign_binding _binding_class = campaign_binding.AttributionType _binding_var = "Attributed_Threat_Actor" _contained_type = RelatedThreatActor _inner_name = "threat_actors" - + class RelatedIncidents(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" @@ -95,12 +102,12 @@ class Campaign(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'campaign' - #descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") - activity = ElementField("Activity", multiple=True) + descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") + activity = ElementField("Activity", Activity, multiple=True) associated_campaigns = ElementField("Associated_Campaigns", AssociatedCampaigns) - attribution = ElementField("Attribution", multiple=True) + attribution = ElementField("Attribution", Attribution, multiple=True) confidence = ElementField("Confidence", Confidence) - references = ElementField("Reference", multiple=True) + #references = ElementField("Reference", multiple=True) status = ElementField("Status", VocabString) intended_effects = ElementField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") names = ElementField("Names", Names) @@ -126,7 +133,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.related_ttps = RelatedTTPs() self.related_incidents = RelatedIncidents() self.related_indicators = RelatedIndicators() - #self.attribution = _AttributionList() + self.attribution = Attribution() self.confidence = None #self.activity = _Activities() self.related_packages = RelatedPackageRefs() diff --git a/stix/common/activity.py b/stix/common/activity.py index c410fcf1..1b832ed9 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -4,9 +4,10 @@ import stix import stix.bindings.stix_common as common_binding import stix.utils +from stix.base import ElementField from .datetimewithprecision import DateTimeWithPrecision -from .structured_text import StructuredTextList +from .structured_text import StructuredTextList, StructuredTextListField class Activity(stix.Entity): @@ -14,18 +15,14 @@ class Activity(stix.Entity): _binding_class = common_binding.ActivityType _namespace = 'http://stix.mitre.org/common-1' + date_time = ElementField("Date_Time", DateTimeWithPrecision) + descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") + def __init__(self): + self._fields = {} self.date_time = None self.description = None - @property - def date_time(self): - return self._date_time - - @date_time.setter - def date_time(self, value): - self._set_var(DateTimeWithPrecision, date_time=value) - @property def description(self): """A single description about the contents or purpose of this object. @@ -45,34 +42,7 @@ def description(self): @description.setter def description(self, value): - self.descriptions = value - - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) + self.descriptions = StructuredTextList(value) def add_description(self, description): """Adds a description to the ``descriptions`` collection. @@ -82,46 +52,3 @@ def add_description(self, description): """ self.descriptions.add(description) - def to_obj(self, return_obj=None, ns_info=None): - super(Activity, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.date_time: - return_obj.Date_Time = self.date_time.to_obj(ns_info=ns_info) - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.date_time = DateTimeWithPrecision.from_obj(obj.Date_Time) - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - - return return_obj - - def to_dict(self): - return stix.utils.to_dict(self) - return super(Activity, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - get = dict_repr.get - return_obj.date_time = DateTimeWithPrecision.from_dict(get('date_time')) - return_obj.descriptions = StructuredTextList.from_dict(get('description')) - - return return_obj diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 84467b0e..601042ba 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -23,24 +23,12 @@ class Confidence(stix.Entity): source = ElementField("Source") def __init__(self, value=None, timestamp=None, description=None, source=None): - import random - self._fields = { 'a': random.random() } + self._fields = {} self.timestamp = timestamp or utils.dates.now() self.timestamp_precision = "second" self.value = value self.description = description self.source = source - print "#######################################################" - print "#######################################################" - print "#######################################################" - print "#######################################################" - print "#######################################################" - print "#######################################################" - print "#######################################################" - print "#######################################################" - print "#######################################################" - print self, self.descriptions, self._fields - pass # TODO: support confidence_assertion_chain # self.confidence_assertion_chain = None diff --git a/stix/common/related.py b/stix/common/related.py index a8456120..194cbcde 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -19,6 +19,8 @@ from .information_source import InformationSource from .confidence import Confidence +from stix.base import AttributeField + Confidence.initClassFields() class GenericRelationship(stix.Entity): @@ -92,7 +94,7 @@ def from_dict(cls, dict_repr, return_obj=None): if not return_obj: return_obj = cls() - print "DICT", dict_repr + #print "DICT", dict_repr return_obj.confidence = Confidence.from_dict(dict_repr.get('confidence')) return_obj.information_source = InformationSource.from_dict(dict_repr.get('information_source')) @@ -190,7 +192,26 @@ def from_dict(cls, dict_repr, return_obj=None): return return_obj - +class GenericRelationshipEntity(stix.Entity): + _namespace = "http://stix.mitre.org/common-1" + _binding = common_binding + _binding_class = _binding.GenericRelationshipListType + + _ALLOWED_SCOPE = ('inclusive', 'exclusive') + + scope = AttributeField("scope") + + def __init__(self, scope=None, *args): + _fields = {} + super(GenericRelationshipEntity, self).__init__(*args) + self.scope = scope + + def __nonzero__(self): + return ( + super(GenericRelationshipList, self).__nonzero__() or + bool(self.scope) + ) + class GenericRelationshipList(stix.EntityList): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 150dccd1..0964988c 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -399,7 +399,7 @@ def to_obj(self, return_obj=None, ns_info=None): the ordinality will be unset. """ - print "STList to_obj called" + #print "STList to_obj called" if not self: return [] From b01dfff0f2240a1b33d3d952a6fe30628a987f22 Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 14 Aug 2015 16:36:40 -0400 Subject: [PATCH 172/438] WIP: Add TypedFields to Indicator --- stix/base.py | 17 ++- stix/indicator/indicator.py | 273 +++++++++--------------------------- 2 files changed, 80 insertions(+), 210 deletions(-) diff --git a/stix/base.py b/stix/base.py index 28b58aaf..d0cbcc15 100644 --- a/stix/base.py +++ b/stix/base.py @@ -728,6 +728,17 @@ def object_from_dict(cls, entity_dict): def dict_from_object(cls, entity_obj): """Convert from object representation to dict representation.""" return cls.from_obj(entity_obj).to_dict() + + @classmethod + def istypeof(cls, obj): + """Check if `cls` is the type of `obj` + + In the normal case, as implemented here, a simple isinstance check is + used. However, there are more complex checks possible. For instance, + EmailAddress.istypeof(obj) checks if obj is an Address object with + a category of Address.CAT_EMAIL + """ + return isinstance(obj, cls) class TypedList(TypedCollection, collections.MutableSequence): @@ -775,7 +786,7 @@ class BaseCoreComponent(Entity): idref = IdField("idref") version = AttributeField("version") timestamp = AttributeField("timestamp") - information_source = ElementField("Information_Source") + #information_source = ElementField("Information_Source") descriptions = None short_descriptions = None handling = ElementField("Handling") @@ -786,7 +797,7 @@ def initClassFields(cls): import common from stix.common.structured_text import StructuredTextList, StructuredTextListField cls.handling.type_ = data_marking.Marking - cls.information_source.type_ = common.InformationSource + #cls.information_source.type_ = common.InformationSource cls.descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") cls.short_descriptions = StructuredTextListField("Short_Description", StructuredTextList, key_name="short_description") @@ -799,7 +810,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.description = description self.short_description = short_description self.version = None - self.information_source = None + #self.information_source = None self.handling = None if timestamp: diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 44c67467..71cbd876 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -23,8 +23,11 @@ # relative from .test_mechanism import TestMechanisms from .sightings import Sightings -from .valid_time import _ValidTimePositions +from .valid_time import ValidTime +from stix.base import ElementField, AttributeField +from stix.common.structured_text import StructuredTextListField +from operator import isSequenceType class SuggestedCOAs(GenericRelationshipList): """The ``SuggestedCOAs`` class provides functionality for adding @@ -178,6 +181,30 @@ class Indicator(stix.BaseCoreComponent): _ALLOWED_COMPOSITION_OPERATORS = ('AND', 'OR') _ID_PREFIX = "indicator" + producer = ElementField("Producer", InformationSource) + observable = ElementField("Observable", Observable, postset_hook = lambda inst,value: inst.set_observables([value])) + indicator_types = ElementField("Indicator_Types") + confidence = ElementField("Confidence", Confidence) + indicated_ttps = ElementField("Indicated_ttps", RelatedTTP, multiple=True) + test_mechanisms = ElementField("Test_Mechanisms", TestMechanisms) + alternative_id = ElementField("Alternative_ID", multiple=True) + suggested_coas = ElementField("Suggested_COAs", SuggestedCOAs) + sightings = ElementField("Sightings", Sightings) + composite_indicator_expression = ElementField("Composite_Indicator_Expression", ObservableComposition) + kill_chain_phases = ElementField("Kill_Chain_Phases", KillChainPhasesReference) + #TODO: should this be singular? + valid_time_positions = ElementField("Valid_Time_Position", ValidTime, multiple=True) + related_indicators = ElementField("Related_Indicators", RelatedIndicators) + related_campaigns = ElementField("Related_Campagins") + likely_impact = ElementField("Likely_Impact", Statement) + negate = AttributeField("negate") + related_packages = ElementField("Related_Packages", RelatedPackageRefs) + + @classmethod + def initClassFields(cls): + cls.indicator_types.type_ = IndicatorTypes + cls.related_campaigns = RelatedCampaignRefs + def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): @@ -194,14 +221,14 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.observables = None self.indicator_types = IndicatorTypes() self.confidence = None - self.indicated_ttps = _IndicatedTTPs() + #self.indicated_ttps = _IndicatedTTPs() self.test_mechanisms = TestMechanisms() self.alternative_id = None self.suggested_coas = SuggestedCOAs() self.sightings = Sightings() self.composite_indicator_expression = None self.kill_chain_phases = KillChainPhasesReference() - self.valid_time_positions = _ValidTimePositions() + #self.valid_time_positions = _ValidTimePositions() self.related_indicators = None self.related_campaigns = RelatedCampaignRefs() self.observable_composition_operator = "OR" @@ -209,60 +236,6 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.negate = None self.related_packages = RelatedPackageRefs() - @property - def producer(self): - """Contains information about the source of the :class:`Indicator`. - - Default Value: ``None`` - - Returns: - An instance of - :class:`stix.common.information_source.InformationSource` - - Raises: - ValueError: If set to a value that is not ``None`` and not an - instance of - :class:`stix.common.information_source.InformationSource` - - """ - return self._producer - - @producer.setter - def producer(self, value): - self._set_var(InformationSource, try_cast=False, producer=value) - - @property - def observable(self): - """A convenience property for accessing or setting the only - ``cybox.core.Observable`` instance held by this Indicator. - - Default Value: Empty ``list``. - - Setting this property results in the ``observables`` property being - reinitialized to an empty ``list`` and appending the input value, - resulting in a ``list`` containing one value. - - Note: - If the ``observables`` list contains more than one item, this - property will only return the first item in the list. - - Returns: - An instance of ``cybox.core.Observable``. - - Raises: - ValueError: If set to a value that cannot be converted to an - instance of ``cybox.core.Observable``. - - - """ - if self.observables: - return self.observables[0] - else: - return None - - @observable.setter - def observable(self, observable): - self._observables = _Observables(observable) @property def observables(self): @@ -288,8 +261,16 @@ def observables(self): @observables.setter def observables(self, value): + # this code causes infinite recursion; observables sets observable which sets obesrvables... + #try: + # self.observable = value[0] + #except TypeError: + # self.observable = value self._observables = _Observables(value) + def set_observables(self, value): + self.observables = value + def add_observable(self, observable): """Adds an observable to the ``observables`` list property of the :class:`Indicator`. @@ -319,9 +300,10 @@ def add_observable(self, observable): """ self.observables.append(observable) + """ @property def alternative_id(self): - """An alternative identifi er for this :class:`Indicator` + ""An alternative identifi er for this :class:`Indicator` This property can be set to a single string identifier or a list of identifiers. If set to a single object, the object will be inserted @@ -332,7 +314,7 @@ def alternative_id(self): Returns: A list of alternative ids. - """ + "" return self._alternative_id @alternative_id.setter @@ -344,7 +326,8 @@ def alternative_id(self, value): self._alternative_id.extend(x for x in value if x) else: self._alternative_id.append(value) - + """ + def add_alternative_id(self, value): """Adds an alternative id to the ``alternative_id`` list property. @@ -360,10 +343,11 @@ def add_alternative_id(self, value): return self.alternative_id.append(value) - + + """ @property def valid_time_positions(self): - """A list of valid time positions for this :class:`Indicator`. + ""A list of valid time positions for this :class:`Indicator`. This property can be set to a single instance or a list of :class:`stix.indicator.valid_time.ValidTime` instances. If set to a @@ -376,13 +360,14 @@ def valid_time_positions(self): A list of :class:`stix.indicator.valid_time.ValidTime` instances. - """ + "" return self._valid_time_positions @valid_time_positions.setter def valid_time_positions(self, value): self._valid_time_positions = _ValidTimePositions(value) - + """ + def add_valid_time_position(self, value): """Adds an valid time position to the ``valid_time_positions`` property list. @@ -400,9 +385,10 @@ def add_valid_time_position(self, value): """ self.valid_time_positions.append(value) + """ @property def indicator_types(self): - """A list of indicator types for this :class:`Indicator`. + ""A list of indicator types for this :class:`Indicator`. This property can be set to lists or single instances of ``str`` or :class:`stix.common.vocabs.VocabString` or an instance @@ -421,12 +407,13 @@ def indicator_types(self): Returns: An instance of ``IndicatorTypes``. - """ + "" return self._indicator_types @indicator_types.setter def indicator_types(self, value): self._indicator_types = IndicatorTypes(value) + """ def add_indicator_type(self, value): """Adds a value to the ``indicator_types`` list property. @@ -450,44 +437,6 @@ def add_indicator_type(self, value): """ self.indicator_types.append(value) - @property - def confidence(self): - """The confidence for this :class:`Indicator`. - - This property can be set to an instance of ``str``, - :class:`stix.common.vocabs.VocabString`, or - :class:`stix.common.confidence.Confidence`. - - Default Value: ``None`` - - Note: - If set to an instance of ``str`` or - :class:`stix.common.vocabs.VocabString`, that value will be wrapped - in an instance of - :class:`stix.common.confidence.Confidence`. - - Returns: - An instance of of - :class:`stix.common.confidence.Confidence`. - - Raises: - ValueError: If set to a ``str`` value that cannot be converted into - an instance of :class:`stix.common.confidence.Confidence`. - - """ - return self._confidence - - @confidence.setter - def confidence(self, value): - self._set_var(Confidence, confidence=value) - - @property - def indicated_ttps(self): - return self._indicated_ttps - - @indicated_ttps.setter - def indicated_ttps(self, value): - self._indicated_ttps = _IndicatedTTPs(value) def add_indicated_ttp(self, v): """Adds an Indicated TTP to the ``indicated_ttps`` list property @@ -515,13 +464,6 @@ def add_indicated_ttp(self, v): """ self.indicated_ttps.append(v) - @property - def test_mechanisms(self): - return self._test_mechanisms - - @test_mechanisms.setter - def test_mechanisms(self, value): - self._test_mechanisms = TestMechanisms(value) def add_test_mechanism(self, tm): """Adds an Test Mechanism to the ``test_mechanisms`` list property @@ -550,17 +492,6 @@ def add_test_mechanism(self, tm): """ self.test_mechanisms.append(tm) - @property - def related_indicators(self): - return self._related_indicators - - @related_indicators.setter - def related_indicators(self, value): - if isinstance(value, RelatedIndicators): - self._related_indicators = value - else: - self._related_indicators = RelatedIndicators(value) - def add_related_indicator(self, indicator): """Adds an Related Indicator to the ``related_indicators`` list property of this :class:`Indicator`. @@ -594,17 +525,6 @@ def add_related_indicator(self, indicator): """ self.related_indicators.append(indicator) - @property - def related_campaigns(self): - return self._related_campaigns - - @related_campaigns.setter - def related_campaigns(self, value): - if isinstance(value, RelatedCampaignRefs): - self._related_campaigns = value - else: - self._related_campaigns = RelatedCampaignRefs(value) - def add_related_campaign(self, value): """Adds a Related Campaign to this Indicator. @@ -650,30 +570,6 @@ def observable_composition_operator(self, value): error = error.format(self._ALLOWED_COMPOSITION_OPERATORS) raise ValueError(error) - @property - def likely_impact(self): - return self._likely_impact - - @likely_impact.setter - def likely_impact(self, value): - self._set_var(Statement, likely_impact=value) - - @property - def negate(self): - return self._negate - - @negate.setter - def negate(self, value): - self._negate = utils.xml_bool(value) - - @property - def kill_chain_phases(self): - return self._kill_chain_phases - - @kill_chain_phases.setter - def kill_chain_phases(self, value): - self._kill_chain_phases = KillChainPhasesReference(value) - def add_kill_chain_phase(self, value): """Add a new Kill Chain Phase reference to this Indicator. @@ -685,14 +581,6 @@ def add_kill_chain_phase(self, value): """ self.kill_chain_phases.append(value) - @property - def related_packages(self): - return self._related_packages - - @related_packages.setter - def related_packages(self, value): - self._related_packages = RelatedPackageRefs(value) - def add_related_package(self, value): self.related_packages.append(value) @@ -865,53 +753,20 @@ def add_object(self, object_): observable = Observable(object_) self.add_observable(observable) + def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(Indicator, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - return_obj.negate = True if self.negate else None - - if self.confidence: - return_obj.Confidence = self.confidence.to_obj(ns_info=ns_info) - if self.indicator_types: - return_obj.Type = self.indicator_types.to_obj(ns_info=ns_info) - if self.indicated_ttps: - return_obj.Indicated_TTP = self.indicated_ttps.to_obj(ns_info=ns_info) - if self.producer: - return_obj.Producer = self.producer.to_obj(ns_info=ns_info) - if self.test_mechanisms: - return_obj.Test_Mechanisms = self.test_mechanisms.to_obj(ns_info=ns_info) - if self.likely_impact: - return_obj.Likely_Impact = self.likely_impact.to_obj(ns_info=ns_info) - if self.alternative_id: - return_obj.Alternative_ID = self.alternative_id - if self.valid_time_positions: - return_obj.Valid_Time_Position = self.valid_time_positions.to_obj(ns_info=ns_info) - if self.suggested_coas: - return_obj.Suggested_COAs = self.suggested_coas.to_obj(ns_info=ns_info) - if self.sightings: - return_obj.Sightings = self.sightings.to_obj(ns_info=ns_info) - if self.composite_indicator_expression: - return_obj.Composite_Indicator_Expression = self.composite_indicator_expression.to_obj(ns_info=ns_info) - if self.kill_chain_phases: - return_obj.Kill_Chain_Phases = self.kill_chain_phases.to_obj(ns_info=ns_info) - if self.related_indicators: - return_obj.Related_Indicators = self.related_indicators.to_obj(ns_info=ns_info) - if self.related_campaigns: - return_obj.Related_Campaigns = self.related_campaigns.to_obj(ns_info=ns_info) - if self.related_packages: - return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) + obj = super(Indicator, self).to_obj(return_obj=return_obj, ns_info=ns_info) + if self.observables: if len(self.observables) > 1: root_observable = self._merge_observables(self.observables) else: root_observable = self.observables[0] - return_obj.Observable = root_observable.to_obj(ns_info=ns_info) + obj.Observable = root_observable.to_obj(ns_info=ns_info) return return_obj - + + """ @classmethod def from_obj(cls, obj, return_obj=None): if not obj: @@ -941,7 +796,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) return return_obj - + """ + def to_dict(self): keys = ('observables', 'observable_composition_operator', 'negate') #d = utils.to_dict(self, skip=keys) @@ -959,7 +815,8 @@ def to_dict(self): d['observable'] = composite_observable.to_dict() return d - + + """ @classmethod def from_dict(cls, dict_repr, return_obj=None): if not dict_repr: @@ -989,7 +846,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) return return_obj - + """ class CompositeIndicatorExpression(stix.EntityList): """Implementation of the STIX ``CompositeIndicatorExpressionType``. @@ -1166,3 +1023,5 @@ class _IndicatedTTPs(stix.TypedList): class _Observables(stix.TypedList): _contained_type = Observable + +Indicator.initClassFields() From 6dd72b8e07af54cd98bdaa5bb99121a8ac42c06d Mon Sep 17 00:00:00 2001 From: apsillers Date: Mon, 17 Aug 2015 12:30:10 -0400 Subject: [PATCH 173/438] WIP: Add many Indicator TypedFields --- stix/base.py | 13 ++- stix/campaign/__init__.py | 11 +- stix/common/campaign_reference.py | 61 ++-------- .../test_mechanism/generic_test_mechanism.py | 43 +++---- stix/indicator/indicator.py | 16 +-- stix/indicator/sightings.py | 79 ++++--------- stix/indicator/test_mechanism.py | 27 ++--- stix/indicator/valid_time.py | 65 +---------- stix/ttp/__init__.py | 109 +++--------------- 9 files changed, 100 insertions(+), 324 deletions(-) diff --git a/stix/base.py b/stix/base.py index d0cbcc15..a42e10be 100644 --- a/stix/base.py +++ b/stix/base.py @@ -680,7 +680,7 @@ def _fix_value(self, value): return new_value - def to_obj(self, ns_info=None): + def to_obj(self, return_obj=None, ns_info=None): #print "TypedCollection to_obj called" return [x.to_obj(ns_info=ns_info) for x in self] @@ -786,7 +786,6 @@ class BaseCoreComponent(Entity): idref = IdField("idref") version = AttributeField("version") timestamp = AttributeField("timestamp") - #information_source = ElementField("Information_Source") descriptions = None short_descriptions = None handling = ElementField("Handling") @@ -796,7 +795,7 @@ def initClassFields(cls): import data_marking import common from stix.common.structured_text import StructuredTextList, StructuredTextListField - cls.handling.type_ = data_marking.Marking + cls.handling.type_ = data_marking.MarkingStructure #cls.information_source.type_ = common.InformationSource cls.descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") cls.short_descriptions = StructuredTextListField("Short_Description", StructuredTextList, key_name="short_description") @@ -826,9 +825,10 @@ def check_version(self, value): utils.check_version(self._ALL_VERSIONS, value) self._version = value + """ @property def timestamp(self): - """The timestam property declares the time of creation and is + ""The timestam property declares the time of creation and is automatically set in ``__init__()``. This property can accept ``datetime.datetime`` or ``str`` values. @@ -847,13 +847,14 @@ def timestamp(self): Returns: An instance of ``datetime.datetime``. - """ + "" return self._timestamp @timestamp.setter def timestamp(self, value): self._timestamp = utils.dates.parse_value(value) - + """ + @property def description(self): """A single description about the contents or purpose of this object. diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 446fb281..d394858f 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -21,7 +21,14 @@ class AssociatedCampaigns(GenericRelationshipList): _contained_type = RelatedCampaign _inner_name = "campaigns" - +class Attribution(GenericRelationshipList): + _namespace = "http://stix.mitre.org/Campaign-1" + _binding = campaign_binding + _binding_class = campaign_binding.AttributionType + _binding_var = "Attributed_Threat_Actor" + _contained_type = RelatedThreatActor + _inner_name = "threat_actors" +""" class Attribution(stix.Entity): threat_actors = ElementField("Attributed_Threat_Actor", RelatedThreatActor, multiple=True, key_name="threat_actors") scope = AttributeField("scope") @@ -36,7 +43,7 @@ def __init__(self, scope=None, *args): _binding_var = "Attributed_Threat_Actor" _contained_type = RelatedThreatActor _inner_name = "threat_actors" - +""" class RelatedIncidents(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" diff --git a/stix/common/campaign_reference.py b/stix/common/campaign_reference.py index e8ff1ebe..b5b598a1 100644 --- a/stix/common/campaign_reference.py +++ b/stix/common/campaign_reference.py @@ -5,6 +5,7 @@ import stix import stix.utils as utils import stix.bindings.stix_common as common_binding +from stix.base import AttributeField, ElementField # relative from .names import Names @@ -15,31 +16,24 @@ class CampaignRef(stix.Entity): _binding = common_binding _binding_class = common_binding.CampaignReferenceType + idref = AttributeField("idref") + timestamp = AttributeField("timestamp") #preset_hook = lambda inst, value : if value is not None or not isinstance(value, datetime.datetime): inst.set_timestamp(utils.dates.parse_value(value)) + names = ElementField("Names", Names) + def __init__(self, idref=None, timestamp=None, **kwargs): super(CampaignRef, self).__init__(**kwargs) self.idref = idref self.timestamp = timestamp self.names = None - @property - def timestamp(self): - return self._timestamp - - @timestamp.setter - def timestamp(self, value): - self._timestamp = utils.dates.parse_value(value) - - @property - def names(self): - return self._names - - @names.setter - def names(self, value): - self._names = Names(value) - def add_name(self, name): self.names.append(name) - + + #timestamp.setter + #def timestamp(self, value): + # self._timestamp = utils.dates.parse_value(value) + +""" def to_obj(self, return_obj=None, ns_info=None): if not return_obj: @@ -57,35 +51,4 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Names = self.names.to_obj() return return_obj - - def to_dict(self): - return super(CampaignRef, self).to_dict() - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.idref = obj.idref - return_obj.timestamp = obj.timestamp - return_obj.names = Names.from_obj(obj.Names) - - return return_obj - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - get = dict_repr.get - return_obj.idref = get("idref") - return_obj.timestamp = get("timestamp") - return_obj.names = Names.from_dict(get("names")) - - return return_obj +""" \ No newline at end of file diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index ba8d35e9..59cd8ad5 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -6,7 +6,8 @@ from stix.common import EncodedCDATA, StructuredTextList, VocabString from stix.indicator.test_mechanism import _BaseTestMechanism import stix.bindings.extensions.test_mechanism.generic as generic_tm_binding - +from stix.base import ElementField, AttributeField +from stix.common.structured_text import StructuredTextListField @stix.register_extension class GenericTestMechanism(_BaseTestMechanism): @@ -15,6 +16,11 @@ class GenericTestMechanism(_BaseTestMechanism): _binding_class = _binding.GenericTestMechanismType _XSI_TYPE = "genericTM:GenericTestMechanismType" + reference_location = ElementField("Reference_Location") + descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") + specification = ElementField("Specification", EncodedCDATA) + type_ = AttributeField("type", VocabString, key_name="type") + def __init__(self, id_=None, idref=None): super(GenericTestMechanism, self).__init__(id_=id_, idref=idref) self.reference_location = None @@ -22,6 +28,7 @@ def __init__(self, id_=None, idref=None): self.type_ = None self.specification = None + """ @property def specification(self): return self._specification @@ -34,7 +41,8 @@ def specification(self, value): self._specification = value else: self._specification = EncodedCDATA(value=value) - + """ + @property def description(self): """A single description about the contents or purpose of this object. @@ -54,34 +62,7 @@ def description(self): @description.setter def description(self, value): - self.descriptions = value - - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) + self.descriptions = StructuredTextList(value) def add_description(self, description): """Adds a description to the ``descriptions`` collection. @@ -91,6 +72,7 @@ def add_description(self, description): """ self.descriptions.add(description) + """ @property def type_(self): return self._type @@ -103,6 +85,7 @@ def type_(self, value): self._type = value else: self._type = VocabString(value) + """ @classmethod def from_obj(cls, obj, return_obj=None): diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 71cbd876..c84d7de9 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -183,27 +183,25 @@ class Indicator(stix.BaseCoreComponent): producer = ElementField("Producer", InformationSource) observable = ElementField("Observable", Observable, postset_hook = lambda inst,value: inst.set_observables([value])) - indicator_types = ElementField("Indicator_Types") + indicator_types = ElementField("Type", IndicatorType, multiple=True, key_name="indicator_types") confidence = ElementField("Confidence", Confidence) - indicated_ttps = ElementField("Indicated_ttps", RelatedTTP, multiple=True) + indicated_ttps = ElementField("Indicated_TTP", RelatedTTP, multiple=True, key_name="indicated_ttps") test_mechanisms = ElementField("Test_Mechanisms", TestMechanisms) alternative_id = ElementField("Alternative_ID", multiple=True) suggested_coas = ElementField("Suggested_COAs", SuggestedCOAs) sightings = ElementField("Sightings", Sightings) composite_indicator_expression = ElementField("Composite_Indicator_Expression", ObservableComposition) kill_chain_phases = ElementField("Kill_Chain_Phases", KillChainPhasesReference) - #TODO: should this be singular? - valid_time_positions = ElementField("Valid_Time_Position", ValidTime, multiple=True) + valid_time_positions = ElementField("Valid_Time_Position", ValidTime, multiple=True, key_name="valid_time_positions") related_indicators = ElementField("Related_Indicators", RelatedIndicators) - related_campaigns = ElementField("Related_Campagins") + related_campaigns = ElementField("Related_Campaigns") likely_impact = ElementField("Likely_Impact", Statement) negate = AttributeField("negate") related_packages = ElementField("Related_Packages", RelatedPackageRefs) @classmethod def initClassFields(cls): - cls.indicator_types.type_ = IndicatorTypes - cls.related_campaigns = RelatedCampaignRefs + cls.related_campaigns.type_ = RelatedCampaignRefs def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): @@ -764,7 +762,7 @@ def to_obj(self, return_obj=None, ns_info=None): root_observable = self.observables[0] obj.Observable = root_observable.to_obj(ns_info=ns_info) - return return_obj + return obj """ @classmethod @@ -806,6 +804,8 @@ def to_dict(self): if self.negate: d['negate'] = True + else: + if 'negate' in d: del d['negate'] if self.observables: if len(self.observables) == 1: diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index 56dbd227..aec3da2c 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -8,29 +8,40 @@ InformationSource ) import stix.bindings.indicator as indicator_binding - +from stix.base import AttributeField, ElementField +from stix.common.structured_text import StructuredTextListField class Sighting(stix.Entity): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = _binding.SightingType + timestamp = AttributeField("timestamp") + timestamp_precision = AttributeField("timestamp_precision") + descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") + source = ElementField("Source", InformationSource) + reference = ElementField("Reference") + confidence = ElementField("Confidence", Confidence) + related_observables = ElementField("Related_Observables") + + @classmethod + def initClassFields(cls): + cls.related_observables.type_ = RelatedObservables + def __init__(self, timestamp=None, timestamp_precision=None, description=None): + self._fields = {} self.timestamp = timestamp or utils.dates.now() self.timestamp_precision = timestamp_precision - self.description = description + self.descriptions = description self.source = None self.reference = None self.confidence = None - self.related_observables = RelatedObservables() - - @property - def timestamp(self): - return self._timestamp + """ @timestamp.setter def timestamp(self, value): self._timestamp = utils.dates.parse_value(value) + """ @property def description(self): @@ -43,45 +54,14 @@ def description(self): the description with the lowest ordinality value. Returns: - An instance of - :class:`.StructuredText` + An instance of :class:`.StructuredText` """ return next(iter(self.descriptions), None) @description.setter def description(self, value): - self.descriptions = value - - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) + self.descriptions = StructuredTextList(value) def add_description(self, description): """Adds a description to the ``descriptions`` collection. @@ -90,23 +70,8 @@ def add_description(self, description): """ self.descriptions.add(description) - - @property - def source(self): - return self._source - - @source.setter - def source(self, value): - self._set_var(InformationSource, try_cast=False, source=value) - - @property - def confidence(self): - return self._confidence - - @confidence.setter - def confidence(self, value): - self._set_var(Confidence, confidence=value) + """ def to_obj(self, return_obj=None, ns_info=None): super(Sighting, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -163,7 +128,7 @@ def from_dict(cls, d, return_obj=None): return_obj.descriptions = StructuredTextList.from_dict(d.get('description')) return_obj.related_observables = RelatedObservables.from_dict(d.get('related_observables')) return return_obj - + """ class Sightings(stix.EntityList): _namespace = "http://stix.mitre.org/Indicator-2" diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index bc255f5a..2812ebe8 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -4,35 +4,26 @@ import stix from stix.common import InformationSource, Statement import stix.bindings.indicator as indicator_binding - +from stix.base import IdField, AttributeField, ElementField class _BaseTestMechanism(stix.Entity): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = indicator_binding.TestMechanismType() + id_ = IdField("id") + idref = IdField("idref") + efficacy = ElementField("Efficacy", Statement) + producer = ElementField("Producer", InformationSource) + def __init__(self, id_=None, idref=None): + self._fields = {} self.id_ = id_ self.idref = idref self.efficacy = None self.producer = None - - @property - def efficacy(self): - return self._efficacy - - @efficacy.setter - def efficacy(self, value): - self._set_var(Statement, efficacy=value) - - @property - def producer(self): - return self._producer - - @producer.setter - def producer(self, value): - self._set_var(InformationSource, try_cast=False, producer=value) + @classmethod def from_obj(cls, obj, return_obj=None): if not obj: @@ -103,7 +94,7 @@ def to_dict(self): d = super(_BaseTestMechanism, self).to_dict() d['xsi:type'] = self._XSI_TYPE # added by subclass return d - + class TestMechanisms(stix.EntityList): _binding = indicator_binding diff --git a/stix/indicator/valid_time.py b/stix/indicator/valid_time.py index c8348a5c..6441fbe0 100644 --- a/stix/indicator/valid_time.py +++ b/stix/indicator/valid_time.py @@ -4,73 +4,18 @@ import stix from stix.common import DateTimeWithPrecision import stix.bindings.indicator as indicator_binding - +from stix.base import ElementField class ValidTime(stix.Entity): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = _binding.ValidTimeType + start_time = ElementField("Start_Time", DateTimeWithPrecision) + end_time = ElementField("End_Time", DateTimeWithPrecision) + def __init__(self, start_time=None, end_time=None): + self._fields = {} self.start_time = start_time self.end_time = end_time - - @property - def start_time(self): - return self._start_time - - @start_time.setter - def start_time(self, value): - self._set_var(DateTimeWithPrecision, start_time=value) - - @property - def end_time(self): - return self._end_time - - @end_time.setter - def end_time(self, value): - self._set_var(DateTimeWithPrecision, end_time=value) - - def to_obj(self, return_obj=None, ns_info=None): - super(ValidTime, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.start_time: - return_obj.Start_Time = self.start_time.to_obj(ns_info=ns_info) - if self.end_time: - return_obj.End_Time = self.end_time.to_obj(ns_info=ns_info) - - return return_obj - - def to_dict(self): - return super(ValidTime, self).to_dict() - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if return_obj is None: - return_obj = cls() - - return_obj.start_time = DateTimeWithPrecision.from_obj(obj.Start_Time) - return_obj.end_time = DateTimeWithPrecision.from_obj(obj.End_Time) - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if return_obj is None: - return_obj = cls() - - return_obj.start_time = DateTimeWithPrecision.from_dict(d.get('start_time')) - return_obj.end_time = DateTimeWithPrecision.from_dict(d.get('end_time')) - - return return_obj - -# NOT AN ACTUAL STIX TYPE -class _ValidTimePositions(stix.TypedList): - _contained_type = ValidTime diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index 9534a446..d9d668af 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -7,11 +7,15 @@ from stix.common import vocabs, Statement from stix.common.kill_chains import KillChainPhasesReference from stix.common.related import RelatedPackageRefs +from stix.ttp.related_ttps import RelatedTTPs +from stix.ttp.exploit_targets import ExploitTargets # relative from .behavior import Behavior from .resource import Resource from .victim_targeting import VictimTargeting +from stix.base import ElementField +from stix.common.vocabs import IntendedEffect class TTP(stix.BaseCoreComponent): @@ -38,6 +42,15 @@ class TTP(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = "ttp" + behavior = ElementField("Behavior", Behavior) + related_ttps = ElementField("Related_TTPs", RelatedTTPs) + intended_effects = ElementField("Intended_Effect", IntendedEffect, multiple=True) + resources = ElementField("Resources", Resource) + victim_targeting = ElementField("Victim_Targeting", VictimTargeting) + exploit_targets = ElementField("Exploit_Targets", ExploitTargets) + related_packages = ElementField("Related_Pacakges", RelatedPackageRefs) + kill_chain_phases = ElementField("Kill_Chain_Phases", KillChainPhasesReference) + def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): @@ -55,35 +68,9 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.intended_effects = None self.resources = None self.victim_targeting = None - self.exploit_targets = ExploitTargets() self.related_packages = None self.kill_chain_phases = None - @property - def behavior(self): - """A :class:`.Behavior` field. - - """ - return self._behavior - - @behavior.setter - def behavior(self, value): - self._set_var(Behavior, try_cast=False, behavior=value) - - @property - def related_ttps(self): - """A collection of :class:`.RelatedTTP` objects. This behaves like a - ``MutableSequence`` Type. - - """ - return self._related_ttps - - @related_ttps.setter - def related_ttps(self, value): - if isinstance(value, RelatedTTPs): - self._related_ttps = value - else: - self._related_ttps = RelatedTTPs(value) def add_related_ttp(self, value): """Adds an Related TTP to the :attr:`related_ttps` list @@ -117,21 +104,6 @@ def add_related_ttp(self, value): """ self.related_ttps.append(value) - @property - def exploit_targets(self): - """A collection of :class:`.ExploitTarget` objects. This behaves like - a ``MutableSequence`` type. - - """ - return self._exploit_targets - - @exploit_targets.setter - def exploit_targets(self, value): - if isinstance(value, ExploitTargets): - self._exploit_targets = value - else: - self._exploit_targets = ExploitTargets(value) - def add_exploit_target(self, value): """Adds a :class:`.ExploitTarget` object to the :attr:`exploit_targets` collection. @@ -139,22 +111,6 @@ def add_exploit_target(self, value): """ self.exploit_targets.append(value) - @property - def intended_effects(self): - """A collection of :class:`.Statement` objects. This behaves like a - ``MutableSequence`` type. - - If set to a string, an attempt will be made to convert it into a - :class:`.Statement` object with its value set to an instance of - :class:`.IntendedEffect`. - - """ - return self._intended_effects - - @intended_effects.setter - def intended_effects(self, value): - self._intended_effects = _IntendedEffects(value) - def add_intended_effect(self, value): """Adds a :class:`.Statement` object to the :attr:`intended_effects` collection. @@ -165,42 +121,6 @@ def add_intended_effect(self, value): """ self.intended_effects.append(value) - @property - def resources(self): - """A collection of :class:`.Resource` objects. This behaves like a - ``MutableSequence`` type. - - """ - return self._resources - - @resources.setter - def resources(self, value): - self._set_var(Resource, resources=value) - - @property - def victim_targeting(self): - """A collection of :class:`.VictimTargeting` objects. This behaves like - a ``MutableSequence`` type. - - """ - return self._victim_targeting - - @victim_targeting.setter - def victim_targeting(self, value): - self._set_var(VictimTargeting, try_cast=False, victim_targeting=value) - - @property - def kill_chain_phases(self): - """A collection of :class:`.KillChainPhaseReference` objects. This - behaves like a ``MutableSequence`` type. - - """ - return self._kill_chain_phases - - @kill_chain_phases.setter - def kill_chain_phases(self, value): - self._kill_chain_phases = KillChainPhasesReference(value) - def add_kill_chain_phase(self, value): """Adds a :class:`.KillChainPhaseReference` to the :attr:`kill_chain_phases` collection. @@ -236,6 +156,7 @@ def add_related_package(self, value): """ self.related_packages.append(value) + """ def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() @@ -307,7 +228,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.kill_chain_phases = KillChainPhasesReference.from_dict(get('kill_chain_phases')) return return_obj - + """ # NOT ACTUAL STIX TYPE class _IntendedEffects(stix.TypedList): From bd6fd6c740bbe874a93275dfe7d0208bd5a503d4 Mon Sep 17 00:00:00 2001 From: apsillers Date: Mon, 17 Aug 2015 16:25:24 -0400 Subject: [PATCH 174/438] WIP: Partial Incident TypedField conversion --- stix/incident/__init__.py | 271 ++++++-------------------------------- 1 file changed, 42 insertions(+), 229 deletions(-) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index c13184b3..b23ea9ab 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -20,7 +20,8 @@ from .impact_assessment import ImpactAssessment from .coa import COATaken, COARequested, COATime # noqa from .history import History - +from stix.base import ElementField +from stix.common.structured_text import StructuredTextListField class Incident(stix.BaseCoreComponent): """Implementation of the STIX Incident. @@ -46,6 +47,40 @@ class Incident(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'incident' + status = ElementField("Status", vocabs.IncidentStatus) + time = ElementField("Time", Time) + victims = ElementField("Victim", Identity, multiple=True, key_name="victims") + attributed_threat_actors = ElementField("Attributed_Threat_Actors") + related_indicators = ElementField("Related_Indicators") + related_observables = ElementField("Related_Observables") + related_incidents = ElementField("Related_Incidents") + related_packages = ElementField("Related_Packages", RelatedPackageRefs) + affected_assets = ElementField("Affected_Assets") + categories = ElementField("Categories") + intended_effects = ElementField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") + leveraged_ttps = ElementField("Leveraged_TTPs") + discovery_methods = ElementField("Discovery_Method", vocabs.DiscoveryMethod, multiple=True, key_name="discovery_methods") + reporter = ElementField("Reporter", InformationSource) + responders = ElementField("Responder", InformationSource, multiple=True, key_name="responders") + coordinators = ElementField("Coordinator", InformationSource, multiple=True, key_name="coordinators") + external_ids = ElementField("External_ID", ExternalID, multiple=True, key_name="external_ids") + impact_assessment = ElementField("Impact_Assessment", ImpactAssessment) + security_compromise = ElementField("Security_Compromise", vocabs.SecurityCompromise) + confidence = ElementField("Confidence", Confidence) + coa_taken = ElementField("COA_Taken", COATaken) + coa_requested = ElementField("COA_Requested", COARequested, multiple=True) + history = ElementField("History", History, multiple=True) + + @classmethod + def initClassFields(cls): + cls.attributed_threat_actors.type_ = AttributedThreatActors + cls.related_indicators.type_ = RelatedIndicators + cls.related_observables.type_ = RelatedObservables + cls.related_incidents.type_ = RelatedIncidents + cls.affected_assets.type_ = AffectedAssets + cls.categories.type_ = IncidentCategories + cls.leveraged_ttps.type_ = LeveragedTTPs + def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): super(Incident, self).__init__( id_=id_, @@ -80,47 +115,6 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, description self.coa_requested = None self.history = History() - - @property - def status(self): - """A :class:`.VocabString` property. If set to a string, an attempt - will be made to convert it to an instance of :class:`.IncidentStatus`. - - """ - return self._status - - @status.setter - def status(self, value): - self._set_vocab(vocabs.IncidentStatus, status=value) - - @property - def time(self): - """Time section of the Incident. This is a :class:`.time.Time` field. - - """ - return self._time - - @time.setter - def time(self, value): - self._set_var(Time, try_cast=False, time=value) - - @property - def intended_effects(self): - """The impact of this intended effects of this Incident. This is a - collection of :class:`.Statement` objects and behaves like a - ``MutableSequence`` type. - - If set to a string, an attempt will be made to convert it into a - :class:`.Statement` object with its value set to an instance of - :class:`.IntendedEffect`. - - """ - return self._intended_effects - - @intended_effects.setter - def intended_effects(self, value): - self._intended_effects = _IntendedEffects(value) - def add_intended_effect(self, value): """Adds a :class:`.Statement` object to the :attr:`intended_effects` collection. @@ -131,17 +125,6 @@ def add_intended_effect(self, value): """ self.intended_effects.append(value) - @property - def victims(self): - """A collection of victim :class:`.Identity` objects. This behaves like - a ``MutableSequence`` type. - - """ - return self._victims - - @victims.setter - def victims(self, value): - self._victims = _Victims(value) def add_victim(self, victim): """Adds a :class:`.IdentityType` value to the :attr:`victims` @@ -150,18 +133,6 @@ def add_victim(self, victim): """ self._victims.append(victim) - @property - def categories(self): - """A collection of :class:`.VocabString` objects. This behaves - like a ``MutableSequence`` type. - - """ - return self._categories - - @categories.setter - def categories(self, value): - self._categories = IncidentCategories(value) - def add_category(self, category): """Adds a :class:`.VocabString` object to the :attr:`categories` collection. @@ -171,18 +142,6 @@ def add_category(self, category): """ self.categories.append(category) - - @property - def affected_assets(self): - """A collection of :class:`.AffectedAsset` objects. This behaves like - a ``MutableSequence`` type. - - """ - return self._affected_assets - - @affected_assets.setter - def affected_assets(self, value): - self._affected_assets = AffectedAssets(value) def add_affected_asset(self, v): """Adds a :class:`.AffectedAsset` object to the :attr:`affected_assets` @@ -191,18 +150,6 @@ def add_affected_asset(self, v): """ self.affected_assets.append(v) - @property - def discovery_methods(self): - """A :class:`.VocabString` collection. This behaves like a - ``MutableSequence`` type. - - """ - return self._discovery_methods - - @discovery_methods.setter - def discovery_methods(self, value): - self._discovery_methods = DiscoveryMethods(value) - def add_discovery_method(self, value): """Adds a :class:`.VocabString` object to the :attr:`discovery_methods` collection. @@ -213,31 +160,6 @@ def add_discovery_method(self, value): """ self.discovery_methods.append(value) - @property - def reporter(self): - """A :class:`.InformationSource` field. - - """ - return self._reporter - - @reporter.setter - def reporter(self, value): - self._set_var(InformationSource, try_cast=False, reporter=value) - - @property - def responders(self): - """A class of :class:`.InformationSource` objects which contain - information about incident responders. - - This behaves like a ``MutableSequence`` type. - - """ - return self._responders - - @responders.setter - def responders(self, value): - self._responders = _InformationSources(value) - def add_responder(self, value): """Adds a :class:`.InformationSource` object to the :attr:`responders` collection. @@ -245,18 +167,6 @@ def add_responder(self, value): """ self.responders.append(value) - @property - def coordinators(self): - """A class of :class:`.InformationSource` objects. This behaves like a - ``MutableSequence`` type. - - """ - return self._coordinators - - @coordinators.setter - def coordinators(self, value): - self._coordinators = _InformationSources(value) - def add_coordinator(self, value): """Adds a :class:`.InformationSource` object to the :attr:`coordinators` collection. @@ -264,18 +174,6 @@ def add_coordinator(self, value): """ self.coordinators.append(value) - @property - def external_ids(self): - return self._external_ids - - @external_ids.setter - def external_ids(self, value): - """A collection of :class:`.ExternalID` objects for capturing - incident tracker identification information. - - """ - self._external_ids = _ExternalIDs(value) - def add_external_id(self, value): """Adds a :class:`.ExternalID` object to the :attr:`external_ids` collection. @@ -283,54 +181,6 @@ def add_external_id(self, value): """ self.external_ids.append(value) - @property - def impact_assessment(self): - """A class :class:`.ImpactAssessment` field. - - """ - return self._impact_assessment - - @impact_assessment.setter - def impact_assessment(self, value): - self._set_var(ImpactAssessment, try_cast=False, impact_assessment=value) - - @property - def security_compromise(self): - """A :class:`.VocabString` field. If set to a string, an attempt will - be made to convert it into an instance of :class:`.SecurityCompromise`. - - """ - return self._security_compromise - - @security_compromise.setter - def security_compromise(self, value): - self._set_vocab(vocabs.SecurityCompromise, security_compromise=value) - - @property - def confidence(self): - """A :class:`.Confidence` field. - - """ - return self._confidence - - @confidence.setter - def confidence(self, value): - self._set_var(Confidence, confidence=value) - - @property - def coa_taken(self): - """A collection of :class:`.COATaken` objects which characterize - courses of action taken during the incident. - - This behaves like a ``MutableSequence`` type. - - """ - return self._coa_taken - - @coa_taken.setter - def coa_taken(self, value): - self._coa_taken = _COAsTaken(value) - def add_coa_taken(self, value): """Adds a :class:`.COATaken` object to the :attr:`coas_taken` collection. @@ -338,20 +188,6 @@ def add_coa_taken(self, value): """ self.coa_taken.append(value) - @property - def coa_requested(self): - """A collection of :class:`.COARequested` objects which characterize - courses of action requested for response to this incident. - - This behaves like a ``MutableSequence`` type. - - """ - return self._coa_requested - - @coa_requested.setter - def coa_requested(self, value): - self._coa_requested = _COAsRequested(value) - def add_coa_requested(self, value): """Adds a :class:`.COARequested` object to the :attr:`coas_requested` collection. @@ -359,18 +195,6 @@ def add_coa_requested(self, value): """ self.coa_requested.append(value) - @property - def related_indicators(self): - """A collection of :class:`.RelatedIndicator` objects characterizing - indicators related to this incident. - - """ - return self._related_indicators - - @related_indicators.setter - def related_indicators(self, value): - self._set_var(RelatedIndicators, related_indicators=value) - def add_related_indicator(self, value): """Adds an Related Indicator to the :attr:`related_indicators` list property of this :class:`Incident`. @@ -403,14 +227,6 @@ def add_related_indicator(self, value): """ self.related_indicators.append(value) - @property - def related_observables(self): - return self._related_observables - - @related_observables.setter - def related_observables(self, value): - self._set_var(RelatedObservables, related_observables=value) - def add_related_observable(self, value): """Adds a Related Observable to the ``related_observables`` list property of this :class:`Incident`. @@ -443,17 +259,10 @@ def add_related_observable(self, value): """ self.related_observables.append(value) - @property - def related_packages(self): - return self._related_packages - - @related_packages.setter - def related_packages(self, value): - self._related_packages = RelatedPackageRefs(value) - def add_related_package(self, value): self.related_packages.append(value) +""" def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() @@ -585,7 +394,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) return return_obj - +""" class AttributedThreatActors(GenericRelationshipList): _namespace = "http://stix.mitre.org/Incident-1" @@ -692,3 +501,7 @@ class _IntendedEffects(stix.TypedList): def _fix_value(self, value): return Statement(value=vocabs.IntendedEffect(value)) + + +Incident.initClassFields() + From 5c6b2a48d2a3420f654ebc930275838ede5ffe76 Mon Sep 17 00:00:00 2001 From: apsillers Date: Wed, 19 Aug 2015 18:51:46 -0400 Subject: [PATCH 175/438] WIP: TypedFields Kill Chains; also Sightings, Confidence, Incident --- stix/common/confidence.py | 4 +- stix/common/kill_chains/__init__.py | 59 ++++++++++++++++++----------- stix/incident/__init__.py | 27 +------------ stix/indicator/sightings.py | 7 +++- 4 files changed, 47 insertions(+), 50 deletions(-) diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 601042ba..9c6e1f2e 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -37,7 +37,8 @@ def __init__(self, value=None, timestamp=None, description=None, source=None): def initClassFields(cls): from .information_source import InformationSource cls.source.type_ = InformationSource - + + """ @property def timestamp(self): return self._timestamp @@ -45,6 +46,7 @@ def timestamp(self): @timestamp.setter def timestamp(self, value): self._timestamp = utils.dates.parse_value(value) + """ @property def description(self): diff --git a/stix/common/kill_chains/__init__.py b/stix/common/kill_chains/__init__.py index 02189dda..83450234 100644 --- a/stix/common/kill_chains/__init__.py +++ b/stix/common/kill_chains/__init__.py @@ -4,32 +4,36 @@ # internal import stix import stix.bindings.stix_common as common_binding - +from stix.base import AttributeField, ElementField class KillChain(stix.Entity): _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' _binding_class = _binding.KillChainType + id_ = AttributeField("id_") + name = AttributeField("name") + definer = AttributeField("definer") + reference = AttributeField("reference") + number_of_phases = AttributeField("number_of_phases") + kill_chain_phases = ElementField("Kill_Chain_Phase", multiple=True, key_name="kill_chain_phases") + + @classmethod + def initClassField(cls): + cls.kill_chain_phases.type_ = KillChainPhase + def __init__(self, id_=None, name=None, definer=None, reference=None): + self._fields = {} self.id_ = id_ self.name = name self.definer = definer self.reference = reference self.number_of_phases = None # can we just do len(self.kill_chain_phases)? - self.kill_chain_phases = None - - @property - def kill_chain_phases(self): - return self._kill_chain_phases - - @kill_chain_phases.setter - def kill_chain_phases(self, value): - self._kill_chain_phases = _KillChainPhases(value) def add_kill_chain_phase(self, value): self.kill_chain_phases.append(value) + """ def to_obj(self, return_obj=None, ns_info=None): super(KillChain, self).to_obj(return_obj=return_obj, ns_info=ns_info) @@ -44,7 +48,8 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.Kill_Chain_Phase = self.kill_chain_phases.to_obj(ns_info=ns_info) return return_obj - + """ + def __eq__(self, other): if self is other: return True @@ -57,6 +62,7 @@ def __eq__(self, other): def __ne__(self, other): return not self.__eq__(other) + """ @classmethod def from_obj(cls, obj, return_obj=None): if not obj: @@ -90,7 +96,7 @@ def from_dict(cls, d, return_obj=None): _KillChainPhases.from_dict(get('kill_chain_phases')) return return_obj - + """ class KillChains(stix.EntityList): _binding = common_binding @@ -106,19 +112,18 @@ class KillChainPhase(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' _binding_class = _binding.KillChainPhaseType + phase_id = AttributeField("phase_id") + name = AttributeField("name") + ordinality = AttributeField("ordinality") + def __init__(self, phase_id=None, name=None, ordinality=None): + self._fields = {} self.phase_id = phase_id self.name = name self.ordinality = ordinality - @property - def phase_id(self): - return self._phase_id - - @phase_id.setter - def phase_id(self, value): - self._set_var(basestring, try_cast=False, phase_id=value) + """ @property def ordinality(self): return self._ordinality @@ -129,7 +134,8 @@ def ordinality(self, value): self._ordinality = int(value) else: self._ordinality = None - + """ + """ def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() @@ -141,7 +147,8 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.ordinality = self.ordinality return return_obj - + """ + def __eq__(self, other): if other is self: return True @@ -157,6 +164,7 @@ def __ne__(self, other): def __hash__(self): return hash(tuple(sorted(self.to_dict().items()))) + """ @classmethod def from_obj(cls, obj, return_obj=None): if not obj: @@ -186,18 +194,23 @@ def from_dict(cls, d, return_obj=None): def to_dict(self): return super(KillChainPhase, self).to_dict() - + """ class KillChainPhaseReference(KillChainPhase): _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' _binding_class = _binding.KillChainPhaseReferenceType + kill_chain_id = AttributeField("kill_chain_id") + kill_chain_name = AttributeField("kill_chain_name") + def __init__(self, phase_id=None, name=None, ordinality=None, kill_chain_id=None, kill_chain_name=None): + self._fields = {} super(KillChainPhaseReference, self).__init__(phase_id, name, ordinality) self.kill_chain_id = kill_chain_id self.kill_chain_name = kill_chain_name + """ def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() @@ -234,7 +247,7 @@ def from_dict(cls, d, return_obj=None): return_obj.kill_chain_id = d.get('kill_chain_id') return_obj.kill_chain_name = d.get('kill_chain_name') return return_obj - + """ class KillChainPhasesReference(stix.EntityList): _binding = common_binding diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index b23ea9ab..d47e40e1 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -67,9 +67,9 @@ class Incident(stix.BaseCoreComponent): impact_assessment = ElementField("Impact_Assessment", ImpactAssessment) security_compromise = ElementField("Security_Compromise", vocabs.SecurityCompromise) confidence = ElementField("Confidence", Confidence) - coa_taken = ElementField("COA_Taken", COATaken) + coa_taken = ElementField("COA_Taken", COATaken, multiple=True) coa_requested = ElementField("COA_Requested", COARequested, multiple=True) - history = ElementField("History", History, multiple=True) + history = ElementField("History", History) @classmethod def initClassFields(cls): @@ -91,29 +91,6 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, description short_description=short_description ) - self.status = None - self.time = None - self.victims = None - self.attributed_threat_actors = AttributedThreatActors() - self.related_indicators = RelatedIndicators() - self.related_observables = RelatedObservables() - self.related_incidents = RelatedIncidents() - self.related_packages = RelatedPackageRefs() - self.affected_assets = None - self.categories = None - self.intended_effects = None - self.leveraged_ttps = LeveragedTTPs() - self.discovery_methods = None - self.reporter = None - self.responders = None - self.coordinators = None - self.external_ids = None - self.impact_assessment = None - self.security_compromise = None - self.confidence = None - self.coa_taken = None - self.coa_requested = None - self.history = History() def add_intended_effect(self, value): """Adds a :class:`.Statement` object to the :attr:`intended_effects` diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index aec3da2c..ccd62a67 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -138,13 +138,17 @@ class Sightings(stix.EntityList): _binding_var = "Sighting" _inner_name = "sightings" + sightings_count = AttributeField("sightings_count") + def __init__(self, sightings_count=None, *args): + self._fields = {} super(Sightings, self).__init__(*args) self.sightings_count = sightings_count def __nonzero__(self): return super(Sightings, self).__nonzero__() or bool(self.sightings_count) + """ @property def sightings_count(self): return self._sightings_count @@ -152,7 +156,8 @@ def sightings_count(self): @sightings_count.setter def sightings_count(self, value): self._set_var(int, sightings_count=value) - + """ + def to_obj(self, return_obj=None, ns_info=None): list_obj = super(Sightings, self).to_obj(return_obj=return_obj, ns_info=ns_info) list_obj.sightings_count = self.sightings_count From 84befaead8058bb23b6012407d53271d998e0be9 Mon Sep 17 00:00:00 2001 From: apsillers Date: Mon, 24 Aug 2015 10:13:32 -0400 Subject: [PATCH 176/438] WIP: Campaign/test fixes --- stix/base.py | 18 +++++++++++++----- stix/campaign/__init__.py | 20 +++++--------------- stix/test/campaign_test.py | 19 +++++++++---------- 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/stix/base.py b/stix/base.py index a42e10be..193c213d 100644 --- a/stix/base.py +++ b/stix/base.py @@ -414,13 +414,18 @@ def from_dict(cls, cls_dict=None, return_obj=None): for field in cls._get_vars(): val = cls_dict.get(field.key_name) if field.type_: - if issubclass(field.type_, EntityList): - val = field.type_.from_list(val) - elif field.multiple: + if field.multiple: if val is not None: - val = [field.type_.from_dict(x) for x in val] + if type(val) is list: + val = [field.type_.from_dict(x) for x in val] + else: + # sometimes multiple fields are supplied with a single dict as input instead of a list + # TypedList (now obsolete) used to do this; now TypedField has to + val = [field.type_.from_dict(val)] else: val = [] + elif issubclass(field.type_, EntityList): + val = field.type_.from_list(val) else: val = field.type_.from_dict(val) else: @@ -624,6 +629,9 @@ def from_dict(cls, dict_repr, return_obj=None, contained_type=None, if not inner_name: inner_name = cls._inner_name + if inner_name == "attribution": + pass + for item in dict_repr.get(inner_name, []): return_obj.append(contained_type.from_dict(item)) @@ -795,7 +803,7 @@ def initClassFields(cls): import data_marking import common from stix.common.structured_text import StructuredTextList, StructuredTextListField - cls.handling.type_ = data_marking.MarkingStructure + cls.handling.type_ = data_marking.Marking #cls.information_source.type_ = common.InformationSource cls.descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") cls.short_descriptions = StructuredTextListField("Short_Description", StructuredTextList, key_name="short_description") diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index d394858f..0879a8e5 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -12,6 +12,7 @@ import stix.bindings.campaign as campaign_binding from stix.common.structured_text import StructuredTextList, StructuredTextListField from stix.base import ElementField, AttributeField +from stix.common.information_source import InformationSource class AssociatedCampaigns(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" @@ -43,7 +44,7 @@ def __init__(self, scope=None, *args): _binding_var = "Attributed_Threat_Actor" _contained_type = RelatedThreatActor _inner_name = "threat_actors" -""" +""" class RelatedIncidents(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" @@ -121,6 +122,7 @@ class Campaign(stix.BaseCoreComponent): related_incidents = ElementField("Related_Incidents", RelatedIncidents) related_indicators = ElementField("Related_Indicators", RelatedIndicators) related_packages = ElementField("Related_Packages", RelatedPackageRefs) + information_source = ElementField("Information_Source", InformationSource) def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): @@ -134,23 +136,15 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, short_description=short_description ) - self.names = None - self.intended_effects = _IntendedEffects() - self.status = None self.related_ttps = RelatedTTPs() self.related_incidents = RelatedIncidents() self.related_indicators = RelatedIndicators() - self.attribution = Attribution() - self.confidence = None - #self.activity = _Activities() self.related_packages = RelatedPackageRefs() def add_intended_effect(self, value): self.intended_effects.append(value) - - def add_activity(self, value): """Adds an :class:`.Activity` object to the :attr:`activity` collection. @@ -301,12 +295,8 @@ def from_dict(cls, dict_repr, return_obj=None): """ # Not Actual STIX Types! -class _AttributionList(stix.TypedList): - _contained_type = Attribution - - -class _Activities(stix.TypedList): - _contained_type = Activity +#class _Activities(stix.TypedList): +# _contained_type = Activity class _IntendedEffects(stix.TypedList): diff --git a/stix/test/campaign_test.py b/stix/test/campaign_test.py index d675c3c2..16e2c8a2 100644 --- a/stix/test/campaign_test.py +++ b/stix/test/campaign_test.py @@ -79,11 +79,11 @@ class AttributionTests(EntityTestCase, unittest.TestCase): class AttributionListTests(TypedListTestCase, unittest.TestCase): - klass = campaign._AttributionList + klass = campaign.Campaign - _full_dict = [ + _full_dict = { 'attribution': [ AttributionTests._full_dict - ] + ] } class AssociatedCampaignsTests(EntityTestCase, unittest.TestCase): @@ -97,12 +97,11 @@ class AssociatedCampaignsTests(EntityTestCase, unittest.TestCase): } -class ActivitiesTests(TypedListTestCase, unittest.TestCase): - klass = campaign._Activities +class ActivityTests(TypedListTestCase, unittest.TestCase): + klass = campaign.Activity - _full_dict = [ - activity_test.ActivityTests._full_dict - ] + _full_dict = activity_test.ActivityTests._full_dict + class CampaignTest(EntityTestCase, unittest.TestCase): @@ -123,10 +122,10 @@ class CampaignTest(EntityTestCase, unittest.TestCase): 'related_ttps': RelatedTTPsTest._full_dict, 'related_incidents': RelatedIncidentsTests._full_dict, 'related_indicators': RelatedIndicatorsTests._full_dict, - 'attribution': AttributionListTests._full_dict, + 'attribution': [AttributionTests._full_dict], 'associated_campaigns': AssociatedCampaignsTests._full_dict, 'confidence': confidence_test.ConfidenceTests._full_dict, - 'activity': ActivitiesTests._full_dict, + 'activity': [ActivityTests._full_dict], 'information_source': information_source_test.InformationSourceTests._full_dict, 'handling': data_marking_test.MarkingTests._full_dict, 'related_packages': related_test.RelatedPackageRefsTests._full_dict From 33986e216c231e64f10e0cc1e09bcb2e4d81fb45 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas Date: Tue, 8 Sep 2015 15:25:59 -0400 Subject: [PATCH 177/438] Added signals.emit() to all classes All classes inside the stix package call emit() in their from_obj() function. --- stix/campaign/__init__.py | 5 +++ stix/coa/__init__.py | 2 ++ stix/coa/objective.py | 6 ++++ stix/coa/structured_coa.py | 2 ++ stix/common/__init__.py | 3 ++ stix/common/activity.py | 5 +++ stix/common/campaign_reference.py | 4 +++ stix/common/confidence.py | 3 ++ stix/common/datetimewithprecision.py | 6 ++++ stix/common/identity.py | 2 ++ stix/common/information_source.py | 2 ++ stix/common/kill_chains/__init__.py | 7 ++++ stix/common/related.py | 7 ++++ stix/common/statement.py | 3 ++ stix/common/structured_text.py | 3 ++ stix/common/tools.py | 4 ++- stix/common/vocabs.py | 3 ++ stix/core/stix_header.py | 5 +++ stix/core/stix_package.py | 4 ++- stix/core/ttps.py | 5 +++ stix/exploit_target/__init__.py | 4 +++ stix/exploit_target/configuration.py | 5 +++ stix/exploit_target/vulnerability.py | 6 ++++ stix/exploit_target/weakness.py | 5 +++ stix/extensions/identity/ciq_identity_3_0.py | 33 ++++++++++++++++++- stix/extensions/malware/maec_4_1_malware.py | 2 ++ stix/extensions/marking/simple_marking.py | 5 +++ .../marking/terms_of_use_marking.py | 5 +++ stix/extensions/marking/tlp.py | 5 +++ .../structured_coa/generic_structured_coa.py | 4 +++ .../test_mechanism/generic_test_mechanism.py | 5 +++ .../open_ioc_2010_test_mechanism.py | 3 ++ .../test_mechanism/snort_test_mechanism.py | 5 +++ .../test_mechanism/yara_test_mechanism.py | 5 +++ stix/incident/__init__.py | 4 +++ stix/incident/affected_asset.py | 4 +++ stix/incident/coa.py | 7 ++++ stix/incident/direct_impact_summary.py | 6 ++++ stix/incident/external_id.py | 6 ++++ stix/incident/history.py | 5 +++ stix/incident/impact_assessment.py | 4 +++ stix/incident/indirect_impact_summary.py | 6 ++++ stix/incident/loss_estimation.py | 6 ++++ stix/incident/property_affected.py | 7 ++++ stix/incident/time.py | 5 +++ stix/incident/total_loss_estimation.py | 5 +++ stix/indicator/indicator.py | 2 ++ stix/indicator/sightings.py | 8 +++++ stix/indicator/test_mechanism.py | 2 ++ stix/indicator/valid_time.py | 6 ++++ stix/report/__init__.py | 4 ++- stix/report/header.py | 5 +++ stix/threat_actor/__init__.py | 5 +++ stix/ttp/__init__.py | 4 +++ stix/ttp/attack_pattern.py | 2 ++ stix/ttp/behavior.py | 6 ++++ stix/ttp/exploit.py | 2 ++ stix/ttp/infrastructure.py | 2 ++ stix/ttp/malware_instance.py | 2 ++ stix/ttp/resource.py | 4 +++ stix/ttp/victim_targeting.py | 2 ++ 61 files changed, 290 insertions(+), 4 deletions(-) diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 451f15ca..418169c7 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix from stix.utils.deprecated import deprecated from stix.common import Activity, Confidence, Statement, VocabString @@ -244,6 +248,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.related_packages = \ RelatedPackageRefs.from_obj(obj.Related_Packages) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/coa/__init__.py b/stix/coa/__init__.py index 2469d53e..63ec1c58 100644 --- a/stix/coa/__init__.py +++ b/stix/coa/__init__.py @@ -3,6 +3,7 @@ # external from cybox.core import Observables +from mixbox import signals # internal import stix @@ -220,6 +221,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.structured_coa = \ _BaseStructuredCOA.from_obj(obj.Structured_COA) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/coa/objective.py b/stix/coa/objective.py index 0c7a5764..933c7465 100644 --- a/stix/coa/objective.py +++ b/stix/coa/objective.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix from stix.common import StructuredTextList, Confidence import stix.bindings.course_of_action as coa_binding @@ -166,6 +170,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.descriptions = StructuredTextList.from_obj(obj.Description) return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) return_obj.applicability_confidence = Confidence.from_obj(obj.Applicability_Confidence) + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/coa/structured_coa.py b/stix/coa/structured_coa.py index 2621e7cb..b28dee11 100644 --- a/stix/coa/structured_coa.py +++ b/stix/coa/structured_coa.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox import signals from mixbox.cache import Cached # internal @@ -33,6 +34,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.id_ = obj.id return_obj.idref = obj.idref + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/common/__init__.py b/stix/common/__init__.py index 5782fe1b..3d5ebb4f 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -3,6 +3,8 @@ from __future__ import absolute_import +from mixbox import signals + from .structured_text import StructuredText, StructuredTextList # noqa from .vocabs import VocabString # noqa from .datetimewithprecision import DateTimeWithPrecision # noqa @@ -89,6 +91,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.value = obj.valueOf_ return_obj.encoded = obj.encoded + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/common/activity.py b/stix/common/activity.py index ed4e23aa..117b4a92 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix import stix.bindings.stix_common as common_binding @@ -105,6 +109,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.date_time = DateTimeWithPrecision.from_obj(obj.Date_Time) return_obj.descriptions = StructuredTextList.from_obj(obj.Description) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/common/campaign_reference.py b/stix/common/campaign_reference.py index e8ff1ebe..00cb252e 100644 --- a/stix/common/campaign_reference.py +++ b/stix/common/campaign_reference.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + # internal import stix import stix.utils as utils @@ -73,6 +76,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.timestamp = obj.timestamp return_obj.names = Names.from_obj(obj.Names) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 5fffea24..a0c671c0 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -3,6 +3,8 @@ from __future__ import absolute_import +from mixbox import signals + import stix import stix.utils as utils import stix.bindings.stix_common as common_binding @@ -156,6 +158,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.descriptions = StructuredTextList.from_obj(obj.Description) return_obj.source = InformationSource.from_obj(obj.Source) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/common/datetimewithprecision.py b/stix/common/datetimewithprecision.py index 503e706e..e9fbbeae 100644 --- a/stix/common/datetimewithprecision.py +++ b/stix/common/datetimewithprecision.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix import stix.utils as utils import stix.bindings.stix_common as common_binding @@ -60,6 +64,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.value = obj.valueOf_ return_obj.precision = obj.precision + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/common/identity.py b/stix/common/identity.py index 11f8b93f..f3538b2e 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox import signals from mixbox.cache import Cached # internal @@ -100,6 +101,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.related_identities = \ RelatedIdentities.from_obj(obj.Related_Identities) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 44d9dfef..10452b6f 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -5,6 +5,7 @@ # external import cybox.common +from mixbox import signals # internal import stix @@ -200,6 +201,7 @@ def from_obj(cls, obj, return_obj=None): if obj.Tools: return_obj.tools = cybox.common.ToolInformationList.from_obj(obj.Tools) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/common/kill_chains/__init__.py b/stix/common/kill_chains/__init__.py index 02189dda..9899c6f2 100644 --- a/stix/common/kill_chains/__init__.py +++ b/stix/common/kill_chains/__init__.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + # internal import stix import stix.bindings.stix_common as common_binding @@ -71,6 +74,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.number_of_phases = obj.number_of_phases return_obj.kill_chain_phases = _KillChainPhases.from_obj(obj.Kill_Chain_Phase) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod @@ -169,6 +173,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.name = obj.name return_obj.ordinality = obj.ordinality + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod @@ -218,6 +223,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.kill_chain_id = obj.kill_chain_id return_obj.kill_chain_name = obj.kill_chain_name + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/common/related.py b/stix/common/related.py index 24f08f85..34adc34a 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -4,6 +4,9 @@ # stdlib from __future__ import absolute_import +# external +from mixbox import signals + # internal import stix import stix.utils as utils @@ -66,6 +69,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.information_source = InformationSource.from_obj(obj.Information_Source) return_obj.relationship = VocabString.from_obj(obj.Relationship) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): @@ -170,6 +174,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.idref = obj.idref return_obj.timestamp = obj.timestamp + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod @@ -248,6 +253,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.scope = obj.scope + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod @@ -382,6 +388,7 @@ def from_obj(cls, obj, return_obj=None): contained_item = getattr(obj, cls._inner_var) return_obj.item = cls._base_type.from_obj(contained_item) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/common/statement.py b/stix/common/statement.py index a7284758..188e4fcb 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -3,6 +3,8 @@ from __future__ import absolute_import +from mixbox import signals + import stix import stix.utils as utils import stix.bindings.stix_common as common_binding @@ -152,6 +154,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.source = InformationSource.from_obj(obj.Source) return_obj.confidence = Confidence.from_obj(obj.Confidence) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index c1257751..42c45551 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -1,6 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import signals + import itertools import contextlib import collections @@ -120,6 +122,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.ordinality = obj.ordinality return_obj.structuring_format = obj.structuring_format + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/common/tools.py b/stix/common/tools.py index 9515306b..91ff107a 100644 --- a/stix/common/tools.py +++ b/stix/common/tools.py @@ -3,6 +3,7 @@ # external import cybox.common +from mixbox import signals # internal import stix @@ -117,7 +118,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.title = obj.Title return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) - + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index ab23e097..3e401c11 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -1,6 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import signals + import stix import stix.bindings.stix_common as stix_common_binding @@ -120,6 +122,7 @@ def from_obj(cls, vocab_obj, return_obj=None): return_obj.vocab_reference = vocab_obj.vocab_reference return_obj.xsi_type = vocab_obj.xsi_type + signals.emit("Entity.created.from_obj", return_obj, vocab_obj) return return_obj @classmethod diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index bf0db5cc..28395a8e 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix from stix.utils.deprecated import deprecated from stix.common import InformationSource, StructuredTextList, VocabString @@ -248,6 +252,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.package_intents = _PackageIntents.from_obj(obj.Package_Intent) return_obj.profiles = obj.Profiles.Profile if obj.Profiles else [] + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 79061ef5..2faf27bc 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -1,7 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -from mixbox import idgen +# external +from mixbox import idgen, signals from mixbox.cache import Cached from cybox.core import Observable, Observables @@ -455,6 +456,7 @@ def from_obj(cls, obj, return_obj=None): if obj.version: return_obj._version = obj.version + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/core/ttps.py b/stix/core/ttps.py index fbbf74a4..6fecab86 100644 --- a/stix/core/ttps.py +++ b/stix/core/ttps.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix import stix.utils as utils from stix.ttp import TTP @@ -68,6 +72,7 @@ def from_obj(cls, obj, return_obj=None): # noqa return_obj.kill_chains = KillChains.from_obj(obj.Kill_Chains) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/exploit_target/__init__.py b/stix/exploit_target/__init__.py index bd884578..c0f81a08 100644 --- a/stix/exploit_target/__init__.py +++ b/stix/exploit_target/__init__.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + # internal import stix import stix.bindings.exploit_target as exploit_target_binding @@ -205,6 +208,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.configuration = _Configurations.from_obj(obj.Configuration) return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/exploit_target/configuration.py b/stix/exploit_target/configuration.py index 04400807..34086e57 100644 --- a/stix/exploit_target/configuration.py +++ b/stix/exploit_target/configuration.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix from stix.common import StructuredTextList import stix.bindings.exploit_target as exploit_target_binding @@ -182,6 +186,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.short_description = StructuredTextList.from_obj(obj.Short_Description) return_obj.cce_id = obj.CCE_ID + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index 89c0563b..bad160bd 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +#external +from mixbox import signals + +# internal import stix import stix.utils as utils import stix.bindings.exploit_target as exploit_target_binding @@ -262,6 +266,7 @@ def from_obj(cls, obj, return_obj=None): if obj.References: return_obj.references = obj.References.Reference + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -341,6 +346,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.environmental_score = obj.Environmental_Score return_obj.environmental_vector = obj.Environmental_Vector + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/exploit_target/weakness.py b/stix/exploit_target/weakness.py index 1bb9c9e3..f3b5e8ac 100644 --- a/stix/exploit_target/weakness.py +++ b/stix/exploit_target/weakness.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix import stix.bindings.exploit_target as exploit_target_binding from stix.common import StructuredTextList @@ -114,6 +118,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.descriptions = StructuredTextList.from_obj(obj.Description) return_obj.cwe_id = obj.CWE_ID + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index e20e6185..0fbd142f 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -1,8 +1,11 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +#external import lxml.etree as et +from mixbox import signals +# internal import stix import stix.utils as utils import stix.common as common @@ -103,6 +106,7 @@ def from_obj(cls, obj, return_obj=None): if specification is not None: return_obj.specification = STIXCIQIdentity3_0.from_obj(specification) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -343,6 +347,7 @@ def from_obj(cls, obj, return_obj=None): if contact_numbers is not None and len(contact_numbers) > 0: return_obj.contact_numbers = [ContactNumber.from_obj(x) for x in contact_numbers[0]] + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): @@ -513,6 +518,7 @@ def from_obj(cls, obj, return_obj=None): if len(administrative_area) > 0: return_obj.administrative_area = AdministrativeArea.from_obj(administrative_area[0]) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod @@ -570,6 +576,7 @@ def from_obj(cls, obj, return_obj=None): for name_element in name_elements: return_obj.name_elements.append(NameElement.from_obj(name_element)) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): @@ -642,6 +649,7 @@ def from_obj(cls, obj, return_obj=None): for name_element in name_elements: return_obj.name_elements.append(NameElement.from_obj(name_element)) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): @@ -695,6 +703,8 @@ def from_obj(cls, obj, return_obj=None): return_obj = cls() return_obj.value = obj.text + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -749,7 +759,8 @@ def from_obj(cls, obj, return_obj=None): if address_lines: for address_line in address_lines: return_obj.address_lines.append(address_line.text) - + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): @@ -872,6 +883,7 @@ def from_obj(cls, obj, return_obj=None): org_name = OrganisationName.from_obj(organisation_name_obj) return_obj.add_organisation_name(org_name) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -963,6 +975,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.value = obj.text return_obj.type = obj.get('Type') + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -1032,6 +1045,7 @@ def from_obj(cls, obj, return_obj=None): person_name_element = PersonNameElement.from_obj(name_element_obj) return_obj.add_name_element(person_name_element) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -1149,6 +1163,7 @@ def from_obj(cls, obj, return_obj=None): sub_division_name = SubDivisionName.from_obj(sub_division_name_obj) return_obj.add_subdivision_name(sub_division_name) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -1209,6 +1224,8 @@ def from_obj(cls, obj, return_obj=None): raise ValueError("Must supply return_obj") return_obj.value = obj.valueOf_ + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): @@ -1287,6 +1304,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.element_type = obj.get('ElementType') return_obj.value = obj.text + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -1360,6 +1378,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.element_type = obj.get('{%s}ElementType' % XML_NS_XNL) return_obj.value = obj.text + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -1440,6 +1459,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.type = obj.get('{%s}Type' % XML_NS_XNL) return_obj.value = obj.text + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -1484,6 +1504,8 @@ def from_obj(cls, obj): return_obj = cls() return_obj.value = obj.text + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -1531,6 +1553,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.type_ = obj.attrib.get('{%s}Type' % XML_NS_XPIL) return_obj.value = obj.text + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -1579,6 +1603,8 @@ def from_obj(cls, obj, return_obj=None): return_obj = cls() return_obj.industry_type = obj.get('{%s}IndustryType' % cls._namespace) + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -1628,6 +1654,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.type_ = obj.get('{%s}Type' % cls._namespace) return_obj.value = obj.text + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -1730,6 +1758,7 @@ def from_obj(cls, obj, return_obj=None): if contact_number_elements is not None and len(contact_number_elements) > 0: return_obj.contact_number_elements = [ContactNumberElement.from_obj(x) for x in contact_number_elements] + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -1812,6 +1841,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.type_ = obj.get('{%s}Type' % cls._namespace) return_obj.value = obj.text + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index 4bf7b044..32529458 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -7,6 +7,7 @@ # external from lxml import etree +from mixbox import signals import mixbox.xml # internal @@ -165,6 +166,7 @@ def from_obj(cls, obj, return_obj=None): else: return_obj.maec = obj.MAEC + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/extensions/marking/simple_marking.py b/stix/extensions/marking/simple_marking.py index b3fafbba..215aef3b 100644 --- a/stix/extensions/marking/simple_marking.py +++ b/stix/extensions/marking/simple_marking.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix from stix.data_marking import MarkingStructure import stix.bindings.extensions.marking.simple_marking as simple_marking_binding @@ -46,6 +50,7 @@ def from_obj(cls, obj, return_obj=None): MarkingStructure.from_obj(obj, return_obj) return_obj.statement = obj.Statement + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/extensions/marking/terms_of_use_marking.py b/stix/extensions/marking/terms_of_use_marking.py index 37b25cb5..d19a30f3 100644 --- a/stix/extensions/marking/terms_of_use_marking.py +++ b/stix/extensions/marking/terms_of_use_marking.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix from stix.data_marking import MarkingStructure import stix.bindings.extensions.marking.terms_of_use_marking as tou_marking_binding @@ -47,6 +51,7 @@ def from_obj(cls, obj, return_obj=None): MarkingStructure.from_obj(obj, return_obj=return_obj) return_obj.terms_of_use = obj.Terms_Of_Use + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/extensions/marking/tlp.py b/stix/extensions/marking/tlp.py index a9870c42..048a6cc8 100644 --- a/stix/extensions/marking/tlp.py +++ b/stix/extensions/marking/tlp.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix from stix.data_marking import MarkingStructure import stix.bindings.extensions.marking.tlp as tlp_binding @@ -46,6 +50,7 @@ def from_obj(cls, obj, return_obj=None): MarkingStructure.from_obj(obj, return_obj=return_obj) return_obj.color = obj.color + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/extensions/structured_coa/generic_structured_coa.py b/stix/extensions/structured_coa/generic_structured_coa.py index ecd74afd..bc05153e 100644 --- a/stix/extensions/structured_coa/generic_structured_coa.py +++ b/stix/extensions/structured_coa/generic_structured_coa.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + # internal import stix from stix.common import EncodedCDATA, StructuredTextList, VocabString @@ -110,6 +113,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.type_ = VocabString.from_obj(obj.Type) return_obj.specification = EncodedCDATA.from_obj(obj.Specification) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index ba8d35e9..db5acf5d 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix import stix.indicator.test_mechanism from stix.common import EncodedCDATA, StructuredTextList, VocabString @@ -117,6 +121,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.type_ = VocabString.from_obj(obj.Type) return_obj.specification = EncodedCDATA.from_obj(obj.Specification) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py index f7ae9eff..86f4beae 100644 --- a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py +++ b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py @@ -6,6 +6,7 @@ # external from lxml import etree +from mixbox import signals import mixbox.xml # internal @@ -80,6 +81,8 @@ def from_obj(cls, obj, return_obj=None): super(OpenIOCTestMechanism, cls).from_obj(obj, return_obj) return_obj.ioc = obj.ioc + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/extensions/test_mechanism/snort_test_mechanism.py b/stix/extensions/test_mechanism/snort_test_mechanism.py index efd12c77..393a554e 100644 --- a/stix/extensions/test_mechanism/snort_test_mechanism.py +++ b/stix/extensions/test_mechanism/snort_test_mechanism.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix from stix.common import EncodedCDATA from stix.indicator import test_mechanism @@ -82,6 +86,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.rate_filters = _EncodedCDATAs.from_obj(obj.Rate_Filter) return_obj.event_suppressions = _EncodedCDATAs.from_obj(obj.Event_Suppression) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/extensions/test_mechanism/yara_test_mechanism.py b/stix/extensions/test_mechanism/yara_test_mechanism.py index dea407bb..fee299a9 100644 --- a/stix/extensions/test_mechanism/yara_test_mechanism.py +++ b/stix/extensions/test_mechanism/yara_test_mechanism.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix import stix.utils import stix.indicator.test_mechanism @@ -45,6 +49,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.version = obj.Version return_obj.rule = EncodedCDATA.from_obj(obj.Rule) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index 9c0d94bd..0caf045f 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -1,7 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals +# internal import stix import stix.bindings.incident as incident_binding from stix.common import ( @@ -573,6 +576,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.contacts = _InformationSources.from_obj(obj.Contact) return_obj.url = obj.URL + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index 9fd39358..3f6ff484 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -3,6 +3,7 @@ # external from cybox.core import Observables +from mixbox import signals # internal import stix @@ -174,6 +175,7 @@ def from_obj(cls, obj, return_obj=None): n = obj.Nature_Of_Security_Effect return_obj.nature_of_security_effect = [PropertyAffected.from_obj(x) for x in n.Property_Affected] + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): @@ -257,6 +259,8 @@ def from_obj(cls, obj, return_obj=None): super(AssetType, cls).from_obj(obj, return_obj=return_obj) return_obj.count_affected = obj.count_affected + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/incident/coa.py b/stix/incident/coa.py index 10828b6d..0ecf385f 100644 --- a/stix/incident/coa.py +++ b/stix/incident/coa.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + # internal import stix import stix.utils as utils @@ -60,6 +63,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.contributors = Contributors.from_obj(obj.Contributors) return_obj.course_of_action = CourseOfAction.from_obj(obj.Course_Of_Action) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): @@ -124,6 +128,7 @@ def from_obj(cls, obj, return_obj=None): super(COARequested, cls).from_obj(obj, return_obj=return_obj) return_obj.priority = obj.priority + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): @@ -186,6 +191,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.start = DateTimeWithPrecision.from_obj(obj.Start) return_obj.end = DateTimeWithPrecision.from_obj(obj.End) + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/incident/direct_impact_summary.py b/stix/incident/direct_impact_summary.py index 1f942e56..a1d8ba5a 100644 --- a/stix/incident/direct_impact_summary.py +++ b/stix/incident/direct_impact_summary.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix from stix.common import VocabString from stix.common.vocabs import ImpactRating @@ -65,6 +69,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.asset_losses = VocabString.from_obj(obj.Asset_Losses) return_obj.business_mission_disruption = VocabString.from_obj(obj.Business_Mission_Disruption) return_obj.response_and_recovery_costs = VocabString.from_obj(obj.Response_And_Recovery_Costs) + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/incident/external_id.py b/stix/incident/external_id.py index 85eb4cd3..4c410537 100644 --- a/stix/incident/external_id.py +++ b/stix/incident/external_id.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix import stix.bindings.incident as incident_binding @@ -49,6 +53,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.value = obj.valueOf_ return_obj.source = obj.source + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/incident/history.py b/stix/incident/history.py index 9650a007..67f683d3 100644 --- a/stix/incident/history.py +++ b/stix/incident/history.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + # internal import stix import stix.utils as utils @@ -69,6 +72,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.time = obj.time return_obj.time_precision = obj.time_precision + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): @@ -139,6 +143,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.action_entry = COATaken.from_obj(obj.Action_Entry) return_obj.journal_entry = JournalEntry.from_obj(obj.Journal_Entry) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/incident/impact_assessment.py b/stix/incident/impact_assessment.py index 2f106e30..3fc49cd6 100644 --- a/stix/incident/impact_assessment.py +++ b/stix/incident/impact_assessment.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + # internal import stix import stix.bindings.incident as incident_binding @@ -100,6 +103,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.impact_qualification = VocabString.from_obj(obj.Impact_Qualification) return_obj.effects = Effects.from_obj(obj.Effects) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/incident/indirect_impact_summary.py b/stix/incident/indirect_impact_summary.py index 9c89a945..623ca420 100644 --- a/stix/incident/indirect_impact_summary.py +++ b/stix/incident/indirect_impact_summary.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix import stix.bindings.incident as incident_binding from stix.common import vocabs, VocabString @@ -76,6 +80,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.brand_and_market_damage = VocabString.from_obj(obj.Brand_And_Market_Damage) return_obj.increased_operating_costs = VocabString.from_obj(obj.Increased_Operating_Costs) return_obj.legal_and_regulatory_costs = VocabString.from_obj(obj.Legal_And_Regulatory_Costs) + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/incident/loss_estimation.py b/stix/incident/loss_estimation.py index dc9540d3..adb67a56 100644 --- a/stix/incident/loss_estimation.py +++ b/stix/incident/loss_estimation.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix import stix.bindings.incident as incident_binding @@ -51,6 +55,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.amount = obj.amount return_obj.iso_currency_code = obj.iso_currency_code + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/incident/property_affected.py b/stix/incident/property_affected.py index 7d735620..b01beb4b 100644 --- a/stix/incident/property_affected.py +++ b/stix/incident/property_affected.py @@ -1,7 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals +# internal import stix from stix.common import vocabs, VocabString, StructuredTextList import stix.bindings.incident as incident_binding @@ -26,6 +29,8 @@ def from_obj(cls, obj, return_obj=None): super(NonPublicDataCompromised, cls).from_obj(obj, return_obj=return_obj) return_obj.data_encrypted = obj.data_encrypted + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): @@ -151,6 +156,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.type_of_availability_loss = VocabString.from_obj(obj.Type_Of_Availability_Loss) return_obj.duration_of_availability_loss = VocabString.from_obj(obj.Duration_Of_Availability_Loss) return_obj.non_public_data_compromised = NonPublicDataCompromised.from_obj(obj.Non_Public_Data_Compromised) + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/incident/time.py b/stix/incident/time.py index d794b070..dcf3990c 100644 --- a/stix/incident/time.py +++ b/stix/incident/time.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix import stix.bindings.incident as incident_binding from stix.common import DateTimeWithPrecision @@ -144,6 +148,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.incident_reported = DateTimeWithPrecision.from_obj(obj.Incident_Reported) return_obj.incident_closed = DateTimeWithPrecision.from_obj(obj.Incident_Closed) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/incident/total_loss_estimation.py b/stix/incident/total_loss_estimation.py index 60a9b061..b74a3e8f 100644 --- a/stix/incident/total_loss_estimation.py +++ b/stix/incident/total_loss_estimation.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + # internal import stix import stix.bindings.incident as incident_binding @@ -55,6 +58,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.initial_reported_total_loss_estimation = LossEstimation.from_obj(obj.Initial_Reported_Total_Loss_Estimation) return_obj.actual_total_loss_estimation = LossEstimation.from_obj(obj.Actual_Total_Loss_Estimation) + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 8d8e3cd4..a6f46b13 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -1081,6 +1081,8 @@ def from_obj(cls, obj, return_obj=None): super(CompositeIndicatorExpression, cls).from_obj(obj, return_obj=return_obj) return_obj.operator = obj.operator + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index 56dbd227..5bbe72a4 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix import stix.utils as utils from stix.common import ( @@ -146,6 +150,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.confidence = Confidence.from_obj(obj.Confidence) return_obj.descriptions = StructuredTextList.from_obj(obj.Description) return_obj.related_observables = RelatedObservables.from_obj(obj.Related_Observables) + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod @@ -208,6 +214,8 @@ def from_obj(cls, obj, return_obj=None): super(Sightings, cls).from_obj(obj, return_obj=return_obj) return_obj.sightings_count = obj.sightings_count + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index b5b39f38..5f895af2 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox import signals from mixbox.cache import Cached # internal @@ -58,6 +59,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.efficacy = Statement.from_obj(obj.Efficacy) return_obj.producer = InformationSource.from_obj(obj.Producer) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/indicator/valid_time.py b/stix/indicator/valid_time.py index c8348a5c..42e5172a 100644 --- a/stix/indicator/valid_time.py +++ b/stix/indicator/valid_time.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix from stix.common import DateTimeWithPrecision import stix.bindings.indicator as indicator_binding @@ -56,6 +60,8 @@ def from_obj(cls, obj, return_obj=None): return_obj.start_time = DateTimeWithPrecision.from_obj(obj.Start_Time) return_obj.end_time = DateTimeWithPrecision.from_obj(obj.End_Time) + + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/report/__init__.py b/stix/report/__init__.py index aa6406ac..e58b55ad 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -1,7 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -from mixbox import idgen +# external +from mixbox import idgen, signals from mixbox.cache import Cached from cybox.core import Observable, Observables @@ -410,6 +411,7 @@ def from_obj(cls, obj, return_obj=None): if obj.version: return_obj.version = obj.version + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod diff --git a/stix/report/header.py b/stix/report/header.py index fd3ebfa4..9a0a6e4b 100644 --- a/stix/report/header.py +++ b/stix/report/header.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix import stix.bindings.report as report_binding from stix.common import InformationSource, StructuredTextList, VocabString @@ -217,6 +221,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.information_source = InformationSource.from_obj(obj.Information_Source) return_obj.intents = _ReportIntents.from_obj(obj.Intent) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/threat_actor/__init__.py b/stix/threat_actor/__init__.py index 95e12674..7d55fb79 100644 --- a/stix/threat_actor/__init__.py +++ b/stix/threat_actor/__init__.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + +# internal import stix import stix.bindings.threat_actor as threat_actor_binding from stix.common import vocabs, Confidence, Identity, Statement @@ -270,6 +274,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.confidence = Confidence.from_obj(obj.Confidence) return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index c6bfc2c3..be4b4bea 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + # internal import stix import stix.bindings.ttp as ttp_binding @@ -281,6 +284,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.kill_chain_phases = KillChainPhasesReference.from_obj(obj.Kill_Chain_Phases) return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/ttp/attack_pattern.py b/stix/ttp/attack_pattern.py index 43014d0c..4a509437 100644 --- a/stix/ttp/attack_pattern.py +++ b/stix/ttp/attack_pattern.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox import signals from mixbox.cache import Cached # internal @@ -232,6 +233,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.descriptions = StructuredTextList.from_obj(obj.Description) return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/ttp/behavior.py b/stix/ttp/behavior.py index f564c5b9..25d7f9ee 100644 --- a/stix/ttp/behavior.py +++ b/stix/ttp/behavior.py @@ -1,5 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. + +# external +from mixbox import signals + +# internal import stix import stix.bindings.ttp as ttp_binding @@ -78,6 +83,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.exploits = Exploits.from_obj(obj.Exploits) return_obj.attack_patterns = AttackPatterns.from_obj(obj.Attack_Patterns) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/ttp/exploit.py b/stix/ttp/exploit.py index 3018efbf..1eab9fbf 100644 --- a/stix/ttp/exploit.py +++ b/stix/ttp/exploit.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox import signals from mixbox.cache import Cached # internal @@ -227,6 +228,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.descriptions = StructuredTextList.from_obj(obj.Description) return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index b5502868..0c0b28fe 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox import signals from mixbox.cache import Cached from cybox.core import Observables @@ -256,6 +257,7 @@ def from_obj(cls, obj, return_obj=None): if obj.Type: return_obj.types = [VocabString.from_obj(x) for x in obj.Type] + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index ab4497e0..8680841e 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox import signals from mixbox.cache import Cached # internal @@ -270,6 +271,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.names = MalwareNames.from_obj(obj.Name) return_obj.types = MalwareTypes.from_obj(obj.Type) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/ttp/resource.py b/stix/ttp/resource.py index ce63576e..41c4b025 100644 --- a/stix/ttp/resource.py +++ b/stix/ttp/resource.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import signals + # internal import stix from stix.common import ToolInformation, Identity @@ -77,6 +80,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.tools = Tools.from_obj(obj.Tools) return_obj.personas = Personas.from_obj(obj.Personas) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): diff --git a/stix/ttp/victim_targeting.py b/stix/ttp/victim_targeting.py index 738d7e6c..0c3b3c6a 100644 --- a/stix/ttp/victim_targeting.py +++ b/stix/ttp/victim_targeting.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox import signals from cybox.core import Observables # internal @@ -80,6 +81,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.targeted_systems = TargetedSystems.from_obj(obj.Targeted_Systems) return_obj.targeted_information = TargetedInformation.from_obj(obj.Targeted_Information) + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj def to_dict(self): From c8ff21ac6d458ec91be073a592ab64849cfe04bc Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 22 Sep 2015 10:18:07 -0400 Subject: [PATCH 178/438] More work on typedfields. Requires bw-typedfields branch on mixbox repo --- stix/base.py | 375 +++--------------------------- stix/campaign/__init__.py | 1 + stix/common/activity.py | 4 +- stix/common/confidence.py | 5 +- stix/common/information_source.py | 7 +- stix/common/structured_text.py | 5 +- 6 files changed, 38 insertions(+), 359 deletions(-) diff --git a/stix/base.py b/stix/base.py index b76c5944..4e42ad4f 100644 --- a/stix/base.py +++ b/stix/base.py @@ -1,20 +1,33 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# builtin +# stdlib import json import collections import itertools import StringIO -from mixbox import fields, entities +# mixbox from mixbox import idgen -from mixbox.binding_utils import save_encoding +from mixbox import fields +from mixbox import binding_utils + from mixbox.cache import Cached +from mixbox.entities import Entity as _MixboxEntity +from mixbox.entities import EntityList as _MixboxEntityList # internal from . import utils +def _structured_text_list(input): + from stix.common.structured_text import StructuredTextList + + if input: + return StructuredTextList(input) + else: + return StructuredTextList() + + def _override(*args, **kwargs): raise NotImplementedError() @@ -28,19 +41,11 @@ class ElementField(fields.TypedField): class IdField(AttributeField): pass -class Entity(object): +class Entity(_MixboxEntity): """Base class for all classes in the STIX API.""" _namespace = None _XSI_TYPE = None - def __init__(self): - self._fields = {} - - def _collect_ns_info(self, ns_info=None): - if not ns_info: - return - ns_info.collect(self) - def _set_var(self, klass, try_cast=True, arg=None, **kwargs): """Sets an instance property value. @@ -78,17 +83,6 @@ def _set_var(self, klass, try_cast=True, arg=None, **kwargs): error = error.format(name, klass, type(item)) raise TypeError(error) - @classmethod - def _get_vars(cls): - import inspect - var_list = [] - for (name, obj) in inspect.getmembers(cls, inspect.isdatadescriptor): - #print name + " " + str(type(obj)) + " " + str(obj.__class__) - if isinstance(obj, fields.TypedField): - var_list.append(obj) - - return var_list - def _set_vocab(self, klass=None, **kwargs): """Sets a controlled vocabulary property value. @@ -116,105 +110,6 @@ def _set_vocab(self, klass=None, **kwargs): else: self._set_var(klass, **kwargs) - @classmethod - def istypeof(cls, obj): - """Check if `cls` is the type of `obj` - - In the normal case, as implemented here, a simple isinstance check is - used. However, there are more complex checks possible. For instance, - EmailAddress.istypeof(obj) checks if obj is an Address object with - a category of Address.CAT_EMAIL - """ - return isinstance(obj, cls) - - def to_obj(self, return_obj=None, ns_info=None): - """Convert to a GenerateDS binding object. - - Subclasses can override this function. - - Returns: - An instance of this Entity's ``_binding_class`` with properties - set from this Entity. - """ - - def _objectify(value, return_obj, ns_info): - """Make `value` suitable for a binding object. - - If `value` is an Entity, call to_obj() on it. Otherwise, return it - unmodified. - """ - try: - #print "objifying", value.to_obj - return value.to_obj(return_obj=return_obj, ns_info=ns_info) - except AttributeError: - if type(value) == dict: - print "dict doesn't have to_obj", return_obj, value - return value - - self._collect_ns_info(ns_info) - - entity_obj = self._binding_class() - #print "entity", entity_obj, self - - vars = {} - for klass in self.__class__.__mro__: - if klass is Entity: - break - vars.update(klass.__dict__.iteritems()) - - #print "vars", vars - #print "self", self.__dict__ - - for name, field in vars.iteritems(): - if isinstance(field, fields.TypedField): - #print name, field.__class__, field.attr_name - val = getattr(self, field.attr_name) - - if field.multiple: - if val: - val = [_objectify(x, return_obj, ns_info) for x in val] - else: - val = [] - else: - #print "objectifying", val - val = _objectify(val, return_obj, ns_info) - #print "objectified", val - - #print "setting on binding", field.name, val - setattr(entity_obj, field.name, val) - - self._finalize_obj(entity_obj) - return entity_obj - - def _finalize_obj(self, entity_obj): - """Subclasses can define additional items in the binding object. - - `entity_obj` should be modified in place. - """ - pass - - @classmethod - def from_obj(cls, cls_obj=None, return_obj=None): - """Create an object from a binding object""" - if not cls_obj: - return None - - if return_obj is None: - entity = cls() - else: - entity = return_obj - - for field in cls._get_vars(): - val = getattr(cls_obj, field.name) - if field.type_: - if field.multiple and val is not None: - val = [field.type_.from_obj(x) for x in val] - else: - val = field.type_.from_obj(val) - setattr(entity, field.attr_name, val) - - return entity - def to_xml(self, include_namespaces=True, include_schemalocs=False, ns_dict=None, schemaloc_dict=None, pretty=True, auto_namespace=True, encoding='utf-8'): @@ -293,7 +188,7 @@ def to_xml(self, include_namespaces=True, include_schemalocs=False, if not pretty: namespace_def = namespace_def.replace('\n\t', ' ') - with save_encoding(encoding): + with binding_utils.save_encoding(encoding): sio = StringIO.StringIO() obj.export( sio.write, # output buffer @@ -311,144 +206,6 @@ def to_xml(self, include_namespaces=True, include_schemalocs=False, return s - def to_json(self): - return json.dumps(self.to_dict()) - - @classmethod - def from_json(cls, json_doc): - """Parses the JSON document `json_doc` and returns a STIX - :class:`Entity` implementation instance. - - Arguments: - json_doc: Input JSON representation of a STIX entity. This can be - a readable object or a JSON string. - - Returns: - An implementation of :class:`.Entity` (e.g., - :class:`.STIXPackage`). - - """ - try: - d = json.load(json_doc) - except AttributeError: # catch the read() error - d = json.loads(json_doc) - - return cls.from_dict(d) - - def to_dict(self): - """Converts a STIX :class:`Entity` implementation into a Python - dictionary. This may be overridden by derived classes. - - Returns: - Python dict with keys set from this Entity. - """ - def _dictify(value): - """Make `value` suitable for a dictionary. - - If `value` is an Entity, call to_dict() on it. Otherwise, return it - unmodified. - """ - try: - return value.to_dict() - except: - return value - - entity_dict = { } - vars = { } - for klass in self.__class__.__mro__: - if klass is Entity: - break - vars.update(klass.__dict__.iteritems()) - - hasAnyTypedField = False - for name, field in vars.iteritems(): - if isinstance(field, fields.TypedField): - hasAnyTypedField = True - - val = getattr(self, field.attr_name) - - if field.multiple: - if val: - val = [_dictify(x) for x in val] - else: - val = [] - else: - val = _dictify(val) - - # Only add non-None objects or non-empty lists - if val is not None and val != []: - entity_dict[field.key_name] = val - - # doesn't quite work, possibly because of inherited TypedFields? - #if not hasAnyTypedField: - # return utils.to_dict(self) - - self._finalize_dict(entity_dict) - - return entity_dict - - def _finalize_dict(self, entity_dict): - """Subclasses can define additional items in the dictionary. - - `entity_dict` should be modified in place. - """ - pass - - @classmethod - def from_dict(cls, cls_dict=None, return_obj=None): - """Convert from dict representation to object representation.""" - if cls_dict is None: - return None - - if return_obj is None: - entity = cls() - else: - entity = return_obj - - # Shortcut if an actual dict is not provided: - if not isinstance(cls_dict, dict): - value = cls_dict - # Call the class's constructor - try: - return cls(value) - except TypeError: - raise TypeError("Could not instantiate a %s from a %s: %s" % - (cls, type(value), value)) - - for field in cls._get_vars(): - val = cls_dict.get(field.key_name) - if field.type_: - if field.multiple: - if val is not None: - if type(val) is list: - val = [field.type_.from_dict(x) for x in val] - else: - # sometimes multiple fields are supplied with a single dict as input instead of a list - # TypedList (now obsolete) used to do this; now TypedField has to - val = [field.type_.from_dict(val)] - else: - val = [] - elif issubclass(field.type_, EntityList): - val = field.type_.from_list(val) - else: - val = field.type_.from_dict(val) - else: - if field.multiple and not val: - val = [] - setattr(entity, field.attr_name, val) - - return entity - - @classmethod - def object_from_dict(cls, entity_dict): - """Convert from dict representation to object representation.""" - return cls.from_dict(entity_dict).to_obj() - - @classmethod - def dict_from_object(cls, entity_obj): - """Convert from object representation to dict representation.""" - return cls.from_obj(entity_obj).to_dict() - def walk(self): return utils.walk.iterwalk(self) @@ -465,94 +222,11 @@ def find(self, id_): return entity -class EntityList(collections.MutableSequence, Entity): - _binding_class = _override - _binding_var = None +class EntityList(_MixboxEntityList): _contained_type = _override _inner_name = None _dict_as_list = False - def __init__(self, *args): - super(EntityList, self).__init__() - self._inner = [] - - if not any(args): - return - - for arg in args: - if utils.is_sequence(arg): - self.extend(arg) - else: - self.append(arg) - - def __nonzero__(self): - return bool(self._inner) - - def __getitem__(self, key): - return self._inner.__getitem__(key) - - def __setitem__(self, key, value): - if not self._is_valid(value): - value = self._fix_value(value) - self._inner.__setitem__(key, value) - - def __delitem__(self, key): - self._inner.__delitem__(key) - - def __len__(self): - return len(self._inner) - - def insert(self, idx, value): - if not value: - return - if not self._is_valid(value): - value = self._fix_value(value) - self._inner.insert(idx, value) - - def _is_valid(self, value): - """Check if this is a valid object to add to the list.""" - # Subclasses can override this function, but if it becomes common, it's - # probably better to use self._contained_type.istypeof(value) - return isinstance(value, self._contained_type) - - def _fix_value(self, value): - """Attempt to coerce value into the correct type. - - Subclasses can override this function. - """ - try: - new_value = self._contained_type(value) - except: - error = "Can't put '{0}' ({1}) into a {2}. Expected a {3} object." - error = error.format( - value, # Input value - type(value), # Type of input value - type(self), # Type of collection - self._contained_type # Expected type of input value - ) - raise ValueError(error) - - return new_value - - # The next four functions can be overridden, but otherwise define the - # default behavior for EntityList subclasses which define the following - # class-level members: - # - _binding_class - # - _binding_var - # - _contained_type - # - _inner_name - - def to_obj(self, return_obj=None, ns_info=None): - super(EntityList, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - objlist = [x.to_obj(ns_info=ns_info) for x in self] - setattr(return_obj, self._binding_var, objlist) - - return return_obj - def to_list(self): return [h.to_dict() for h in self] @@ -604,7 +278,7 @@ def from_list(cls, list_repr, return_obj=None, contained_type=None): return cls.from_dict(list_repr, return_obj) try: - list_repr = list_repr[getattr(cls, '_inner_name')] + list_repr = list_repr[cls._inner_name] except: pass @@ -799,9 +473,11 @@ class BaseCoreComponent(Cached, Entity): idref = IdField("idref") version = AttributeField("version") timestamp = AttributeField("timestamp") + handling = ElementField("Handling") + + # These are defined in init_typed_fields due to circular imports descriptions = None short_descriptions = None - handling = ElementField("Handling") @classmethod def initClassFields(cls): @@ -821,8 +497,8 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.id_ = id_ or idgen.create_id(self._ID_PREFIX) self.idref = idref self.title = title - self.description = description - self.short_description = short_description + self.descriptions = _structured_text_list(description) + self.short_descriptions = _structured_text_list(short_description) self.version = None #self.information_source = None self.handling = None @@ -832,6 +508,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, else: self.timestamp = utils.dates.now() if not idref else None + # TODO: add this as a callback_hook to version TypedField def check_version(self, value): if not value: diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 02919d07..98a9c105 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -29,6 +29,7 @@ class Attribution(GenericRelationshipList): _binding_var = "Attributed_Threat_Actor" _contained_type = RelatedThreatActor _inner_name = "threat_actors" + """ class Attribution(stix.Entity): threat_actors = ElementField("Attributed_Threat_Actor", RelatedThreatActor, multiple=True, key_name="threat_actors") diff --git a/stix/common/activity.py b/stix/common/activity.py index 1b832ed9..6f629459 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -19,9 +19,9 @@ class Activity(stix.Entity): descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") def __init__(self): - self._fields = {} + super(Activity, self).__init__() self.date_time = None - self.description = None + self.descriptions = StructuredTextList() @property def description(self): diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 9c6e1f2e..4df503de 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -23,7 +23,8 @@ class Confidence(stix.Entity): source = ElementField("Source") def __init__(self, value=None, timestamp=None, description=None, source=None): - self._fields = {} + super(Confidence, self).__init__() + self.timestamp = timestamp or utils.dates.now() self.timestamp_precision = "second" self.value = value @@ -62,7 +63,7 @@ def description(self): An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions), "None") + return next(iter(self.descriptions), None) @description.setter def description(self, value): diff --git a/stix/common/information_source.py b/stix/common/information_source.py index f1557a86..799d8c8b 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -1,8 +1,6 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -from __future__ import absolute_import - # external import cybox.common @@ -19,6 +17,7 @@ from mixbox.entities import Entity from cybox.common.tools import ToolInformationList + class InformationSource(stix.Entity): _binding = stix_common_binding _binding_class = stix_common_binding.InformationSourceType @@ -39,9 +38,9 @@ def initClassFields(cls): def __init__(self, description=None, identity=None, time=None, tools=None, contributing_sources=None, references=None): super(InformationSource, self).__init__() - #self._fields = {} + self.identity = identity - self.description = description + self.descriptions = StructuredTextList(description) self.contributing_sources = contributing_sources self.time = time self.tools = tools diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 67fdc9d7..0a0c1c12 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -26,8 +26,8 @@ class StructuredText(stix.Entity): structure xpath selectors. value: The text value of this object. structuring_format: The format of the text. For example, ``html5``. - """ + _binding = stix_common_binding _binding_class = _binding.StructuredTextType _namespace = 'http://stix.mitre.org/common-1' @@ -37,7 +37,8 @@ class StructuredText(stix.Entity): structuring_format = AttributeField("structuring_format") def __init__(self, value=None, ordinality=None): - self._fields = {} + super(StructuredText, self).__init__() + self.id_ = None self.value = value self.structuring_format = None From 2592c3c6e5499476bc26e1d23ce4492cf883e183 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 10:43:04 -0400 Subject: [PATCH 179/438] * Added stix.common.references module. * Fixed unittests for information_source module and structured_text module. * Added id unsetting to IdrefField.__set__() * Added idref unsetting to IdField.__set__() --- stix/__init__.py | 2 +- stix/base.py | 31 +++++++++++++++++++--- stix/common/information_source.py | 9 ++++--- stix/common/references.py | 43 +++++++++++++++++++++++++++++++ stix/common/structured_text.py | 5 +++- 5 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 stix/common/references.py diff --git a/stix/__init__.py b/stix/__init__.py index 25d05965..36de6864 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -3,7 +3,7 @@ # Make sure base gets imported before common. from .base import (Entity, EntityList, TypedCollection, TypedList, # noqa - BaseCoreComponent) + BaseCoreComponent, ElementField, AttributeField) #: Mapping of xsi:types to implementation/extension classes _EXTENSION_MAP = {} diff --git a/stix/base.py b/stix/base.py index 4e42ad4f..8ec98e5e 100644 --- a/stix/base.py +++ b/stix/base.py @@ -35,11 +35,34 @@ def _override(*args, **kwargs): class AttributeField(fields.TypedField): pass + class ElementField(fields.TypedField): pass + class IdField(AttributeField): - pass + def __set__(self, instance, value): + """Set the id field to `value`. If `value` is not None or an empty + string, unset the idref fields on `instance`. + """ + super(IdField, self).__set__(instance, value) + + if value: + fields.unset(instance, IdrefField) + + + +class IdrefField(AttributeField): + def __set__(self, instance, value): + """Set the idref field to `value`. If `value` is not None or an empty + string, unset the id fields on `instance`. + """ + super(IdrefField, self).__set__(instance, value) + + if value: + fields.unset(instance, IdField) + + class Entity(_MixboxEntity): """Base class for all classes in the STIX API.""" @@ -68,7 +91,7 @@ def _set_var(self, klass, try_cast=True, arg=None, **kwargs): and the field value is the value. """ - name, item = kwargs.iteritems().next() + name, item = next(kwargs.iteritems()) attr = utils.private_name(name) # 'title' => '_title' if item is None: @@ -103,7 +126,7 @@ def _set_vocab(self, klass=None, **kwargs): from stix.common import VocabString klass = klass or VocabString - item = kwargs.itervalues().next() + item = next(kwargs.itervalues()) if isinstance(item, VocabString): self._set_var(VocabString, **kwargs) @@ -470,7 +493,7 @@ class BaseCoreComponent(Cached, Entity): title = ElementField("Title") id_ = IdField("id") - idref = IdField("idref") + idref = IdrefField("idref") version = AttributeField("version") timestamp = AttributeField("timestamp") handling = ElementField("Handling") diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 799d8c8b..8b38d4aa 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -10,7 +10,9 @@ import stix.bindings.stix_common as stix_common_binding # relative -from . import vocabs, VocabString +from . import vocabs +from .vocabs import VocabString +from .references import References from .identity import Identity from .structured_text import StructuredTextList, StructuredTextListField from stix.base import ElementField @@ -28,9 +30,8 @@ class InformationSource(stix.Entity): contributing_sources = ElementField("Contributing_Sources") time = ElementField("Time", cybox.common.Time) roles = ElementField("Role", VocabString, multiple=True, key_name="roles") - - tools = ElementField("Tools", ToolInformationList) #TODO: shows up, but broken - references = ElementField("References") #TODO: list-setting behavior does not match + tools = ElementField("Tools", ToolInformationList) + references = ElementField("References", References) @classmethod def initClassFields(cls): diff --git a/stix/common/references.py b/stix/common/references.py new file mode 100644 index 00000000..7a235f9e --- /dev/null +++ b/stix/common/references.py @@ -0,0 +1,43 @@ +import stix +from stix.bindings import stix_common as stix_common_binding + + +class References(stix.Entity): + _binding = stix_common_binding + _binding_class = stix_common_binding.ReferencesType + _namespace = 'http://stix.mitre.org/common-1' + + # Fields + reference = stix.ElementField("Reference", multiple=True) + + def __init__(self, references=None): + super(References, self).__init__() + self.reference = references + + def __iter__(self): + for r in self.reference: + yield r + + def __getitem__(self, item): + return self.reference[item] + + def __setitem__(self, key, value): + self.reference[key] = value + + def __delitem__(self, key): + del self.reference[key] + + def to_dict(self): + return [x for x in self.reference] + + @classmethod + def from_dict(cls, cls_dict=None, return_obj=None): + if not cls_dict: + return None + + if not return_obj: + return_obj = cls() + + return_obj.reference = [x for x in cls_dict] + + return return_obj diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 0a0c1c12..c36b5e75 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -8,7 +8,9 @@ import stix import stix.utils as utils import stix.bindings.stix_common as stix_common_binding -from stix.base import AttributeField, ElementField + +# typed fields +from stix.base import AttributeField, ElementField, IdField #: Default ordinality value for StructuredText. DEFAULT_ORDINALITY = 1 @@ -32,6 +34,7 @@ class StructuredText(stix.Entity): _binding_class = _binding.StructuredTextType _namespace = 'http://stix.mitre.org/common-1' + id_ = IdField("id") ordinality = AttributeField("ordinality") value = AttributeField("value") structuring_format = AttributeField("structuring_format") From 1b3ac55fc1171b6327cdf3d55a88cf7afb18504d Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 10:59:51 -0400 Subject: [PATCH 180/438] Added ContentField to stix.base. Refactored StructuredText to utilize it. Maybe this should just be a TypedField? --- stix/base.py | 4 +++ stix/common/structured_text.py | 49 +++------------------------------- 2 files changed, 7 insertions(+), 46 deletions(-) diff --git a/stix/base.py b/stix/base.py index 8ec98e5e..4a115071 100644 --- a/stix/base.py +++ b/stix/base.py @@ -40,6 +40,10 @@ class ElementField(fields.TypedField): pass +class ContentField(fields.TypedField): + pass + + class IdField(AttributeField): def __set__(self, instance, value): """Set the id field to `value`. If `value` is not None or an empty diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index c36b5e75..a7526d3b 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -10,7 +10,7 @@ import stix.bindings.stix_common as stix_common_binding # typed fields -from stix.base import AttributeField, ElementField, IdField +from stix.base import AttributeField, ElementField, IdField, ContentField #: Default ordinality value for StructuredText. DEFAULT_ORDINALITY = 1 @@ -36,7 +36,7 @@ class StructuredText(stix.Entity): id_ = IdField("id") ordinality = AttributeField("ordinality") - value = AttributeField("value") + value = ContentField("valueOf_", key_name="value") structuring_format = AttributeField("structuring_format") def __init__(self, value=None, ordinality=None): @@ -47,25 +47,6 @@ def __init__(self, value=None, ordinality=None): self.structuring_format = None self.ordinality = ordinality - def to_obj(self, return_obj=None, ns_info=None): - """Converts this object into a binding object. - - """ - if not return_obj: - return_obj = self._binding_class() - - super(StructuredText, self).to_obj( - return_obj=return_obj, - ns_info=ns_info - ) - - return_obj.id = self.id_ - return_obj.valueOf_ = self.value - return_obj.ordinality = self.ordinality - return_obj.structuring_format = self.structuring_format - - return return_obj - def is_plain(self): plain = ( (not self.id_) and @@ -89,27 +70,6 @@ def to_dict(self): else: return super(StructuredText, self).to_dict() - @classmethod - def from_obj(cls, obj, return_obj=None): - """Create an object from the input binding object. - - Args: - obj: A generateDS binding object. - - """ - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.id_ = obj.id - return_obj.value = obj.valueOf_ - return_obj.ordinality = obj.ordinality - return_obj.structuring_format = obj.structuring_format - - return return_obj - @classmethod def from_dict(cls, d, return_obj=None): """Creates an object from the input dictionary. @@ -127,10 +87,7 @@ def from_dict(cls, d, return_obj=None): if not isinstance(d, dict): return_obj.value = d else: - return_obj.id_ = d.get('id') - return_obj.value = d.get('value') - return_obj.ordinality = d.get('ordinality') - return_obj.structuring_format = d.get('structuring_format') + return_obj = super(StructuredText, cls).from_dict(d, return_obj) return return_obj From 921479a51d7e50ea5c1da439aa59b7c173b17186 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 12:44:51 -0400 Subject: [PATCH 181/438] Added VocabField to stix.common.vocabs --- stix/common/vocabs.py | 53 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index ab23e097..b78ad932 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -4,9 +4,58 @@ import stix import stix.bindings.stix_common as stix_common_binding +from mixbox import fields + + +class VocabField(fields.TypedField): + """TypedField subclass for VocabString fields.""" + + def __init__(self, *args, **kwargs): + """Intercepts the __init__() call to TypedField. + + Set the type that will be used in from_dict and from_obj calls to + :class:`VocabString`. + + Set the type that will be used in ``__set__`` for casting as the + original ``type_`` argument, or :class:`VocabString` if no `type_` + argument was provided. + + """ + super(VocabField, self).__init__(*args, **kwargs) + + if self.type_: + self.__vocab_impl = self.type_ + else: + self.__vocab_impl = VocabString + + # TODO: can we take this out. It shouldn't be necessary since type_ + # should always be a subclass of VocabString. + self.type_ = VocabString # Force this so from_dict/from_obj works. + + def _clean(self, value): + """Validate and clean a candidate value for this Vocab. This overrides + the ``_clean()`` method on :class:`.TypedField`. + + 1) If the value is ``None``, return ``None`` + 2) If the value is an instance of ``VocabString``, return it. + 3) Attempt to cast the value to the default VocabString type if there + is one, else try to cast it to VocabString. + 4) raise a ValueError + + """ + vocab = self.__vocab_impl + + if value is None: + return None + elif isinstance(value, VocabString): + return value + elif vocab._try_cast: # noqa + return vocab(value) + + error_fmt = "%s must be a %s, not a %s" + error = error_fmt % (self.name, self.type_, type(value)) + raise ValueError(error) -# TODO: handle normalization -# from cybox.utils import normalize_to_xml, denormalize_from_xml class VocabString(stix.Entity): From 0903f71a81481557efa3f059640c16b7e9c10647 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 12:46:18 -0400 Subject: [PATCH 182/438] Added typed fields to Statement --- stix/common/statement.py | 137 ++++++--------------------------------- 1 file changed, 19 insertions(+), 118 deletions(-) diff --git a/stix/common/statement.py b/stix/common/statement.py index a7284758..baa569ed 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -7,9 +7,11 @@ import stix.utils as utils import stix.bindings.stix_common as common_binding +from stix.base import AttributeField, ElementField + from .confidence import Confidence from .structured_text import StructuredTextList -from .vocabs import VocabString, HighMediumLow +from .vocabs import VocabField, HighMediumLow class Statement(stix.Entity): @@ -17,8 +19,20 @@ class Statement(stix.Entity): _binding = common_binding _binding_class = common_binding.StatementType + # Fields + timestamp = AttributeField("timestamp") + timestamp_precision = AttributeField("timestamp_precision") + value = VocabField("Value", HighMediumLow) + descriptions = ElementField("Description", StructuredTextList) + confidence = ElementField("Confidence", Confidence) + + # Set by init_typed_fields() to avoid + source = None + def __init__(self, value=None, timestamp=None, description=None, source=None): + super(Statement, self).__init__() + self.timestamp = timestamp or utils.dates.now() self.timestamp_precision = "second" self.value = value @@ -26,31 +40,11 @@ def __init__(self, value=None, timestamp=None, description=None, self.source = source self.confidence = None - @property - def timestamp(self): - return self._timestamp - - @timestamp.setter - def timestamp(self, value): - self._timestamp = utils.dates.parse_value(value) - - @property - def value(self): - return self._value - - @value.setter - def value(self, value): - self._set_vocab(HighMediumLow, value=value) + @classmethod + def _init_typed_fields(cls): + from stix.common.information_source import InformationSource + cls.source = ElementField("Source", InformationSource) - @property - def source(self): - return self._source - - @source.setter - def source(self, value): - from .information_source import InformationSource - self._set_var(InformationSource, try_cast=False, source=value) - @property def description(self): """A single description about the contents or purpose of this object. @@ -72,33 +66,6 @@ def description(self): def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. @@ -106,69 +73,3 @@ def add_description(self, description): """ self.descriptions.add(description) - - def to_obj(self, return_obj=None, ns_info=None): - super(Statement, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - obj = self._binding_class() - obj.timestamp_precision = self.timestamp_precision - - if self.timestamp: - obj.timestamp = self.timestamp.isoformat() - if self.value: - obj.Value = self.value.to_obj(ns_info=ns_info) - if self.descriptions: - obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.source: - obj.Source = self.source.to_obj(ns_info=ns_info) - if self.confidence: - obj.Confidence = self.confidence.to_obj(ns_info=ns_info) - - return obj - - def to_dict(self): - skip = ('timestamp_precision',) - d = utils.to_dict(self, skip=skip) - - if self.timestamp_precision != 'second': - d['timestamp_precision'] = self.timestamp_precision - - return d - - @classmethod - def from_obj(cls, obj, return_obj=None): - from .information_source import InformationSource - - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.timestamp = obj.timestamp - return_obj.timestamp_precision = obj.timestamp_precision - return_obj.value = VocabString.from_obj(obj.Value) - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.source = InformationSource.from_obj(obj.Source) - return_obj.confidence = Confidence.from_obj(obj.Confidence) - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - from .information_source import InformationSource - - if not d: - return None - - if not return_obj: - return_obj = cls() - - return_obj.timestamp = d.get('timestamp') - return_obj.timestamp_precision = d.get('timestamp_precision', 'second') - return_obj.value = VocabString.from_dict(d.get('value')) - return_obj.descriptions = StructuredTextList.from_dict(d.get('description')) - return_obj.source = InformationSource.from_dict(d.get('source')) - return_obj.confidence = Confidence.from_dict(d.get('confidence')) - - return return_obj From bb4c41e37c3c53b4a7d020922307848db41378bc Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 12:46:59 -0400 Subject: [PATCH 183/438] Added missing call to Statement._init_typed_fields() and removed comments code from InformationSource --- stix/common/__init__.py | 4 ++ stix/common/information_source.py | 91 +------------------------------ 2 files changed, 7 insertions(+), 88 deletions(-) diff --git a/stix/common/__init__.py b/stix/common/__init__.py index 5782fe1b..d28f4ad0 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -131,3 +131,7 @@ def __str__(self): def __unicode__(self): return unicode(self.value) + + +# Initialize typefield +Statement._init_typed_fields() \ No newline at end of file diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 8b38d4aa..3829a577 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -16,7 +16,7 @@ from .identity import Identity from .structured_text import StructuredTextList, StructuredTextListField from stix.base import ElementField -from mixbox.entities import Entity + from cybox.common.tools import ToolInformationList @@ -50,23 +50,8 @@ def __init__(self, description=None, identity=None, time=None, tools=None, contr def add_contributing_source(self, value): self.contributing_sources.append(value) - - #@property - #def references(self): - # return self._references - - #@references.setter - #def references(self, value): - # self._references = [] - - # if not value: - # return - # elif utils.is_sequence(value): - # for v in value: - # self.add_reference(v) - # else: - # self.add_reference(value) - + + def add_reference(self, value): if not value: return @@ -102,73 +87,10 @@ def add_description(self, description): """ self.descriptions.add(description) - #@property - #def tools(self): - # return self._tools - - #@tools.setter - #def tools(self, value): - # self._set_var(cybox.common.ToolInformationList, try_cast=False, tools=value) - - #@property - #def roles(self): - # return self._roles - - #@roles.setter - #def roles(self, value): - # self._roles = _Roles(value) def add_role(self, value): self.roles.append(value) - -""" - def to_obj(self, return_obj=None, ns_info=None): - super(InformationSource, self).to_obj( - return_obj=return_obj, - ns_info=ns_info - ) - - if not return_obj: - return_obj = self._binding_class() - - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.references: - return_obj.References = stix_common_binding.ReferencesType(Reference=self.references) - if self.contributing_sources: - return_obj.Contributing_Sources = self.contributing_sources.to_obj(ns_info=ns_info) - if self.identity: - return_obj.Identity = self.identity.to_obj(ns_info=ns_info) - if self.time: - return_obj.Time = self.time.to_obj(ns_info=ns_info) - if self.tools: - return_obj.Tools = self.tools.to_obj(ns_info=ns_info) - if self.roles: - return_obj.Role = self.roles.to_obj(ns_info=ns_info) - - return return_obj - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.description = StructuredTextList.from_obj(obj.Description) - return_obj.identity = Identity.from_obj(obj.Identity) - return_obj.contributing_sources = ContributingSources.from_obj(obj.Contributing_Sources) - return_obj.roles = _Roles.from_obj(obj.Role) - - if obj.References: - return_obj.references = obj.References.Reference - if obj.Time: - return_obj.time = cybox.common.Time.from_obj(obj.Time) - if obj.Tools: - return_obj.tools = cybox.common.ToolInformationList.from_obj(obj.Tools) - - return return_obj -""" class ContributingSources(stix.EntityList): _namespace = "http://stix.mitre.org/common-1" @@ -179,12 +101,5 @@ class ContributingSources(stix.EntityList): _inner_name = "sources" -# NOT AN ACTUAL STIX TYPE! -#class _Roles(stix.TypedList): -# _contained_type = VocabString -# -# def _fix_value(self, value): -# return vocabs.InformationSourceRole(value) - # finally, initialize field types that would be circular dependencies InformationSource.initClassFields() From da639146aebe27a99c0648b0ad232d7a44fec76b Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 12:48:47 -0400 Subject: [PATCH 184/438] s/initClassFields/_init_typed_fields --- stix/__init__.py | 2 +- stix/base.py | 2 +- stix/common/confidence.py | 2 +- stix/common/information_source.py | 6 ++---- stix/common/related.py | 2 +- stix/incident/__init__.py | 4 ++-- stix/indicator/indicator.py | 4 ++-- stix/indicator/sightings.py | 2 +- 8 files changed, 11 insertions(+), 13 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index 36de6864..e9773d4b 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -134,4 +134,4 @@ def supported_stix_version(): # because common depends on base, we can only set the TypeFields types on # BaseCoreComponent to common classes after both common and base are imported -BaseCoreComponent.initClassFields() +BaseCoreComponent._init_typed_fields() diff --git a/stix/base.py b/stix/base.py index 4a115071..d940c7c6 100644 --- a/stix/base.py +++ b/stix/base.py @@ -507,7 +507,7 @@ class BaseCoreComponent(Cached, Entity): short_descriptions = None @classmethod - def initClassFields(cls): + def _init_typed_fields(cls): import data_marking import common from stix.common.structured_text import StructuredTextList, StructuredTextListField diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 4df503de..462da4a0 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -35,7 +35,7 @@ def __init__(self, value=None, timestamp=None, description=None, source=None): # called in stix.common.related @classmethod - def initClassFields(cls): + def _init_typed_fields(cls): from .information_source import InformationSource cls.source.type_ = InformationSource diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 3829a577..76ff97d1 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -6,11 +6,9 @@ # internal import stix -import stix.utils as utils import stix.bindings.stix_common as stix_common_binding # relative -from . import vocabs from .vocabs import VocabString from .references import References from .identity import Identity @@ -34,7 +32,7 @@ class InformationSource(stix.Entity): references = ElementField("References", References) @classmethod - def initClassFields(cls): + def _init_typed_fields(cls): cls.contributing_sources.type_ = ContributingSources def __init__(self, description=None, identity=None, time=None, tools=None, contributing_sources=None, references=None): @@ -102,4 +100,4 @@ class ContributingSources(stix.EntityList): # finally, initialize field types that would be circular dependencies -InformationSource.initClassFields() +InformationSource._init_typed_fields() diff --git a/stix/common/related.py b/stix/common/related.py index 194cbcde..f0492f92 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -21,7 +21,7 @@ from stix.base import AttributeField -Confidence.initClassFields() +Confidence._init_typed_fields() class GenericRelationship(stix.Entity): _namespace = "http://stix.mitre.org/common-1" diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index 2a4a6f55..a0986725 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -72,7 +72,7 @@ class Incident(stix.BaseCoreComponent): history = ElementField("History", History) @classmethod - def initClassFields(cls): + def _init_typed_fields(cls): cls.attributed_threat_actors.type_ = AttributedThreatActors cls.related_indicators.type_ = RelatedIndicators cls.related_observables.type_ = RelatedObservables @@ -484,5 +484,5 @@ def _fix_value(self, value): return Statement(value=vocabs.IntendedEffect(value)) -Incident.initClassFields() +Incident._init_typed_fields() diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 4f17ace1..481f02c1 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -200,7 +200,7 @@ class Indicator(stix.BaseCoreComponent): related_packages = ElementField("Related_Packages", RelatedPackageRefs) @classmethod - def initClassFields(cls): + def _init_typed_fields(cls): cls.related_campaigns.type_ = RelatedCampaignRefs def __init__(self, id_=None, idref=None, timestamp=None, title=None, @@ -1024,4 +1024,4 @@ class _IndicatedTTPs(stix.TypedList): class _Observables(stix.TypedList): _contained_type = Observable -Indicator.initClassFields() +Indicator._init_typed_fields() diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index ccd62a67..bba14253 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -25,7 +25,7 @@ class Sighting(stix.Entity): related_observables = ElementField("Related_Observables") @classmethod - def initClassFields(cls): + def _init_typed_fields(cls): cls.related_observables.type_ = RelatedObservables def __init__(self, timestamp=None, timestamp_precision=None, description=None): From d4525bf6a6da4c295c8b269bb9495c2aab83da33 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 13:13:10 -0400 Subject: [PATCH 185/438] Added stix.Entity to MRO of stix.EntityList so that stix.EntityList.to_xml() would be called instead of mixbox's --- stix/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/base.py b/stix/base.py index d940c7c6..bb565365 100644 --- a/stix/base.py +++ b/stix/base.py @@ -249,7 +249,7 @@ def find(self, id_): return entity -class EntityList(_MixboxEntityList): +class EntityList(Entity, _MixboxEntityList): _contained_type = _override _inner_name = None _dict_as_list = False From dfcd3cff39146fe157372c9069fcd07a73758cb3 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 13:13:46 -0400 Subject: [PATCH 186/438] Cleanup. --- stix/common/confidence.py | 7 +++++-- stix/common/names.py | 2 +- stix/indicator/sightings.py | 8 ++++---- stix/test/__init__.py | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 462da4a0..72d651a0 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -7,10 +7,12 @@ import stix.utils as utils import stix.bindings.stix_common as common_binding -from . import vocabs, VocabString -from .structured_text import StructuredTextList, StructuredTextListField from stix.base import ElementField, AttributeField +from .vocabs import VocabString +from .structured_text import StructuredTextList, StructuredTextListField + + class Confidence(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' _binding = common_binding @@ -30,6 +32,7 @@ def __init__(self, value=None, timestamp=None, description=None, source=None): self.value = value self.description = description self.source = source + # TODO: support confidence_assertion_chain # self.confidence_assertion_chain = None diff --git a/stix/common/names.py b/stix/common/names.py index 31a95943..ca0d2e3e 100644 --- a/stix/common/names.py +++ b/stix/common/names.py @@ -10,7 +10,7 @@ class Names(stix.EntityList): - _namespace = "http://stix.mitre.org/common-1" + _namespace = 'http://stix.mitre.org/common-1' _binding = common_binding _binding_class = _binding.NamesType _contained_type = VocabString diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index bba14253..752b2fcd 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -24,10 +24,6 @@ class Sighting(stix.Entity): confidence = ElementField("Confidence", Confidence) related_observables = ElementField("Related_Observables") - @classmethod - def _init_typed_fields(cls): - cls.related_observables.type_ = RelatedObservables - def __init__(self, timestamp=None, timestamp_precision=None, description=None): self._fields = {} self.timestamp = timestamp or utils.dates.now() @@ -37,6 +33,10 @@ def __init__(self, timestamp=None, timestamp_precision=None, description=None): self.reference = None self.confidence = None + @classmethod + def _init_typed_fields(cls): + cls.related_observables.type_ = RelatedObservables + """ @timestamp.setter def timestamp(self, value): diff --git a/stix/test/__init__.py b/stix/test/__init__.py index 3abf314b..13f40bf0 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -113,7 +113,7 @@ def round_trip(o, output=False, list_=False): print str(ex) ns_info.finalize() print ns_info.finalized_namespaces - raise ex + raise if output: print(xml_string) From 3fc66ace6de7f98dff2439595672343c741e2b48 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 20:31:34 -0400 Subject: [PATCH 187/438] Added DateTimeField to BaseCoreComponent --- stix/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/base.py b/stix/base.py index bb565365..ffe478d8 100644 --- a/stix/base.py +++ b/stix/base.py @@ -499,7 +499,7 @@ class BaseCoreComponent(Cached, Entity): id_ = IdField("id") idref = IdrefField("idref") version = AttributeField("version") - timestamp = AttributeField("timestamp") + timestamp = fields.DateTimeField("timestamp") handling = ElementField("Handling") # These are defined in init_typed_fields due to circular imports From 78736347b72c35ca542113ef77551b4ac4c8499d Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 20:50:25 -0400 Subject: [PATCH 188/438] Added typedfield support to DateTimeWithPrecision --- stix/common/datetimewithprecision.py | 75 +++++++++++----------------- 1 file changed, 28 insertions(+), 47 deletions(-) diff --git a/stix/common/datetimewithprecision.py b/stix/common/datetimewithprecision.py index 503e706e..09ffaf80 100644 --- a/stix/common/datetimewithprecision.py +++ b/stix/common/datetimewithprecision.py @@ -1,71 +1,52 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox.fields import DateTimeField + import stix import stix.utils as utils import stix.bindings.stix_common as common_binding +from stix.base import ContentField, AttributeField + + + DATE_PRECISION_VALUES = ("year", "month", "day") TIME_PRECISION_VALUES = ("hour", "minute", "second") DATETIME_PRECISION_VALUES = DATE_PRECISION_VALUES + TIME_PRECISION_VALUES +def _validate_precision(instance, value): + if value is None: + return + elif value in DATETIME_PRECISION_VALUES: + return + else: + error = "The precision must be one of {0}. Received '{1}'" + error = error.format(DATE_PRECISION_VALUES, value) + raise ValueError(error) + + class DateTimeWithPrecision(stix.Entity): _binding = common_binding _binding_class = _binding.DateTimeWithPrecisionType _namespace = 'http://stix.mitre.org/common-1' + value = DateTimeField("valueOf_", key_name="value") + precision = AttributeField("precision", preset_hook=_validate_precision) + def __init__(self, value=None, precision='second'): super(DateTimeWithPrecision, self).__init__() + self.value = value self.precision = precision - @property - def value(self): - return self._value - - @value.setter - def value(self, value): - self._value = utils.dates.parse_value(value) - - @property - def precision(self): - return self._precision - - @precision.setter - def precision(self, value): - if value not in DATETIME_PRECISION_VALUES: - error = "The precision must be one of {0}. Received '{1}'" - error = error.format(DATE_PRECISION_VALUES, value) - raise ValueError(error) - - self._precision = value - - def to_obj(self, return_obj=None, ns_info=None): - super(DateTimeWithPrecision, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - obj = self._binding_class() - obj.valueOf_ = utils.dates.serialize_value(self.value) - obj.precision = self.precision - return obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.value = obj.valueOf_ - return_obj.precision = obj.precision - return return_obj def to_dict(self): if self.precision == 'second': return utils.dates.serialize_value(self.value) - + d = { 'value': utils.dates.serialize_value(self.value), 'precision':self.precision @@ -74,17 +55,17 @@ def to_dict(self): return d @classmethod - def from_dict(cls, dict_, return_obj=None): - if not dict_: + def from_dict(cls, cls_dict=None, return_obj=None): + if not cls_dict: return None if not return_obj: return_obj = cls() - if not isinstance(dict_, dict): - return_obj.value = dict_ + if not isinstance(cls_dict, dict): + return_obj.value = cls_dict else: - return_obj.precision = dict_.get('precision') - return_obj.value = dict_.get('value') + return_obj.precision = cls_dict.get('precision') + return_obj.value = cls_dict.get('value') return return_obj From bbc7a70f2ca2859ab9ec962272b6099fccfb6380 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 20:54:33 -0400 Subject: [PATCH 189/438] Fixed error message in _validate_precision --- stix/common/datetimewithprecision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/common/datetimewithprecision.py b/stix/common/datetimewithprecision.py index 09ffaf80..d5630c36 100644 --- a/stix/common/datetimewithprecision.py +++ b/stix/common/datetimewithprecision.py @@ -24,7 +24,7 @@ def _validate_precision(instance, value): return else: error = "The precision must be one of {0}. Received '{1}'" - error = error.format(DATE_PRECISION_VALUES, value) + error = error.format(DATETIME_PRECISION_VALUES, value) raise ValueError(error) From aec829da8de5880b77d264f68ec5d95eff659c1f Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 20:54:56 -0400 Subject: [PATCH 190/438] Cleanup --- stix/common/datetimewithprecision.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/stix/common/datetimewithprecision.py b/stix/common/datetimewithprecision.py index d5630c36..978c5786 100644 --- a/stix/common/datetimewithprecision.py +++ b/stix/common/datetimewithprecision.py @@ -7,10 +7,7 @@ import stix.utils as utils import stix.bindings.stix_common as common_binding -from stix.base import ContentField, AttributeField - - - +from stix.base import AttributeField DATE_PRECISION_VALUES = ("year", "month", "day") TIME_PRECISION_VALUES = ("hour", "minute", "second") From d92a482f6d6c3857dfcd24a566d708cfc8acc3e6 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 21:10:22 -0400 Subject: [PATCH 191/438] Added DateTimeField to CampaignRef --- stix/common/campaign_reference.py | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/stix/common/campaign_reference.py b/stix/common/campaign_reference.py index b5b598a1..74925d48 100644 --- a/stix/common/campaign_reference.py +++ b/stix/common/campaign_reference.py @@ -1,9 +1,11 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox.fields import DateTimeField + # internal import stix -import stix.utils as utils import stix.bindings.stix_common as common_binding from stix.base import AttributeField, ElementField @@ -17,7 +19,7 @@ class CampaignRef(stix.Entity): _binding_class = common_binding.CampaignReferenceType idref = AttributeField("idref") - timestamp = AttributeField("timestamp") #preset_hook = lambda inst, value : if value is not None or not isinstance(value, datetime.datetime): inst.set_timestamp(utils.dates.parse_value(value)) + timestamp = DateTimeField("timestamp") names = ElementField("Names", Names) def __init__(self, idref=None, timestamp=None, **kwargs): @@ -28,27 +30,3 @@ def __init__(self, idref=None, timestamp=None, **kwargs): def add_name(self, name): self.names.append(name) - - #timestamp.setter - #def timestamp(self, value): - # self._timestamp = utils.dates.parse_value(value) - -""" - def to_obj(self, return_obj=None, ns_info=None): - - if not return_obj: - return_obj = self._binding_class() - - return_obj = super(CampaignRef, self).to_obj( - return_obj=return_obj, - ns_info=ns_info - ) - - return_obj.idref = self.idref - return_obj.timestamp = utils.serialize_value(self.timestamp) - - if self.names: - return_obj.Names = self.names.to_obj() - - return return_obj -""" \ No newline at end of file From 6269cf2a9fead461b5a9cc7f85b5ed77372c0b05 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 21:11:20 -0400 Subject: [PATCH 192/438] Added DateTimeField to Confidence --- stix/common/confidence.py | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 72d651a0..6c1112c1 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -3,6 +3,8 @@ from __future__ import absolute_import +from mixbox.fields import DateTimeField + import stix import stix.utils as utils import stix.bindings.stix_common as common_binding @@ -11,7 +13,7 @@ from .vocabs import VocabString from .structured_text import StructuredTextList, StructuredTextListField - +from .datetimewithprecision import validate_precision class Confidence(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' @@ -20,8 +22,8 @@ class Confidence(stix.Entity): value = ElementField("Value", VocabString) descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") - timestamp = AttributeField("timestamp") - timestamp_precision = AttributeField("timestamp_precision") + timestamp = DateTimeField("timestamp") + timestamp_precision = AttributeField("timestamp_precision", preset_hook=validate_precision) source = ElementField("Source") def __init__(self, value=None, timestamp=None, description=None, source=None): @@ -41,16 +43,6 @@ def __init__(self, value=None, timestamp=None, description=None, source=None): def _init_typed_fields(cls): from .information_source import InformationSource cls.source.type_ = InformationSource - - """ - @property - def timestamp(self): - return self._timestamp - - @timestamp.setter - def timestamp(self, value): - self._timestamp = utils.dates.parse_value(value) - """ @property def description(self): @@ -84,15 +76,6 @@ def add_description(self, description): """ self.descriptions.add(description) - # @property - # def confidence_assertion_chain(self): - # return self._confidence_assertion_chain - - # @confidence_assertion_chain.setter - # def confidence_assertion_chain(self, value): - # if value: - # raise NotImplementedError() - # class ConfidenceAssertionChain(stix.Entity): # _namespace = 'http://stix.mitre.org/common-2' From b442b98a917ea8897b3b0c0c221c27275aef1453 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 21:11:36 -0400 Subject: [PATCH 193/438] Made validate_precision function public --- stix/common/datetimewithprecision.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stix/common/datetimewithprecision.py b/stix/common/datetimewithprecision.py index 978c5786..a719a890 100644 --- a/stix/common/datetimewithprecision.py +++ b/stix/common/datetimewithprecision.py @@ -14,7 +14,7 @@ DATETIME_PRECISION_VALUES = DATE_PRECISION_VALUES + TIME_PRECISION_VALUES -def _validate_precision(instance, value): +def validate_precision(instance, value): if value is None: return elif value in DATETIME_PRECISION_VALUES: @@ -31,7 +31,7 @@ class DateTimeWithPrecision(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' value = DateTimeField("valueOf_", key_name="value") - precision = AttributeField("precision", preset_hook=_validate_precision) + precision = AttributeField("precision", preset_hook=validate_precision) def __init__(self, value=None, precision='second'): super(DateTimeWithPrecision, self).__init__() @@ -44,7 +44,7 @@ def to_dict(self): if self.precision == 'second': return utils.dates.serialize_value(self.value) - d = { + d = { 'value': utils.dates.serialize_value(self.value), 'precision':self.precision } From 4dac27f1d17314dcd03d610fe6c02852cdd18d2a Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 21:13:16 -0400 Subject: [PATCH 194/438] Removed **kwargs from CampaignRef.__init__() --- stix/common/campaign_reference.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stix/common/campaign_reference.py b/stix/common/campaign_reference.py index 74925d48..d05c2de5 100644 --- a/stix/common/campaign_reference.py +++ b/stix/common/campaign_reference.py @@ -22,8 +22,9 @@ class CampaignRef(stix.Entity): timestamp = DateTimeField("timestamp") names = ElementField("Names", Names) - def __init__(self, idref=None, timestamp=None, **kwargs): - super(CampaignRef, self).__init__(**kwargs) + def __init__(self, idref=None, timestamp=None): + super(CampaignRef, self).__init__() + self.idref = idref self.timestamp = timestamp self.names = None From f4b1adfa7e27cb06ac4dffdb5e2ccfbc7cf632c1 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 21:43:21 -0400 Subject: [PATCH 195/438] Cleanup of BaseCoreComponent --- stix/base.py | 173 +++++++-------------------------------------------- 1 file changed, 22 insertions(+), 151 deletions(-) diff --git a/stix/base.py b/stix/base.py index ffe478d8..e9693ca0 100644 --- a/stix/base.py +++ b/stix/base.py @@ -20,7 +20,7 @@ from . import utils def _structured_text_list(input): - from stix.common.structured_text import StructuredTextList + if input: return StructuredTextList(input) @@ -491,6 +491,11 @@ def insert(self, idx, value): self._inner.insert(idx, value) +def _validate_version(cls, instance, value): + if value: + utils.check_version(instance._ALL_VERSIONS, value) + + class BaseCoreComponent(Cached, Entity): _ALL_VERSIONS = () _ID_PREFIX = None @@ -498,82 +503,42 @@ class BaseCoreComponent(Cached, Entity): title = ElementField("Title") id_ = IdField("id") idref = IdrefField("idref") - version = AttributeField("version") + version = AttributeField("version", preset_hook=_validate_version) timestamp = fields.DateTimeField("timestamp") - handling = ElementField("Handling") # These are defined in init_typed_fields due to circular imports - descriptions = None - short_descriptions = None + handling = None + descriptions = None + short_descriptions = None + @classmethod def _init_typed_fields(cls): - import data_marking - import common + from stix.data_marking import Marking from stix.common.structured_text import StructuredTextList, StructuredTextListField - cls.handling.type_ = data_marking.Marking - #cls.information_source.type_ = common.InformationSource + + cls.handling = fields.TypedField("Handling", Marking) cls.descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") cls.short_descriptions = StructuredTextListField("Short_Description", StructuredTextList, key_name="short_description") def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): - + + from stix.common.structured_text import StructuredTextList + super(BaseCoreComponent, self).__init__() - + self.id_ = id_ or idgen.create_id(self._ID_PREFIX) self.idref = idref self.title = title - self.descriptions = _structured_text_list(description) - self.short_descriptions = _structured_text_list(short_description) - self.version = None - #self.information_source = None - self.handling = None + self.descriptions = StructuredTextList(description) + self.short_descriptions = StructuredTextList(short_description) if timestamp: self.timestamp = timestamp else: self.timestamp = utils.dates.now() if not idref else None - - # TODO: add this as a callback_hook to version TypedField - def check_version(self, value): - if not value: - self._version = None - else: - utils.check_version(self._ALL_VERSIONS, value) - self._version = value - - # - # @property - # def timestamp(self): - # """The timestam property declares the time of creation and is - # automatically set in ``__init__()``. - # - # This property can accept ``datetime.datetime`` or ``str`` values. - # If an ``str`` value is supplied, a best-effort attempt is made to - # parse it into an instance of ``datetime.datetime``. - # - # Default Value: A ``datetime.dateime`` instance with a value of the - # date/time when ``__init__()`` was called. - # - # Note: - # If an ``idref`` is set during ``__init__()``, the value of - # ``timestamp`` will not automatically generated and instead default - # to the ``timestamp`` parameter, which has a default value of - # ``None``. - # - # Returns: - # An instance of ``datetime.datetime``. - # - # """ - # return self._timestamp - # - # @timestamp.setter - # def timestamp(self, value): - # self._timestamp = utils.dates.parse_value(value) - # - @property def description(self): """A single description about the contents or purpose of this object. @@ -586,20 +551,17 @@ def description(self): Returns: An instance of :class:`.StructuredText` - """ return next(iter(self.descriptions), None) @description.setter def description(self, value): - from stix.common.structured_text import StructuredTextList - self.descriptions = StructuredTextList(value) + self.descriptions = value def add_description(self, description): """Adds a description to the ``descriptions`` collection. This is the same as calling "foo.descriptions.add(bar)". - """ self.descriptions.add(description) @@ -616,107 +578,16 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` - """ return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): - from stix.common.structured_text import StructuredTextList - self.short_descriptions = StructuredTextList(value) + self.short_descriptions = value def add_short_description(self, description): """Adds a description to the ``short_descriptions`` collection. This is the same as calling "foo.short_descriptions.add(bar)". - """ self.short_descriptions.add(description) - - # - # @classmethod - # def from_obj(cls, obj, return_obj=None): - # from stix.common import StructuredTextList, InformationSource - # from stix.data_marking import Marking - # - # if not return_obj: - # raise ValueError("Must provide a return_obj argument") - # - # if not obj: - # raise ValueError("Must provide an obj argument") - # - # return_obj.id_ = obj.id - # return_obj.idref = obj.idref - # return_obj.timestamp = obj.timestamp - # - # # These may not be found on the input obj if it isn't a full - # # type definition (e.g., used as a reference) - # return_obj.version = getattr(obj, 'version', None) - # return_obj.title = getattr(obj, 'Title', None) - # return_obj.descriptions = \ - # StructuredTextList.from_obj(getattr(obj, 'Description', None)) - # return_obj.short_descriptions = \ - # StructuredTextList.from_obj(getattr(obj, 'Short_Description', None)) - # return_obj.information_source = \ - # InformationSource.from_obj(getattr(obj, 'Information_Source', None)) - # return_obj.handling = \ - # Marking.from_obj(getattr(obj, 'Handling', None)) - # - # return return_obj - # - # def to_obj(self, return_obj=None, ns_info=None): - # if not return_obj: - # raise ValueError("Must provide a return_obj argument") - # - # super(BaseCoreComponent, self).to_obj( - # return_obj=return_obj, - # ns_info=ns_info - # ) - # - # return_obj.id = self.id_ - # return_obj.idref = self.idref - # return_obj.version = self.version - # return_obj.Title = self.title - # - # if self.timestamp: - # return_obj.timestamp = utils.dates.serialize_value(self.timestamp) - # if self.descriptions: - # return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - # if self.short_descriptions: - # return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) - # if self.information_source: - # return_obj.Information_Source = self.information_source.to_obj(ns_info=ns_info) - # if self.handling: - # return_obj.Handling = self.handling.to_obj(ns_info=ns_info) - # - # return return_obj - # - # @classmethod - # def from_dict(cls, d, return_obj=None): - # from stix.common import StructuredTextList, InformationSource - # from stix.data_marking import Marking - # - # if not return_obj: - # raise ValueError("Must provide a return_obj argument") - # - # get = d.get - # return_obj.id_ = get('id') - # return_obj.idref = get('idref') - # return_obj.timestamp = get('timestamp') - # return_obj.version = get('version') - # return_obj.title = get('title') - # return_obj.descriptions = \ - # StructuredTextList.from_dict(get('description')) - # return_obj.short_descriptions = \ - # StructuredTextList.from_dict(get('short_description')) - # return_obj.information_source = \ - # InformationSource.from_dict(get('information_source')) - # return_obj.handling = \ - # Marking.from_dict(get('handling')) - # - # return return_obj - # - # def to_dict(self): - # return super(BaseCoreComponent, self).to_dict() - # - # From 3dca4f42c91eca4ed90e7db9cc2225a85f0305a2 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 24 Sep 2015 21:58:37 -0400 Subject: [PATCH 196/438] Added TypedField support to EncodedCDATA --- stix/base.py | 3 +- stix/common/__init__.py | 64 +++++------------------------------------ 2 files changed, 8 insertions(+), 59 deletions(-) diff --git a/stix/base.py b/stix/base.py index e9693ca0..acfbb42a 100644 --- a/stix/base.py +++ b/stix/base.py @@ -65,8 +65,7 @@ def __set__(self, instance, value): if value: fields.unset(instance, IdField) - - + class Entity(_MixboxEntity): """Base class for all classes in the STIX API.""" diff --git a/stix/common/__init__.py b/stix/common/__init__.py index d28f4ad0..23f40562 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -3,6 +3,8 @@ from __future__ import absolute_import +from mixbox.fields import TypedField, CDATAField + from .structured_text import StructuredText, StructuredTextList # noqa from .vocabs import VocabString # noqa from .datetimewithprecision import DateTimeWithPrecision # noqa @@ -61,71 +63,19 @@ class EncodedCDATA(stix.Entity): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = _binding.EncodedCDATAType - + + value = CDATAField("valueOf_", key_name="value") + encoded = TypedField("encoded") + def __init__(self, value=None, encoded=None): + super(EncodedCDATA, self).__init__() self.value = value self.encoded = encoded - @property - def value(self): - return self._value - - @value.setter - def value(self, value): - self._value = utils.strip_cdata(value) - @property def cdata(self): return utils.cdata(self.value) - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.value = obj.valueOf_ - return_obj.encoded = obj.encoded - - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - super(EncodedCDATA, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - return_obj.encoded = self.encoded - return_obj.valueOf_ = utils.cdata(self.value) - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - - if not return_obj: - return_obj = cls() - - return_obj.value = utils.strip_cdata(d.get('value')) - return_obj.encoded = bool(d.get('encoded')) - - return return_obj - - def to_dict(self): - d = {} - - if not self.value: - return d - - d['value'] = utils.strip_cdata(self.value) - d['encoded'] = bool(self.encoded) - - return d - def __str__(self): return self.__unicode__().encode("utf-8") From a593b93a9d799f3286d2f1f8f3be6fdf28b7676e Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Fri, 25 Sep 2015 16:16:38 -0400 Subject: [PATCH 197/438] Updated Identity class to use typedfields. Need to think about the possibility of making a Factory for Identity. --- stix/common/__init__.py | 6 +++-- stix/common/datetimewithprecision.py | 2 -- stix/common/identity.py | 36 ++++++++-------------------- stix/common/related.py | 7 ++++-- 4 files changed, 19 insertions(+), 32 deletions(-) diff --git a/stix/common/__init__.py b/stix/common/__init__.py index 23f40562..038821fc 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -83,5 +83,7 @@ def __unicode__(self): return unicode(self.value) -# Initialize typefield -Statement._init_typed_fields() \ No newline at end of file +# Initialize typed fields which could not be done in the class definition +Statement._init_typed_fields() +Identity._init_typed_fields() +Confidence._init_typed_fields() diff --git a/stix/common/datetimewithprecision.py b/stix/common/datetimewithprecision.py index a719a890..3fe3e21c 100644 --- a/stix/common/datetimewithprecision.py +++ b/stix/common/datetimewithprecision.py @@ -35,11 +35,9 @@ class DateTimeWithPrecision(stix.Entity): def __init__(self, value=None, precision='second'): super(DateTimeWithPrecision, self).__init__() - self.value = value self.precision = precision - def to_dict(self): if self.precision == 'second': return utils.dates.serialize_value(self.value) diff --git a/stix/common/identity.py b/stix/common/identity.py index e217c3f4..a18f42e0 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -7,22 +7,25 @@ # internal import stix import stix.bindings.stix_common as common_binding -from stix.base import ElementField, IdField +from stix.base import ElementField, IdField, IdrefField from stix.bindings.stix_common import IdentityType + class Identity(Cached, stix.Entity): _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' _binding_class = IdentityType id_ = IdField("id") - idref = IdField("idref") + idref = IdrefField("idref") name = ElementField("Name") - related_identities = ElementField("Related_Identities") + + # Set in _init_typed_fields() due to circular imports + related_identities = None @classmethod - def initializeClassFields(cls): - cls.related_identities.type = RelatedIdentities + def _init_typed_fields(cls): + cls.related_identities = ElementField("Related_Identities", RelatedIdentities) def __init__(self, id_=None, idref=None, name=None, related_identities=None): super(Identity, self).__init__() @@ -32,23 +35,6 @@ def __init__(self, id_=None, idref=None, name=None, related_identities=None): self.name = name self.related_identities = related_identities - def to_obj(self, return_obj=None, ns_info=None): - super(Identity, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding.IdentityType() - - return_obj.id = self.id_ - return_obj.idref = self.idref - - if self.name: - return_obj.Name = self.name - if self.related_identities: - return_obj.Related_Identities = \ - self.related_identities.to_obj(ns_info=ns_info) - - return return_obj - @staticmethod def lookup_class(xsi_type): if not xsi_type: @@ -75,8 +61,8 @@ def from_obj(cls, obj, return_obj=None): return return_obj - def to_dict(self): - return super(Identity, self).to_dict() + # def to_dict(self): + # return super(Identity, self).to_dict() @classmethod def from_dict(cls, dict_repr, return_obj=None): @@ -112,8 +98,6 @@ class RelatedIdentities(stix.EntityList): _contained_type = RelatedIdentity _inner_name = "identities" -# this must come after RelatedIdentities definition -Identity.initializeClassFields() # Backwards compatibility add_extension = stix.add_extension diff --git a/stix/common/related.py b/stix/common/related.py index f0492f92..bd761d54 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -11,6 +11,8 @@ import stix.bindings.stix_core as core_binding import stix.bindings.report as report_binding +from stix.base import AttributeField + # deprecation warnings from stix.utils.deprecated import idref_deprecated, deprecated @@ -19,9 +21,8 @@ from .information_source import InformationSource from .confidence import Confidence -from stix.base import AttributeField -Confidence._init_typed_fields() + class GenericRelationship(stix.Entity): _namespace = "http://stix.mitre.org/common-1" @@ -29,6 +30,8 @@ class GenericRelationship(stix.Entity): _binding_class = common_binding.GenericRelationshipType def __init__(self, confidence=None, information_source=None, relationship=None): + super(GenericRelationship, self).__init__() + self.confidence = confidence self.information_source = information_source self.relationship = relationship From 4bcf0a635a9172ab60eaa532b0cec3a42bdabb46 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 28 Sep 2015 11:28:24 -0400 Subject: [PATCH 198/438] Moved Idfield and IdrefField to mixbox. --- stix/base.py | 34 ++------------------------------ stix/common/identity.py | 13 ++++++------ stix/common/structured_text.py | 7 ++++--- stix/indicator/test_mechanism.py | 8 +++++--- 4 files changed, 18 insertions(+), 44 deletions(-) diff --git a/stix/base.py b/stix/base.py index acfbb42a..2dc94bcf 100644 --- a/stix/base.py +++ b/stix/base.py @@ -19,14 +19,6 @@ # internal from . import utils -def _structured_text_list(input): - - - if input: - return StructuredTextList(input) - else: - return StructuredTextList() - def _override(*args, **kwargs): raise NotImplementedError() @@ -44,28 +36,6 @@ class ContentField(fields.TypedField): pass -class IdField(AttributeField): - def __set__(self, instance, value): - """Set the id field to `value`. If `value` is not None or an empty - string, unset the idref fields on `instance`. - """ - super(IdField, self).__set__(instance, value) - - if value: - fields.unset(instance, IdrefField) - - - -class IdrefField(AttributeField): - def __set__(self, instance, value): - """Set the idref field to `value`. If `value` is not None or an empty - string, unset the id fields on `instance`. - """ - super(IdrefField, self).__set__(instance, value) - - if value: - fields.unset(instance, IdField) - class Entity(_MixboxEntity): """Base class for all classes in the STIX API.""" @@ -500,8 +470,8 @@ class BaseCoreComponent(Cached, Entity): _ID_PREFIX = None title = ElementField("Title") - id_ = IdField("id") - idref = IdrefField("idref") + id_ = fields.IdField("id") + idref = fields.IdrefField("idref") version = AttributeField("version", preset_hook=_validate_version) timestamp = fields.DateTimeField("timestamp") diff --git a/stix/common/identity.py b/stix/common/identity.py index a18f42e0..c54e0d91 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -2,22 +2,26 @@ # See LICENSE.txt for complete terms. # external +from mixbox import fields from mixbox.cache import Cached # internal import stix import stix.bindings.stix_common as common_binding -from stix.base import ElementField, IdField, IdrefField +from stix.base import ElementField from stix.bindings.stix_common import IdentityType + + + class Identity(Cached, stix.Entity): _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' _binding_class = IdentityType - id_ = IdField("id") - idref = IdrefField("idref") + id_ = fields.IdField("id") + idref = fields.IdrefField("idref") name = ElementField("Name") # Set in _init_typed_fields() due to circular imports @@ -61,9 +65,6 @@ def from_obj(cls, obj, return_obj=None): return return_obj - # def to_dict(self): - # return super(Identity, self).to_dict() - @classmethod def from_dict(cls, dict_repr, return_obj=None): import stix.extensions.identity.ciq_identity_3_0 # noqa diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index a7526d3b..72e58193 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -1,16 +1,17 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. - import itertools import contextlib import collections +from mixbox import fields + import stix import stix.utils as utils import stix.bindings.stix_common as stix_common_binding # typed fields -from stix.base import AttributeField, ElementField, IdField, ContentField +from stix.base import AttributeField, ElementField, ContentField #: Default ordinality value for StructuredText. DEFAULT_ORDINALITY = 1 @@ -34,7 +35,7 @@ class StructuredText(stix.Entity): _binding_class = _binding.StructuredTextType _namespace = 'http://stix.mitre.org/common-1' - id_ = IdField("id") + id_ = fields.IdField("id") ordinality = AttributeField("ordinality") value = ContentField("valueOf_", key_name="value") structuring_format = AttributeField("structuring_format") diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index 0ba52a5d..bfda5864 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox import fields from mixbox.cache import Cached # internal @@ -10,15 +11,16 @@ # bindings import stix.bindings.indicator as indicator_binding -from stix.base import IdField, AttributeField, ElementField +from stix.base import AttributeField, ElementField + class _BaseTestMechanism(Cached, stix.Entity): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = indicator_binding.TestMechanismType() - id_ = IdField("id") - idref = IdField("idref") + id_ = fields.IdField("id") + idref = fields.IdField("idref") efficacy = ElementField("Efficacy", Statement) producer = ElementField("Producer", InformationSource) From 577ae8c8c08dc9b3b05180b53836edba7fb09c67 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 1 Oct 2015 09:55:11 -0400 Subject: [PATCH 199/438] Updated ToolInformation to use TypedFields. --- stix/common/tools.py | 57 ++++++++++---------------------------------- 1 file changed, 12 insertions(+), 45 deletions(-) diff --git a/stix/common/tools.py b/stix/common/tools.py index 9515306b..7d39b2d9 100644 --- a/stix/common/tools.py +++ b/stix/common/tools.py @@ -2,33 +2,29 @@ # See LICENSE.txt for complete terms. # external +from mixbox import fields import cybox.common # internal import stix -import stix.utils as utils import stix.bindings.stix_common as common_binding # relative from .structured_text import StructuredTextList + class ToolInformation(stix.Entity, cybox.common.ToolInformation): _namespace = 'http://stix.mitre.org/common-1' _binding = common_binding _binding_class = common_binding.ToolInformationType - + + title = fields.TypedField("Title") + short_descriptions = fields.TypedField("Short_Description", StructuredTextList, key_name="short_description") + def __init__(self, title=None, short_description=None, tool_name=None, tool_vendor=None): super(ToolInformation, self).__init__(tool_name=tool_name, tool_vendor=tool_vendor) self.title = title self.short_description = short_description - - @property - def title(self): - return self._title - - @title.setter - def title(self, value): - self._title = value @property def short_description(self): @@ -52,35 +48,6 @@ def short_description(self): def short_description(self, value): self.short_descriptions = value - @property - def short_descriptions(self): - """A :class:`.StructuredTextList` object, containing short descriptions - about the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - short descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of :class:`.StructuredTextList` - - """ - return self._short_description - - @short_descriptions.setter - def short_descriptions(self, value): - self._short_description = StructuredTextList(value) - def add_short_description(self, description): """Adds a description to the ``short_descriptions`` collection. @@ -100,33 +67,33 @@ def to_obj(self, return_obj=None, ns_info=None): ns_info=ns_info ) - return_obj.Title = self.title - if self.short_descriptions: - return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) - return return_obj @classmethod def from_obj(cls, obj, return_obj=None): if not obj: return None + if not return_obj: return_obj = cls() cybox.common.ToolInformation.from_obj(obj, return_obj) - + return_obj.title = obj.Title return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) return return_obj def to_dict(self): - return utils.to_dict(self) + d = stix.Entity.to_dict(self) + d.update(cybox.common.ToolInformation.to_dict(self)) + return d @classmethod def from_dict(cls, dict_repr, return_obj=None): if not dict_repr: return None + if not return_obj: return_obj = cls() From 4bc632eb1b49ad4916e8ed799fc66a2add2675b2 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 1 Oct 2015 11:21:05 -0400 Subject: [PATCH 200/438] Added TypedFields to VocabString. --- stix/common/vocabs.py | 68 +++++++++++++------------------------------ 1 file changed, 21 insertions(+), 47 deletions(-) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index b78ad932..d51d10fb 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -7,6 +7,21 @@ from mixbox import fields +def validate_value(instance, value): + allowed = instance._ALLOWED_VALUES + + if not value: + return + elif not allowed: + return + elif value in allowed: + return + else: + error = "Value must be one of {allowed}. Received '{value}'" + error = error.format(**locals()) + raise ValueError(error) + + class VocabField(fields.TypedField): """TypedField subclass for VocabString fields.""" @@ -67,31 +82,18 @@ class VocabString(stix.Entity): _XSI_TYPE = None _ALLOWED_VALUES = None + value = fields.TypedField("valueOf_", key_name="value", preset_hook=validate_value) + vocab_name = fields.TypedField("vocab_name") + vocab_reference = fields.TypedField("vocab_reference") + xsi_type = fields.TypedField("xsi_type", key_name="xsi:type") + def __init__(self, value=None): super(VocabString, self).__init__() self.value = value self.xsi_type = self._XSI_TYPE - self.vocab_name = None self.vocab_reference = None - @property - def value(self): - return self._value - - @value.setter - def value(self, v): - allowed = self._ALLOWED_VALUES - - if not v: - self._value = None - elif allowed and (v not in allowed): - error = "Value must be one of {0}. Received '{1}'" - error = error.format(allowed, v) - raise ValueError(error) - else: - self._value = v - def __str__(self): return str(self.value) @@ -117,39 +119,11 @@ def lookup_class(xsi_type): except ValueError: return VocabString - def to_obj(self, return_obj=None, ns_info=None): - super(VocabString, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - # TODO: handle normalization - # vocab_obj.valueOf_ = normalize_to_xml(self.value) - return_obj.valueOf_ = self.value - return_obj.xsi_type = self.xsi_type - - if self.vocab_name is not None: - return_obj.vocab_name = self.vocab_name - if self.vocab_reference is not None: - return_obj.vocab_reference = self.vocab_reference - - return return_obj - def to_dict(self): if self.is_plain(): return self.value + return super(VocabString, self).to_dict() - d = {} - if self.value is not None: - d['value'] = self.value - if self.xsi_type is not None: - d['xsi:type'] = self.xsi_type - if self.vocab_name is not None: - d['vocab_name'] = self.vocab_name - if self.vocab_reference is not None: - d['vocab_reference'] = self.vocab_reference - - return d @classmethod def from_obj(cls, vocab_obj, return_obj=None): From 5d712f7415c8032a8fc090edb2bb7cb8e96f5fe3 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 1 Oct 2015 11:23:46 -0400 Subject: [PATCH 201/438] Removed init_typed_fields() methods. Replaced functionality with TypedField lazy type resolution capabilities (passing a string python path into the type_ kwarg.) --- stix/__init__.py | 4 ---- stix/base.py | 17 +++-------------- stix/common/__init__.py | 6 ------ stix/common/confidence.py | 8 +------- stix/common/identity.py | 11 +---------- stix/common/information_source.py | 9 +-------- stix/common/statement.py | 11 +++-------- stix/incident/__init__.py | 28 +++++++--------------------- stix/indicator/indicator.py | 7 +------ stix/indicator/sightings.py | 7 ++----- 10 files changed, 19 insertions(+), 89 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index e9773d4b..e268f08f 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -131,7 +131,3 @@ def supported_stix_version(): """ return ('1.1.1', '1.2') - -# because common depends on base, we can only set the TypeFields types on -# BaseCoreComponent to common classes after both common and base are imported -BaseCoreComponent._init_typed_fields() diff --git a/stix/base.py b/stix/base.py index 2dc94bcf..166eaf54 100644 --- a/stix/base.py +++ b/stix/base.py @@ -472,23 +472,12 @@ class BaseCoreComponent(Cached, Entity): title = ElementField("Title") id_ = fields.IdField("id") idref = fields.IdrefField("idref") + descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList", key_name="description") + short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList", key_name="short_description") version = AttributeField("version", preset_hook=_validate_version) timestamp = fields.DateTimeField("timestamp") + handling = fields.TypedField("Handling", type_="stix.data_marking.Marking") - # These are defined in init_typed_fields due to circular imports - handling = None - descriptions = None - short_descriptions = None - - - @classmethod - def _init_typed_fields(cls): - from stix.data_marking import Marking - from stix.common.structured_text import StructuredTextList, StructuredTextListField - - cls.handling = fields.TypedField("Handling", Marking) - cls.descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") - cls.short_descriptions = StructuredTextListField("Short_Description", StructuredTextList, key_name="short_description") def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): diff --git a/stix/common/__init__.py b/stix/common/__init__.py index 038821fc..db6f7585 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -81,9 +81,3 @@ def __str__(self): def __unicode__(self): return unicode(self.value) - - -# Initialize typed fields which could not be done in the class definition -Statement._init_typed_fields() -Identity._init_typed_fields() -Confidence._init_typed_fields() diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 6c1112c1..8c744290 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -24,7 +24,7 @@ class Confidence(stix.Entity): descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") timestamp = DateTimeField("timestamp") timestamp_precision = AttributeField("timestamp_precision", preset_hook=validate_precision) - source = ElementField("Source") + source = ElementField("Source", type_="stix.common.InformationSource") def __init__(self, value=None, timestamp=None, description=None, source=None): super(Confidence, self).__init__() @@ -37,12 +37,6 @@ def __init__(self, value=None, timestamp=None, description=None, source=None): # TODO: support confidence_assertion_chain # self.confidence_assertion_chain = None - - # called in stix.common.related - @classmethod - def _init_typed_fields(cls): - from .information_source import InformationSource - cls.source.type_ = InformationSource @property def description(self): diff --git a/stix/common/identity.py b/stix/common/identity.py index c54e0d91..b27c210e 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -12,9 +12,6 @@ from stix.bindings.stix_common import IdentityType - - - class Identity(Cached, stix.Entity): _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' @@ -23,13 +20,7 @@ class Identity(Cached, stix.Entity): id_ = fields.IdField("id") idref = fields.IdrefField("idref") name = ElementField("Name") - - # Set in _init_typed_fields() due to circular imports - related_identities = None - - @classmethod - def _init_typed_fields(cls): - cls.related_identities = ElementField("Related_Identities", RelatedIdentities) + related_identities = fields.TypedField("Related_Identities", type_="stix.common.identity.RelatedIdentities") def __init__(self, id_=None, idref=None, name=None, related_identities=None): super(Identity, self).__init__() diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 76ff97d1..b4494087 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -25,16 +25,12 @@ class InformationSource(stix.Entity): identity = ElementField("Identity", Identity) descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") - contributing_sources = ElementField("Contributing_Sources") + contributing_sources = ElementField("Contributing_Sources", type_="stix.common.information_source.ContributingSources") time = ElementField("Time", cybox.common.Time) roles = ElementField("Role", VocabString, multiple=True, key_name="roles") tools = ElementField("Tools", ToolInformationList) references = ElementField("References", References) - @classmethod - def _init_typed_fields(cls): - cls.contributing_sources.type_ = ContributingSources - def __init__(self, description=None, identity=None, time=None, tools=None, contributing_sources=None, references=None): super(InformationSource, self).__init__() @@ -98,6 +94,3 @@ class ContributingSources(stix.EntityList): _contained_type = InformationSource _inner_name = "sources" - -# finally, initialize field types that would be circular dependencies -InformationSource._init_typed_fields() diff --git a/stix/common/statement.py b/stix/common/statement.py index baa569ed..853eb1bd 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -3,6 +3,8 @@ from __future__ import absolute_import +from mixbox import fields + import stix import stix.utils as utils import stix.bindings.stix_common as common_binding @@ -25,9 +27,7 @@ class Statement(stix.Entity): value = VocabField("Value", HighMediumLow) descriptions = ElementField("Description", StructuredTextList) confidence = ElementField("Confidence", Confidence) - - # Set by init_typed_fields() to avoid - source = None + source = fields.TypedField("Source", type_="stix.common.InformationSource") def __init__(self, value=None, timestamp=None, description=None, source=None): @@ -40,11 +40,6 @@ def __init__(self, value=None, timestamp=None, description=None, self.source = source self.confidence = None - @classmethod - def _init_typed_fields(cls): - from stix.common.information_source import InformationSource - cls.source = ElementField("Source", InformationSource) - @property def description(self): """A single description about the contents or purpose of this object. diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index a0986725..c955b48f 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -50,15 +50,15 @@ class Incident(stix.BaseCoreComponent): status = ElementField("Status", vocabs.IncidentStatus) time = ElementField("Time", Time) victims = ElementField("Victim", Identity, multiple=True, key_name="victims") - attributed_threat_actors = ElementField("Attributed_Threat_Actors") - related_indicators = ElementField("Related_Indicators") - related_observables = ElementField("Related_Observables") - related_incidents = ElementField("Related_Incidents") + attributed_threat_actors = ElementField("Attributed_Threat_Actors", type_="stix.incident.AttributedThreatActors") + related_indicators = ElementField("Related_Indicators", type_="stix.incident.RelatedIndicators") + related_observables = ElementField("Related_Observables", type_="stix.incident.RelatedObservables") + related_incidents = ElementField("Related_Incidents", type_="stix.incident.RelatedIncidents") related_packages = ElementField("Related_Packages", RelatedPackageRefs) - affected_assets = ElementField("Affected_Assets") - categories = ElementField("Categories") + affected_assets = ElementField("Affected_Assets", type_="stix.incident.AffectedAssets") + categories = ElementField("Categories", type_="stix.incident.IncidentCategories") intended_effects = ElementField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") - leveraged_ttps = ElementField("Leveraged_TTPs") + leveraged_ttps = ElementField("Leveraged_TTPs", type_="stix.incident.LeveragedTTPs") discovery_methods = ElementField("Discovery_Method", vocabs.DiscoveryMethod, multiple=True, key_name="discovery_methods") reporter = ElementField("Reporter", InformationSource) responders = ElementField("Responder", InformationSource, multiple=True, key_name="responders") @@ -71,16 +71,6 @@ class Incident(stix.BaseCoreComponent): coa_requested = ElementField("COA_Requested", COARequested, multiple=True) history = ElementField("History", History) - @classmethod - def _init_typed_fields(cls): - cls.attributed_threat_actors.type_ = AttributedThreatActors - cls.related_indicators.type_ = RelatedIndicators - cls.related_observables.type_ = RelatedObservables - cls.related_incidents.type_ = RelatedIncidents - cls.affected_assets.type_ = AffectedAssets - cls.categories.type_ = IncidentCategories - cls.leveraged_ttps.type_ = LeveragedTTPs - def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): super(Incident, self).__init__( id_=id_, @@ -482,7 +472,3 @@ class _IntendedEffects(stix.TypedList): def _fix_value(self, value): return Statement(value=vocabs.IntendedEffect(value)) - - -Incident._init_typed_fields() - diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 481f02c1..c35bb1af 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -194,14 +194,11 @@ class Indicator(stix.BaseCoreComponent): kill_chain_phases = ElementField("Kill_Chain_Phases", KillChainPhasesReference) valid_time_positions = ElementField("Valid_Time_Position", ValidTime, multiple=True, key_name="valid_time_positions") related_indicators = ElementField("Related_Indicators", RelatedIndicators) - related_campaigns = ElementField("Related_Campaigns") + related_campaigns = ElementField("Related_Campaigns", type_="stix.indicator.RelatedCampaigns") likely_impact = ElementField("Likely_Impact", Statement) negate = AttributeField("negate") related_packages = ElementField("Related_Packages", RelatedPackageRefs) - @classmethod - def _init_typed_fields(cls): - cls.related_campaigns.type_ = RelatedCampaignRefs def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): @@ -1023,5 +1020,3 @@ class _IndicatedTTPs(stix.TypedList): class _Observables(stix.TypedList): _contained_type = Observable - -Indicator._init_typed_fields() diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index 752b2fcd..39f13338 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -11,6 +11,7 @@ from stix.base import AttributeField, ElementField from stix.common.structured_text import StructuredTextListField + class Sighting(stix.Entity): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding @@ -22,7 +23,7 @@ class Sighting(stix.Entity): source = ElementField("Source", InformationSource) reference = ElementField("Reference") confidence = ElementField("Confidence", Confidence) - related_observables = ElementField("Related_Observables") + related_observables = ElementField("Related_Observables", "stix.indicator.sightings.RelatedObservables") def __init__(self, timestamp=None, timestamp_precision=None, description=None): self._fields = {} @@ -33,10 +34,6 @@ def __init__(self, timestamp=None, timestamp_precision=None, description=None): self.reference = None self.confidence = None - @classmethod - def _init_typed_fields(cls): - cls.related_observables.type_ = RelatedObservables - """ @timestamp.setter def timestamp(self, value): From 3017ae12cc186ef683ce60fa76e1a30cb3cfd6a6 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 1 Oct 2015 15:44:09 -0400 Subject: [PATCH 202/438] Added support to TypedFields to stix.common.kill_chains code. Other typedfield cleanup. --- stix/base.py | 8 +- stix/common/kill_chains/__init__.py | 167 ++-------------------------- stix/data_marking.py | 1 + stix/indicator/sightings.py | 26 ++--- 4 files changed, 24 insertions(+), 178 deletions(-) diff --git a/stix/base.py b/stix/base.py index 166eaf54..680f14e6 100644 --- a/stix/base.py +++ b/stix/base.py @@ -460,7 +460,7 @@ def insert(self, idx, value): self._inner.insert(idx, value) -def _validate_version(cls, instance, value): +def _validate_version(instance, value): if value: utils.check_version(instance._ALL_VERSIONS, value) @@ -482,15 +482,13 @@ class BaseCoreComponent(Cached, Entity): def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): - from stix.common.structured_text import StructuredTextList - super(BaseCoreComponent, self).__init__() self.id_ = id_ or idgen.create_id(self._ID_PREFIX) self.idref = idref self.title = title - self.descriptions = StructuredTextList(description) - self.short_descriptions = StructuredTextList(short_description) + self.descriptions = fields.TypedField(description) + self.short_descriptions = fields.TypedField(short_description) if timestamp: self.timestamp = timestamp diff --git a/stix/common/kill_chains/__init__.py b/stix/common/kill_chains/__init__.py index 83450234..28f438d0 100644 --- a/stix/common/kill_chains/__init__.py +++ b/stix/common/kill_chains/__init__.py @@ -1,6 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + # internal import stix import stix.bindings.stix_common as common_binding @@ -11,19 +13,16 @@ class KillChain(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' _binding_class = _binding.KillChainType - id_ = AttributeField("id_") + id_ = AttributeField("id") name = AttributeField("name") definer = AttributeField("definer") reference = AttributeField("reference") number_of_phases = AttributeField("number_of_phases") - kill_chain_phases = ElementField("Kill_Chain_Phase", multiple=True, key_name="kill_chain_phases") - - @classmethod - def initClassField(cls): - cls.kill_chain_phases.type_ = KillChainPhase + kill_chain_phases = ElementField("Kill_Chain_Phase", type_="stix.common.kill_chains.KillChainPhase", multiple=True, key_name="kill_chain_phases") def __init__(self, id_=None, name=None, definer=None, reference=None): - self._fields = {} + super(KillChain, self).__init__() + self.id_ = id_ self.name = name self.definer = definer @@ -33,23 +32,6 @@ def __init__(self, id_=None, name=None, definer=None, reference=None): def add_kill_chain_phase(self, value): self.kill_chain_phases.append(value) - """ - def to_obj(self, return_obj=None, ns_info=None): - super(KillChain, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - return_obj.id = self.id_ - return_obj.name = self.name - return_obj.definer = self.definer - return_obj.reference = self.reference - return_obj.number_of_phases = self.number_of_phases - return_obj.Kill_Chain_Phase = self.kill_chain_phases.to_obj(ns_info=ns_info) - - return return_obj - """ - def __eq__(self, other): if self is other: return True @@ -62,41 +44,6 @@ def __eq__(self, other): def __ne__(self, other): return not self.__eq__(other) - """ - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.id_ = obj.id - return_obj.name = obj.name - return_obj.definer = obj.definer - return_obj.reference = obj.reference - return_obj.number_of_phases = obj.number_of_phases - return_obj.kill_chain_phases = _KillChainPhases.from_obj(obj.Kill_Chain_Phase) - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if not return_obj: - return_obj = cls() - - get = d.get - return_obj.id_ = get('id') - return_obj.name = get('name') - return_obj.definer = get('definer') - return_obj.reference = get('reference') - return_obj.number_of_phases = get('number_of_phases') - return_obj.kill_chain_phases = \ - _KillChainPhases.from_dict(get('kill_chain_phases')) - - return return_obj - """ class KillChains(stix.EntityList): _binding = common_binding @@ -114,41 +61,15 @@ class KillChainPhase(stix.Entity): phase_id = AttributeField("phase_id") name = AttributeField("name") - ordinality = AttributeField("ordinality") + ordinality = fields.IntegerField("ordinality") def __init__(self, phase_id=None, name=None, ordinality=None): - self._fields = {} + super(KillChainPhase, self).__init__() + self.phase_id = phase_id self.name = name self.ordinality = ordinality - - """ - @property - def ordinality(self): - return self._ordinality - - @ordinality.setter - def ordinality(self, value): - if value is not None: - self._ordinality = int(value) - else: - self._ordinality = None - """ - """ - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(KillChainPhase, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - return_obj.phase_id = self.phase_id - return_obj.name = self.name - return_obj.ordinality = self.ordinality - - return return_obj - """ - def __eq__(self, other): if other is self: return True @@ -164,37 +85,6 @@ def __ne__(self, other): def __hash__(self): return hash(tuple(sorted(self.to_dict().items()))) - """ - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.phase_id = obj.phase_id - return_obj.name = obj.name - return_obj.ordinality = obj.ordinality - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if not return_obj: - return_obj = cls() - - return_obj.phase_id = d.get('phase_id') - return_obj.name = d.get('name') - return_obj.ordinality = d.get('ordinality') - - return return_obj - - def to_dict(self): - return super(KillChainPhase, self).to_dict() - """ class KillChainPhaseReference(KillChainPhase): _binding = common_binding @@ -205,49 +95,10 @@ class KillChainPhaseReference(KillChainPhase): kill_chain_name = AttributeField("kill_chain_name") def __init__(self, phase_id=None, name=None, ordinality=None, kill_chain_id=None, kill_chain_name=None): - self._fields = {} super(KillChainPhaseReference, self).__init__(phase_id, name, ordinality) self.kill_chain_id = kill_chain_id self.kill_chain_name = kill_chain_name - """ - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(KillChainPhaseReference, self).to_obj(return_obj=return_obj, ns_info=ns_info) - return_obj.kill_chain_id = self.kill_chain_id - return_obj.kill_chain_name = self.kill_chain_name - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - super(KillChainPhaseReference, cls).from_obj(obj, return_obj=return_obj) - - return_obj.kill_chain_id = obj.kill_chain_id - return_obj.kill_chain_name = obj.kill_chain_name - return return_obj - - def to_dict(self): - return super(KillChainPhaseReference, self).to_dict() - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if not return_obj: - return_obj = cls() - - super(KillChainPhaseReference, cls).from_dict(d, return_obj=return_obj) - return_obj.kill_chain_id = d.get('kill_chain_id') - return_obj.kill_chain_name = d.get('kill_chain_name') - return return_obj - """ class KillChainPhasesReference(stix.EntityList): _binding = common_binding diff --git a/stix/data_marking.py b/stix/data_marking.py index ce077f9b..354c662e 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. # external +from mixbox import fields from mixbox.cache import Cached # internal diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index 39f13338..8dcd5859 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -1,12 +1,14 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + import stix import stix.utils as utils -from stix.common import ( - GenericRelationshipList, RelatedObservable, StructuredTextList, Confidence, - InformationSource -) +from stix.common import (GenericRelationshipList, RelatedObservable, + StructuredTextList, Confidence, InformationSource) +from stix.common.datetimewithprecision import validate_precision + import stix.bindings.indicator as indicator_binding from stix.base import AttributeField, ElementField from stix.common.structured_text import StructuredTextListField @@ -17,16 +19,17 @@ class Sighting(stix.Entity): _binding = indicator_binding _binding_class = _binding.SightingType - timestamp = AttributeField("timestamp") - timestamp_precision = AttributeField("timestamp_precision") + timestamp = fields.DateTimeField("timestamp") + timestamp_precision = fields.TypedField("timestamp_precision", preset_hook=validate_precision) descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") source = ElementField("Source", InformationSource) reference = ElementField("Reference") confidence = ElementField("Confidence", Confidence) - related_observables = ElementField("Related_Observables", "stix.indicator.sightings.RelatedObservables") + related_observables = ElementField("Related_Observables", type_="stix.indicator.sightings.RelatedObservables") def __init__(self, timestamp=None, timestamp_precision=None, description=None): - self._fields = {} + super(Sighting, self).__init__() + self.timestamp = timestamp or utils.dates.now() self.timestamp_precision = timestamp_precision self.descriptions = description @@ -34,12 +37,6 @@ def __init__(self, timestamp=None, timestamp_precision=None, description=None): self.reference = None self.confidence = None - """ - @timestamp.setter - def timestamp(self, value): - self._timestamp = utils.dates.parse_value(value) - """ - @property def description(self): """A single description about the contents or purpose of this object. @@ -138,7 +135,6 @@ class Sightings(stix.EntityList): sightings_count = AttributeField("sightings_count") def __init__(self, sightings_count=None, *args): - self._fields = {} super(Sightings, self).__init__(*args) self.sightings_count = sightings_count From 8f6224140535430a56dff1236a36d3323bbafe2a Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 1 Oct 2015 16:29:01 -0400 Subject: [PATCH 203/438] Broken commit. Began work on updating STIXHeader to use TypedFields. --- stix/base.py | 2 +- stix/common/related.py | 423 ++++++++++++++--------------- stix/common/structured_text.py | 1 + stix/core/stix_header.py | 366 +++++++++++++------------ stix/test/core/stix_header_test.py | 10 +- stix/utils/deprecated.py | 1 - 6 files changed, 408 insertions(+), 395 deletions(-) diff --git a/stix/base.py b/stix/base.py index 680f14e6..e7e00611 100644 --- a/stix/base.py +++ b/stix/base.py @@ -230,7 +230,7 @@ def to_dict(self): if self._dict_as_list: return self.to_list() - d = utils.to_dict(self, skip=('inner',)) + d = super(EntityList, self).to_dict() if self._inner: d[self._inner_name] = [h.to_dict() for h in self] diff --git a/stix/common/related.py b/stix/common/related.py index bd761d54..24fd7264 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -1,8 +1,6 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. - -# stdlib -from __future__ import absolute_import +from mixbox import fields # internal import stix @@ -17,11 +15,12 @@ from stix.utils.deprecated import idref_deprecated, deprecated # relative -from .vocabs import VocabString +from .vocabs import VocabString, VocabField from .information_source import InformationSource from .confidence import Confidence +ALLOWED_SCOPE = ('inclusive', 'exclusive') class GenericRelationship(stix.Entity): @@ -29,92 +28,95 @@ class GenericRelationship(stix.Entity): _binding = common_binding _binding_class = common_binding.GenericRelationshipType + confidence = fields.TypedField("Confidence", Confidence) + information_source = fields.TypedField("Information_Source", InformationSource) + relationship = VocabField("Relationship") + def __init__(self, confidence=None, information_source=None, relationship=None): super(GenericRelationship, self).__init__() - self.confidence = confidence self.information_source = information_source self.relationship = relationship - @property - def confidence(self): - return self._confidence - - @confidence.setter - def confidence(self, value): - self._set_var(Confidence, confidence=value) - - @property - def information_source(self): - return self._information_source - - @information_source.setter - def information_source(self, value): - self._set_var(InformationSource, try_cast=False, information_source=value) - - @property - def relationship(self): - return self._relationship - - @relationship.setter - def relationship(self, value): - self._set_vocab(relationship=value) - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.confidence = Confidence.from_obj(obj.Confidence) - return_obj.information_source = InformationSource.from_obj(obj.Information_Source) - return_obj.relationship = VocabString.from_obj(obj.Relationship) - - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - super(GenericRelationship, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.confidence: - return_obj.Confidence = self.confidence.to_obj(ns_info=ns_info) - if self.information_source: - return_obj.Information_Source = self.information_source.to_obj(ns_info=ns_info) - if self.relationship: - return_obj.Relationship = self.relationship.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - #print "DICT", dict_repr - - return_obj.confidence = Confidence.from_dict(dict_repr.get('confidence')) - return_obj.information_source = InformationSource.from_dict(dict_repr.get('information_source')) - return_obj.relationship = VocabString.from_dict(dict_repr.get('relationship')) - - return return_obj - - def to_dict(self,): - d = {} - if self.confidence: - d['confidence'] = self.confidence.to_dict() - if self.information_source: - d['information_source'] = self.information_source.to_dict() - if self.relationship: - d['relationship'] = self.relationship.to_dict() - - return d + # @property + # def confidence(self): + # return self._confidence + # + # @confidence.setter + # def confidence(self, value): + # self._set_var(Confidence, confidence=value) + # + # @property + # def information_source(self): + # return self._information_source + # + # @information_source.setter + # def information_source(self, value): + # self._set_var(InformationSource, try_cast=False, information_source=value) + # + # @property + # def relationship(self): + # return self._relationship + # + # @relationship.setter + # def relationship(self, value): + # self._set_vocab(relationship=value) + # + # @classmethod + # def from_obj(cls, obj, return_obj=None): + # if not obj: + # return None + # + # if not return_obj: + # return_obj = cls() + # + # return_obj.confidence = Confidence.from_obj(obj.Confidence) + # return_obj.information_source = InformationSource.from_obj(obj.Information_Source) + # return_obj.relationship = VocabString.from_obj(obj.Relationship) + # + # return return_obj + # + # def to_obj(self, return_obj=None, ns_info=None): + # super(GenericRelationship, self).to_obj(return_obj=return_obj, ns_info=ns_info) + # + # if not return_obj: + # return_obj = self._binding_class() + # + # if self.confidence: + # return_obj.Confidence = self.confidence.to_obj(ns_info=ns_info) + # if self.information_source: + # return_obj.Information_Source = self.information_source.to_obj(ns_info=ns_info) + # if self.relationship: + # return_obj.Relationship = self.relationship.to_obj(ns_info=ns_info) + # + # return return_obj + # + # @classmethod + # def from_dict(cls, dict_repr, return_obj=None): + # if not dict_repr: + # return None + # + # if not return_obj: + # return_obj = cls() + # + # #print "DICT", dict_repr + # + # return_obj.confidence = Confidence.from_dict(dict_repr.get('confidence')) + # return_obj.information_source = InformationSource.from_dict(dict_repr.get('information_source')) + # return_obj.relationship = VocabString.from_dict(dict_repr.get('relationship')) + # + # return return_obj + # + # def to_dict(self,): + # d = {} + # if self.confidence: + # d['confidence'] = self.confidence.to_dict() + # if self.information_source: + # d['information_source'] = self.information_source.to_dict() + # if self.relationship: + # d['relationship'] = self.relationship.to_dict() + # + # return d class RelatedPackageRef(GenericRelationship): @@ -122,6 +124,9 @@ class RelatedPackageRef(GenericRelationship): _binding = common_binding _binding_class = common_binding.RelatedPackageRefType + idref = fields.IdrefField("idref") + timestamp = fields.DateTimeField("timestamp") + def __init__(self, idref=None, timestamp=None, confidence=None, information_source=None, relationship=None): @@ -134,66 +139,66 @@ def __init__(self, idref=None, timestamp=None, confidence=None, self.idref = idref self.timestamp = timestamp - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - return_obj = super(RelatedPackageRef, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if self.idref: - return_obj.idref = self.idref - if self.timestamp: - return_obj.timestamp = self.timestamp - - return return_obj - - @property - def timestamp(self): - return self._timestamp - - @timestamp.setter - def timestamp(self, value): - self._timestamp = utils.dates.parse_value(value) - - def to_dict(self): - d = super(RelatedPackageRef, self).to_dict() - - if self.idref: - d['idref'] = self.idref - if self.timestamp: - d['timestamp'] = utils.dates.serialize_value(self.timestamp) - - return d - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - super(RelatedPackageRef, cls).from_obj(obj, return_obj) - - return_obj.idref = obj.idref - return_obj.timestamp = obj.timestamp - - return return_obj - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - super(RelatedPackageRef, cls).from_dict(dict_repr, return_obj) - - return_obj.idref = dict_repr.get("idref") - return_obj.timestamp = dict_repr.get("timestamp") - - return return_obj + # def to_obj(self, return_obj=None, ns_info=None): + # if not return_obj: + # return_obj = self._binding_class() + # + # return_obj = super(RelatedPackageRef, self).to_obj(return_obj=return_obj, ns_info=ns_info) + # + # if self.idref: + # return_obj.idref = self.idref + # if self.timestamp: + # return_obj.timestamp = self.timestamp + # + # return return_obj + # + # @property + # def timestamp(self): + # return self._timestamp + # + # @timestamp.setter + # def timestamp(self, value): + # self._timestamp = utils.dates.parse_value(value) + # + # def to_dict(self): + # d = super(RelatedPackageRef, self).to_dict() + # + # if self.idref: + # d['idref'] = self.idref + # if self.timestamp: + # d['timestamp'] = utils.dates.serialize_value(self.timestamp) + # + # return d + # + # @classmethod + # def from_obj(cls, obj, return_obj=None): + # if not obj: + # return None + # + # if not return_obj: + # return_obj = cls() + # + # super(RelatedPackageRef, cls).from_obj(obj, return_obj) + # + # return_obj.idref = obj.idref + # return_obj.timestamp = obj.timestamp + # + # return return_obj + # + # @classmethod + # def from_dict(cls, dict_repr, return_obj=None): + # if not dict_repr: + # return None + # + # if not return_obj: + # return_obj = cls() + # + # super(RelatedPackageRef, cls).from_dict(dict_repr, return_obj) + # + # return_obj.idref = dict_repr.get("idref") + # return_obj.timestamp = dict_repr.get("timestamp") + # + # return return_obj class GenericRelationshipEntity(stix.Entity): _namespace = "http://stix.mitre.org/common-1" @@ -205,7 +210,7 @@ class GenericRelationshipEntity(stix.Entity): scope = AttributeField("scope") def __init__(self, scope=None, *args): - _fields = {} + super(GenericRelationshipEntity, self).__init__(*args) self.scope = scope @@ -214,13 +219,24 @@ def __nonzero__(self): super(GenericRelationshipList, self).__nonzero__() or bool(self.scope) ) - + +def _validate_scope(instance, value): + if not value: + return + elif value in ALLOWED_SCOPE: + return + else: + msg = "Scope must be one of {0}. Received '{1}'" + msg = msg.format(ALLOWED_SCOPE, value) + raise ValueError(msg) + + class GenericRelationshipList(stix.EntityList): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = _binding.GenericRelationshipListType - _ALLOWED_SCOPE = ('inclusive', 'exclusive') + scope = fields.TypedField("scope", preset_hook=_validate_scope) def __init__(self, scope=None, *args): super(GenericRelationshipList, self).__init__(*args) @@ -231,74 +247,53 @@ def __nonzero__(self): super(GenericRelationshipList, self).__nonzero__() or bool(self.scope) ) - - #def __iter__(self): - # print "ITER", self._inner_name, len(self) - # return getattr(self, self._inner_name) - - @property - def scope(self): - return self._scope - - @scope.setter - def scope(self, value): - if value is None or value in self._ALLOWED_SCOPE: - self._scope = value - return - - msg = "Scope must be one of {0}. Received '{1}'" - msg = msg.format(self._ALLOWED_SCOPE, value) - raise ValueError(msg) - - def to_obj(self, return_obj=None, ns_info=None): - list_obj = super(GenericRelationshipList, self).to_obj( - return_obj=return_obj, - ns_info=ns_info - ) - - list_obj.scope = self.scope - return list_obj - - def to_dict(self): - return super(GenericRelationshipList, self).to_dict() - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if return_obj is None: - return_obj = cls() - - super(GenericRelationshipList, cls).from_obj( - obj, - return_obj=return_obj, - contained_type=cls._contained_type, - binding_var=cls._binding_var - ) - - return_obj.scope = obj.scope - - return return_obj - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if return_obj is None: - return_obj = cls() - - super(GenericRelationshipList, cls).from_dict( - dict_repr, - return_obj=return_obj, - contained_type=cls._contained_type, - inner_name=cls._inner_name - ) - return_obj.scope = dict_repr.get('scope') - - return return_obj + # def to_obj(self, return_obj=None, ns_info=None): + # list_obj = super(GenericRelationshipList, self).to_obj( + # return_obj=return_obj, + # ns_info=ns_info + # ) + # + # list_obj.scope = self.scope + # return list_obj + # + # @classmethod + # def from_obj(cls, obj, return_obj=None): + # if not obj: + # return None + # + # if return_obj is None: + # return_obj = cls() + # + # super(GenericRelationshipList, cls).from_obj( + # obj, + # return_obj=return_obj, + # contained_type=cls._contained_type, + # binding_var=cls._binding_var + # ) + # + # return_obj.scope = obj.scope + # + # return return_obj + # + # @classmethod + # def from_dict(cls, dict_repr, return_obj=None): + # if not dict_repr: + # return None + # + # if return_obj is None: + # return_obj = cls() + # + # super(GenericRelationshipList, cls).from_dict( + # dict_repr, + # return_obj=return_obj, + # contained_type=cls._contained_type, + # inner_name=cls._inner_name + # ) + # + # return_obj.scope = dict_repr.get('scope') + # + # return return_obj class RelatedPackages(GenericRelationshipList): diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 72e58193..bfd65ba3 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -135,6 +135,7 @@ class StructuredTextList(stix.TypedCollection, collections.Sequence): """ _contained_type = StructuredText + _try_cast = True def __init__(self, *args): stix.TypedCollection.__init__(self, *args) diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index bf0db5cc..c3c09940 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -1,15 +1,21 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + import stix from stix.utils.deprecated import deprecated from stix.common import InformationSource, StructuredTextList, VocabString -from stix.common.vocabs import PackageIntent +from stix.common.vocabs import VocabField, PackageIntent from stix.data_marking import Marking import stix.bindings.stix_common as stix_common_binding import stix.bindings.stix_core as stix_core_binding +def _deprecated(instance, value): + deprecated(value) + + class STIXHeader(stix.Entity): """The STIX Package Header. @@ -32,27 +38,39 @@ class STIXHeader(stix.Entity): """ _binding = stix_core_binding + _binding_class = _binding.STIXHeaderType _namespace = 'http://stix.mitre.org/stix-1' + title = fields.TypedField("Title") + package_intents = VocabField("Package_Intents", PackageIntent, multiple=True, preset_hook=_deprecated) + descriptions = fields.TypedField("Description", type_=StructuredTextList, key_name="description", preset_hook=_deprecated) + short_descriptions = fields.TypedField("Short_Description", type_=StructuredTextList, key_name="short_description", preset_hook=_deprecated) + handling = fields.TypedField("Handling", Marking) + information_source = fields.TypedField("Information_Source", InformationSource) + profiles = fields.TypedField("Profiles", multiple=True) + + def __init__(self, package_intents=None, description=None, handling=None, information_source=None, title=None, short_description=None): + super(STIXHeader, self).__init__() + self.package_intents = package_intents self.title = title self.description = description self.short_description = short_description self.handling = handling self.information_source = information_source - self.profiles = [] + self.profiles = None - @property - def title(self): - return self._title - - @title.setter - def title(self, value): - deprecated(value) - self._title = value + # @property + # def title(self): + # return self._title + # + # @title.setter + # def title(self, value): + # deprecated(value) + # self._title = value @property def description(self): @@ -76,36 +94,36 @@ def description(self): def description(self, value): self.descriptions = value - @property - def descriptions(self): - """**DEPRECATED**. A :class:`.StructuredTextList` object, containing - descriptions about the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - deprecated(value) - self._description = StructuredTextList(value) + # @property + # def descriptions(self): + # """**DEPRECATED**. A :class:`.StructuredTextList` object, containing + # descriptions about the purpose or intent of this object. + # + # This is typically used for the purpose of providing multiple + # descriptions with different classificaton markings. + # + # Iterating over this object will yield its contents sorted by their + # ``ordinality`` value. + # + # Default Value: Empty :class:`.StructuredTextList` object. + # + # Note: + # IF this is set to a value that is not an instance of + # :class:`.StructuredText`, an effort will ne made to convert it. + # If this is set to an iterable, any values contained that are not + # an instance of :class:`.StructuredText` will be be converted. + # + # Returns: + # An instance of + # :class:`.StructuredTextList` + # + # """ + # return self._description + # + # @descriptions.setter + # def descriptions(self, value): + # deprecated(value) + # self._description = StructuredTextList(value) def add_description(self, description): """**DEPRECATED**. Adds a description to the ``descriptions`` @@ -138,35 +156,35 @@ def short_description(self): def short_description(self, value): self.short_descriptions = value - @property - def short_descriptions(self): - """**DEPRECATED**. A :class:`.StructuredTextList` object, containing - short descriptions about the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - short descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of :class:`.StructuredTextList` - - """ - return self._short_description - - @short_descriptions.setter - def short_descriptions(self, value): - deprecated(value) - self._short_description = StructuredTextList(value) + # @property + # def short_descriptions(self): + # """**DEPRECATED**. A :class:`.StructuredTextList` object, containing + # short descriptions about the purpose or intent of this object. + # + # This is typically used for the purpose of providing multiple + # short descriptions with different classificaton markings. + # + # Iterating over this object will yield its contents sorted by their + # ``ordinality`` value. + # + # Default Value: Empty :class:`.StructuredTextList` object. + # + # Note: + # IF this is set to a value that is not an instance of + # :class:`.StructuredText`, an effort will ne made to convert it. + # If this is set to an iterable, any values contained that are not + # an instance of :class:`.StructuredText` will be be converted. + # + # Returns: + # An instance of :class:`.StructuredTextList` + # + # """ + # return self._short_description + # + # @short_descriptions.setter + # def short_descriptions(self, value): + # deprecated(value) + # self._short_description = StructuredTextList(value) def add_short_description(self, description): """**DEPRECATED**. Adds a description to the ``short_descriptions`` @@ -178,30 +196,30 @@ def add_short_description(self, description): deprecated(description) self.short_descriptions.add(description) - @property - def handling(self): - """The :class:`.Marking` section of this Header. This section contains - data marking information. - - """ - return self._handling - - @handling.setter - def handling(self, value): - self._set_var(Marking, try_cast=False, handling=value) - - @property - def package_intents(self): - """**DEPRECATED**. A collection of :class:`.VocabString` controlled - vocabulary objects defining the intent of the STIX Package. - - """ - return self._package_intents - - @package_intents.setter - def package_intents(self, value): - deprecated(value) - self._package_intents = _PackageIntents(value) + # @property + # def handling(self): + # """The :class:`.Marking` section of this Header. This section contains + # data marking information. + # + # """ + # return self._handling + # + # @handling.setter + # def handling(self, value): + # self._set_var(Marking, try_cast=False, handling=value) + # + # @property + # def package_intents(self): + # """**DEPRECATED**. A collection of :class:`.VocabString` controlled + # vocabulary objects defining the intent of the STIX Package. + # + # """ + # return self._package_intents + # + # @package_intents.setter + # def package_intents(self, value): + # deprecated(value) + # self._package_intents = _PackageIntents(value) def add_package_intent(self, package_intent): """**DEPRECATED**. Adds :class:`.VocabString` object to the @@ -214,16 +232,16 @@ def add_package_intent(self, package_intent): deprecated(package_intent) self.package_intents.append(package_intent) - @property - def information_source(self): - """The :class:`.InformationSource` section of the STIX Header. - - """ - return self._information_source - - @information_source.setter - def information_source(self, value): - self._set_var(InformationSource, try_cast=False, information_source=value) + # @property + # def information_source(self): + # """The :class:`.InformationSource` section of the STIX Header. + # + # """ + # return self._information_source + # + # @information_source.setter + # def information_source(self, value): + # self._set_var(InformationSource, try_cast=False, information_source=value) def add_profile(self, profile): """Adds a profile to the STIX Header. A Profile is represented by a @@ -232,74 +250,74 @@ def add_profile(self, profile): """ self.profiles.append(profile) - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.title = obj.Title - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) - return_obj.handling = Marking.from_obj(obj.Handling) - return_obj.information_source = InformationSource.from_obj(obj.Information_Source) - return_obj.package_intents = _PackageIntents.from_obj(obj.Package_Intent) - return_obj.profiles = obj.Profiles.Profile if obj.Profiles else [] - - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - super(STIXHeader, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding.STIXHeaderType() - - if self.title: - return_obj.Title = self.title - if self.package_intents: - return_obj.Package_Intent = self.package_intents.to_obj(ns_info=ns_info) - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.short_descriptions: - return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) - if self.handling: - return_obj.Handling = self.handling.to_obj(ns_info=ns_info) - if self.information_source: - return_obj.Information_Source = self.information_source.to_obj(ns_info=ns_info) - if self.profiles: - return_obj.Profiles = stix_common_binding.ProfilesType(Profile=self.profiles) - - return return_obj - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - get = dict_repr.get - - return_obj.title = get('title') - return_obj.package_intents = _PackageIntents.from_list(get('package_intents')) - return_obj.descriptions = StructuredTextList.from_dict(get('description')) - return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) - return_obj.handling = Marking.from_dict(get('handling')) - return_obj.information_source = InformationSource.from_dict(get('information_source')) - return_obj.profiles = get('profiles') - - return return_obj - - def to_dict(self): - return super(STIXHeader, self).to_dict() - - -# NOT AN ACTUAL STIX TYPE! -class _PackageIntents(stix.TypedList): - _contained_type = VocabString - - def _fix_value(self, value): - return PackageIntent(value) + # @classmethod + # def from_obj(cls, obj, return_obj=None): + # if not obj: + # return None + # + # if not return_obj: + # return_obj = cls() + # + # return_obj.title = obj.Title + # return_obj.descriptions = StructuredTextList.from_obj(obj.Description) + # return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) + # return_obj.handling = Marking.from_obj(obj.Handling) + # return_obj.information_source = InformationSource.from_obj(obj.Information_Source) + # return_obj.package_intents = _PackageIntents.from_obj(obj.Package_Intent) + # return_obj.profiles = obj.Profiles.Profile if obj.Profiles else [] + # + # return return_obj + # + # def to_obj(self, return_obj=None, ns_info=None): + # super(STIXHeader, self).to_obj(return_obj=return_obj, ns_info=ns_info) + # + # if not return_obj: + # return_obj = self._binding.STIXHeaderType() + # + # if self.title: + # return_obj.Title = self.title + # if self.package_intents: + # return_obj.Package_Intent = self.package_intents.to_obj(ns_info=ns_info) + # if self.descriptions: + # return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) + # if self.short_descriptions: + # return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) + # if self.handling: + # return_obj.Handling = self.handling.to_obj(ns_info=ns_info) + # if self.information_source: + # return_obj.Information_Source = self.information_source.to_obj(ns_info=ns_info) + # if self.profiles: + # return_obj.Profiles = stix_common_binding.ProfilesType(Profile=self.profiles) + # + # return return_obj + # + # @classmethod + # def from_dict(cls, dict_repr, return_obj=None): + # if not dict_repr: + # return None + # + # if not return_obj: + # return_obj = cls() + # + # get = dict_repr.get + # + # return_obj.title = get('title') + # return_obj.package_intents = _PackageIntents.from_list(get('package_intents')) + # return_obj.descriptions = StructuredTextList.from_dict(get('description')) + # return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) + # return_obj.handling = Marking.from_dict(get('handling')) + # return_obj.information_source = InformationSource.from_dict(get('information_source')) + # return_obj.profiles = get('profiles') + # + # return return_obj + # + # def to_dict(self): + # return super(STIXHeader, self).to_dict() + +# +# # NOT AN ACTUAL STIX TYPE! +# class _PackageIntents(stix.TypedList): +# _contained_type = VocabString +# +# def _fix_value(self, value): +# return PackageIntent(value) diff --git a/stix/test/core/stix_header_test.py b/stix/test/core/stix_header_test.py index fb7c3791..432b7474 100644 --- a/stix/test/core/stix_header_test.py +++ b/stix/test/core/stix_header_test.py @@ -16,11 +16,11 @@ class STIXHeaderTests(EntityTestCase, unittest.TestCase): klass = core.STIXHeader _full_dict = { 'title': "A Title", - 'description': "A really, really long description", - 'short_description': 'A really, really short description', - 'handling': data_marking_test.MarkingTests._full_dict, - 'information_source': information_source_test.InformationSourceTests._full_dict, - 'profiles': ['foo', 'bar'] + # 'description': "A really, really long description", + # 'short_description': 'A really, really short description', + # 'handling': data_marking_test.MarkingTests._full_dict, + # 'information_source': information_source_test.InformationSourceTests._full_dict, + # 'profiles': ['foo', 'bar'] } @silence_warnings diff --git a/stix/utils/deprecated.py b/stix/utils/deprecated.py index 7d56fb96..588594cb 100644 --- a/stix/utils/deprecated.py +++ b/stix/utils/deprecated.py @@ -38,4 +38,3 @@ def deprecated(value): fmt = "The use of this field has been deprecated. Received '{0}' object." msg = fmt.format(type(value).__name__) warnings.warn(msg) - From 7112894053c416bf26226f68ac206640a5f605c2 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Sun, 4 Oct 2015 21:18:00 -0400 Subject: [PATCH 204/438] Updated STIxHeader to use TypedFields. * Added common/profiles.py module and Profiles class. * Added References and Profiles imports in common/__init__.py * Removed unnecessary methods from STIXHeader. --- stix/common/__init__.py | 2 + stix/common/profiles.py | 43 +++++++++ stix/core/stix_header.py | 185 +-------------------------------------- 3 files changed, 49 insertions(+), 181 deletions(-) create mode 100644 stix/common/profiles.py diff --git a/stix/common/__init__.py b/stix/common/__init__.py index db6f7585..520376e0 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -16,6 +16,8 @@ from .tools import ToolInformation # noqa from .names import Names # noqa from .campaign_reference import CampaignRef # noqa +from .references import References # noqa +from .profiles import Profiles # noqa from .related import ( # noqa GenericRelationshipList, RelatedCampaign, RelatedCOA, RelatedExploitTarget, RelatedIdentity, RelatedIncident, diff --git a/stix/common/profiles.py b/stix/common/profiles.py new file mode 100644 index 00000000..bebb5236 --- /dev/null +++ b/stix/common/profiles.py @@ -0,0 +1,43 @@ +import stix +from stix.bindings import stix_common as stix_common_binding + + +class Profiles(stix.Entity): + _binding = stix_common_binding + _binding_class = stix_common_binding.ProfilesType + _namespace = 'http://stix.mitre.org/common-1' + + # Fields + profile = stix.ElementField("Profile", multiple=True) + + def __init__(self, profiles=None): + super(Profiles, self).__init__() + self.profile = profiles + + def __iter__(self): + for x in self.profile: + yield x + + def __getitem__(self, item): + return self.profile[item] + + def __setitem__(self, key, value): + self.profile[key] = value + + def __delitem__(self, key): + del self.profile[key] + + def to_dict(self): + return [x for x in self.profile] + + @classmethod + def from_dict(cls, cls_dict=None, return_obj=None): + if not cls_dict: + return None + + if not return_obj: + return_obj = cls() + + return_obj.profile = [x for x in cls_dict] + + return return_obj diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index c3c09940..60c6cb88 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -5,10 +5,9 @@ import stix from stix.utils.deprecated import deprecated -from stix.common import InformationSource, StructuredTextList, VocabString +from stix.common import InformationSource, StructuredTextList, Profiles from stix.common.vocabs import VocabField, PackageIntent from stix.data_marking import Marking -import stix.bindings.stix_common as stix_common_binding import stix.bindings.stix_core as stix_core_binding @@ -41,13 +40,13 @@ class STIXHeader(stix.Entity): _binding_class = _binding.STIXHeaderType _namespace = 'http://stix.mitre.org/stix-1' - title = fields.TypedField("Title") - package_intents = VocabField("Package_Intents", PackageIntent, multiple=True, preset_hook=_deprecated) + title = fields.TypedField("Title", preset_hook=_deprecated) + package_intents = VocabField("Package_Intent", PackageIntent, multiple=True, preset_hook=_deprecated) descriptions = fields.TypedField("Description", type_=StructuredTextList, key_name="description", preset_hook=_deprecated) short_descriptions = fields.TypedField("Short_Description", type_=StructuredTextList, key_name="short_description", preset_hook=_deprecated) handling = fields.TypedField("Handling", Marking) information_source = fields.TypedField("Information_Source", InformationSource) - profiles = fields.TypedField("Profiles", multiple=True) + profiles = fields.TypedField("Profiles", Profiles) def __init__(self, package_intents=None, description=None, handling=None, @@ -63,15 +62,6 @@ def __init__(self, package_intents=None, description=None, handling=None, self.information_source = information_source self.profiles = None - # @property - # def title(self): - # return self._title - # - # @title.setter - # def title(self, value): - # deprecated(value) - # self._title = value - @property def description(self): """**DEPRECATED**. A single description about the contents or @@ -94,37 +84,6 @@ def description(self): def description(self, value): self.descriptions = value - # @property - # def descriptions(self): - # """**DEPRECATED**. A :class:`.StructuredTextList` object, containing - # descriptions about the purpose or intent of this object. - # - # This is typically used for the purpose of providing multiple - # descriptions with different classificaton markings. - # - # Iterating over this object will yield its contents sorted by their - # ``ordinality`` value. - # - # Default Value: Empty :class:`.StructuredTextList` object. - # - # Note: - # IF this is set to a value that is not an instance of - # :class:`.StructuredText`, an effort will ne made to convert it. - # If this is set to an iterable, any values contained that are not - # an instance of :class:`.StructuredText` will be be converted. - # - # Returns: - # An instance of - # :class:`.StructuredTextList` - # - # """ - # return self._description - # - # @descriptions.setter - # def descriptions(self, value): - # deprecated(value) - # self._description = StructuredTextList(value) - def add_description(self, description): """**DEPRECATED**. Adds a description to the ``descriptions`` collection. @@ -156,36 +115,6 @@ def short_description(self): def short_description(self, value): self.short_descriptions = value - # @property - # def short_descriptions(self): - # """**DEPRECATED**. A :class:`.StructuredTextList` object, containing - # short descriptions about the purpose or intent of this object. - # - # This is typically used for the purpose of providing multiple - # short descriptions with different classificaton markings. - # - # Iterating over this object will yield its contents sorted by their - # ``ordinality`` value. - # - # Default Value: Empty :class:`.StructuredTextList` object. - # - # Note: - # IF this is set to a value that is not an instance of - # :class:`.StructuredText`, an effort will ne made to convert it. - # If this is set to an iterable, any values contained that are not - # an instance of :class:`.StructuredText` will be be converted. - # - # Returns: - # An instance of :class:`.StructuredTextList` - # - # """ - # return self._short_description - # - # @short_descriptions.setter - # def short_descriptions(self, value): - # deprecated(value) - # self._short_description = StructuredTextList(value) - def add_short_description(self, description): """**DEPRECATED**. Adds a description to the ``short_descriptions`` collection. @@ -196,30 +125,6 @@ def add_short_description(self, description): deprecated(description) self.short_descriptions.add(description) - # @property - # def handling(self): - # """The :class:`.Marking` section of this Header. This section contains - # data marking information. - # - # """ - # return self._handling - # - # @handling.setter - # def handling(self, value): - # self._set_var(Marking, try_cast=False, handling=value) - # - # @property - # def package_intents(self): - # """**DEPRECATED**. A collection of :class:`.VocabString` controlled - # vocabulary objects defining the intent of the STIX Package. - # - # """ - # return self._package_intents - # - # @package_intents.setter - # def package_intents(self, value): - # deprecated(value) - # self._package_intents = _PackageIntents(value) def add_package_intent(self, package_intent): """**DEPRECATED**. Adds :class:`.VocabString` object to the @@ -232,17 +137,6 @@ def add_package_intent(self, package_intent): deprecated(package_intent) self.package_intents.append(package_intent) - # @property - # def information_source(self): - # """The :class:`.InformationSource` section of the STIX Header. - # - # """ - # return self._information_source - # - # @information_source.setter - # def information_source(self, value): - # self._set_var(InformationSource, try_cast=False, information_source=value) - def add_profile(self, profile): """Adds a profile to the STIX Header. A Profile is represented by a string URI. @@ -250,74 +144,3 @@ def add_profile(self, profile): """ self.profiles.append(profile) - # @classmethod - # def from_obj(cls, obj, return_obj=None): - # if not obj: - # return None - # - # if not return_obj: - # return_obj = cls() - # - # return_obj.title = obj.Title - # return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - # return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) - # return_obj.handling = Marking.from_obj(obj.Handling) - # return_obj.information_source = InformationSource.from_obj(obj.Information_Source) - # return_obj.package_intents = _PackageIntents.from_obj(obj.Package_Intent) - # return_obj.profiles = obj.Profiles.Profile if obj.Profiles else [] - # - # return return_obj - # - # def to_obj(self, return_obj=None, ns_info=None): - # super(STIXHeader, self).to_obj(return_obj=return_obj, ns_info=ns_info) - # - # if not return_obj: - # return_obj = self._binding.STIXHeaderType() - # - # if self.title: - # return_obj.Title = self.title - # if self.package_intents: - # return_obj.Package_Intent = self.package_intents.to_obj(ns_info=ns_info) - # if self.descriptions: - # return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - # if self.short_descriptions: - # return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) - # if self.handling: - # return_obj.Handling = self.handling.to_obj(ns_info=ns_info) - # if self.information_source: - # return_obj.Information_Source = self.information_source.to_obj(ns_info=ns_info) - # if self.profiles: - # return_obj.Profiles = stix_common_binding.ProfilesType(Profile=self.profiles) - # - # return return_obj - # - # @classmethod - # def from_dict(cls, dict_repr, return_obj=None): - # if not dict_repr: - # return None - # - # if not return_obj: - # return_obj = cls() - # - # get = dict_repr.get - # - # return_obj.title = get('title') - # return_obj.package_intents = _PackageIntents.from_list(get('package_intents')) - # return_obj.descriptions = StructuredTextList.from_dict(get('description')) - # return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) - # return_obj.handling = Marking.from_dict(get('handling')) - # return_obj.information_source = InformationSource.from_dict(get('information_source')) - # return_obj.profiles = get('profiles') - # - # return return_obj - # - # def to_dict(self): - # return super(STIXHeader, self).to_dict() - -# -# # NOT AN ACTUAL STIX TYPE! -# class _PackageIntents(stix.TypedList): -# _contained_type = VocabString -# -# def _fix_value(self, value): -# return PackageIntent(value) From c58176afe75c9c7d5465986df817ce9ebef698a6 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Sun, 4 Oct 2015 21:25:14 -0400 Subject: [PATCH 205/438] Made _validate_scope() a public function and moved it in the source file. --- stix/common/related.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/stix/common/related.py b/stix/common/related.py index 24fd7264..7fd3598c 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -23,6 +23,17 @@ ALLOWED_SCOPE = ('inclusive', 'exclusive') +def validate_scope(instance, value): + if not value: + return + elif value in ALLOWED_SCOPE: + return + else: + msg = "Scope must be one of {0}. Received '{1}'" + msg = msg.format(ALLOWED_SCOPE, value) + raise ValueError(msg) + + class GenericRelationship(stix.Entity): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding @@ -220,16 +231,6 @@ def __nonzero__(self): bool(self.scope) ) -def _validate_scope(instance, value): - if not value: - return - elif value in ALLOWED_SCOPE: - return - else: - msg = "Scope must be one of {0}. Received '{1}'" - msg = msg.format(ALLOWED_SCOPE, value) - raise ValueError(msg) - class GenericRelationshipList(stix.EntityList): _namespace = "http://stix.mitre.org/common-1" From 6de00eec26d50640d5e47c8fee382ff1629ad1d7 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Sun, 4 Oct 2015 22:08:54 -0400 Subject: [PATCH 206/438] Fixed reference to validate_scope function --- stix/common/related.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/common/related.py b/stix/common/related.py index 7fd3598c..f093e308 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -237,7 +237,7 @@ class GenericRelationshipList(stix.EntityList): _binding = common_binding _binding_class = _binding.GenericRelationshipListType - scope = fields.TypedField("scope", preset_hook=_validate_scope) + scope = fields.TypedField("scope", preset_hook=validate_scope) def __init__(self, scope=None, *args): super(GenericRelationshipList, self).__init__(*args) From 2aada81c29089ba5d53d92bb84388a196b9a1bec Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 5 Oct 2015 11:10:17 -0400 Subject: [PATCH 207/438] Updated EntityList to use most of mixbox EntityList code. * Only to_xml() overridden from mixbox EntityList due to namespace processing differences. * Updated stix.common code to pass all stix.test.common unit tests with the exception of the related_tests.py module. --- stix/base.py | 92 +-------------------- stix/common/information_source.py | 5 +- stix/common/names.py | 2 - stix/common/profiles.py | 23 ++++-- stix/common/references.py | 24 ++++-- stix/common/related.py | 4 +- stix/test/common/identity_test.py | 1 - stix/test/common/information_source_test.py | 1 - stix/test/core/stix_header_test.py | 6 +- 9 files changed, 41 insertions(+), 117 deletions(-) diff --git a/stix/base.py b/stix/base.py index e7e00611..c6c382dd 100644 --- a/stix/base.py +++ b/stix/base.py @@ -218,98 +218,12 @@ def find(self, id_): return entity -class EntityList(Entity, _MixboxEntityList): +class EntityList(_MixboxEntityList, Entity): _contained_type = _override _inner_name = None - _dict_as_list = False - def to_list(self): - return [h.to_dict() for h in self] - - def to_dict(self): - if self._dict_as_list: - return self.to_list() - - d = super(EntityList, self).to_dict() - - if self._inner: - d[self._inner_name] = [h.to_dict() for h in self] - - return d - - @classmethod - def from_obj(cls, obj, return_obj=None, contained_type=None, - binding_var=None): - if not obj: - return None - - if return_obj is None: - return_obj = cls() - if not contained_type: - contained_type = cls._contained_type - if not binding_var: - binding_var = cls._binding_var - - for item in getattr(obj, binding_var): - return_obj.append(contained_type.from_obj(item)) - - return return_obj - - @classmethod - def from_list(cls, list_repr, return_obj=None, contained_type=None): - from stix.common.related import GenericRelationshipList - - if not utils.is_sequence(list_repr): - return None - - if return_obj is None: - return_obj = cls() - if not contained_type: - contained_type = cls._contained_type - - #print list_repr.__class__, isinstance(list_repr, GenericRelationshipList) - - # GenericRelationshipList is not actually a list; it's dict with a list member - if issubclass(cls, GenericRelationshipList): - return cls.from_dict(list_repr, return_obj) - - try: - list_repr = list_repr[cls._inner_name] - except: - pass - - - return_obj.extend(contained_type.from_dict(x) for x in list_repr) - return return_obj - - @classmethod - def from_dict(cls, dict_repr, return_obj=None, contained_type=None, - inner_name=None): - - if cls._dict_as_list: - return cls.from_list( - dict_repr, - return_obj=return_obj, - contained_type=contained_type, - ) - - if not isinstance(dict_repr, dict): - return None - - if return_obj is None: - return_obj = cls() - if not contained_type: - contained_type = cls._contained_type - if not inner_name: - inner_name = cls._inner_name - - if inner_name == "attribution": - pass - - for item in dict_repr.get(inner_name, []): - return_obj.append(contained_type.from_dict(item)) - - return return_obj + def to_xml(self, *args, **kwargs): + return Entity.to_xml(self, *args, **kwargs) class TypedCollection(object): diff --git a/stix/common/information_source.py b/stix/common/information_source.py index b4494087..565a9164 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -3,9 +3,11 @@ # external import cybox.common +from cybox.common.tools import ToolInformationList # internal import stix +from stix.base import ElementField import stix.bindings.stix_common as stix_common_binding # relative @@ -13,9 +15,6 @@ from .references import References from .identity import Identity from .structured_text import StructuredTextList, StructuredTextListField -from stix.base import ElementField - -from cybox.common.tools import ToolInformationList class InformationSource(stix.Entity): diff --git a/stix/common/names.py b/stix/common/names.py index ca0d2e3e..6136afe5 100644 --- a/stix/common/names.py +++ b/stix/common/names.py @@ -15,5 +15,3 @@ class Names(stix.EntityList): _binding_class = _binding.NamesType _contained_type = VocabString _binding_var = 'Name' - _inner_name = 'names' - _dict_as_list = True diff --git a/stix/common/profiles.py b/stix/common/profiles.py index bebb5236..500f1151 100644 --- a/stix/common/profiles.py +++ b/stix/common/profiles.py @@ -1,8 +1,13 @@ +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +import collections + import stix from stix.bindings import stix_common as stix_common_binding -class Profiles(stix.Entity): +class Profiles(collections.MutableSequence, stix.Entity): _binding = stix_common_binding _binding_class = stix_common_binding.ProfilesType _namespace = 'http://stix.mitre.org/common-1' @@ -14,21 +19,23 @@ def __init__(self, profiles=None): super(Profiles, self).__init__() self.profile = profiles - def __iter__(self): - for x in self.profile: - yield x + def __len__(self): + return self.profile.__len__() def __getitem__(self, item): - return self.profile[item] + return self.profile.__getitem__(item) def __setitem__(self, key, value): - self.profile[key] = value + self.profile.__setitem__(key, value) def __delitem__(self, key): - del self.profile[key] + self.profile.__delitem__(key) + + def insert(self, index, value): + self.profile.insert(index, value) def to_dict(self): - return [x for x in self.profile] + return [x for x in self] @classmethod def from_dict(cls, cls_dict=None, return_obj=None): diff --git a/stix/common/references.py b/stix/common/references.py index 7a235f9e..678d1077 100644 --- a/stix/common/references.py +++ b/stix/common/references.py @@ -1,8 +1,12 @@ +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. +import collections + import stix from stix.bindings import stix_common as stix_common_binding -class References(stix.Entity): +class References(collections.MutableSequence, stix.Entity): _binding = stix_common_binding _binding_class = stix_common_binding.ReferencesType _namespace = 'http://stix.mitre.org/common-1' @@ -14,21 +18,23 @@ def __init__(self, references=None): super(References, self).__init__() self.reference = references - def __iter__(self): - for r in self.reference: - yield r + def __len__(self): + return self.reference.__len__() def __getitem__(self, item): - return self.reference[item] + return self.reference.__getitem__(item) def __setitem__(self, key, value): - self.reference[key] = value + self.reference.__setitem__(key, value) def __delitem__(self, key): - del self.reference[key] + self.reference.__delitem__(key) + + def insert(self, index, value): + self.reference.insert(index, value) def to_dict(self): - return [x for x in self.reference] + return [x for x in self] @classmethod def from_dict(cls, cls_dict=None, return_obj=None): @@ -40,4 +46,4 @@ def from_dict(cls, cls_dict=None, return_obj=None): return_obj.reference = [x for x in cls_dict] - return return_obj + return return_obj \ No newline at end of file diff --git a/stix/common/related.py b/stix/common/related.py index f093e308..faf2c6d0 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -45,6 +45,7 @@ class GenericRelationship(stix.Entity): def __init__(self, confidence=None, information_source=None, relationship=None): super(GenericRelationship, self).__init__() + self.confidence = confidence self.information_source = information_source self.relationship = relationship @@ -355,6 +356,7 @@ class _BaseRelated(GenericRelationship): def __init__(self, item=None, confidence=None, information_source=None, relationship=None): + super(_BaseRelated, self).__init__( confidence, information_source, @@ -389,7 +391,7 @@ def to_obj(self, return_obj=None, ns_info=None): return return_obj def to_dict(self): - d = utils.to_dict(self, skip=('item',)) + d = super(_BaseRelated, self).to_dict() if self.item: d[self._inner_var.lower()] = self.item.to_dict() diff --git a/stix/test/common/identity_test.py b/stix/test/common/identity_test.py index 5d318875..46887359 100644 --- a/stix/test/common/identity_test.py +++ b/stix/test/common/identity_test.py @@ -14,7 +14,6 @@ class IdentityTests(EntityTestCase, unittest.TestCase): 'id': "foo", 'name': "Me", 'related_identities': { - #'scope': 'inclusive', 'identities': [ { 'confidence': {'value': {'value': "Medium", 'xsi:type':'stixVocabs:HighMediumLowVocab-1.0'}}, diff --git a/stix/test/common/information_source_test.py b/stix/test/common/information_source_test.py index cace5256..97e56f2c 100644 --- a/stix/test/common/information_source_test.py +++ b/stix/test/common/information_source_test.py @@ -42,7 +42,6 @@ class InformationSourceTests(EntityTestCase, unittest.TestCase): } ] }, - 'references' : ['http://example.com'], 'time': { 'start_time': "2010-11-12T01:02:03", 'end_time': "2013-12-11T03:02:01", diff --git a/stix/test/core/stix_header_test.py b/stix/test/core/stix_header_test.py index 432b7474..3cd580bd 100644 --- a/stix/test/core/stix_header_test.py +++ b/stix/test/core/stix_header_test.py @@ -16,10 +16,10 @@ class STIXHeaderTests(EntityTestCase, unittest.TestCase): klass = core.STIXHeader _full_dict = { 'title': "A Title", - # 'description': "A really, really long description", - # 'short_description': 'A really, really short description', + 'description': "A really, really long description", + 'short_description': 'A really, really short description', # 'handling': data_marking_test.MarkingTests._full_dict, - # 'information_source': information_source_test.InformationSourceTests._full_dict, + 'information_source': information_source_test.InformationSourceTests._full_dict, # 'profiles': ['foo', 'bar'] } From 5b0b1f21f840668d6924aaa3ddaf43b80b7bce04 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 5 Oct 2015 12:14:48 -0400 Subject: [PATCH 208/438] Broken commit. Began working on removing return_obj argument from Entity/EntityList/TypedCollection fields. --- stix/base.py | 4 +--- stix/common/datetimewithprecision.py | 21 ++++++------------ stix/common/identity.py | 33 ++++++++++++++-------------- stix/common/profiles.py | 11 ++++------ stix/common/references.py | 11 ++++------ stix/common/structured_text.py | 23 +------------------ 6 files changed, 33 insertions(+), 70 deletions(-) diff --git a/stix/base.py b/stix/base.py index c6c382dd..cde3dbfc 100644 --- a/stix/base.py +++ b/stix/base.py @@ -36,7 +36,6 @@ class ContentField(fields.TypedField): pass - class Entity(_MixboxEntity): """Base class for all classes in the STIX API.""" _namespace = None @@ -141,7 +140,6 @@ def to_xml(self, include_namespaces=True, include_schemalocs=False, :class:`Entity` instance. Default character encoding is ``utf-8``. """ - from .utils import nsparser parser = nsparser.NamespaceParser() @@ -276,7 +274,7 @@ def _fix_value(self, value): return new_value - def to_obj(self, return_obj=None, ns_info=None): + def to_obj(self, ns_info=None): #print "TypedCollection to_obj called" return [x.to_obj(ns_info=ns_info) for x in self] diff --git a/stix/common/datetimewithprecision.py b/stix/common/datetimewithprecision.py index 3fe3e21c..7b6c66d4 100644 --- a/stix/common/datetimewithprecision.py +++ b/stix/common/datetimewithprecision.py @@ -41,26 +41,19 @@ def __init__(self, value=None, precision='second'): def to_dict(self): if self.precision == 'second': return utils.dates.serialize_value(self.value) - - d = { - 'value': utils.dates.serialize_value(self.value), - 'precision':self.precision - } - - return d + return super(DateTimeWithPrecision, self).to_dict() @classmethod - def from_dict(cls, cls_dict=None, return_obj=None): + def from_dict(cls, cls_dict=None): if not cls_dict: return None - if not return_obj: - return_obj = cls() + obj = super(DateTimeWithPrecision, cls).from_dict(cls_dict) if not isinstance(cls_dict, dict): - return_obj.value = cls_dict + obj.value = cls_dict else: - return_obj.precision = cls_dict.get('precision') - return_obj.value = cls_dict.get('value') + obj.precision = cls_dict.get('precision') + obj.value = cls_dict.get('value') - return return_obj + return obj diff --git a/stix/common/identity.py b/stix/common/identity.py index b27c210e..27ced0ff 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -38,26 +38,25 @@ def lookup_class(xsi_type): return stix.lookup_extension(xsi_type) @classmethod - def from_obj(cls, obj, return_obj=None): + def from_obj(cls, obj, partial=None): import stix.extensions.identity.ciq_identity_3_0 # noqa if not obj: return None - if not return_obj: + if not partial: klass = stix.lookup_extension(obj, default=cls) - return_obj = klass.from_obj(obj, return_obj=klass()) + partial = klass.from_obj(obj, partial=klass()) else: - return_obj.id_ = obj.id - return_obj.idref = obj.idref - return_obj.name = obj.Name - return_obj.related_identities = \ - RelatedIdentities.from_obj(obj.Related_Identities) + partial.id_ = obj.id + partial.idref = obj.idref + partial.name = obj.Name + partial.related_identities = RelatedIdentities.from_obj(obj.Related_Identities) - return return_obj + return partial @classmethod - def from_dict(cls, dict_repr, return_obj=None): + def from_dict(cls, dict_repr, partial=None): import stix.extensions.identity.ciq_identity_3_0 # noqa if not dict_repr: @@ -65,17 +64,17 @@ def from_dict(cls, dict_repr, return_obj=None): get = dict_repr.get - if not return_obj: + if not partial: klass = stix.lookup_extension(get('xsi:type'), default=cls) - return_obj = klass.from_dict(dict_repr, klass()) + partial = klass.from_dict(dict_repr, klass()) else: - return_obj.name = get('name') - return_obj.id_ = get('id') - return_obj.idref = get('idref') - return_obj.related_identities = \ + partial.name = get('name') + partial.id_ = get('id') + partial.idref = get('idref') + partial.related_identities = \ RelatedIdentities.from_dict(get('related_identities')) - return return_obj + return partial # We can't import RelatedIdentity until we have defined the Identity class. diff --git a/stix/common/profiles.py b/stix/common/profiles.py index 500f1151..a9f50c88 100644 --- a/stix/common/profiles.py +++ b/stix/common/profiles.py @@ -38,13 +38,10 @@ def to_dict(self): return [x for x in self] @classmethod - def from_dict(cls, cls_dict=None, return_obj=None): + def from_dict(cls, cls_dict=None): if not cls_dict: return None - if not return_obj: - return_obj = cls() - - return_obj.profile = [x for x in cls_dict] - - return return_obj + obj = cls() + obj.profile = [x for x in cls_dict] + return obj diff --git a/stix/common/references.py b/stix/common/references.py index 678d1077..bc0d5bc0 100644 --- a/stix/common/references.py +++ b/stix/common/references.py @@ -37,13 +37,10 @@ def to_dict(self): return [x for x in self] @classmethod - def from_dict(cls, cls_dict=None, return_obj=None): + def from_dict(cls, cls_dict=None): if not cls_dict: return None - if not return_obj: - return_obj = cls() - - return_obj.reference = [x for x in cls_dict] - - return return_obj \ No newline at end of file + obj = cls() + obj.reference = [x for x in cls_dict] + return obj \ No newline at end of file diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index bfd65ba3..2a5bc93c 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -71,27 +71,6 @@ def to_dict(self): else: return super(StructuredText, self).to_dict() - @classmethod - def from_dict(cls, d, return_obj=None): - """Creates an object from the input dictionary. - - Args: - d: A dictionary representation of this object. - - """ - if not d: - return None - - if not return_obj: - return_obj = cls() - - if not isinstance(d, dict): - return_obj.value = d - else: - return_obj = super(StructuredText, cls).from_dict(d, return_obj) - - return return_obj - def __str__(self): """Returns a UTF-8 encoded string representation of the ``value``. @@ -347,7 +326,7 @@ def remove(self, value): """ self._inner.remove(value) - def to_obj(self, return_obj=None, ns_info=None): + def to_obj(self, ns_info=None): """Returns a binding object list for the StructuredTextList. If the list has a length of 1, and its member has an ordinality of 1, From c19038356f7b94d626968c4f04b18b8971715a5f Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 5 Oct 2015 13:10:52 -0400 Subject: [PATCH 209/438] Updated most stix.common Entity/EntityList method signatures to align with base class (removed return_obj). --- stix/campaign/__init__.py | 2 +- stix/common/datetimewithprecision.py | 11 ++---- stix/common/identity.py | 8 ++-- stix/common/related.py | 43 ++++++++------------- stix/common/tools.py | 47 ----------------------- stix/common/vocabs.py | 56 +++++++++++++--------------- stix/data_marking.py | 31 +++++---------- 7 files changed, 61 insertions(+), 137 deletions(-) diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 98a9c105..24be3de0 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -116,7 +116,7 @@ class Campaign(stix.BaseCoreComponent): associated_campaigns = ElementField("Associated_Campaigns", AssociatedCampaigns) attribution = ElementField("Attribution", Attribution, multiple=True) confidence = ElementField("Confidence", Confidence) - #references = ElementField("Reference", multiple=True) + # references = ElementField("Reference", multiple=True) status = ElementField("Status", VocabString) intended_effects = ElementField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") names = ElementField("Names", Names) diff --git a/stix/common/datetimewithprecision.py b/stix/common/datetimewithprecision.py index 7b6c66d4..6a5389ff 100644 --- a/stix/common/datetimewithprecision.py +++ b/stix/common/datetimewithprecision.py @@ -44,16 +44,13 @@ def to_dict(self): return super(DateTimeWithPrecision, self).to_dict() @classmethod - def from_dict(cls, cls_dict=None): + def from_dict(cls, cls_dict): if not cls_dict: return None - - obj = super(DateTimeWithPrecision, cls).from_dict(cls_dict) - - if not isinstance(cls_dict, dict): + elif not isinstance(cls_dict, dict): + obj = cls() obj.value = cls_dict else: - obj.precision = cls_dict.get('precision') - obj.value = cls_dict.get('value') + obj = super(DateTimeWithPrecision, cls).from_dict(cls_dict) return obj diff --git a/stix/common/identity.py b/stix/common/identity.py index 27ced0ff..a141fcef 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -56,17 +56,17 @@ def from_obj(cls, obj, partial=None): return partial @classmethod - def from_dict(cls, dict_repr, partial=None): + def from_dict(cls, cls_dict, partial=None): import stix.extensions.identity.ciq_identity_3_0 # noqa - if not dict_repr: + if not cls_dict: return None - get = dict_repr.get + get = cls_dict.get if not partial: klass = stix.lookup_extension(get('xsi:type'), default=cls) - partial = klass.from_dict(dict_repr, klass()) + partial = klass.from_dict(cls_dict, klass()) else: partial.name = get('name') partial.id_ = get('id') diff --git a/stix/common/related.py b/stix/common/related.py index faf2c6d0..16d84131 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -379,16 +379,13 @@ def _set_item(self, value): self._item = value - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(_BaseRelated, self).to_obj(return_obj=return_obj, ns_info=ns_info) + def to_obj(self, ns_info=None): + obj = super(_BaseRelated, self).to_obj(ns_info=ns_info) if self.item: - setattr(return_obj, self._inner_var, self.item.to_obj(ns_info=ns_info)) + setattr(obj, self._inner_var, self.item.to_obj(ns_info=ns_info)) - return return_obj + return obj def to_dict(self): d = super(_BaseRelated, self).to_dict() @@ -399,34 +396,26 @@ def to_dict(self): return d @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: + def from_obj(cls, cls_obj): + if not cls_obj: return None - if not return_obj: - return_obj = cls() - - super(_BaseRelated, cls).from_obj(obj, return_obj) - - contained_item = getattr(obj, cls._inner_var) - return_obj.item = cls._base_type.from_obj(contained_item) + obj = super(_BaseRelated, cls).from_obj(cls_obj) + contained_item = getattr(cls_obj, cls._inner_var) + obj.item = cls._base_type.from_obj(contained_item) - return return_obj + return obj @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: + def from_dict(cls, cls_dict): + if not cls_dict: return None - if not return_obj: - return_obj = cls() - - super(_BaseRelated, cls).from_dict(dict_repr, return_obj) - - contained_item = dict_repr.get(cls._inner_var.lower()) - return_obj.item = cls._base_type.from_dict(contained_item) + obj = super(_BaseRelated, cls).from_dict(cls_dict) + contained_item = cls_dict.get(cls._inner_var.lower()) + obj.item = cls._base_type.from_dict(contained_item) - return return_obj + return obj class RelatedCampaign(_BaseRelated): diff --git a/stix/common/tools.py b/stix/common/tools.py index 7d39b2d9..209907b7 100644 --- a/stix/common/tools.py +++ b/stix/common/tools.py @@ -55,50 +55,3 @@ def add_short_description(self, description): """ self.short_descriptions.add(description) - - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - stix.Entity.to_obj(self, return_obj=return_obj, ns_info=ns_info) - cybox.common.ToolInformation.to_obj( - self, - return_obj=return_obj, - ns_info=ns_info - ) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - cybox.common.ToolInformation.from_obj(obj, return_obj) - - return_obj.title = obj.Title - return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) - - return return_obj - - def to_dict(self): - d = stix.Entity.to_dict(self) - d.update(cybox.common.ToolInformation.to_dict(self)) - return d - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - cybox.common.ToolInformation.from_dict(dict_repr, return_obj) - return_obj.title = dict_repr.get('title') - return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) - - return return_obj diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index d51d10fb..fb244a92 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -126,51 +126,47 @@ def to_dict(self): @classmethod - def from_obj(cls, vocab_obj, return_obj=None): - if not vocab_obj: + def from_obj(cls, cls_obj, partial=None): + if not cls_obj: return None - if not return_obj: - klass = cls.lookup_class(vocab_obj.xsi_type) - return klass.from_obj(vocab_obj, return_obj=klass()) - - # xsi_type should be set automatically by the class's constructor. - - # TODO: handle denormalization - # vocab_str.value = denormalize_from_xml(vocab_obj.valueOf_) - return_obj.value = vocab_obj.valueOf_ - return_obj.vocab_name = vocab_obj.vocab_name - return_obj.vocab_reference = vocab_obj.vocab_reference - return_obj.xsi_type = vocab_obj.xsi_type + if not partial: + klass = cls.lookup_class(cls_obj.xsi_type) + return klass.from_obj(cls_obj, partial=klass()) + + partial.value = cls_obj.valueOf_ + partial.vocab_name = cls_obj.vocab_name + partial.vocab_reference = cls_obj.vocab_reference + partial.xsi_type = cls_obj.xsi_type - return return_obj + return partial @classmethod - def from_dict(cls, vocab_dict, return_obj=None): - if not vocab_dict: + def from_dict(cls, cls_dict, partial=None): + if not cls_dict: return None - if not return_obj: - if isinstance(vocab_dict, dict): - get = vocab_dict.get + if not partial: + if isinstance(cls_dict, dict): + get = cls_dict.get klass = cls.lookup_class(get('xsi:type')) - return klass.from_dict(vocab_dict, return_obj=klass()) + return klass.from_dict(cls_dict, partial=klass()) else: - return_obj = cls() + partial = cls() # xsi_type should be set automatically by the class's constructor. # In case this is a "plain" string, just set it. - if not isinstance(vocab_dict, dict): - return_obj.value = vocab_dict + if not isinstance(cls_dict, dict): + partial.value = cls_dict else: - get = vocab_dict.get - return_obj.value = get('value') - return_obj.vocab_name = get('vocab_name') - return_obj.vocab_reference = get('vocab_reference') - return_obj.xsi_type = get('xsi:type') + get = cls_dict.get + partial.value = get('value') + partial.vocab_name = get('vocab_name') + partial.vocab_reference = get('vocab_reference') + partial.xsi_type = get('xsi:type') - return return_obj + return partial def _get_terms(vocab_class): diff --git a/stix/data_marking.py b/stix/data_marking.py index 354c662e..ecb2c5f3 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -32,13 +32,8 @@ def markings(self, value): def add_marking(self, value): self._markings.append(value) - def to_obj(self, return_obj=None, ns_info=None): - super(Marking, self).to_obj( - return_obj=return_obj, - ns_info=ns_info - ) - - obj = self._binding_class() + def to_obj(self, ns_info=None): + obj = super(Marking, self).to_obj(ns_info=ns_info) if self.markings: obj.Marking = self.markings.to_obj(ns_info=ns_info) @@ -49,29 +44,23 @@ def to_list(self): return self.markings.to_list() if self.markings else [] @classmethod - def from_obj(cls, obj, return_obj=None): + def from_obj(cls, obj): if not obj: return None - if not return_obj: - return_obj = cls() - - return_obj.markings = _MarkingSpecifications.from_obj(obj.Marking) - - return return_obj + obj = super(Marking, cls).from_obj(obj) + obj.markings = _MarkingSpecifications.from_obj(obj.Marking) + return obj @classmethod - def from_list(cls, markings_list, return_obj=None): + def from_list(cls, markings_list): if not markings_list: return None - if not return_obj: - return_obj = cls() - + obj = cls() mlist = _MarkingSpecifications.from_list(markings_list) - return_obj.markings = mlist - - return return_obj + obj.markings = mlist + return obj to_dict = to_list from_dict = from_list From 61689946c801f30ff4373af8e956420eb0b5584d Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Mon, 5 Oct 2015 14:50:08 -0400 Subject: [PATCH 210/438] Fixed accidental omission of call to collect namespace info in this extension's to_obj() method. --- stix/extensions/identity/ciq_identity_3_0.py | 1 + 1 file changed, 1 insertion(+) diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index e20e6185..a792c8a4 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -66,6 +66,7 @@ def specification(self, value): self._specification = value def to_obj(self, return_obj=None, ns_info=None): + self._collect_ns_info(ns_info) if not return_obj: return_obj = self._binding_class() From 49ea6b29a7e92a247c7c03d9287e848dba574ff9 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Mon, 5 Oct 2015 14:54:42 -0400 Subject: [PATCH 211/438] Bugfixes: - exception re-raised incorrectly - fixed a type check in EntityTestCase.test_round_trip_full(). The original test tested whether the type of self is 'type' (which is the type of types). That's certainly not what was intended. --- stix/test/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stix/test/__init__.py b/stix/test/__init__.py index 97b43d12..e61d2c37 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -111,7 +111,7 @@ def round_trip(o, output=False, list_=False): print str(ex) ns_info.finalize() print ns_info.finalized_namespaces - raise ex + raise if output: print(xml_string) @@ -157,7 +157,7 @@ def _combine(self, d): @silence_warnings def test_round_trip_full(self): # Don't run this test on the base class - if type(self) == type(EntityTestCase): + if type(self) is EntityTestCase: return ent = self.klass.from_dict(self._full_dict) From 5c349893ea51619e04fff319b04f4c0b839aff74 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Mon, 5 Oct 2015 15:08:11 -0400 Subject: [PATCH 212/438] Code revamps to use mixbox NamespaceSet's, rather than python-stix's own custom namespace collection mechanisms. --- stix/base.py | 38 +-- stix/bindings/stix_common.py | 8 +- stix/utils/nsparser.py | 522 ++++++++++------------------------- 3 files changed, 159 insertions(+), 409 deletions(-) diff --git a/stix/base.py b/stix/base.py index f9ef7ebc..5393c2d8 100644 --- a/stix/base.py +++ b/stix/base.py @@ -10,6 +10,7 @@ from mixbox import idgen from mixbox.binding_utils import save_encoding from mixbox.cache import Cached +import mixbox.namespaces # internal from . import utils @@ -145,14 +146,6 @@ def to_xml(self, include_namespaces=True, include_schemalocs=False, """ from .utils import nsparser - parser = nsparser.NamespaceParser() - - if auto_namespace: - ns_info = nsparser.NamespaceInfo() - else: - ns_info = None - - obj = self.to_obj(ns_info=ns_info) if (not auto_namespace) and (not ns_dict): raise Exception( @@ -160,31 +153,30 @@ def to_xml(self, include_namespaces=True, include_schemalocs=False, "or missing." ) + ns_info = nsparser.NamespaceInfo() + + obj = self.to_obj(ns_info=ns_info if auto_namespace else None) + + ns_info.finalize(ns_dict=ns_dict, schemaloc_dict=schemaloc_dict) + if auto_namespace: - ns_info.finalize(ns_dict=ns_dict, schemaloc_dict=schemaloc_dict) obj_ns_dict = ns_info.binding_namespaces else: - ns_info = nsparser.NamespaceInfo() - ns_info.finalized_namespaces = ns_dict or {} - ns_info.finalized_schemalocs = schemaloc_dict or {} obj_ns_dict = dict( itertools.chain( - ns_dict.iteritems(), - nsparser.DEFAULT_STIX_NAMESPACES.iteritems() + ns_info.binding_namespaces.iteritems(), + mixbox.namespaces.get_full_ns_map().iteritems() ) ) namespace_def = "" if include_namespaces: - xmlns = parser.get_xmlns_str(ns_info.finalized_namespaces) - namespace_def += ("\n\t" + xmlns) - - if include_schemalocs and include_namespaces: - schemaloc = parser.get_schemaloc_str(ns_info.finalized_schemalocs) - namespace_def += ("\n\t" + schemaloc) - - if not pretty: - namespace_def = namespace_def.replace('\n\t', ' ') + delim = "\n\t" if pretty else " " + xmlns = ns_info.get_xmlns_string(delim) + namespace_def += (delim + xmlns) + if include_schemalocs: + schemaloc = ns_info.get_schema_location_string(delim) + namespace_def += (delim + schemaloc) with save_encoding(encoding): sio = StringIO.StringIO() diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index 257fd74e..f4373fb9 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -3700,16 +3700,16 @@ def buildAttributes(self, node, attrs, already_processed): if value is not None and 'xsi:type' not in already_processed: already_processed.add('xsi:type') - from stix.utils import DEFAULT_STIX_NAMESPACES + from mixbox.namespaces import lookup_name typeinfo = get_type_info(node) # Override the prefix if its mapped to a known STIX namespace. # This will help prevent class resolution failures in # stix.lookup_extension(). - if typeinfo.ns in DEFAULT_STIX_NAMESPACES: - ns = typeinfo.ns + prefix = lookup_name(typeinfo.ns) + if prefix: typename = typeinfo.typename - xsi_type = "%s:%s" % (DEFAULT_STIX_NAMESPACES[ns], typename) + xsi_type = "%s:%s" % (prefix, typename) else: xsi_type = value diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index 2804482f..fccb927e 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -1,52 +1,23 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -import collections import itertools import warnings from mixbox import idgen from mixbox.entities import Entity - -import cybox -import cybox.core -import cybox.common -from cybox.utils.nsparser import CYBOX_NAMESPACES +import mixbox.namespaces # internal import stix -# relative -from . import ignored -from .walk import iterwalk - - -class DuplicatePrefixError(Exception): - def __init__(self, message, prefix, namespaces): - super(DuplicatePrefixError, self).__init__(message) - self.prefix = prefix - self.namespaces = namespaces - class NamespaceInfo(object): - # These appear in every exported document - - _BASELINE_NAMESPACES = { - 'xsi': 'http://www.w3.org/2001/XMLSchema-instance', - 'stix': 'http://stix.mitre.org/stix-1', - 'stixCommon': 'http://stix.mitre.org/common-1', - 'stixVocabs': 'http://stix.mitre.org/default_vocabularies-1', - 'cybox': 'http://cybox.mitre.org/cybox-2', - 'cyboxCommon': 'http://cybox.mitre.org/common-2', - 'cyboxVocabs': 'http://cybox.mitre.org/default_vocabularies-2' - } def __init__(self): # Namespaces that are "collected" from the Python objects during - # serialization. Key is the namespace alias/prefix. Value is the - # namespace. There are many classes without a defined prefix, so - # the ``None`` prefix is predefined as a ``set()``. - self._collected_namespaces = {None: set()} + # serialization. This will be a (mixbox) NamespaceSet. + self._collected_namespaces = None # Namespaces and schemalocations that are attached to STIX/CybOX # entities when parsed from an external source. @@ -80,11 +51,8 @@ def _parse_collected_classes(self): klass for klass in collected if issubclass(klass, entity_klasses) ) - # Local function for adding namespaces that have no defined prefix - # mapping at the class-level. These will be resolved in the - # self._finalize_namespaces() function. - no_alias = self._collected_namespaces[None].add - + alias_to_ns_uri = {} + no_alias_ns_uris = [] for klass in entity_subclasses: # Prevents exception being raised if/when # collections.MutableSequence or another base class appears in the @@ -98,7 +66,7 @@ def _parse_collected_classes(self): # used for its namespace. alias = getattr(klass, "_XSI_NS", None) if alias: - self._collected_namespaces[alias] = ns + alias_to_ns_uri[alias] = ns continue # Many stix/cybox entity classes have an _XSI_TYPE attribute that @@ -106,16 +74,34 @@ def _parse_collected_classes(self): # associated xsi:type. xsi_type = getattr(klass, "_XSI_TYPE", None) if not xsi_type: - no_alias(ns) + no_alias_ns_uris.append(ns) continue # Attempt to split the xsi:type attribute value into the ns alias # and the typename. typeinfo = xsi_type.split(":") if len(typeinfo) == 2: - self._collected_namespaces[typeinfo[0]] = ns + alias_to_ns_uri[typeinfo[0]] = ns else: - no_alias(ns) + no_alias_ns_uris.append(ns) + + # Unrecognized namespace URIs will cause an error at this stage. + self._collected_namespaces = mixbox.namespaces.make_namespace_subset_from_uris( + itertools.chain(alias_to_ns_uri.itervalues(), no_alias_ns_uris) + ) + + # For some reason, prefixes are specified in API class vars and also in + # our big namespace tables. From python-cybox issue #274 [1], I + # conclude that the tables may take priority here. And those are + # already going to be preferred at this point. So the only thing I can + # think to do with class var values is fill in any missing prefixes + # we may have (but I doubt there will be any). + # + # 1. https://github.com/CybOXProject/python-cybox/issues/274 + for prefix, ns_uri in alias_to_ns_uri.iteritems(): + if self._collected_namespaces.preferred_prefix_for_namespace(ns_uri) is None: + self._collected_namespaces.set_preferred_prefix_for_namespace( + ns_uri, prefix, True) def _fix_example_namespace(self): """Attempts to resolve issues where our samples use @@ -137,48 +123,6 @@ def _fix_example_namespace(self): self._input_namespaces[example_prefix] = idgen.EXAMPLE_NAMESPACE.name - def _check_namespaces(self, ns_dict): - """Check that all the prefixes in `ns_dict` are mapped to only - one namespace. - - Args: - ns_dict: A ``prefix: [namespaces]`` dictionary. - - Raises: - ` .DuplicatePrefixError: If a prefix is mapped to more than one - namespace. - - """ - for prefix, namespaces in ns_dict.iteritems(): - if len(namespaces) == 1: - continue - - error = "Namespace prefix '{0}' mapped to multiple namespaces: {1}" - error = error.format(prefix, namespaces) - - raise DuplicatePrefixError( - message=error, - prefix=prefix, - namespaces=tuple(namespaces) - ) - - def _resolve_unprefixed(self, no_prefix): - """Resolve namespace aliases for the unprefixed namespaces found on - collected python-stix objects. - - Args: - A collection of namespaces that were not mapped to a namespace - prefix by a python Object. - - """ - collected_unprefixed = {} - - for ns in no_prefix: - alias = DEFAULT_STIX_NAMESPACES[ns] - collected_unprefixed[alias] = ns - - return collected_unprefixed - def _finalize_namespaces(self, ns_dict=None): """Returns a dictionary of namespaces to be exported with an XML document. @@ -187,69 +131,50 @@ def _finalize_namespaces(self, ns_dict=None): during the execution of ``collect()`` and ``_parse_collected_classes()`` and attempts to merge them all. - Returns: - An ``alias: namespace`` dictionary containing all namespaces - required to be present on an exported document. - Raises: - .DuplicatePrefixError: If namespace prefix was mapped to more than - one namespace. + mixbox.namespaces.DuplicatePrefixError: If namespace prefix was + mapped to more than one namespace. """ - if not ns_dict: - ns_dict = {} - # Copy and flip the input dictionary from ns=>alias to alias=>ns - user_namespaces = {} - for ns, alias in ns_dict.iteritems(): - user_namespaces[alias] = ns - - # Our return value - ns_dict = collections.defaultdict(set) + if ns_dict: + # Add the user's entries to our set + for ns, alias in ns_dict.iteritems(): + self._collected_namespaces.add_namespace_uri(ns, alias) # Add the ID namespaces - id_alias = idgen.get_id_namespace_alias() - id_ns = idgen.get_id_namespace() - ns_dict[id_alias].add(id_ns) - - # Build namespace dictionaries from the collected Entity objects. - collected_prefixed = dict(self._collected_namespaces.iteritems()) - - # Pop the unprefixed entries. - no_prefix = collected_prefixed.pop(None, set()) - - # Resolve namespace aliases for the unprefixed namespaces. - collected_unprefixed = self._resolve_unprefixed(no_prefix) + self._collected_namespaces.add_namespace_uri( + idgen.get_id_namespace(), + idgen.get_id_namespace_alias() + ) # Remap the example namespace to the one expected by the APIs if the # sample example namespace is found. self._fix_example_namespace() - # All the namespaces dictionaries we need to merge and export. - namespace_dicts = itertools.chain( - self._BASELINE_NAMESPACES.iteritems(), - self._input_namespaces.iteritems(), - collected_prefixed.iteritems(), - collected_unprefixed.iteritems(), - user_namespaces.iteritems() - ) + # Add _input_namespaces + for prefix, uri in self._input_namespaces.iteritems(): + self._collected_namespaces.add_namespace_uri(uri, prefix) - # Build our merged namespace dictionary. It will be inspected for - # duplicate ns prefix mappings. - for alias, ns in namespace_dicts: - ns_dict[alias].add(ns) + # Add some default XML namespaces to make sure they're there. + self._collected_namespaces.import_from(mixbox.namespaces.XML_NAMESPACES) - # Check that all the prefixes are mapped to only one namespace - self._check_namespaces(ns_dict) + # python-stix's generateDS-generated binding classes can't handle + # default namespaces. So make sure there are no preferred defaults in + # the set. Get prefixes from the global namespace set if we have to. + for ns_uri in self._collected_namespaces.namespace_uris: + if self._collected_namespaces.preferred_prefix_for_namespace(ns_uri) is None: + prefixes = self._collected_namespaces.get_prefixes(ns_uri) + if len(prefixes) > 0: + prefix = next(iter(prefixes)) + else: + prefix = mixbox.namespaces.lookup_name(ns_uri) - # Flatten the dictionary by popping the namespace from the namespace - # set values in ns_dict. - flattened = {} - for alias, ns_set in ns_dict.iteritems(): - flattened[alias] = ns_set.pop() + if prefix is None: + raise mixbox.namespaces.NoPrefixesError(ns_uri) - # Return the flattened dictionary - return flattened + self._collected_namespaces.set_preferred_prefix_for_namespace( + ns_uri, prefix, True) def _finalize_schemalocs(self, schemaloc_dict=None): # If schemaloc_dict was passed in, make a copy so we don't mistakenly @@ -259,9 +184,6 @@ def _finalize_schemalocs(self, schemaloc_dict=None): else: schemaloc_dict = {} - # Get our id namespace - id_ns = idgen.get_id_namespace() - # Build our schemalocation dictionary! # # Initialize it from values found in the parsed, input schemalocations @@ -271,56 +193,51 @@ def _finalize_schemalocs(self, schemaloc_dict=None): # If there is a schemalocation found in both the parsed schemalocs and # the schema_loc dict, use the schemaloc_dict value. for ns, loc in self._input_schemalocs.iteritems(): - if ns in schemaloc_dict: - continue - schemaloc_dict[ns] = loc - - # Iterate over the finalized namespaces for a document and attempt - # to map them to schemalocations. Warn if the namespace should have a - # schemalocation and we can't find it anywhere. - nsset = set(self.finalized_namespaces.itervalues()) - for ns in nsset: - if ns in DEFAULT_STIX_SCHEMALOCATIONS: - schemaloc_dict[ns] = DEFAULT_STIX_SCHEMALOCATIONS[ns] - elif ns in schemaloc_dict: - continue - elif (ns == id_ns) or (ns in XML_NAMESPACES): - continue - else: - error = "Unable to map namespace '{0}' to schemaLocation" - warnings.warn(error.format(ns)) - - return schemaloc_dict - - def _finalize_binding_namespaces(self): - """Returns a namespace-to-prefix dictionary view of the - finalized_namespaces (which are mapped prefix-to-namespace). - - The bindings expect an NS-to-prefix mapping, while our ns processing - code builds dictionaries that map prefix-to-Namespace(s). Because of - this, we need to flip our dictionaries before handing them off to the - bindings for serialization. - - """ - if not self.finalized_namespaces: - return {} # TODO: Should this return the DEFAULT_STIX_NAMESPACES? + if ns not in schemaloc_dict: + schemaloc_dict[ns] = loc - binding_namespaces = {} - for alias, ns in self.finalized_namespaces.iteritems(): - binding_namespaces[ns] = alias + # Now use the merged dict to update any schema locations we don't + # already have. + for ns, loc in schemaloc_dict.iteritems(): + if self._collected_namespaces.contains_namespace(ns) and \ + self._collected_namespaces.get_schema_location(ns) is None: + self._collected_namespaces.set_schema_location(ns, loc) - # Always use the default STIX prefixes for STIX namespaces. - # This is because of xsi:type prefixes used by the STIX/CybOX user-level - # API classes. - binding_namespaces.update(DEFAULT_STIX_NAMESPACES) + # Warn if we are missing any schemalocations + id_ns = idgen.get_id_namespace() + for ns in self._collected_namespaces.namespace_uris: + if self._collected_namespaces.get_schema_location(ns) is None: + if ns == id_ns or \ + mixbox.namespaces.XML_NAMESPACES.contains_namespace(ns) or \ + ns in schemaloc_dict: + continue - return binding_namespaces + error = "Unable to map namespace '{0}' to schemaLocation" + warnings.warn(error.format(ns)) def finalize(self, ns_dict=None, schemaloc_dict=None): self._parse_collected_classes() - self.finalized_namespaces = self._finalize_namespaces(ns_dict) - self.finalized_schemalocs = self._finalize_schemalocs(schemaloc_dict) - self.binding_namespaces = self._finalize_binding_namespaces() + self._finalize_namespaces(ns_dict) + self._finalize_schemalocs(schemaloc_dict) + + self.finalized_namespaces = \ + self._collected_namespaces.get_prefix_uri_map() + self.finalized_schemalocs = \ + self._collected_namespaces.get_uri_schemaloc_map() + self.binding_namespaces = \ + self._collected_namespaces.get_uri_prefix_map() + + def get_xmlns_string(self, delim): + if self._collected_namespaces is None: + return "" + return self._collected_namespaces.get_xmlns_string( + preferred_prefixes_only=False, delim=delim + ) + + def get_schema_location_string(self, delim): + if self._collected_namespaces is None: + return "" + return self._collected_namespaces.get_schemaloc_string(delim=delim) def collect(self, entity): # Collect all the classes we need to inspect for namespace information @@ -337,208 +254,49 @@ def collect(self, entity): self._input_schemalocs.update(entity.__input_schemalocations__) -class NamespaceParser(object): - def __init__(self): - pass - - def get_namespaces(self, entity, ns_dict=None): - ns_info = NamespaceInfo() - - for node in iterwalk(entity): - ns_info.collect(node) - - ns_info.finalize(ns_dict=ns_dict) - return ns_info.finalized_namespaces - - def get_namespace_schemalocation_dict(self, entity, ns_dict=None, schemaloc_dict=None): - ns_info = NamespaceInfo() - - for node in iterwalk(entity): - ns_info.collect(node) - - ns_info.finalize(ns_dict=ns_dict, schemaloc_dict=schemaloc_dict) - return ns_info.finalized_schemalocs - - def get_xmlns_str(self, ns_dict): - pairs = sorted(ns_dict.iteritems()) - return "\n\t".join( - 'xmlns:%s="%s"' % (alias, ns) for alias, ns in pairs - ) - - def get_schemaloc_str(self, schemaloc_dict): - if not schemaloc_dict: - return "" - - schemaloc_str_start = 'xsi:schemaLocation="\n\t' - schemaloc_str_end = '"' - - pairs = sorted(schemaloc_dict.iteritems()) - schemaloc_str_content = "\n\t".join( - "%s %s" % (ns, loc) for ns, loc in pairs - ) - - return schemaloc_str_start + schemaloc_str_content + schemaloc_str_end - - def get_namespace_def_str(self, namespaces, schemaloc_dict): - if not any((namespaces, schemaloc_dict)): - return "" - - parts = ( - self.get_xmlns_str(namespaces), - self.get_schemaloc_str(schemaloc_dict) - ) +Namespace = mixbox.namespaces.Namespace + +NS_CAMPAIGN_OBJECT = Namespace("http://stix.mitre.org/Campaign-1", "campaign", "http://stix.mitre.org/XMLSchema/campaign/1.2/campaign.xsd") +NS_CAPEC_OBJECT = Namespace("http://capec.mitre.org/capec-2", "capec", "") +NS_CIQIDENTITY_OBJECT = Namespace("http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1", "ciqIdentity", "http://stix.mitre.org/XMLSchema/extensions/identity/ciq_3.0/1.2/ciq_3.0_identity.xsd") +NS_COA_OBJECT = Namespace("http://stix.mitre.org/CourseOfAction-1", "coa", "http://stix.mitre.org/XMLSchema/course_of_action/1.2/course_of_action.xsd") +NS_CVRF_OBJECT = Namespace("http://www.icasi.org/CVRF/schema/cvrf/1.1", "cvrf", "") +NS_ET_OBJECT = Namespace("http://stix.mitre.org/ExploitTarget-1", "et", "http://stix.mitre.org/XMLSchema/exploit_target/1.2/exploit_target.xsd") +NS_GENERICSTRUCTUREDCOA_OBJECT = Namespace("http://stix.mitre.org/extensions/StructuredCOA#Generic-1", "genericStructuredCOA", "http://stix.mitre.org/XMLSchema/extensions/structured_coa/generic/1.2/generic_structured_coa.xsd") +NS_GENERICTM_OBJECT = Namespace("http://stix.mitre.org/extensions/TestMechanism#Generic-1", "genericTM", "http://stix.mitre.org/XMLSchema/extensions/test_mechanism/generic/1.2/generic_test_mechanism.xsd") +NS_INCIDENT_OBJECT = Namespace("http://stix.mitre.org/Incident-1", "incident", "http://stix.mitre.org/XMLSchema/incident/1.2/incident.xsd") +NS_INDICATOR_OBJECT = Namespace("http://stix.mitre.org/Indicator-2", "indicator", "http://stix.mitre.org/XMLSchema/indicator/2.2/indicator.xsd") +NS_IOC_OBJECT = Namespace("http://schemas.mandiant.com/2010/ioc", "ioc", "") +NS_IOCTR_OBJECT = Namespace("http://schemas.mandiant.com/2010/ioc/TR/", "ioc-tr", "") +NS_MARKING_OBJECT = Namespace("http://data-marking.mitre.org/Marking-1", "marking", "http://stix.mitre.org/XMLSchema/data_marking/1.2/data_marking.xsd") +NS_OVALDEF_OBJECT = Namespace("http://oval.mitre.org/XMLSchema/oval-definitions-5", "oval-def", "") +NS_OVALVAR_OBJECT = Namespace("http://oval.mitre.org/XMLSchema/oval-variables-5", "oval-var", "") +NS_REPORT_OBJECT = Namespace("http://stix.mitre.org/Report-1", "report", "http://stix.mitre.org/XMLSchema/report/1.0/report.xsd") +NS_SIMPLEMARKING_OBJECT = Namespace("http://data-marking.mitre.org/extensions/MarkingStructure#Simple-1", "simpleMarking", "http://stix.mitre.org/XMLSchema/extensions/marking/simple/1.2/simple_marking.xsd") +NS_SNORTTM_OBJECT = Namespace("http://stix.mitre.org/extensions/TestMechanism#Snort-1", "snortTM", "http://stix.mitre.org/XMLSchema/extensions/test_mechanism/snort/1.2/snort_test_mechanism.xsd") +NS_STIX_OBJECT = Namespace("http://stix.mitre.org/stix-1", "stix", "http://stix.mitre.org/XMLSchema/core/1.2/stix_core.xsd") +NS_STIXCAPEC_OBJECT = Namespace("http://stix.mitre.org/extensions/AP#CAPEC2.7-1", "stix-capec", "http://stix.mitre.org/XMLSchema/extensions/attack_pattern/capec_2.7/1.1/capec_2.7_attack_pattern.xsd") +NS_STIXCIQADDRESS_OBJECT = Namespace("http://stix.mitre.org/extensions/Address#CIQAddress3.0-1", "stix-ciqaddress", "http://stix.mitre.org/XMLSchema/extensions/address/ciq_3.0/1.2/ciq_3.0_address.xsd") +NS_STIXCVRF_OBJECT = Namespace("http://stix.mitre.org/extensions/Vulnerability#CVRF-1", "stix-cvrf", "http://stix.mitre.org/XMLSchema/extensions/vulnerability/cvrf_1.1/1.2/cvrf_1.1_vulnerability.xsd") +NS_STIXMAEC_OBJECT = Namespace("http://stix.mitre.org/extensions/Malware#MAEC4.1-1", "stix-maec", "http://stix.mitre.org/XMLSchema/extensions/malware/maec_4.1/1.1/maec_4.1_malware.xsd") +NS_STIXOPENIOC_OBJECT = Namespace("http://stix.mitre.org/extensions/TestMechanism#OpenIOC2010-1", "stix-openioc", "http://stix.mitre.org/XMLSchema/extensions/test_mechanism/open_ioc_2010/1.2/open_ioc_2010_test_mechanism.xsd") +NS_STIXOVAL_OBJECT = Namespace("http://stix.mitre.org/extensions/TestMechanism#OVAL5.10-1", "stix-oval", "http://stix.mitre.org/XMLSchema/extensions/test_mechanism/oval_5.10/1.2/oval_5.10_test_mechanism.xsd") +NS_STIXCOMMON_OBJECT = Namespace("http://stix.mitre.org/common-1", "stixCommon", "http://stix.mitre.org/XMLSchema/common/1.2/stix_common.xsd") +NS_STIXVOCABS_OBJECT = Namespace("http://stix.mitre.org/default_vocabularies-1", "stixVocabs", "http://stix.mitre.org/XMLSchema/default_vocabularies/1.2.0/stix_default_vocabularies.xsd") +NS_TA_OBJECT = Namespace("http://stix.mitre.org/ThreatActor-1", "ta", "http://stix.mitre.org/XMLSchema/threat_actor/1.2/threat_actor.xsd") +NS_TLPMARKING_OBJECT = Namespace("http://data-marking.mitre.org/extensions/MarkingStructure#TLP-1", "tlpMarking", "http://stix.mitre.org/XMLSchema/extensions/marking/tlp/1.2/tlp_marking.xsd") +NS_TOUMARKING_OBJECT = Namespace("http://data-marking.mitre.org/extensions/MarkingStructure#Terms_Of_Use-1", "TOUMarking", "http://stix.mitre.org/XMLSchema/extensions/marking/terms_of_use/1.1/terms_of_use_marking.xsd") +NS_TTP_OBJECT = Namespace("http://stix.mitre.org/TTP-1", "ttp", "http://stix.mitre.org/XMLSchema/ttp/1.2/ttp.xsd") +NS_XAL_OBJECT = Namespace("urn:oasis:names:tc:ciq:xal:3", "xal", "http://stix.mitre.org/XMLSchema/external/oasis_ciq_3.0/xAL.xsd") +NS_XNL_OBJECT = Namespace("urn:oasis:names:tc:ciq:xnl:3", "xnl", "http://stix.mitre.org/XMLSchema/external/oasis_ciq_3.0/xNL.xsd") +NS_XPIL_OBJECT = Namespace("urn:oasis:names:tc:ciq:xpil:3", "xpil", "http://stix.mitre.org/XMLSchema/external/oasis_ciq_3.0/xPIL.xsd") +NS_YARATM_OBJECT = Namespace("http://stix.mitre.org/extensions/TestMechanism#YARA-1", "yaraTM", "http://stix.mitre.org/XMLSchema/extensions/test_mechanism/yara/1.2/yara_test_mechanism.xsd") + +STIX_NAMESPACES = mixbox.namespaces.NamespaceSet() + +# Magic to automatically register all Namespaces defined in this module. +for k, v in globals().items(): + if k.startswith('NS_'): + mixbox.namespaces.register_namespace(v) + STIX_NAMESPACES.add_namespace(v) - return "\n\t".join(parts) - - -#: Schema locations for standard XML namespaces -XML_NAMESPACES = { - 'http://www.w3.org/2001/XMLSchema-instance': 'xsi', - 'http://www.w3.org/2001/XMLSchema': 'xs', - 'http://www.w3.org/1999/xlink': 'xlink', - 'http://www.w3.org/2000/09/xmldsig#': 'ds' -} - -#: Schema locations for namespaces defined by the STIX language -STIX_NS_TO_SCHEMALOCATION = { - 'http://data-marking.mitre.org/Marking-1': 'http://stix.mitre.org/XMLSchema/data_marking/1.2/data_marking.xsd', - 'http://data-marking.mitre.org/extensions/MarkingStructure#Simple-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/simple/1.2/simple_marking.xsd', - 'http://data-marking.mitre.org/extensions/MarkingStructure#TLP-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/tlp/1.2/tlp_marking.xsd', - 'http://data-marking.mitre.org/extensions/MarkingStructure#Terms_Of_Use-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/terms_of_use/1.1/terms_of_use_marking.xsd', - 'http://stix.mitre.org/Campaign-1': 'http://stix.mitre.org/XMLSchema/campaign/1.2/campaign.xsd', - 'http://stix.mitre.org/CourseOfAction-1': 'http://stix.mitre.org/XMLSchema/course_of_action/1.2/course_of_action.xsd', - 'http://stix.mitre.org/ExploitTarget-1': 'http://stix.mitre.org/XMLSchema/exploit_target/1.2/exploit_target.xsd', - 'http://stix.mitre.org/Incident-1': 'http://stix.mitre.org/XMLSchema/incident/1.2/incident.xsd', - 'http://stix.mitre.org/Indicator-2': 'http://stix.mitre.org/XMLSchema/indicator/2.2/indicator.xsd', - 'http://stix.mitre.org/Report-1': 'http://stix.mitre.org/XMLSchema/report/1.0/report.xsd', - 'http://stix.mitre.org/TTP-1': 'http://stix.mitre.org/XMLSchema/ttp/1.2/ttp.xsd', - 'http://stix.mitre.org/ThreatActor-1': 'http://stix.mitre.org/XMLSchema/threat_actor/1.2/threat_actor.xsd', - 'http://stix.mitre.org/common-1': 'http://stix.mitre.org/XMLSchema/common/1.2/stix_common.xsd', - 'http://stix.mitre.org/default_vocabularies-1': 'http://stix.mitre.org/XMLSchema/default_vocabularies/1.2.0/stix_default_vocabularies.xsd', - 'http://stix.mitre.org/extensions/AP#CAPEC2.7-1': 'http://stix.mitre.org/XMLSchema/extensions/attack_pattern/capec_2.7/1.1/capec_2.7_attack_pattern.xsd', - 'http://stix.mitre.org/extensions/Address#CIQAddress3.0-1': 'http://stix.mitre.org/XMLSchema/extensions/address/ciq_3.0/1.2/ciq_3.0_address.xsd', - 'http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1': 'http://stix.mitre.org/XMLSchema/extensions/identity/ciq_3.0/1.2/ciq_3.0_identity.xsd', - 'http://stix.mitre.org/extensions/Malware#MAEC4.1-1': 'http://stix.mitre.org/XMLSchema/extensions/malware/maec_4.1/1.1/maec_4.1_malware.xsd', - 'http://stix.mitre.org/extensions/StructuredCOA#Generic-1': 'http://stix.mitre.org/XMLSchema/extensions/structured_coa/generic/1.2/generic_structured_coa.xsd', - 'http://stix.mitre.org/extensions/TestMechanism#Generic-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/generic/1.2/generic_test_mechanism.xsd', - 'http://stix.mitre.org/extensions/TestMechanism#OVAL5.10-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/oval_5.10/1.2/oval_5.10_test_mechanism.xsd', - 'http://stix.mitre.org/extensions/TestMechanism#OpenIOC2010-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/open_ioc_2010/1.2/open_ioc_2010_test_mechanism.xsd', - 'http://stix.mitre.org/extensions/TestMechanism#Snort-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/snort/1.2/snort_test_mechanism.xsd', - 'http://stix.mitre.org/extensions/TestMechanism#YARA-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/yara/1.2/yara_test_mechanism.xsd', - 'http://stix.mitre.org/extensions/Vulnerability#CVRF-1': 'http://stix.mitre.org/XMLSchema/extensions/vulnerability/cvrf_1.1/1.2/cvrf_1.1_vulnerability.xsd', - 'http://stix.mitre.org/stix-1': 'http://stix.mitre.org/XMLSchema/core/1.2/stix_core.xsd' -} - -#: Schema locations for namespaces defined by the CybOX language -CYBOX_NS_TO_SCHEMALOCATION = dict( - (x.name, x.schema_location) for x in CYBOX_NAMESPACES if x.schema_location -) - -#: Schema locations for namespaces not defined by STIX, but hosted on the STIX website -EXT_NS_TO_SCHEMALOCATION = { - 'urn:oasis:names:tc:ciq:xal:3': 'http://stix.mitre.org/XMLSchema/external/oasis_ciq_3.0/xAL.xsd', - 'urn:oasis:names:tc:ciq:xpil:3': 'http://stix.mitre.org/XMLSchema/external/oasis_ciq_3.0/xPIL.xsd', - 'urn:oasis:names:tc:ciq:xnl:3': 'http://stix.mitre.org/XMLSchema/external/oasis_ciq_3.0/xNL.xsd' -} - -#: Default namespace->alias mappings. These can be overriden by user-provided dictionaries on export. -DEFAULT_STIX_NS_TO_PREFIX = { - 'http://cybox.mitre.org/common-2': 'cyboxCommon', - 'http://cybox.mitre.org/cybox-2': 'cybox', - 'http://data-marking.mitre.org/Marking-1': 'marking', - 'http://data-marking.mitre.org/extensions/MarkingStructure#Simple-1': 'simpleMarking', - 'http://data-marking.mitre.org/extensions/MarkingStructure#TLP-1': 'tlpMarking', - 'http://data-marking.mitre.org/extensions/MarkingStructure#Terms_Of_Use-1': 'TOUMarking', - 'http://stix.mitre.org/Campaign-1': 'campaign', - 'http://stix.mitre.org/CourseOfAction-1': 'coa', - 'http://stix.mitre.org/ExploitTarget-1': 'et', - 'http://stix.mitre.org/Incident-1': 'incident', - 'http://stix.mitre.org/Indicator-2': 'indicator', - 'http://stix.mitre.org/TTP-1': 'ttp', - 'http://stix.mitre.org/ThreatActor-1': 'ta', - 'http://stix.mitre.org/Report-1': 'report', - 'http://stix.mitre.org/stix-1': 'stix', - 'http://stix.mitre.org/common-1': 'stixCommon', - 'http://stix.mitre.org/default_vocabularies-1': 'stixVocabs', - 'http://stix.mitre.org/extensions/AP#CAPEC2.7-1': 'stix-capec', - 'http://stix.mitre.org/extensions/Address#CIQAddress3.0-1': 'stix-ciqaddress', - 'http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1': 'ciqIdentity', - 'http://stix.mitre.org/extensions/Malware#MAEC4.1-1': 'stix-maec', - 'http://stix.mitre.org/extensions/StructuredCOA#Generic-1': 'genericStructuredCOA', - 'http://stix.mitre.org/extensions/TestMechanism#Generic-1': 'genericTM', - 'http://stix.mitre.org/extensions/TestMechanism#OVAL5.10-1': 'stix-oval', - 'http://stix.mitre.org/extensions/TestMechanism#OpenIOC2010-1': 'stix-openioc', - 'http://stix.mitre.org/extensions/TestMechanism#Snort-1': 'snortTM', - 'http://stix.mitre.org/extensions/TestMechanism#YARA-1': 'yaraTM', - 'http://stix.mitre.org/extensions/Vulnerability#CVRF-1': 'stix-cvrf' -} - -#: Mapping of extension namespaces to their (typical) prefixes. -DEFAULT_EXT_TO_PREFIX = { - 'http://capec.mitre.org/capec-2': 'capec', - 'http://maec.mitre.org/XMLSchema/maec-package-2': 'maecPackage', - 'http://oval.mitre.org/XMLSchema/oval-definitions-5': 'oval-def', - 'http://oval.mitre.org/XMLSchema/oval-variables-5': 'oval-var', - 'http://schemas.mandiant.com/2010/ioc': 'ioc', - 'http://schemas.mandiant.com/2010/ioc/TR/': 'ioc-tr', - 'http://www.icasi.org/CVRF/schema/cvrf/1.1': 'cvrf', - 'urn:oasis:names:tc:ciq:xal:3': 'xal', - 'urn:oasis:names:tc:ciq:xpil:3': 'xpil', - 'urn:oasis:names:tc:ciq:xnl:3': 'xnl' -} - -#: Mapping of CybOX namespaces to default aliases -DEFAULT_CYBOX_NAMESPACES = dict( - (x.name, x.prefix) for x in CYBOX_NAMESPACES -) - - -#: Mapping of all STIX/STIX Extension/CybOX/XML namespaces -DEFAULT_STIX_NAMESPACES = dict( - itertools.chain( - DEFAULT_CYBOX_NAMESPACES.iteritems(), - XML_NAMESPACES.iteritems(), - DEFAULT_STIX_NS_TO_PREFIX.iteritems(), - DEFAULT_EXT_TO_PREFIX.iteritems() - ) -) - -#: Prefix-to-namespace mapping of the `DEFAULT_STIX_NAMESPACES` mapping -DEFAULT_STIX_PREFIX_TO_NAMESPACE = dict( - (alias, ns) for ns, alias in DEFAULT_STIX_NAMESPACES.iteritems() -) - -#: Tuple of all keys found in `DEFAULT_STIX_NAMESPACES` mapping. -DEFAULT_STIX_NAMESPACES_TUPLE = tuple(DEFAULT_STIX_NAMESPACES.keys()) - -#: Mapping of STIX/CybOX/STIX Extension namespaces to canonical schema locations -DEFAULT_STIX_SCHEMALOCATIONS = dict( - itertools.chain( - STIX_NS_TO_SCHEMALOCATION.iteritems(), - EXT_NS_TO_SCHEMALOCATION.iteritems(), - CYBOX_NS_TO_SCHEMALOCATION.iteritems(), - ) -) - -# python-maec support code -with ignored(ImportError): - from maec.utils.nsparser import MAEC_NAMESPACES - - ns_to_prefix = dict( - (x.name, x.prefix) for x in MAEC_NAMESPACES - ) - - del ns_to_prefix['http://maec.mitre.org/default_vocabularies-1'] - - prefix_to_ns = dict( - (prefix, ns) for (ns, prefix) in ns_to_prefix.iteritems() - ) - - ns_to_schemalocation = dict( - (x.name, x.schema_location) for x in MAEC_NAMESPACES if x.schema_location - ) - - DEFAULT_STIX_NAMESPACES.update(ns_to_prefix) - DEFAULT_STIX_PREFIX_TO_NAMESPACE.update(prefix_to_ns) - DEFAULT_STIX_NAMESPACES_TUPLE = tuple(DEFAULT_STIX_NAMESPACES.iterkeys()) - DEFAULT_STIX_SCHEMALOCATIONS.update(ns_to_schemalocation) From 7b0cfb57e6bae2361654e5ae1e369e5d2604d22c Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Mon, 5 Oct 2015 15:09:13 -0400 Subject: [PATCH 213/438] Fixed the nsparser test to work with the revamped namespace collection mechanisms. --- stix/test/utils/nsparser_test.py | 34 ++++++++++++++------------------ 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/stix/test/utils/nsparser_test.py b/stix/test/utils/nsparser_test.py index da4cdaa9..1909a732 100644 --- a/stix/test/utils/nsparser_test.py +++ b/stix/test/utils/nsparser_test.py @@ -9,6 +9,7 @@ import lxml.etree # internal +import mixbox.namespaces import stix from stix.core import STIXPackage from stix.utils import nsparser, silence_warnings @@ -29,17 +30,17 @@ class A(stix.Entity): - _namespace = "test:a" + _namespace = nsparser.NS_STIX_OBJECT.name _XSI_TYPE = "a:AType" class B(A): - _namespace = "test:b" + _namespace = nsparser.NS_STIXCOMMON_OBJECT.name _XSI_TYPE = "b:BType" class C(B): - _namespace = "test:c" + _namespace = nsparser.NS_INDICATOR_OBJECT.name _XSI_TYPE = "c:CType" @@ -57,7 +58,7 @@ def test_nsinfo_collect(self): # Parse collected classes nsinfo._parse_collected_classes() - self.assertEqual(len(nsinfo._collected_namespaces), 4) # noqa + self.assertEqual(len(nsinfo._collected_namespaces), 3) # noqa def test_namespace_collect(self): """Test that NamespaceInfo correctly pulls namespaces from all classes @@ -82,10 +83,6 @@ def test_user_provided_ns(self): """ p = STIXPackage() - nsinfo = nsparser.NamespaceInfo() - - # Collect classes - nsinfo.collect(p) TEST_PREFIX = 'test' TEST_NS = 'a:unit:test' @@ -97,12 +94,6 @@ def test_user_provided_ns(self): NEW_STIX_NS: NEW_STIX_PREFIX } - finalized = nsinfo._finalize_namespaces(ns_dict=test_dict) - nsinfo.finalized_namespaces - - self.assertEqual(finalized.get(TEST_PREFIX), TEST_NS) - self.assertEqual(finalized.get(NEW_STIX_PREFIX), NEW_STIX_NS) - # Parse the exported document and make sure that the namespaces # made it through the serialization process. xml = p.to_xml(ns_dict=test_dict) @@ -119,19 +110,24 @@ def test_duplicate_ns_prefix(self): bad = {'bad:ns': 'stix'} # 'stix' is already default ns prefix self.assertRaises( - nsparser.DuplicatePrefixError, + mixbox.namespaces.DuplicatePrefixError, p.to_xml, ns_dict=bad ) # Build a valid stix document that has a default namespace remapped - # to another namespace. We remap 'cybox' to a bogus ns here. + # to another namespace. We remap 'stixCommon' to a bogus ns here. xml = ( """""" + timestamp="2015-04-09T14:22:25.620831+00:00"> + + A unit test + + """ ) sio = StringIO.StringIO(xml) @@ -139,7 +135,7 @@ def test_duplicate_ns_prefix(self): # Exporting should raise an error. self.assertRaises( - nsparser.DuplicatePrefixError, + mixbox.namespaces.DuplicatePrefixError, p.to_xml ) From eb85d94d0e4c702ec0a0b941b8e3a159352ef615 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 5 Oct 2015 19:55:42 -0400 Subject: [PATCH 214/438] Refactored deprecated module function names. Added deprecated.fields() function to use as a preset hook on a TypedField. --- stix/base.py | 8 +- stix/campaign/__init__.py | 4 +- stix/common/related.py | 200 +------------------------------------- stix/core/__init__.py | 30 ++---- stix/core/stix_header.py | 14 +-- stix/core/ttps.py | 4 +- stix/utils/deprecated.py | 11 ++- 7 files changed, 34 insertions(+), 237 deletions(-) diff --git a/stix/base.py b/stix/base.py index cde3dbfc..4698cac4 100644 --- a/stix/base.py +++ b/stix/base.py @@ -9,12 +9,10 @@ # mixbox from mixbox import idgen +from mixbox import entities from mixbox import fields from mixbox import binding_utils - from mixbox.cache import Cached -from mixbox.entities import Entity as _MixboxEntity -from mixbox.entities import EntityList as _MixboxEntityList # internal from . import utils @@ -36,7 +34,7 @@ class ContentField(fields.TypedField): pass -class Entity(_MixboxEntity): +class Entity(entities.Entity): """Base class for all classes in the STIX API.""" _namespace = None _XSI_TYPE = None @@ -216,7 +214,7 @@ def find(self, id_): return entity -class EntityList(_MixboxEntityList, Entity): +class EntityList(entities.EntityList, Entity): _contained_type = _override _inner_name = None diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 24be3de0..98abf8aa 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -2,7 +2,7 @@ # See LICENSE.txt for complete terms. import stix -from stix.utils.deprecated import deprecated +from stix.utils import deprecated from stix.common import Activity, Confidence, Statement, VocabString from stix.common.related import ( GenericRelationshipList, RelatedCampaign, RelatedIncident, RelatedIndicator, @@ -65,7 +65,7 @@ class RelatedIndicators(GenericRelationshipList): _inner_name = "indicators" def _is_valid(self, value): - deprecated(value) + deprecated.warn(value) return super(RelatedIndicators, self)._is_valid(value) diff --git a/stix/common/related.py b/stix/common/related.py index 16d84131..7c9fda60 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -4,7 +4,6 @@ # internal import stix -import stix.utils as utils import stix.bindings.stix_common as common_binding import stix.bindings.stix_core as core_binding import stix.bindings.report as report_binding @@ -12,7 +11,7 @@ from stix.base import AttributeField # deprecation warnings -from stix.utils.deprecated import idref_deprecated, deprecated +from stix.utils import deprecated # relative from .vocabs import VocabString, VocabField @@ -50,86 +49,6 @@ def __init__(self, confidence=None, information_source=None, relationship=None): self.information_source = information_source self.relationship = relationship - # @property - # def confidence(self): - # return self._confidence - # - # @confidence.setter - # def confidence(self, value): - # self._set_var(Confidence, confidence=value) - # - # @property - # def information_source(self): - # return self._information_source - # - # @information_source.setter - # def information_source(self, value): - # self._set_var(InformationSource, try_cast=False, information_source=value) - # - # @property - # def relationship(self): - # return self._relationship - # - # @relationship.setter - # def relationship(self, value): - # self._set_vocab(relationship=value) - # - # @classmethod - # def from_obj(cls, obj, return_obj=None): - # if not obj: - # return None - # - # if not return_obj: - # return_obj = cls() - # - # return_obj.confidence = Confidence.from_obj(obj.Confidence) - # return_obj.information_source = InformationSource.from_obj(obj.Information_Source) - # return_obj.relationship = VocabString.from_obj(obj.Relationship) - # - # return return_obj - # - # def to_obj(self, return_obj=None, ns_info=None): - # super(GenericRelationship, self).to_obj(return_obj=return_obj, ns_info=ns_info) - # - # if not return_obj: - # return_obj = self._binding_class() - # - # if self.confidence: - # return_obj.Confidence = self.confidence.to_obj(ns_info=ns_info) - # if self.information_source: - # return_obj.Information_Source = self.information_source.to_obj(ns_info=ns_info) - # if self.relationship: - # return_obj.Relationship = self.relationship.to_obj(ns_info=ns_info) - # - # return return_obj - # - # @classmethod - # def from_dict(cls, dict_repr, return_obj=None): - # if not dict_repr: - # return None - # - # if not return_obj: - # return_obj = cls() - # - # #print "DICT", dict_repr - # - # return_obj.confidence = Confidence.from_dict(dict_repr.get('confidence')) - # return_obj.information_source = InformationSource.from_dict(dict_repr.get('information_source')) - # return_obj.relationship = VocabString.from_dict(dict_repr.get('relationship')) - # - # return return_obj - # - # def to_dict(self,): - # d = {} - # if self.confidence: - # d['confidence'] = self.confidence.to_dict() - # if self.information_source: - # d['information_source'] = self.information_source.to_dict() - # if self.relationship: - # d['relationship'] = self.relationship.to_dict() - # - # return d - class RelatedPackageRef(GenericRelationship): _namespace = "http://stix.mitre.org/common-1" @@ -151,66 +70,6 @@ def __init__(self, idref=None, timestamp=None, confidence=None, self.idref = idref self.timestamp = timestamp - # def to_obj(self, return_obj=None, ns_info=None): - # if not return_obj: - # return_obj = self._binding_class() - # - # return_obj = super(RelatedPackageRef, self).to_obj(return_obj=return_obj, ns_info=ns_info) - # - # if self.idref: - # return_obj.idref = self.idref - # if self.timestamp: - # return_obj.timestamp = self.timestamp - # - # return return_obj - # - # @property - # def timestamp(self): - # return self._timestamp - # - # @timestamp.setter - # def timestamp(self, value): - # self._timestamp = utils.dates.parse_value(value) - # - # def to_dict(self): - # d = super(RelatedPackageRef, self).to_dict() - # - # if self.idref: - # d['idref'] = self.idref - # if self.timestamp: - # d['timestamp'] = utils.dates.serialize_value(self.timestamp) - # - # return d - # - # @classmethod - # def from_obj(cls, obj, return_obj=None): - # if not obj: - # return None - # - # if not return_obj: - # return_obj = cls() - # - # super(RelatedPackageRef, cls).from_obj(obj, return_obj) - # - # return_obj.idref = obj.idref - # return_obj.timestamp = obj.timestamp - # - # return return_obj - # - # @classmethod - # def from_dict(cls, dict_repr, return_obj=None): - # if not dict_repr: - # return None - # - # if not return_obj: - # return_obj = cls() - # - # super(RelatedPackageRef, cls).from_dict(dict_repr, return_obj) - # - # return_obj.idref = dict_repr.get("idref") - # return_obj.timestamp = dict_repr.get("timestamp") - # - # return return_obj class GenericRelationshipEntity(stix.Entity): _namespace = "http://stix.mitre.org/common-1" @@ -245,57 +104,8 @@ def __init__(self, scope=None, *args): self.scope = scope def __nonzero__(self): - return ( - super(GenericRelationshipList, self).__nonzero__() or - bool(self.scope) - ) - - # def to_obj(self, return_obj=None, ns_info=None): - # list_obj = super(GenericRelationshipList, self).to_obj( - # return_obj=return_obj, - # ns_info=ns_info - # ) - # - # list_obj.scope = self.scope - # return list_obj - # - # @classmethod - # def from_obj(cls, obj, return_obj=None): - # if not obj: - # return None - # - # if return_obj is None: - # return_obj = cls() - # - # super(GenericRelationshipList, cls).from_obj( - # obj, - # return_obj=return_obj, - # contained_type=cls._contained_type, - # binding_var=cls._binding_var - # ) - # - # return_obj.scope = obj.scope - # - # return return_obj - # - # @classmethod - # def from_dict(cls, dict_repr, return_obj=None): - # if not dict_repr: - # return None - # - # if return_obj is None: - # return_obj = cls() - # - # super(GenericRelationshipList, cls).from_dict( - # dict_repr, - # return_obj=return_obj, - # contained_type=cls._contained_type, - # inner_name=cls._inner_name - # ) - # - # return_obj.scope = dict_repr.get('scope') - # - # return return_obj + return (super(GenericRelationshipList, self).__nonzero__() or + bool(self.scope)) class RelatedPackages(GenericRelationshipList): @@ -336,7 +146,7 @@ def _fix_value(self, value): raise TypeError(error) def _is_valid(self, value): - deprecated(value) + deprecated.warn(value) return stix.EntityList._is_valid(self, value) @@ -499,7 +309,7 @@ class RelatedPackage(_BaseRelated): @_BaseRelated.item.setter def item(self, value): - idref_deprecated(value) + deprecated.idref(value) _BaseRelated.item.fset(self, value) class RelatedReport(_BaseRelated): diff --git a/stix/core/__init__.py b/stix/core/__init__.py index b6519141..dcd16eed 100644 --- a/stix/core/__init__.py +++ b/stix/core/__init__.py @@ -5,7 +5,7 @@ import stix # deprecations -from stix.utils.deprecated import idref_deprecated +from stix.utils import deprecated # component imports from stix.campaign import Campaign @@ -27,11 +27,9 @@ class Campaigns(stix.EntityList): _binding_class = _binding.CampaignsType _contained_type = Campaign _binding_var = "Campaign" - _inner_name = "campaigns" - _dict_as_list = True def _is_valid(self, value): - idref_deprecated(value) + deprecated.idref(value) return stix.EntityList._is_valid(self, value) @@ -41,11 +39,9 @@ class CoursesOfAction(stix.EntityList): _binding_class = _binding.CoursesOfActionType _contained_type = CourseOfAction _binding_var = "Course_Of_Action" - _inner_name = "courses_of_action" - _dict_as_list = True def _is_valid(self, value): - idref_deprecated(value) + deprecated.idref(value) return stix.EntityList._is_valid(self, value) @@ -55,11 +51,9 @@ class ExploitTargets(stix.EntityList): _binding_class = _binding.ExploitTargetsType _contained_type = ExploitTarget _binding_var = "Exploit_Target" - _inner_name = "exploit_targets" - _dict_as_list = True def _is_valid(self, value): - idref_deprecated(value) + deprecated.idref(value) return stix.EntityList._is_valid(self, value) @@ -69,11 +63,9 @@ class Incidents(stix.EntityList): _binding_class = _binding.IncidentsType _contained_type = Incident _binding_var = "Incident" - _inner_name = "incidents" - _dict_as_list = True def _is_valid(self, value): - idref_deprecated(value) + deprecated.idref(value) return stix.EntityList._is_valid(self, value) @@ -83,11 +75,9 @@ class Indicators(stix.EntityList): _binding_class = _binding.IndicatorsType _contained_type = Indicator _binding_var = "Indicator" - _inner_name = "indicators" - _dict_as_list = True def _is_valid(self, value): - idref_deprecated(value) + deprecated.idref(value) return stix.EntityList._is_valid(self, value) @@ -97,11 +87,9 @@ class ThreatActors(stix.EntityList): _binding_class = _binding.ThreatActorsType _contained_type = ThreatActor _binding_var = "Threat_Actor" - _inner_name = "threat_actors" - _dict_as_list = True def _is_valid(self, value): - idref_deprecated(value) + deprecated.idref(value) return stix.EntityList._is_valid(self, value) @@ -111,11 +99,9 @@ class Reports(stix.EntityList): _binding_class = _binding.ReportsType _contained_type = Report _binding_var = "Report" - _inner_name = "reports" - _dict_as_list = True def _is_valid(self, value): - idref_deprecated(value) + deprecated.idref(value) return stix.EntityList._is_valid(self, value) diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index 60c6cb88..9deede08 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -4,17 +4,13 @@ from mixbox import fields import stix -from stix.utils.deprecated import deprecated +from stix.utils import deprecated from stix.common import InformationSource, StructuredTextList, Profiles from stix.common.vocabs import VocabField, PackageIntent from stix.data_marking import Marking import stix.bindings.stix_core as stix_core_binding -def _deprecated(instance, value): - deprecated(value) - - class STIXHeader(stix.Entity): """The STIX Package Header. @@ -40,10 +36,10 @@ class STIXHeader(stix.Entity): _binding_class = _binding.STIXHeaderType _namespace = 'http://stix.mitre.org/stix-1' - title = fields.TypedField("Title", preset_hook=_deprecated) - package_intents = VocabField("Package_Intent", PackageIntent, multiple=True, preset_hook=_deprecated) - descriptions = fields.TypedField("Description", type_=StructuredTextList, key_name="description", preset_hook=_deprecated) - short_descriptions = fields.TypedField("Short_Description", type_=StructuredTextList, key_name="short_description", preset_hook=_deprecated) + title = fields.TypedField("Title", preset_hook=deprecated.field) + package_intents = VocabField("Package_Intent", PackageIntent, multiple=True, preset_hook=deprecated.field) + descriptions = fields.TypedField("Description", type_=StructuredTextList, key_name="description", preset_hook=deprecated.field) + short_descriptions = fields.TypedField("Short_Description", type_=StructuredTextList, key_name="short_description", preset_hook=deprecated.field) handling = fields.TypedField("Handling", Marking) information_source = fields.TypedField("Information_Source", InformationSource) profiles = fields.TypedField("Profiles", Profiles) diff --git a/stix/core/ttps.py b/stix/core/ttps.py index fbbf74a4..a355de68 100644 --- a/stix/core/ttps.py +++ b/stix/core/ttps.py @@ -8,7 +8,7 @@ from stix.bindings import stix_core as core_binding # deprecation warnings -from stix.utils.deprecated import idref_deprecated +from stix.utils import deprecated class TTPs(stix.EntityList): _binding = core_binding @@ -42,7 +42,7 @@ def add_ttp(self, ttp): self.append(ttp) def _is_valid(self, value): - idref_deprecated(value) + deprecated.idref(value) return stix.EntityList._is_valid(self, value) def to_obj(self, return_obj=None, ns_info=None): diff --git a/stix/utils/deprecated.py b/stix/utils/deprecated.py index 588594cb..7283c780 100644 --- a/stix/utils/deprecated.py +++ b/stix/utils/deprecated.py @@ -6,7 +6,7 @@ from . import is_sequence -def idref_deprecated(entity): +def idref(entity): """Raises a Python UserWarning if `entity` arguments contains an idref value. @@ -21,7 +21,14 @@ def idref_deprecated(entity): warnings.warn(msg) -def deprecated(value): +def field(instance, value): + """Raise a Python UserWarning if the `value` is not None. This is to be + used with a TypedField preset or postset hook. + """ + warn(value) + + +def warn(value): """Raises a Python UserWarning if `value` is not None. This is typically going to be used inside setter functions for deprecated From e2a8941632014006ef47a1d36bd4045ed90076a1 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 5 Oct 2015 19:56:02 -0400 Subject: [PATCH 215/438] Updated STIXPackage to use TypedFields. Need to update component classes before this will work. --- stix/core/stix_package.py | 335 ++++---------------------------------- 1 file changed, 32 insertions(+), 303 deletions(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 79061ef5..3152db84 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -1,31 +1,34 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# mixbox from mixbox import idgen +from mixbox import fields from mixbox.cache import Cached +# cybox from cybox.core import Observable, Observables # base import stix # utility imports -import stix.utils as utils -import stix.utils.parser as parser -from stix.utils.deprecated import deprecated +from .. import utils +from ..utils import parser +from ..utils import deprecated # component imports -from stix.campaign import Campaign -from stix.coa import CourseOfAction -from stix.exploit_target import ExploitTarget -from stix.indicator import Indicator -from stix.incident import Incident -from stix.threat_actor import ThreatActor -from stix.ttp import TTP -from stix.report import Report +from ..campaign import Campaign +from ..coa import CourseOfAction +from ..exploit_target import ExploitTarget +from ..indicator import Indicator +from ..incident import Incident +from ..threat_actor import ThreatActor +from ..ttp import TTP +from ..report import Report # relationship imports -from stix.common.related import RelatedPackages +from ..common.related import RelatedPackages # relative imports from .stix_header import STIXHeader @@ -67,6 +70,22 @@ class STIXPackage(Cached, stix.Entity): _version = "1.2" _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") + id_ = fields.IdField("id") + idref = fields.IdrefField("idref", preset_hook=deprecated.field) + version = fields.TypedField("version") + timestamp = fields.DateTimeField("timestamp", preset_hook=deprecated.field) + stix_header = fields.TypedField("STIX_Header", STIXHeader) + campaigns = fields.TypedField("Campaigns", Campaigns) + courses_of_action = fields.TypedField("Courses_Of_Action", CoursesOfAction) + exploit_targets = fields.TypedField("Exploit_Targets", ExploitTargets) + observables = fields.TypedField("Observables", Observables) + indicators = fields.TypedField("Indicators", Indicators) + incidents = fields.TypedField("Incidents", Incidents) + threat_actors = fields.TypedField("Threat_Actors", ThreatActors) + ttps = fields.TypedField("TTPs", TTPs) + related_packages = fields.TypedField("Related_Packages", RelatedPackages) + reports = fields.TypedField("Reports", Reports) + def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, courses_of_action=None, exploit_targets=None, indicators=None, observables=None, incidents=None, threat_actors=None, @@ -89,89 +108,6 @@ def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, self.reports = reports self.timestamp = timestamp - @property - def id_(self): - """A globally unique identifier for this Report. By default, one - will be generated automatically. - - """ - return self._id - - @id_.setter - def id_(self, value): - if not value: - self._id = None - else: - self._id = value - self.idref = None - - @property - def idref(self): - """A reference to another Report identifier. Setting this will unset - any previous ``id`` values. - - """ - return self._idref - - @idref.setter - def idref(self, value): - deprecated(value) - - if not value: - self._idref = None - else: - self._idref = value - self.id_ = None # unset id_ if idref is present - - @property - def timestamp(self): - """Specifies a timestamp for the definition of this specifc Report - object. - - """ - return self._timestamp - - @timestamp.setter - def timestamp(self, value): - deprecated(value) - self._timestamp = utils.dates.parse_value(value) - - @property - def version(self): - """The schematic version of this component. - - Note: - This property refers to the version of the schema component - type and should not be used for the purpose of content versioning. - - Default Value: '1.2' - - """ - return self._version - - @property - def stix_header(self): - """The :class:`.STIXHeader` section of the STIX Package. - - """ - return self._stix_header - - @stix_header.setter - def stix_header(self, value): - self._set_var(STIXHeader, try_cast=False, stix_header=value) - - @property - def indicators(self): - """The top-level :class:`.Indicator` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._indicators - - @indicators.setter - def indicators(self, value): - self._indicators = Indicators(value) - def add_indicator(self, indicator): """Adds an :class:`.Indicator` object to the :attr:`indicators` collection. @@ -179,36 +115,12 @@ def add_indicator(self, indicator): """ self.indicators.append(indicator) - @property - def campaigns(self): - """The top-level :class:`.Campaign` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._campaigns - - @campaigns.setter - def campaigns(self, value): - self._campaigns = Campaigns(value) - def add_campaign(self, campaign): """Adds a :class:`Campaign` object to the :attr:`campaigns` collection. """ self.campaigns.append(campaign) - @property - def observables(self): - """The top-level ``Observable`` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._observables - - @observables.setter - def observables(self, value): - self._set_var(Observables, observables=value) - def add_observable(self, observable): """Adds an ``Observable`` object to the :attr:`observables` collection. @@ -221,18 +133,6 @@ def add_observable(self, observable): else: self.observables.add(observable) - @property - def incidents(self): - """The top-level :class:`.Incident` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._incidents - - @incidents.setter - def incidents(self, value): - self._incidents = Incidents(value) - def add_incident(self, incident): """Adds an :class:`.Incident` object to the :attr:`incidents` collection. @@ -240,18 +140,6 @@ def add_incident(self, incident): """ self.incidents.append(incident) - @property - def threat_actors(self): - """The top-level :class:`.ThreatActor` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._threat_actors - - @threat_actors.setter - def threat_actors(self, value): - self._threat_actors = ThreatActors(value) - def add_threat_actor(self, threat_actor): """Adds an :class:`.ThreatActor` object to the :attr:`threat_actors` collection. @@ -259,18 +147,6 @@ def add_threat_actor(self, threat_actor): """ self._threat_actors.append(threat_actor) - @property - def courses_of_action(self): - """The top-level :class:`.CourseOfAction` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._courses_of_action - - @courses_of_action.setter - def courses_of_action(self, value): - self._courses_of_action = CoursesOfAction(value) - def add_course_of_action(self, course_of_action): """Adds an :class:`.CourseOfAction` object to the :attr:`courses_of_action` collection. @@ -278,18 +154,6 @@ def add_course_of_action(self, course_of_action): """ self._courses_of_action.append(course_of_action) - @property - def exploit_targets(self): - """The top-level :class:`.ExploitTarget` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._exploit_targets - - @exploit_targets.setter - def exploit_targets(self, value): - self._exploit_targets = ExploitTargets(value) - def add_exploit_target(self, exploit_target): """Adds an :class:`.ExploitTarget` object to the :attr:`exploit_targets` collection. @@ -297,59 +161,18 @@ def add_exploit_target(self, exploit_target): """ self._exploit_targets.append(exploit_target) - @property - def ttps(self): - """The top-level :class:`.TTP` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._ttps - - @ttps.setter - def ttps(self, value): - if isinstance(value, TTPs): - self._ttps = value - else: - self._ttps = TTPs(value) - def add_ttp(self, ttp): """Adds an :class:`.TTP` object to the :attr:`ttps` collection. """ self.ttps.append(ttp) - @property - def reports(self): - """A collection of :class:`.Report` objects. This behaves like a - ``MutableSequence`` object. - - """ - return self._reports - - @reports.setter - def reports(self, value): - self._reports = Reports(value) - def add_report(self, report): """Adds a :class:`.Report` object to the :attr:`reports` collection. """ self.reports.append(report) - @property - def related_packages(self): - """**DEPRECATED**. A collection of :class:`.RelatedPackage` objects. - - """ - return self._related_packages - - @related_packages.setter - def related_packages(self, value): - if isinstance(value, RelatedPackages): - self._related_packages = value - else: - self._related_packages = RelatedPackages(value) - def add_related_package(self, related_package): """Adds a :class:`.RelatedPackage` object to the :attr:`related_packages` collection. @@ -374,7 +197,7 @@ def add(self, entity): Incident: self.add_incident, Indicator: self.add_indicator, ThreatActor: self.add_threat_actor, - TTP: self.add_threat_actor, + TTP: self.add_ttp, Report: self.add_report, Observable: self.add_observable, } @@ -387,100 +210,6 @@ def add(self, entity): error = error.format(type(entity)) raise TypeError(error) - def to_obj(self, return_obj=None, ns_info=None): - super(STIXPackage, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - return_obj.id = self.id_ - return_obj.idref = self.idref - return_obj.version = STIXPackage._version # noqa - return_obj.timestamp = utils.dates.serialize_value(self.timestamp) - - if self.stix_header: - return_obj.STIX_Header = self.stix_header.to_obj(ns_info=ns_info) - if self.campaigns: - return_obj.Campaigns = self.campaigns.to_obj(ns_info=ns_info) - if self.courses_of_action: - return_obj.Courses_Of_Action = self.courses_of_action.to_obj(ns_info=ns_info) - if self.exploit_targets: - return_obj.Exploit_Targets = self.exploit_targets.to_obj(ns_info=ns_info) - if self.indicators: - return_obj.Indicators = self.indicators.to_obj(ns_info=ns_info) - if self.observables: - return_obj.Observables = self.observables.to_obj(ns_info=ns_info) - if self.incidents: - return_obj.Incidents = self.incidents.to_obj(ns_info=ns_info) - if self.threat_actors: - return_obj.Threat_Actors = self.threat_actors.to_obj(ns_info=ns_info) - if self.ttps: - return_obj.TTPs = self.ttps.to_obj(ns_info=ns_info) - if self.related_packages: - return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) - if self.reports: - return_obj.Reports = self.reports.to_obj(ns_info=ns_info) - - return return_obj - - def to_dict(self): - d = utils.to_dict(self) - - if 'version' in d: - d['version'] = STIXPackage._version # noqa - - return d - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not return_obj: - return_obj = cls() - - return_obj.id_ = obj.id - return_obj.idref = obj.idref - return_obj.timestamp = obj.timestamp - return_obj.stix_header = STIXHeader.from_obj(obj.STIX_Header) - return_obj.campaigns = Campaigns.from_obj(obj.Campaigns) - return_obj.courses_of_action = CoursesOfAction.from_obj(obj.Courses_Of_Action) - return_obj.exploit_targets = ExploitTargets.from_obj(obj.Exploit_Targets) - return_obj.indicators = Indicators.from_obj(obj.Indicators) - return_obj.observables = Observables.from_obj(obj.Observables) - return_obj.incidents = Incidents.from_obj(obj.Incidents) - return_obj.threat_actors = ThreatActors.from_obj(obj.Threat_Actors) - return_obj.ttps = TTPs.from_obj(obj.TTPs) - return_obj.related_packages = RelatedPackages.from_obj(obj.Related_Packages) - return_obj.reports = Reports.from_obj(obj.Reports) - - # Don't overwrite this unless passed in. - if obj.version: - return_obj._version = obj.version - - return return_obj - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not return_obj: - return_obj = cls() - - get = dict_repr.get - return_obj.id_ = get('id') - return_obj.idref = get('idref') - return_obj.timestamp = get('timestamp') - return_obj._version = get('version', cls._version) - return_obj.stix_header = STIXHeader.from_dict(get('stix_header')) - return_obj.campaigns = Campaigns.from_dict(get('campaigns')) - return_obj.courses_of_action = CoursesOfAction.from_dict(get('courses_of_action')) - return_obj.exploit_targets = ExploitTargets.from_dict(get('exploit_targets')) - return_obj.indicators = Indicators.from_dict(get('indicators')) - return_obj.observables = Observables.from_dict(get('observables')) - return_obj.incidents = Incidents.from_dict(get('incidents')) - return_obj.threat_actors = ThreatActors.from_dict(get('threat_actors')) - return_obj.ttps = TTPs.from_dict(get('ttps')) - return_obj.related_packages = RelatedPackages.from_dict(get('related_packages')) - return_obj.reports = Reports.from_dict(get('reports')) - - return return_obj - @classmethod def from_xml(cls, xml_file, encoding=None): """Parses the `xml_file` file-like object and returns a From 1e41008143b9d14eae4f17e6a2b34977fd3afb23 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 5 Oct 2015 20:39:26 -0400 Subject: [PATCH 216/438] Replaced all referecnes to AttributeField, ElementField, and StructuredTextListField with mixbox TypedField. --- stix/__init__.py | 2 +- stix/base.py | 16 +---- stix/campaign/__init__.py | 35 +++++----- stix/common/activity.py | 9 +-- stix/common/campaign_reference.py | 11 ++-- stix/common/confidence.py | 16 ++--- stix/common/datetimewithprecision.py | 7 +- stix/common/identity.py | 3 +- stix/common/information_source.py | 18 +++--- stix/common/kill_chains/__init__.py | 21 +++--- stix/common/profiles.py | 4 +- stix/common/references.py | 4 +- stix/common/related.py | 4 +- stix/common/statement.py | 10 ++- stix/common/structured_text.py | 15 ++--- .../structured_coa/generic_structured_coa.py | 7 +- .../test_mechanism/generic_test_mechanism.py | 12 ++-- stix/incident/__init__.py | 64 +++++++++---------- stix/indicator/indicator.py | 51 +++++++-------- stix/indicator/sightings.py | 16 ++--- stix/indicator/test_mechanism.py | 5 +- stix/indicator/valid_time.py | 6 +- stix/ttp/__init__.py | 23 +++---- 23 files changed, 166 insertions(+), 193 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index e268f08f..4e40df88 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -3,7 +3,7 @@ # Make sure base gets imported before common. from .base import (Entity, EntityList, TypedCollection, TypedList, # noqa - BaseCoreComponent, ElementField, AttributeField) + BaseCoreComponent) #: Mapping of xsi:types to implementation/extension classes _EXTENSION_MAP = {} diff --git a/stix/base.py b/stix/base.py index 4698cac4..232bd18c 100644 --- a/stix/base.py +++ b/stix/base.py @@ -22,18 +22,6 @@ def _override(*args, **kwargs): raise NotImplementedError() -class AttributeField(fields.TypedField): - pass - - -class ElementField(fields.TypedField): - pass - - -class ContentField(fields.TypedField): - pass - - class Entity(entities.Entity): """Base class for all classes in the STIX API.""" _namespace = None @@ -379,12 +367,12 @@ class BaseCoreComponent(Cached, Entity): _ALL_VERSIONS = () _ID_PREFIX = None - title = ElementField("Title") + title = fields.TypedField("Title") id_ = fields.IdField("id") idref = fields.IdrefField("idref") descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList", key_name="description") short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList", key_name="short_description") - version = AttributeField("version", preset_hook=_validate_version) + version = fields.TypedField("version", preset_hook=_validate_version) timestamp = fields.DateTimeField("timestamp") handling = fields.TypedField("Handling", type_="stix.data_marking.Marking") diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 98abf8aa..ef970910 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -1,6 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + import stix from stix.utils import deprecated from stix.common import Activity, Confidence, Statement, VocabString @@ -10,8 +12,7 @@ ) from stix.common import vocabs import stix.bindings.campaign as campaign_binding -from stix.common.structured_text import StructuredTextList, StructuredTextListField -from stix.base import ElementField, AttributeField +from stix.common.structured_text import StructuredTextList from stix.common.information_source import InformationSource class AssociatedCampaigns(GenericRelationshipList): @@ -32,8 +33,8 @@ class Attribution(GenericRelationshipList): """ class Attribution(stix.Entity): - threat_actors = ElementField("Attributed_Threat_Actor", RelatedThreatActor, multiple=True, key_name="threat_actors") - scope = AttributeField("scope") + threat_actors = fields.TypedField("Attributed_Threat_Actor", RelatedThreatActor, multiple=True, key_name="threat_actors") + scope = fields.TypedField("scope") def __init__(self, scope=None, *args): self._fields = {} @@ -111,19 +112,19 @@ class Campaign(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'campaign' - descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") - activity = ElementField("Activity", Activity, multiple=True) - associated_campaigns = ElementField("Associated_Campaigns", AssociatedCampaigns) - attribution = ElementField("Attribution", Attribution, multiple=True) - confidence = ElementField("Confidence", Confidence) - # references = ElementField("Reference", multiple=True) - status = ElementField("Status", VocabString) - intended_effects = ElementField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") - names = ElementField("Names", Names) - related_incidents = ElementField("Related_Incidents", RelatedIncidents) - related_indicators = ElementField("Related_Indicators", RelatedIndicators) - related_packages = ElementField("Related_Packages", RelatedPackageRefs) - information_source = ElementField("Information_Source", InformationSource) + descriptions = fields.TypedField("Description", StructuredTextList, key_name="description") + activity = fields.TypedField("Activity", Activity, multiple=True) + associated_campaigns = fields.TypedField("Associated_Campaigns", AssociatedCampaigns) + attribution = fields.TypedField("Attribution", Attribution, multiple=True) + confidence = fields.TypedField("Confidence", Confidence) + # references = fields.TypedField("Reference", multiple=True) + status = fields.TypedField("Status", VocabString) + intended_effects = fields.TypedField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") + names = fields.TypedField("Names", Names) + related_incidents = fields.TypedField("Related_Incidents", RelatedIncidents) + related_indicators = fields.TypedField("Related_Indicators", RelatedIndicators) + related_packages = fields.TypedField("Related_Packages", RelatedPackageRefs) + information_source = fields.TypedField("Information_Source", InformationSource) def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): diff --git a/stix/common/activity.py b/stix/common/activity.py index 6f629459..af373a53 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -1,13 +1,14 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + import stix import stix.bindings.stix_common as common_binding import stix.utils -from stix.base import ElementField from .datetimewithprecision import DateTimeWithPrecision -from .structured_text import StructuredTextList, StructuredTextListField +from .structured_text import StructuredTextList class Activity(stix.Entity): @@ -15,8 +16,8 @@ class Activity(stix.Entity): _binding_class = common_binding.ActivityType _namespace = 'http://stix.mitre.org/common-1' - date_time = ElementField("Date_Time", DateTimeWithPrecision) - descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") + date_time = fields.TypedField("Date_Time", DateTimeWithPrecision) + descriptions = fields.TypedField("Description", StructuredTextList, key_name="description") def __init__(self): super(Activity, self).__init__() diff --git a/stix/common/campaign_reference.py b/stix/common/campaign_reference.py index d05c2de5..fc116ee5 100644 --- a/stix/common/campaign_reference.py +++ b/stix/common/campaign_reference.py @@ -2,12 +2,11 @@ # See LICENSE.txt for complete terms. # external -from mixbox.fields import DateTimeField +from mixbox import fields # internal import stix import stix.bindings.stix_common as common_binding -from stix.base import AttributeField, ElementField # relative from .names import Names @@ -18,13 +17,13 @@ class CampaignRef(stix.Entity): _binding = common_binding _binding_class = common_binding.CampaignReferenceType - idref = AttributeField("idref") - timestamp = DateTimeField("timestamp") - names = ElementField("Names", Names) + idref = fields.TypedField("idref") + timestamp = fields.DateTimeField("timestamp") + names = fields.TypedField("Names", Names) def __init__(self, idref=None, timestamp=None): super(CampaignRef, self).__init__() - + self.idref = idref self.timestamp = timestamp self.names = None diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 8c744290..33e6aa86 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -3,16 +3,14 @@ from __future__ import absolute_import -from mixbox.fields import DateTimeField +from mixbox import fields import stix import stix.utils as utils import stix.bindings.stix_common as common_binding -from stix.base import ElementField, AttributeField - from .vocabs import VocabString -from .structured_text import StructuredTextList, StructuredTextListField +from .structured_text import StructuredTextList from .datetimewithprecision import validate_precision class Confidence(stix.Entity): @@ -20,11 +18,11 @@ class Confidence(stix.Entity): _binding = common_binding _binding_class = common_binding.ConfidenceType - value = ElementField("Value", VocabString) - descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") - timestamp = DateTimeField("timestamp") - timestamp_precision = AttributeField("timestamp_precision", preset_hook=validate_precision) - source = ElementField("Source", type_="stix.common.InformationSource") + value = fields.TypedField("Value", VocabString) + descriptions = fields.TypedField("Description", StructuredTextList, key_name="description") + timestamp = fields.DateTimeField("timestamp") + timestamp_precision = fields.TypedField("timestamp_precision", preset_hook=validate_precision) + source = fields.TypedField("Source", type_="stix.common.InformationSource") def __init__(self, value=None, timestamp=None, description=None, source=None): super(Confidence, self).__init__() diff --git a/stix/common/datetimewithprecision.py b/stix/common/datetimewithprecision.py index 6a5389ff..5775a099 100644 --- a/stix/common/datetimewithprecision.py +++ b/stix/common/datetimewithprecision.py @@ -1,13 +1,12 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -from mixbox.fields import DateTimeField +from mixbox import fields import stix import stix.utils as utils import stix.bindings.stix_common as common_binding -from stix.base import AttributeField DATE_PRECISION_VALUES = ("year", "month", "day") TIME_PRECISION_VALUES = ("hour", "minute", "second") @@ -30,8 +29,8 @@ class DateTimeWithPrecision(stix.Entity): _binding_class = _binding.DateTimeWithPrecisionType _namespace = 'http://stix.mitre.org/common-1' - value = DateTimeField("valueOf_", key_name="value") - precision = AttributeField("precision", preset_hook=validate_precision) + value = fields.DateTimeField("valueOf_", key_name="value") + precision = fields.TypedField("precision", preset_hook=validate_precision) def __init__(self, value=None, precision='second'): super(DateTimeWithPrecision, self).__init__() diff --git a/stix/common/identity.py b/stix/common/identity.py index a141fcef..d36c55b3 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -8,7 +8,6 @@ # internal import stix import stix.bindings.stix_common as common_binding -from stix.base import ElementField from stix.bindings.stix_common import IdentityType @@ -19,7 +18,7 @@ class Identity(Cached, stix.Entity): id_ = fields.IdField("id") idref = fields.IdrefField("idref") - name = ElementField("Name") + name = fields.TypedField("Name") related_identities = fields.TypedField("Related_Identities", type_="stix.common.identity.RelatedIdentities") def __init__(self, id_=None, idref=None, name=None, related_identities=None): diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 565a9164..ee2bd5fb 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -2,19 +2,19 @@ # See LICENSE.txt for complete terms. # external +from mixbox import fields import cybox.common from cybox.common.tools import ToolInformationList # internal import stix -from stix.base import ElementField import stix.bindings.stix_common as stix_common_binding # relative from .vocabs import VocabString from .references import References from .identity import Identity -from .structured_text import StructuredTextList, StructuredTextListField +from .structured_text import StructuredTextList class InformationSource(stix.Entity): @@ -22,13 +22,13 @@ class InformationSource(stix.Entity): _binding_class = stix_common_binding.InformationSourceType _namespace = 'http://stix.mitre.org/common-1' - identity = ElementField("Identity", Identity) - descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") - contributing_sources = ElementField("Contributing_Sources", type_="stix.common.information_source.ContributingSources") - time = ElementField("Time", cybox.common.Time) - roles = ElementField("Role", VocabString, multiple=True, key_name="roles") - tools = ElementField("Tools", ToolInformationList) - references = ElementField("References", References) + identity = fields.TypedField("Identity", Identity) + descriptions = fields.TypedField("Description", StructuredTextList, key_name="description") + contributing_sources = fields.TypedField("Contributing_Sources", type_="stix.common.information_source.ContributingSources") + time = fields.TypedField("Time", cybox.common.Time) + roles = fields.TypedField("Role", VocabString, multiple=True, key_name="roles") + tools = fields.TypedField("Tools", ToolInformationList) + references = fields.TypedField("References", References) def __init__(self, description=None, identity=None, time=None, tools=None, contributing_sources=None, references=None): super(InformationSource, self).__init__() diff --git a/stix/common/kill_chains/__init__.py b/stix/common/kill_chains/__init__.py index 28f438d0..f29bffe6 100644 --- a/stix/common/kill_chains/__init__.py +++ b/stix/common/kill_chains/__init__.py @@ -6,19 +6,18 @@ # internal import stix import stix.bindings.stix_common as common_binding -from stix.base import AttributeField, ElementField class KillChain(stix.Entity): _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' _binding_class = _binding.KillChainType - id_ = AttributeField("id") - name = AttributeField("name") - definer = AttributeField("definer") - reference = AttributeField("reference") - number_of_phases = AttributeField("number_of_phases") - kill_chain_phases = ElementField("Kill_Chain_Phase", type_="stix.common.kill_chains.KillChainPhase", multiple=True, key_name="kill_chain_phases") + id_ = fields.TypedField("id") + name = fields.TypedField("name") + definer = fields.TypedField("definer") + reference = fields.TypedField("reference") + number_of_phases = fields.TypedField("number_of_phases") + kill_chain_phases = fields.TypedField("Kill_Chain_Phase", type_="stix.common.kill_chains.KillChainPhase", multiple=True, key_name="kill_chain_phases") def __init__(self, id_=None, name=None, definer=None, reference=None): super(KillChain, self).__init__() @@ -59,8 +58,8 @@ class KillChainPhase(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' _binding_class = _binding.KillChainPhaseType - phase_id = AttributeField("phase_id") - name = AttributeField("name") + phase_id = fields.TypedField("phase_id") + name = fields.TypedField("name") ordinality = fields.IntegerField("ordinality") def __init__(self, phase_id=None, name=None, ordinality=None): @@ -91,8 +90,8 @@ class KillChainPhaseReference(KillChainPhase): _namespace = 'http://stix.mitre.org/common-1' _binding_class = _binding.KillChainPhaseReferenceType - kill_chain_id = AttributeField("kill_chain_id") - kill_chain_name = AttributeField("kill_chain_name") + kill_chain_id = fields.TypedField("kill_chain_id") + kill_chain_name = fields.TypedField("kill_chain_name") def __init__(self, phase_id=None, name=None, ordinality=None, kill_chain_id=None, kill_chain_name=None): super(KillChainPhaseReference, self).__init__(phase_id, name, ordinality) diff --git a/stix/common/profiles.py b/stix/common/profiles.py index a9f50c88..1a4311e2 100644 --- a/stix/common/profiles.py +++ b/stix/common/profiles.py @@ -3,6 +3,8 @@ import collections +from mixbox import fields + import stix from stix.bindings import stix_common as stix_common_binding @@ -13,7 +15,7 @@ class Profiles(collections.MutableSequence, stix.Entity): _namespace = 'http://stix.mitre.org/common-1' # Fields - profile = stix.ElementField("Profile", multiple=True) + profile = fields.TypedField("Profile", multiple=True) def __init__(self, profiles=None): super(Profiles, self).__init__() diff --git a/stix/common/references.py b/stix/common/references.py index bc0d5bc0..2bb4d5be 100644 --- a/stix/common/references.py +++ b/stix/common/references.py @@ -2,6 +2,8 @@ # See LICENSE.txt for complete terms. import collections +from mixbox import fields + import stix from stix.bindings import stix_common as stix_common_binding @@ -12,7 +14,7 @@ class References(collections.MutableSequence, stix.Entity): _namespace = 'http://stix.mitre.org/common-1' # Fields - reference = stix.ElementField("Reference", multiple=True) + reference = fields.TypedField("Reference", multiple=True) def __init__(self, references=None): super(References, self).__init__() diff --git a/stix/common/related.py b/stix/common/related.py index 7c9fda60..6cec9ebe 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -8,8 +8,6 @@ import stix.bindings.stix_core as core_binding import stix.bindings.report as report_binding -from stix.base import AttributeField - # deprecation warnings from stix.utils import deprecated @@ -78,7 +76,7 @@ class GenericRelationshipEntity(stix.Entity): _ALLOWED_SCOPE = ('inclusive', 'exclusive') - scope = AttributeField("scope") + scope = fields.TypedField("scope") def __init__(self, scope=None, *args): diff --git a/stix/common/statement.py b/stix/common/statement.py index 853eb1bd..4a44853a 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -9,8 +9,6 @@ import stix.utils as utils import stix.bindings.stix_common as common_binding -from stix.base import AttributeField, ElementField - from .confidence import Confidence from .structured_text import StructuredTextList from .vocabs import VocabField, HighMediumLow @@ -22,11 +20,11 @@ class Statement(stix.Entity): _binding_class = common_binding.StatementType # Fields - timestamp = AttributeField("timestamp") - timestamp_precision = AttributeField("timestamp_precision") + timestamp = fields.TypedField("timestamp") + timestamp_precision = fields.TypedField("timestamp_precision") value = VocabField("Value", HighMediumLow) - descriptions = ElementField("Description", StructuredTextList) - confidence = ElementField("Confidence", Confidence) + descriptions = fields.TypedField("Description", StructuredTextList) + confidence = fields.TypedField("Confidence", Confidence) source = fields.TypedField("Source", type_="stix.common.InformationSource") def __init__(self, value=None, timestamp=None, description=None, diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 2a5bc93c..331d42e7 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -10,17 +10,11 @@ import stix.utils as utils import stix.bindings.stix_common as stix_common_binding -# typed fields -from stix.base import AttributeField, ElementField, ContentField #: Default ordinality value for StructuredText. DEFAULT_ORDINALITY = 1 -class StructuredTextListField(ElementField): - pass - - class StructuredText(stix.Entity): """Used for storing descriptive text elements. @@ -36,10 +30,11 @@ class StructuredText(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' id_ = fields.IdField("id") - ordinality = AttributeField("ordinality") - value = ContentField("valueOf_", key_name="value") - structuring_format = AttributeField("structuring_format") - + ordinality = fields.TypedField("ordinality") + value = fields.TypedField("valueOf_", key_name="value") + structuring_format = fields.TypedField("structuring_format") + + def __init__(self, value=None, ordinality=None): super(StructuredText, self).__init__() diff --git a/stix/extensions/structured_coa/generic_structured_coa.py b/stix/extensions/structured_coa/generic_structured_coa.py index 8c97ddb3..073eef77 100644 --- a/stix/extensions/structured_coa/generic_structured_coa.py +++ b/stix/extensions/structured_coa/generic_structured_coa.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import fields + # internal import stix from stix.common import EncodedCDATA, StructuredTextList, VocabString @@ -8,7 +11,7 @@ # bindings import stix.bindings.extensions.structured_coa.generic as generic_structured_coa_binding -from stix.base import ElementField + @stix.register_extension class GenericStructuredCOA(_BaseStructuredCOA): @@ -17,7 +20,7 @@ class GenericStructuredCOA(_BaseStructuredCOA): _binding_class = _binding.GenericStructuredCOAType _XSI_TYPE = "genericStructuredCOA:GenericStructuredCOAType" - specification = ElementField("Specification", EncodedCDATA) + specification = fields.TypedField("Specification", EncodedCDATA) def __init__(self, id_=None, idref=None): super(GenericStructuredCOA, self).__init__(id_=id_, idref=idref) diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index 59cd8ad5..ab930c7b 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -1,13 +1,13 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + import stix import stix.indicator.test_mechanism from stix.common import EncodedCDATA, StructuredTextList, VocabString from stix.indicator.test_mechanism import _BaseTestMechanism import stix.bindings.extensions.test_mechanism.generic as generic_tm_binding -from stix.base import ElementField, AttributeField -from stix.common.structured_text import StructuredTextListField @stix.register_extension class GenericTestMechanism(_BaseTestMechanism): @@ -16,10 +16,10 @@ class GenericTestMechanism(_BaseTestMechanism): _binding_class = _binding.GenericTestMechanismType _XSI_TYPE = "genericTM:GenericTestMechanismType" - reference_location = ElementField("Reference_Location") - descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") - specification = ElementField("Specification", EncodedCDATA) - type_ = AttributeField("type", VocabString, key_name="type") + reference_location = fields.TypedField("Reference_Location") + descriptions = fields.TypedField("Description", StructuredTextList, key_name="description") + specification = fields.TypedField("Specification", EncodedCDATA) + type_ = fields.TypedField("type", VocabString, key_name="type") def __init__(self, id_=None, idref=None): super(GenericTestMechanism, self).__init__(id_=id_, idref=idref) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index c955b48f..8ed12834 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -1,16 +1,15 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. - +from mixbox import fields import stix import stix.bindings.incident as incident_binding -from stix.common import ( - vocabs, Identity, Statement, VocabString,InformationSource, Confidence -) -from stix.common.related import ( - GenericRelationshipList, RelatedIndicator, RelatedThreatActor, RelatedTTP, - RelatedObservable, RelatedIncident, RelatedPackageRefs -) +from stix.common import vocabs +from stix.common import (Identity, Statement, VocabString, InformationSource, + Confidence) +from stix.common.related import (GenericRelationshipList, RelatedIndicator, + RelatedThreatActor, RelatedTTP, RelatedObservable, RelatedIncident, + RelatedPackageRefs) # relative from .affected_asset import AffectedAsset @@ -20,8 +19,7 @@ from .impact_assessment import ImpactAssessment from .coa import COATaken, COARequested, COATime # noqa from .history import History -from stix.base import ElementField -from stix.common.structured_text import StructuredTextListField + class Incident(stix.BaseCoreComponent): """Implementation of the STIX Incident. @@ -47,29 +45,29 @@ class Incident(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'incident' - status = ElementField("Status", vocabs.IncidentStatus) - time = ElementField("Time", Time) - victims = ElementField("Victim", Identity, multiple=True, key_name="victims") - attributed_threat_actors = ElementField("Attributed_Threat_Actors", type_="stix.incident.AttributedThreatActors") - related_indicators = ElementField("Related_Indicators", type_="stix.incident.RelatedIndicators") - related_observables = ElementField("Related_Observables", type_="stix.incident.RelatedObservables") - related_incidents = ElementField("Related_Incidents", type_="stix.incident.RelatedIncidents") - related_packages = ElementField("Related_Packages", RelatedPackageRefs) - affected_assets = ElementField("Affected_Assets", type_="stix.incident.AffectedAssets") - categories = ElementField("Categories", type_="stix.incident.IncidentCategories") - intended_effects = ElementField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") - leveraged_ttps = ElementField("Leveraged_TTPs", type_="stix.incident.LeveragedTTPs") - discovery_methods = ElementField("Discovery_Method", vocabs.DiscoveryMethod, multiple=True, key_name="discovery_methods") - reporter = ElementField("Reporter", InformationSource) - responders = ElementField("Responder", InformationSource, multiple=True, key_name="responders") - coordinators = ElementField("Coordinator", InformationSource, multiple=True, key_name="coordinators") - external_ids = ElementField("External_ID", ExternalID, multiple=True, key_name="external_ids") - impact_assessment = ElementField("Impact_Assessment", ImpactAssessment) - security_compromise = ElementField("Security_Compromise", vocabs.SecurityCompromise) - confidence = ElementField("Confidence", Confidence) - coa_taken = ElementField("COA_Taken", COATaken, multiple=True) - coa_requested = ElementField("COA_Requested", COARequested, multiple=True) - history = ElementField("History", History) + status = fields.TypedField("Status", vocabs.IncidentStatus) + time = fields.TypedField("Time", Time) + victims = fields.TypedField("Victim", Identity, multiple=True, key_name="victims") + attributed_threat_actors = fields.TypedField("Attributed_Threat_Actors", type_="stix.incident.AttributedThreatActors") + related_indicators = fields.TypedField("Related_Indicators", type_="stix.incident.RelatedIndicators") + related_observables = fields.TypedField("Related_Observables", type_="stix.incident.RelatedObservables") + related_incidents = fields.TypedField("Related_Incidents", type_="stix.incident.RelatedIncidents") + related_packages = fields.TypedField("Related_Packages", RelatedPackageRefs) + affected_assets = fields.TypedField("Affected_Assets", type_="stix.incident.AffectedAssets") + categories = fields.TypedField("Categories", type_="stix.incident.IncidentCategories") + intended_effects = fields.TypedField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") + leveraged_ttps = fields.TypedField("Leveraged_TTPs", type_="stix.incident.LeveragedTTPs") + discovery_methods = fields.TypedField("Discovery_Method", vocabs.DiscoveryMethod, multiple=True, key_name="discovery_methods") + reporter = fields.TypedField("Reporter", InformationSource) + responders = fields.TypedField("Responder", InformationSource, multiple=True, key_name="responders") + coordinators = fields.TypedField("Coordinator", InformationSource, multiple=True, key_name="coordinators") + external_ids = fields.TypedField("External_ID", ExternalID, multiple=True, key_name="external_ids") + impact_assessment = fields.TypedField("Impact_Assessment", ImpactAssessment) + security_compromise = fields.TypedField("Security_Compromise", vocabs.SecurityCompromise) + confidence = fields.TypedField("Confidence", Confidence) + coa_taken = fields.TypedField("COA_Taken", COATaken, multiple=True) + coa_requested = fields.TypedField("COA_Requested", COARequested, multiple=True) + history = fields.TypedField("History", History) def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): super(Incident, self).__init__( diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index c35bb1af..fd20ba35 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -2,20 +2,17 @@ # See LICENSE.txt for complete terms. # external +from mixbox import fields + from cybox.core import Observable, ObservableComposition from cybox.common import Time # internal import stix -import stix.utils as utils -from stix.common import ( - Identity, InformationSource, VocabString, Confidence, - RelatedTTP, Statement, CampaignRef -) -from stix.common.related import ( - GenericRelationshipList, RelatedCOA, RelatedIndicator, RelatedCampaignRef, - RelatedPackageRefs -) +from stix.common import (Identity, InformationSource, VocabString, Confidence, + RelatedTTP, Statement, CampaignRef) +from stix.common.related import (GenericRelationshipList, RelatedCOA, + RelatedIndicator, RelatedCampaignRef, RelatedPackageRefs) from stix.common.vocabs import IndicatorType from stix.common.kill_chains import KillChainPhasesReference import stix.bindings.indicator as indicator_binding @@ -25,8 +22,6 @@ from .sightings import Sightings from .valid_time import ValidTime -from stix.base import ElementField, AttributeField -from stix.common.structured_text import StructuredTextListField from operator import isSequenceType class SuggestedCOAs(GenericRelationshipList): @@ -181,23 +176,23 @@ class Indicator(stix.BaseCoreComponent): _ALLOWED_COMPOSITION_OPERATORS = ('AND', 'OR') _ID_PREFIX = "indicator" - producer = ElementField("Producer", InformationSource) - observable = ElementField("Observable", Observable, postset_hook = lambda inst,value: inst.set_observables([value])) - indicator_types = ElementField("Type", IndicatorType, multiple=True, key_name="indicator_types") - confidence = ElementField("Confidence", Confidence) - indicated_ttps = ElementField("Indicated_TTP", RelatedTTP, multiple=True, key_name="indicated_ttps") - test_mechanisms = ElementField("Test_Mechanisms", TestMechanisms) - alternative_id = ElementField("Alternative_ID", multiple=True) - suggested_coas = ElementField("Suggested_COAs", SuggestedCOAs) - sightings = ElementField("Sightings", Sightings) - composite_indicator_expression = ElementField("Composite_Indicator_Expression", ObservableComposition) - kill_chain_phases = ElementField("Kill_Chain_Phases", KillChainPhasesReference) - valid_time_positions = ElementField("Valid_Time_Position", ValidTime, multiple=True, key_name="valid_time_positions") - related_indicators = ElementField("Related_Indicators", RelatedIndicators) - related_campaigns = ElementField("Related_Campaigns", type_="stix.indicator.RelatedCampaigns") - likely_impact = ElementField("Likely_Impact", Statement) - negate = AttributeField("negate") - related_packages = ElementField("Related_Packages", RelatedPackageRefs) + producer = fields.TypedField("Producer", InformationSource) + observable = fields.TypedField("Observable", Observable, postset_hook = lambda inst,value: inst.set_observables([value])) + indicator_types = fields.TypedField("Type", IndicatorType, multiple=True, key_name="indicator_types") + confidence = fields.TypedField("Confidence", Confidence) + indicated_ttps = fields.TypedField("Indicated_TTP", RelatedTTP, multiple=True, key_name="indicated_ttps") + test_mechanisms = fields.TypedField("Test_Mechanisms", TestMechanisms) + alternative_id = fields.TypedField("Alternative_ID", multiple=True) + suggested_coas = fields.TypedField("Suggested_COAs", SuggestedCOAs) + sightings = fields.TypedField("Sightings", Sightings) + composite_indicator_expression = fields.TypedField("Composite_Indicator_Expression", ObservableComposition) + kill_chain_phases = fields.TypedField("Kill_Chain_Phases", KillChainPhasesReference) + valid_time_positions = fields.TypedField("Valid_Time_Position", ValidTime, multiple=True, key_name="valid_time_positions") + related_indicators = fields.TypedField("Related_Indicators", RelatedIndicators) + related_campaigns = fields.TypedField("Related_Campaigns", type_="stix.indicator.RelatedCampaigns") + likely_impact = fields.TypedField("Likely_Impact", Statement) + negate = fields.TypedField("negate") + related_packages = fields.TypedField("Related_Packages", RelatedPackageRefs) def __init__(self, id_=None, idref=None, timestamp=None, title=None, diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index 8dcd5859..532dec68 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -4,14 +4,12 @@ from mixbox import fields import stix -import stix.utils as utils +from stix import utils from stix.common import (GenericRelationshipList, RelatedObservable, StructuredTextList, Confidence, InformationSource) from stix.common.datetimewithprecision import validate_precision import stix.bindings.indicator as indicator_binding -from stix.base import AttributeField, ElementField -from stix.common.structured_text import StructuredTextListField class Sighting(stix.Entity): @@ -21,11 +19,11 @@ class Sighting(stix.Entity): timestamp = fields.DateTimeField("timestamp") timestamp_precision = fields.TypedField("timestamp_precision", preset_hook=validate_precision) - descriptions = StructuredTextListField("Description", StructuredTextList, key_name="description") - source = ElementField("Source", InformationSource) - reference = ElementField("Reference") - confidence = ElementField("Confidence", Confidence) - related_observables = ElementField("Related_Observables", type_="stix.indicator.sightings.RelatedObservables") + descriptions = fields.TypedField("Description", StructuredTextList, key_name="description") + source = fields.TypedField("Source", InformationSource) + reference = fields.TypedField("Reference") + confidence = fields.TypedField("Confidence", Confidence) + related_observables = fields.TypedField("Related_Observables", type_="stix.indicator.sightings.RelatedObservables") def __init__(self, timestamp=None, timestamp_precision=None, description=None): super(Sighting, self).__init__() @@ -132,7 +130,7 @@ class Sightings(stix.EntityList): _binding_var = "Sighting" _inner_name = "sightings" - sightings_count = AttributeField("sightings_count") + sightings_count = fields.TypedField("sightings_count") def __init__(self, sightings_count=None, *args): super(Sightings, self).__init__(*args) diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index bfda5864..a63312fe 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -11,7 +11,6 @@ # bindings import stix.bindings.indicator as indicator_binding -from stix.base import AttributeField, ElementField class _BaseTestMechanism(Cached, stix.Entity): @@ -21,8 +20,8 @@ class _BaseTestMechanism(Cached, stix.Entity): id_ = fields.IdField("id") idref = fields.IdField("idref") - efficacy = ElementField("Efficacy", Statement) - producer = ElementField("Producer", InformationSource) + efficacy = fields.TypedField("Efficacy", Statement) + producer = fields.TypedField("Producer", InformationSource) def __init__(self, id_=None, idref=None): self._fields = {} diff --git a/stix/indicator/valid_time.py b/stix/indicator/valid_time.py index 6441fbe0..12747ebd 100644 --- a/stix/indicator/valid_time.py +++ b/stix/indicator/valid_time.py @@ -1,18 +1,18 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields import stix from stix.common import DateTimeWithPrecision import stix.bindings.indicator as indicator_binding -from stix.base import ElementField class ValidTime(stix.Entity): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = _binding.ValidTimeType - start_time = ElementField("Start_Time", DateTimeWithPrecision) - end_time = ElementField("End_Time", DateTimeWithPrecision) + start_time = fields.TypedField("Start_Time", DateTimeWithPrecision) + end_time = fields.TypedField("End_Time", DateTimeWithPrecision) def __init__(self, start_time=None, end_time=None): self._fields = {} diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index 43413a5e..a74381e5 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -1,10 +1,13 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields # internal import stix import stix.bindings.ttp as ttp_binding -from stix.common import vocabs, Statement +from stix.common import vocabs +from stix.common import Statement +from stix.common.vocabs import IntendedEffect from stix.common.kill_chains import KillChainPhasesReference from stix.common.related import RelatedPackageRefs from stix.ttp.related_ttps import RelatedTTPs @@ -14,8 +17,6 @@ from .behavior import Behavior from .resource import Resource from .victim_targeting import VictimTargeting -from stix.base import ElementField -from stix.common.vocabs import IntendedEffect class TTP(stix.BaseCoreComponent): @@ -42,14 +43,14 @@ class TTP(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = "ttp" - behavior = ElementField("Behavior", Behavior) - related_ttps = ElementField("Related_TTPs", RelatedTTPs) - intended_effects = ElementField("Intended_Effect", IntendedEffect, multiple=True) - resources = ElementField("Resources", Resource) - victim_targeting = ElementField("Victim_Targeting", VictimTargeting) - exploit_targets = ElementField("Exploit_Targets", ExploitTargets) - related_packages = ElementField("Related_Pacakges", RelatedPackageRefs) - kill_chain_phases = ElementField("Kill_Chain_Phases", KillChainPhasesReference) + behavior = fields.TypedField("Behavior", Behavior) + related_ttps = fields.TypedField("Related_TTPs", RelatedTTPs) + intended_effects = fields.TypedField("Intended_Effect", IntendedEffect, multiple=True) + resources = fields.TypedField("Resources", Resource) + victim_targeting = fields.TypedField("Victim_Targeting", VictimTargeting) + exploit_targets = fields.TypedField("Exploit_Targets", ExploitTargets) + related_packages = fields.TypedField("Related_Pacakges", RelatedPackageRefs) + kill_chain_phases = fields.TypedField("Kill_Chain_Phases", KillChainPhasesReference) def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): From c3b3380ec441ebf42cee292b42ebb9937eeb4a49 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 5 Oct 2015 21:27:32 -0400 Subject: [PATCH 217/438] Refactored report Header class to use TypedFields. --- stix/report/header.py | 178 +++------------------------------------ stix/test/report_test.py | 1 + 2 files changed, 15 insertions(+), 164 deletions(-) diff --git a/stix/report/header.py b/stix/report/header.py index fd3ebfa4..f95f5dbc 100644 --- a/stix/report/header.py +++ b/stix/report/header.py @@ -1,10 +1,12 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + import stix import stix.bindings.report as report_binding -from stix.common import InformationSource, StructuredTextList, VocabString -from stix.common.vocabs import ReportIntent +from stix.common import InformationSource, StructuredTextList +from stix.common.vocabs import VocabField, ReportIntent from stix.data_marking import Marking @@ -28,11 +30,21 @@ class Header(stix.Entity): """ _binding = report_binding + _binding_class = _binding.HeaderType _namespace = 'http://stix.mitre.org/Report-1' + title = fields.TypedField("Title") + descriptions = fields.TypedField("Description", type_=StructuredTextList) + short_descriptions = fields.TypedField("Short_Description", type_=StructuredTextList) + intents = VocabField("Intent", ReportIntent, multiple=True, key_name="intents") + handling = fields.TypedField("Handling", Marking) + information_source = fields.TypedField("Information_Source", InformationSource) + def __init__(self, title=None, description=None, short_description=None, handling=None, intents=None, information_source=None): + super(Header, self).__init__() + self.intents = intents self.title = title self.description = description @@ -61,36 +73,6 @@ def description(self): def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. @@ -120,35 +102,6 @@ def short_description(self): def short_description(self, value): self.short_descriptions = value - @property - def short_descriptions(self): - """A :class:`.StructuredTextList` object, containing short descriptions - about the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - short descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of :class:`.StructuredTextList` - - """ - return self._short_description - - @short_descriptions.setter - def short_descriptions(self, value): - self._short_description = StructuredTextList(value) - def add_short_description(self, description): """Adds a description to the ``short_descriptions`` collection. @@ -157,30 +110,6 @@ def add_short_description(self, description): """ self.short_descriptions.add(description) - @property - def handling(self): - """The :class:`.Marking` section of this Header. This section contains - data marking information. - - """ - return self._handling - - @handling.setter - def handling(self, value): - self._set_var(Marking, try_cast=False, handling=value) - - @property - def intents(self): - """A collection of :class:`.VocabString` controlled vocabulary - objects. - - """ - return self._intents - - @intents.setter - def intents(self, value): - self._intents = _ReportIntents(value) - def add_intent(self, intent): """Adds :class:`.VocabString` object to the :attr:`intents` collection. @@ -190,82 +119,3 @@ def add_intent(self, intent): """ self.intents.append(intent) - - @property - def information_source(self): - """The :class:`.InformationSource` section of the Header. - - """ - return self._information_source - - @information_source.setter - def information_source(self, value): - self._set_var(InformationSource, try_cast=False, information_source=value) - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.title = obj.Title - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) - return_obj.handling = Marking.from_obj(obj.Handling) - return_obj.information_source = InformationSource.from_obj(obj.Information_Source) - return_obj.intents = _ReportIntents.from_obj(obj.Intent) - - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - super(Header, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding.HeaderType() - - if self.title: - return_obj.Title = self.title - if self.intents: - return_obj.Intent = self.intents.to_obj(ns_info=ns_info) - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.short_descriptions: - return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) - if self.handling: - return_obj.Handling = self.handling.to_obj(ns_info=ns_info) - if self.information_source: - return_obj.Information_Source = self.information_source.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - get = dict_repr.get - - return_obj.title = get('title') - return_obj.intents = _ReportIntents.from_list(get('intents')) - return_obj.descriptions = StructuredTextList.from_dict(get('description')) - return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) - return_obj.handling = Marking.from_dict(get('handling')) - return_obj.information_source = InformationSource.from_dict(get('information_source')) - - return return_obj - - def to_dict(self): - return super(Header, self).to_dict() - - -# NOT AN ACTUAL STIX TYPE! -class _ReportIntents(stix.TypedList): - _contained_type = VocabString - - def _fix_value(self, value): - return ReportIntent(value) diff --git a/stix/test/report_test.py b/stix/test/report_test.py index 8786d3d9..5ba9cf77 100644 --- a/stix/test/report_test.py +++ b/stix/test/report_test.py @@ -18,6 +18,7 @@ class HeaderTests(EntityTestCase, unittest.TestCase): 'short_description': 'A really, really short description', 'handling': data_marking_test.MarkingTests._full_dict, 'information_source': information_source_test.InformationSourceTests._full_dict, + 'intents': ["foo", "bar"] } def test_duplicate_package_intent(self): From 09f9832cc3833d361e71091fdc6ac54e3d3f575b Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 5 Oct 2015 21:28:04 -0400 Subject: [PATCH 218/438] More TypedFields updates. All data marking code is broken at the moment. Considering a EntityFactory class. --- stix/base.py | 4 +- stix/campaign/__init__.py | 2 +- stix/common/activity.py | 2 +- stix/common/confidence.py | 2 +- stix/common/information_source.py | 2 +- stix/common/tools.py | 2 +- stix/core/stix_header.py | 4 +- stix/data_marking.py | 259 +++++------------- stix/extensions/marking/tlp.py | 48 +--- .../test_mechanism/generic_test_mechanism.py | 2 +- stix/indicator/sightings.py | 2 +- 11 files changed, 81 insertions(+), 248 deletions(-) diff --git a/stix/base.py b/stix/base.py index 232bd18c..8cc21763 100644 --- a/stix/base.py +++ b/stix/base.py @@ -370,8 +370,8 @@ class BaseCoreComponent(Cached, Entity): title = fields.TypedField("Title") id_ = fields.IdField("id") idref = fields.IdrefField("idref") - descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList", key_name="description") - short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList", key_name="short_description") + descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList") + short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList") version = fields.TypedField("version", preset_hook=_validate_version) timestamp = fields.DateTimeField("timestamp") handling = fields.TypedField("Handling", type_="stix.data_marking.Marking") diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index ef970910..15d605d2 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -112,7 +112,7 @@ class Campaign(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'campaign' - descriptions = fields.TypedField("Description", StructuredTextList, key_name="description") + descriptions = fields.TypedField("Description", StructuredTextList) activity = fields.TypedField("Activity", Activity, multiple=True) associated_campaigns = fields.TypedField("Associated_Campaigns", AssociatedCampaigns) attribution = fields.TypedField("Attribution", Attribution, multiple=True) diff --git a/stix/common/activity.py b/stix/common/activity.py index af373a53..1ed5c2ab 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -17,7 +17,7 @@ class Activity(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' date_time = fields.TypedField("Date_Time", DateTimeWithPrecision) - descriptions = fields.TypedField("Description", StructuredTextList, key_name="description") + descriptions = fields.TypedField("Description", StructuredTextList) def __init__(self): super(Activity, self).__init__() diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 33e6aa86..acc1f44b 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -19,7 +19,7 @@ class Confidence(stix.Entity): _binding_class = common_binding.ConfidenceType value = fields.TypedField("Value", VocabString) - descriptions = fields.TypedField("Description", StructuredTextList, key_name="description") + descriptions = fields.TypedField("Description", StructuredTextList) timestamp = fields.DateTimeField("timestamp") timestamp_precision = fields.TypedField("timestamp_precision", preset_hook=validate_precision) source = fields.TypedField("Source", type_="stix.common.InformationSource") diff --git a/stix/common/information_source.py b/stix/common/information_source.py index ee2bd5fb..5c2586c2 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -23,7 +23,7 @@ class InformationSource(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' identity = fields.TypedField("Identity", Identity) - descriptions = fields.TypedField("Description", StructuredTextList, key_name="description") + descriptions = fields.TypedField("Description", StructuredTextList) contributing_sources = fields.TypedField("Contributing_Sources", type_="stix.common.information_source.ContributingSources") time = fields.TypedField("Time", cybox.common.Time) roles = fields.TypedField("Role", VocabString, multiple=True, key_name="roles") diff --git a/stix/common/tools.py b/stix/common/tools.py index 209907b7..6ec44a4d 100644 --- a/stix/common/tools.py +++ b/stix/common/tools.py @@ -19,7 +19,7 @@ class ToolInformation(stix.Entity, cybox.common.ToolInformation): _binding_class = common_binding.ToolInformationType title = fields.TypedField("Title") - short_descriptions = fields.TypedField("Short_Description", StructuredTextList, key_name="short_description") + short_descriptions = fields.TypedField("Short_Description", StructuredTextList) def __init__(self, title=None, short_description=None, tool_name=None, tool_vendor=None): super(ToolInformation, self).__init__(tool_name=tool_name, tool_vendor=tool_vendor) diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index 9deede08..8a4d0a27 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -38,8 +38,8 @@ class STIXHeader(stix.Entity): title = fields.TypedField("Title", preset_hook=deprecated.field) package_intents = VocabField("Package_Intent", PackageIntent, multiple=True, preset_hook=deprecated.field) - descriptions = fields.TypedField("Description", type_=StructuredTextList, key_name="description", preset_hook=deprecated.field) - short_descriptions = fields.TypedField("Short_Description", type_=StructuredTextList, key_name="short_description", preset_hook=deprecated.field) + descriptions = fields.TypedField("Description", type_=StructuredTextList, preset_hook=deprecated.field) + short_descriptions = fields.TypedField("Short_Description", type_=StructuredTextList, preset_hook=deprecated.field) handling = fields.TypedField("Handling", Marking) information_source = fields.TypedField("Information_Source", InformationSource) profiles = fields.TypedField("Profiles", Profiles) diff --git a/stix/data_marking.py b/stix/data_marking.py index ecb2c5f3..c6fc6593 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -13,193 +13,31 @@ import stix.bindings.data_marking as stix_data_marking_binding -class Marking(stix.Entity): - _binding = stix_data_marking_binding - _binding_class = stix_data_marking_binding.MarkingType - _namespace = 'http://data-marking.mitre.org/Marking-1' - - def __init__(self, markings=None): - self.markings = _MarkingSpecifications(markings) - - @property - def markings(self): - return self._markings - - @markings.setter - def markings(self, value): - self._markings = _MarkingSpecifications(value) - - def add_marking(self, value): - self._markings.append(value) - - def to_obj(self, ns_info=None): - obj = super(Marking, self).to_obj(ns_info=ns_info) - - if self.markings: - obj.Marking = self.markings.to_obj(ns_info=ns_info) - - return obj - - def to_list(self): - return self.markings.to_list() if self.markings else [] - - @classmethod - def from_obj(cls, obj): - if not obj: - return None - - obj = super(Marking, cls).from_obj(obj) - obj.markings = _MarkingSpecifications.from_obj(obj.Marking) - return obj - - @classmethod - def from_list(cls, markings_list): - if not markings_list: - return None - - obj = cls() - mlist = _MarkingSpecifications.from_list(markings_list) - obj.markings = mlist - return obj - - to_dict = to_list - from_dict = from_list - - -class MarkingSpecification(Cached, stix.Entity): - _binding = stix_data_marking_binding - _binding_class = stix_data_marking_binding.MarkingSpecificationType - _namespace = 'http://data-marking.mitre.org/Marking-1' - - def __init__(self, controlled_structure=None, marking_structures=None): - super(MarkingSpecification, self).__init__() - - self.id_ = None - self.idref = None - self.version = None - self.controlled_structure = controlled_structure - self.marking_structures = _MarkingStructures(marking_structures) - self.information_source = None - - @property - def information_source(self): - return self._information_source - - @information_source.setter - def information_source(self, value): - self._set_var(InformationSource, try_cast=False, information_source=value) - - @property - def marking_structures(self): - return self._marking_structures - - @marking_structures.setter - def marking_structures(self, value): - self._marking_structures = _MarkingStructures(value) - - def to_obj(self, return_obj=None, ns_info=None): - super(MarkingSpecification, self).to_obj( - return_obj=return_obj, - ns_info=ns_info - ) - - obj = self._binding_class() - - obj.id = self.id_ - obj.idref = self.idref - obj.version = self.version - obj.Controlled_Structure = self.controlled_structure - obj.Marking_Structure = self.marking_structures.to_obj(ns_info=ns_info) - - if self.information_source: - obj.Information_Source = self.information_source.to_obj(ns_info=ns_info) - - return obj - - def to_dict(self): - return super(MarkingSpecification, self).to_dict() - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.id_ = obj.id - return_obj.idref = obj.idref - return_obj.version = obj.version - return_obj.controlled_structure = obj.Controlled_Structure - return_obj.marking_structures = _MarkingStructures.from_obj(obj.Marking_Structure) - return_obj.information_source = InformationSource.from_obj(obj.Information_Source) - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if not return_obj: - return_obj = cls() - - get = d.get # PEP8 line length fix - return_obj.id_ = get('id') - return_obj.idref = get('idref') - return_obj.version = get('version') - return_obj.controlled_structure = get('controlled_structure') - return_obj.marking_structures = _MarkingStructures.from_dict( - get('marking_structures') - ) - return_obj.information_source = InformationSource.from_dict( - get('information_source') - ) - - return return_obj - - class MarkingStructure(Cached, stix.Entity): _binding = stix_data_marking_binding _binding_class = stix_data_marking_binding.MarkingStructureType _namespace = 'http://data-marking.mitre.org/Marking-1' _XSI_TYPE = None # overridden by subclasses + id_ = fields.IdField("id") + idref = fields.IdrefField("idref") + marking_model_name = fields.TypedField("marking_model_name") + marking_mode_ref = fields.TypedField("marking_model_ref") + def __init__(self): + super(MarkingStructure, self).__init__() + self.id_ = None self.idref = None self.marking_model_name = None self.marking_model_ref = None - def to_obj(self, return_obj=None, ns_info=None): - super(MarkingStructure, self).to_obj( - return_obj=return_obj, - ns_info=ns_info - ) - - if not return_obj: - return_obj = self._binding_class() - - return_obj.id = self.id_ - return_obj.idref = self.idref - return_obj.marking_model_name = self.marking_model_name - return_obj.marking_model_ref = self.marking_model_ref - - return return_obj - def to_dict(self): - d = {} + d = super(MarkingStructure, self).to_dict() if self._XSI_TYPE: d['xsi:type'] = self._XSI_TYPE - if self.id_: - d['id'] = self.id_ - if self.idref: - d['idref'] = self.idref - if self.marking_model_name: - d['marking_model_name'] = self.marking_model_name - if self.marking_model_ref: - d['marking_model_ref'] = self.marking_model_ref - return d @staticmethod @@ -210,58 +48,95 @@ def lookup_class(xsi_type): return stix.lookup_extension(xsi_type) @classmethod - def from_obj(cls, obj, return_obj=None): + def from_obj(cls, cls_obj, partial=None): import stix.extensions.marking.tlp # noqa import stix.extensions.marking.simple_marking # noqa import stix.extensions.marking.terms_of_use_marking # noqa - if not obj: + if not cls_obj: return None - if return_obj: - m = return_obj - m.id_ = obj.id - m.idref = obj.idref - m.marking_model_name = obj.marking_model_name - m.marking_model_ref = obj.marking_model_ref + if partial: + m = partial + m.id_ = cls_obj.id + m.idref = cls_obj.idref + m.marking_model_name = cls_obj.marking_model_name + m.marking_model_ref = cls_obj.marking_model_ref else: - klass = stix.lookup_extension(obj, default=cls) - m = klass.from_obj(obj, return_obj=klass()) + klass = stix.lookup_extension(cls_obj, default=cls) + m = klass.from_obj(cls_obj, klass()) return m @classmethod - def from_dict(cls, d, return_obj=None): + def from_dict(cls, cls_dict, partial=None): import stix.extensions.marking.tlp # noqa import stix.extensions.marking.simple_marking # noqa import stix.extensions.marking.terms_of_use_marking # noqa - - if not d: + + if not cls_dict: return None - get = d.get - - if return_obj is not None: - m = return_obj + get = cls_dict.get + + if partial is not None: + m = partial m.id_ = get('id') m.idref = get('idref') m.marking_model_name = get('marking_model_name') m.marking_model_ref = get('marking_model_ref') else: klass = stix.lookup_extension(get('xsi:type'), default=cls) - m = klass.from_dict(d, return_obj=klass()) + m = klass.from_dict(cls_dict, klass()) return m -# Not Actual STIX Types! -class _MarkingSpecifications(stix.TypedList): +class MarkingSpecification(Cached, stix.Entity): + _binding = stix_data_marking_binding + _binding_class = stix_data_marking_binding.MarkingSpecificationType + _namespace = 'http://data-marking.mitre.org/Marking-1' + + id_ = fields.IdField("id") + idref = fields.IdrefField("idref") + version = fields.TypedField("version") + controlled_structure = fields.TypedField("Controlled_Structure") + marking_structures = fields.TypedField("Marking_Structure", MarkingStructure, multiple=True, key_name="marking_structures") + information_source = fields.TypedField("Information_Source", InformationSource) + + def __init__(self, controlled_structure=None, marking_structures=None): + super(MarkingSpecification, self).__init__() + + self.id_ = None + self.idref = None + self.version = None + self.controlled_structure = controlled_structure + self.marking_structures = marking_structures + self.information_source = None + + +class Marking(stix.EntityList): + _binding = stix_data_marking_binding + _binding_class = stix_data_marking_binding.MarkingType + _namespace = 'http://data-marking.mitre.org/Marking-1' _contained_type = MarkingSpecification + _binding_var = "Marking" + + def __init__(self, markings=None): + super(Marking, self).__init__(markings) + @property + def markings(self): + return self._inner + + @markings.setter + def markings(self, value): + self._inner = [] + self.extend(value) -class _MarkingStructures(stix.TypedList): - _contained_type = MarkingStructure + def add_marking(self, value): + self.markings.append(value) # Backwards compatibility diff --git a/stix/extensions/marking/tlp.py b/stix/extensions/marking/tlp.py index a9870c42..5b8b732c 100644 --- a/stix/extensions/marking/tlp.py +++ b/stix/extensions/marking/tlp.py @@ -1,5 +1,6 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields import stix from stix.data_marking import MarkingStructure @@ -13,51 +14,8 @@ class TLPMarkingStructure(MarkingStructure): _namespace = 'http://data-marking.mitre.org/extensions/MarkingStructure#TLP-1' _XSI_TYPE = "tlpMarking:TLPMarkingStructureType" + color = fields.TypedField("color") + def __init__(self, color=None): super(TLPMarkingStructure, self).__init__() self.color = color - - def to_obj(self, return_obj=None, ns_info=None): - super(TLPMarkingStructure, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - MarkingStructure.to_obj(self, return_obj=return_obj, ns_info=ns_info) - return_obj.color = self.color - - return return_obj - - def to_dict(self): - d = MarkingStructure.to_dict(self) - if self.color: - d['color'] = self.color - - return d - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - MarkingStructure.from_obj(obj, return_obj=return_obj) - return_obj.color = obj.color - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - - if not return_obj: - return_obj = cls() - - MarkingStructure.from_dict(d, return_obj) - return_obj.color = d.get('color') - - return return_obj - diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index ab930c7b..e8450f1f 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -17,7 +17,7 @@ class GenericTestMechanism(_BaseTestMechanism): _XSI_TYPE = "genericTM:GenericTestMechanismType" reference_location = fields.TypedField("Reference_Location") - descriptions = fields.TypedField("Description", StructuredTextList, key_name="description") + descriptions = fields.TypedField("Description", StructuredTextList) specification = fields.TypedField("Specification", EncodedCDATA) type_ = fields.TypedField("type", VocabString, key_name="type") diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index 532dec68..087ed39c 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -19,7 +19,7 @@ class Sighting(stix.Entity): timestamp = fields.DateTimeField("timestamp") timestamp_precision = fields.TypedField("timestamp_precision", preset_hook=validate_precision) - descriptions = fields.TypedField("Description", StructuredTextList, key_name="description") + descriptions = fields.TypedField("Description", StructuredTextList) source = fields.TypedField("Source", InformationSource) reference = fields.TypedField("Reference") confidence = fields.TypedField("Confidence", Confidence) From e2d1e002de445f2c804ea1aba580a3ea6a3e04bb Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 6 Oct 2015 08:47:53 -0400 Subject: [PATCH 219/438] Added MarkingStructureFactory class to data_marking module. Refactored data marking extensions to use typed fields. --- stix/common/confidence.py | 1 + stix/data_marking.py | 62 ++++--------------- stix/extensions/marking/simple_marking.py | 49 ++------------- .../marking/terms_of_use_marking.py | 49 ++------------- 4 files changed, 21 insertions(+), 140 deletions(-) diff --git a/stix/common/confidence.py b/stix/common/confidence.py index acc1f44b..9ffaa159 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -13,6 +13,7 @@ from .structured_text import StructuredTextList from .datetimewithprecision import validate_precision + class Confidence(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' _binding = common_binding diff --git a/stix/data_marking.py b/stix/data_marking.py index c6fc6593..f4e03cb3 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -3,6 +3,7 @@ # external from mixbox import fields +from mixbox import entities from mixbox.cache import Cached # internal @@ -13,6 +14,15 @@ import stix.bindings.data_marking as stix_data_marking_binding +class MarkingStructureFactory(entities.EntityFactory): + @classmethod + def entity_class(cls, key): + import stix.extensions.marking.tlp # noqa + import stix.extensions.marking.simple_marking # noqa + import stix.extensions.marking.terms_of_use_marking # noqa + return stix.lookup_extension(key, default=MarkingStructure) + + class MarkingStructure(Cached, stix.Entity): _binding = stix_data_marking_binding _binding_class = stix_data_marking_binding.MarkingStructureType @@ -42,55 +52,7 @@ def to_dict(self): @staticmethod def lookup_class(xsi_type): - if not xsi_type: - return MarkingStructure - - return stix.lookup_extension(xsi_type) - - @classmethod - def from_obj(cls, cls_obj, partial=None): - import stix.extensions.marking.tlp # noqa - import stix.extensions.marking.simple_marking # noqa - import stix.extensions.marking.terms_of_use_marking # noqa - - if not cls_obj: - return None - - if partial: - m = partial - m.id_ = cls_obj.id - m.idref = cls_obj.idref - m.marking_model_name = cls_obj.marking_model_name - m.marking_model_ref = cls_obj.marking_model_ref - - else: - klass = stix.lookup_extension(cls_obj, default=cls) - m = klass.from_obj(cls_obj, klass()) - - return m - - @classmethod - def from_dict(cls, cls_dict, partial=None): - import stix.extensions.marking.tlp # noqa - import stix.extensions.marking.simple_marking # noqa - import stix.extensions.marking.terms_of_use_marking # noqa - - if not cls_dict: - return None - - get = cls_dict.get - - if partial is not None: - m = partial - m.id_ = get('id') - m.idref = get('idref') - m.marking_model_name = get('marking_model_name') - m.marking_model_ref = get('marking_model_ref') - else: - klass = stix.lookup_extension(get('xsi:type'), default=cls) - m = klass.from_dict(cls_dict, klass()) - - return m + return stix.lookup_extension(xsi_type, default=MarkingStructure) class MarkingSpecification(Cached, stix.Entity): @@ -102,7 +64,7 @@ class MarkingSpecification(Cached, stix.Entity): idref = fields.IdrefField("idref") version = fields.TypedField("version") controlled_structure = fields.TypedField("Controlled_Structure") - marking_structures = fields.TypedField("Marking_Structure", MarkingStructure, multiple=True, key_name="marking_structures") + marking_structures = fields.TypedField("Marking_Structure", MarkingStructure, factory=MarkingStructureFactory, multiple=True, key_name="marking_structures") information_source = fields.TypedField("Information_Source", InformationSource) def __init__(self, controlled_structure=None, marking_structures=None): diff --git a/stix/extensions/marking/simple_marking.py b/stix/extensions/marking/simple_marking.py index b3fafbba..bcf41193 100644 --- a/stix/extensions/marking/simple_marking.py +++ b/stix/extensions/marking/simple_marking.py @@ -1,6 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + import stix from stix.data_marking import MarkingStructure import stix.bindings.extensions.marking.simple_marking as simple_marking_binding @@ -13,51 +15,8 @@ class SimpleMarkingStructure(MarkingStructure): _namespace = 'http://data-marking.mitre.org/extensions/MarkingStructure#Simple-1' _XSI_TYPE = "simpleMarking:SimpleMarkingStructureType" + statement = fields.TypedField("Statement") + def __init__(self, statement=None): super(SimpleMarkingStructure, self).__init__() self.statement = statement - - def to_obj(self, return_obj=None, ns_info=None): - super(SimpleMarkingStructure, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - MarkingStructure.to_obj(self, return_obj=return_obj, ns_info=ns_info) - return_obj.Statement = self.statement - - return return_obj - - def to_dict(self): - d = MarkingStructure.to_dict(self) - if self.statement: - d['statement'] = self.statement - - return d - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - MarkingStructure.from_obj(obj, return_obj) - return_obj.statement = obj.Statement - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - - if not return_obj: - return_obj = cls() - - MarkingStructure.from_dict(d, return_obj=return_obj) - return_obj.statement = d.get('statement') - - return return_obj - diff --git a/stix/extensions/marking/terms_of_use_marking.py b/stix/extensions/marking/terms_of_use_marking.py index 37b25cb5..2df6ea1d 100644 --- a/stix/extensions/marking/terms_of_use_marking.py +++ b/stix/extensions/marking/terms_of_use_marking.py @@ -1,6 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + import stix from stix.data_marking import MarkingStructure import stix.bindings.extensions.marking.terms_of_use_marking as tou_marking_binding @@ -13,51 +15,8 @@ class TermsOfUseMarkingStructure(MarkingStructure): _namespace = 'http://data-marking.mitre.org/extensions/MarkingStructure#Terms_Of_Use-1' _XSI_TYPE = "TOUMarking:TermsOfUseMarkingStructureType" + terms_of_use = fields.TypedField("Terms_Of_Use") + def __init__(self, terms_of_use=None): super(TermsOfUseMarkingStructure, self).__init__() self.terms_of_use = terms_of_use - - def to_obj(self, return_obj=None, ns_info=None): - super(TermsOfUseMarkingStructure, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - MarkingStructure.to_obj(self, return_obj=return_obj, ns_info=ns_info) - return_obj.Terms_Of_Use = self.terms_of_use - - return return_obj - - def to_dict(self): - d = MarkingStructure.to_dict(self) - - if self.terms_of_use: - d['terms_of_use'] = self.terms_of_use - - return d - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - MarkingStructure.from_obj(obj, return_obj=return_obj) - return_obj.terms_of_use = obj.Terms_Of_Use - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - - if not return_obj: - return_obj = cls() - - MarkingStructure.from_dict(d, return_obj) - return_obj.terms_of_use = d.get('terms_of_use') - - return return_obj From 585006452c4d1b1725306430e818d519d9147340 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 6 Oct 2015 10:39:40 -0400 Subject: [PATCH 220/438] Made _BaseRelated and subclasses use TypedFields for item member. Removed _contained_type setting hikinks from common/__init__.py --- stix/common/__init__.py | 31 --------- stix/common/related.py | 145 ++++++++++------------------------------ 2 files changed, 35 insertions(+), 141 deletions(-) diff --git a/stix/common/__init__.py b/stix/common/__init__.py index 520376e0..6ce767c8 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -26,41 +26,10 @@ RelatedReport ) -# Patch in base types of Related* types -from stix.core import STIXPackage -from cybox.core import Observable -from stix.campaign import Campaign -from stix.coa import CourseOfAction -from stix.exploit_target import ExploitTarget -from stix.incident import Incident -from stix.indicator import Indicator -from stix.report import Report -from stix.threat_actor import ThreatActor -from stix.ttp import TTP - - -RelatedCampaign._base_type = Campaign # noqa -RelatedCOA._base_type = CourseOfAction # noqa -RelatedExploitTarget._base_type = ExploitTarget # noqa -RelatedIdentity._base_type = Identity # noqa -RelatedIncident._base_type = Incident # noqa -RelatedIndicator._base_type = Indicator # noqa -RelatedThreatActor._base_type = ThreatActor # noqa -RelatedTTP._base_type = TTP # noqa -RelatedObservable._base_type = Observable # noqa -RelatedPackage._base_type = STIXPackage # noqa -RelatedReport._base_type = Report # noqa -RelatedCampaignRef._base_type = CampaignRef # noqa - -# Patch contained types -RelatedPackages._contained_type = RelatedPackage # noqa -RelatedReports._contained_type = RelatedReport # noqa - import stix import stix.utils as utils import stix.bindings.stix_common as common_binding - class EncodedCDATA(stix.Entity): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding diff --git a/stix/common/related.py b/stix/common/related.py index 6cec9ebe..c992c74b 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -1,6 +1,7 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields +from cybox.core import Observable # internal import stix @@ -12,7 +13,7 @@ from stix.utils import deprecated # relative -from .vocabs import VocabString, VocabField +from .vocabs import VocabField from .information_source import InformationSource from .confidence import Confidence @@ -106,24 +107,6 @@ def __nonzero__(self): bool(self.scope)) -class RelatedPackages(GenericRelationshipList): - _namespace = 'http://stix.mitre.org/stix-1' - _binding = core_binding - _binding_class = core_binding.RelatedPackagesType - _binding_var = "Related_Package" - # _contained_type is patched in common/__init__.py - _inner_name = "related_packages" - - -class RelatedReports(GenericRelationshipList): - _namespace = 'http://stix.mitre.org/Report-1' - _binding = report_binding - _binding_class = report_binding.RelatedReportsType - _binding_var = "Related_Report" - # _contained_type is patched in common/__init__.py - _inner_name = "related_reports" - - class RelatedPackageRefs(stix.EntityList): _namespace = 'http://stix.mitre.org/common-1' _binding = common_binding @@ -152,15 +135,10 @@ class _BaseRelated(GenericRelationship): """A base class for related types. This class is not a real STIX type and should not be directly instantiated. - """ - # Subclasses should define - # - _base_type - # - _inner_var (This is the name of the contained XML element, and the - # lowercase version is used for the key name in the - # dictionary representation). - _base_type = None - _inner_var = None + Note: + Subclasses must supply a TypedField named `item`! + """ def __init__(self, item=None, confidence=None, information_source=None, relationship=None): @@ -172,155 +150,102 @@ def __init__(self, item=None, confidence=None, ) self.item = item - @property - def item(self): - return self._item - - @item.setter - def item(self, value): - self._set_item(value) - - def _set_item(self, value): - if value and not isinstance(value, self._base_type): - error = "Value must be instance of %s" % self._base_type.__name__ - raise ValueError(error) - - self._item = value - - def to_obj(self, ns_info=None): - obj = super(_BaseRelated, self).to_obj(ns_info=ns_info) - - if self.item: - setattr(obj, self._inner_var, self.item.to_obj(ns_info=ns_info)) - - return obj - - def to_dict(self): - d = super(_BaseRelated, self).to_dict() - - if self.item: - d[self._inner_var.lower()] = self.item.to_dict() - - return d - - @classmethod - def from_obj(cls, cls_obj): - if not cls_obj: - return None - - obj = super(_BaseRelated, cls).from_obj(cls_obj) - contained_item = getattr(cls_obj, cls._inner_var) - obj.item = cls._base_type.from_obj(contained_item) - - return obj - - @classmethod - def from_dict(cls, cls_dict): - if not cls_dict: - return None - - obj = super(_BaseRelated, cls).from_dict(cls_dict) - contained_item = cls_dict.get(cls._inner_var.lower()) - obj.item = cls._base_type.from_dict(contained_item) - - return obj - class RelatedCampaign(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedCampaignType - # _base_type is set in common/__init__.py - _inner_var = "Campaign" + item = fields.TypedField("Campaign", type_="stix.campaign.Campaign") class RelatedCOA(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedCourseOfActionType - # _base_type is set in common/__init__.py - _inner_var = "Course_Of_Action" + item = fields.TypedField("Course_Of_Action", type_="stix.coa.CourseOfAction") class RelatedExploitTarget(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedExploitTargetType - # _base_type is set in common/__init__.py - _inner_var = "Exploit_Target" + item = fields.TypedField("Exploit_Target", type_="stix.exploit_target.ExploitTarget") class RelatedIdentity(_BaseRelated): _namespace = 'http://stix.mitre.org/common-1' _binding = common_binding _binding_class = common_binding.RelatedIdentityType - # _base_type is set in common/__init__.py - _inner_var = "Identity" + item = fields.TypedField("Identity", type_="stix.common.identity.Identity", factory="stix.common.identity.IdentityFactory") class RelatedIncident(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedIncidentType - # _base_type is set in common/__init__.py - _inner_var = "Incident" - + item = fields.TypedField("Incident", type_="stix.incident.Incident") class RelatedIndicator(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedIndicatorType - # _base_type is set in common/__init__.py - _inner_var = "Indicator" + item = fields.TypedField("Indicator", type_="stix.indicator.Indicator") class RelatedObservable(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedObservableType - # _base_type is set in common/__init__.py - _inner_var = "Observable" - + item = fields.TypedField("Observable", type_=Observable) class RelatedThreatActor(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedThreatActorType - # _base_type is set in common/__init__.py - _inner_var = "Threat_Actor" + item = fields.TypedField("ThreatActor", type_="stix.threat_actor.ThreatActor") class RelatedTTP(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedTTPType - # _base_type is set in common/__init__.py - _inner_var = "TTP" + item = fields.TypedField("TTP", type_="stix.ttp.TTP") class RelatedPackage(_BaseRelated): _namespace = "http://stix.mitre.org/stix-1" _binding = core_binding _binding_class = core_binding.RelatedPackageType - # _base_type is set in common/__init__.py - _inner_var = "Package" + item = fields.TypedField("Package", type_="stix.core.STIXPackage", preset_hook=deprecated.field) - @_BaseRelated.item.setter - def item(self, value): - deprecated.idref(value) - _BaseRelated.item.fset(self, value) class RelatedReport(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedReportType - # _base_type is set in common/__init__.py - _inner_var = "Report" + item = fields.TypedField("Report", type_="stix.report.Report") class RelatedCampaignRef(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = _binding.RelatedCampaignReferenceType - # _base_type is set in common/__init__.py - _inner_var = "Campaign" + item = fields.TypedField("Campaign", type_="stix.common.CampaignRef") + + +class RelatedPackages(GenericRelationshipList): + _namespace = 'http://stix.mitre.org/stix-1' + _binding = core_binding + _binding_class = core_binding.RelatedPackagesType + _binding_var = "Related_Package" + _contained_type = RelatedPackage + _inner_name = "related_packages" + + +class RelatedReports(GenericRelationshipList): + _namespace = 'http://stix.mitre.org/Report-1' + _binding = report_binding + _binding_class = report_binding.RelatedReportsType + _binding_var = "Related_Report" + _contained_type = RelatedReport + _inner_name = "related_reports" From a643e384052d87649a1ed8195b4411d2a7c41542 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 6 Oct 2015 10:40:03 -0400 Subject: [PATCH 221/438] Added IdentityFactory to stix.common.identity --- stix/common/identity.py | 54 +++----------------- stix/common/information_source.py | 4 +- stix/extensions/identity/ciq_identity_3_0.py | 33 ++++-------- stix/incident/__init__.py | 6 +-- stix/indicator/indicator.py | 5 +- stix/ttp/resource.py | 4 -- 6 files changed, 27 insertions(+), 79 deletions(-) diff --git a/stix/common/identity.py b/stix/common/identity.py index d36c55b3..03e1a2cf 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -3,6 +3,7 @@ # external from mixbox import fields +from mixbox import entities from mixbox.cache import Cached # internal @@ -11,6 +12,13 @@ from stix.bindings.stix_common import IdentityType +class IdentityFactory(entities.EntityFactory): + @classmethod + def entity_class(cls, key): + import stix.extensions.identity.ciq_identity_3_0 # noqa + return stix.lookup_extension(key, default=Identity) + + class Identity(Cached, stix.Entity): _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' @@ -29,52 +37,6 @@ def __init__(self, id_=None, idref=None, name=None, related_identities=None): self.name = name self.related_identities = related_identities - @staticmethod - def lookup_class(xsi_type): - if not xsi_type: - raise ValueError("xsi:type is required") - - return stix.lookup_extension(xsi_type) - - @classmethod - def from_obj(cls, obj, partial=None): - import stix.extensions.identity.ciq_identity_3_0 # noqa - - if not obj: - return None - - if not partial: - klass = stix.lookup_extension(obj, default=cls) - partial = klass.from_obj(obj, partial=klass()) - else: - partial.id_ = obj.id - partial.idref = obj.idref - partial.name = obj.Name - partial.related_identities = RelatedIdentities.from_obj(obj.Related_Identities) - - return partial - - @classmethod - def from_dict(cls, cls_dict, partial=None): - import stix.extensions.identity.ciq_identity_3_0 # noqa - - if not cls_dict: - return None - - get = cls_dict.get - - if not partial: - klass = stix.lookup_extension(get('xsi:type'), default=cls) - partial = klass.from_dict(cls_dict, klass()) - else: - partial.name = get('name') - partial.id_ = get('id') - partial.idref = get('idref') - partial.related_identities = \ - RelatedIdentities.from_dict(get('related_identities')) - - return partial - # We can't import RelatedIdentity until we have defined the Identity class. from stix.common.related import RelatedIdentity diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 5c2586c2..8f1d0b75 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -13,7 +13,7 @@ # relative from .vocabs import VocabString from .references import References -from .identity import Identity +from .identity import Identity, IdentityFactory from .structured_text import StructuredTextList @@ -22,7 +22,7 @@ class InformationSource(stix.Entity): _binding_class = stix_common_binding.InformationSourceType _namespace = 'http://stix.mitre.org/common-1' - identity = fields.TypedField("Identity", Identity) + identity = fields.TypedField("Identity", type_=Identity, factory=IdentityFactory) descriptions = fields.TypedField("Description", StructuredTextList) contributing_sources = fields.TypedField("Contributing_Sources", type_="stix.common.information_source.ContributingSources") time = fields.TypedField("Time", cybox.common.Time) diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index e20e6185..12672466 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -65,45 +65,34 @@ def specification(self, value): self._specification = value - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(CIQIdentity3_0Instance, self).to_obj(return_obj) - - # return_obj.id = self.id_ - # return_obj.idref = self.idref_ - return_obj.xsi_type = self._XSI_TYPE + def to_obj(self, ns_info=None): + obj = super(CIQIdentity3_0Instance, self).to_obj() + obj.xsi_type = self._XSI_TYPE if self.roles: for role in self.roles: - return_obj.add_Role(role) + obj.add_Role(role) if self.specification: - return_obj.Specification = self.specification.to_obj(ns_info=ns_info) + obj.Specification = self.specification.to_obj(ns_info=ns_info) - return return_obj + return obj @classmethod - def from_obj(cls, obj, return_obj=None): - if obj is None: - return None - if not return_obj: - return_obj = cls() - - super(CIQIdentity3_0Instance, cls).from_obj(obj, return_obj) + def from_obj(cls, cls_obj): + obj = super(CIQIdentity3_0Instance, cls).from_obj(cls_obj) roles = obj.Role specification = obj.Specification if roles: for role in roles: - return_obj.add_role(role) + obj.add_role(role) if specification is not None: - return_obj.specification = STIXCIQIdentity3_0.from_obj(specification) + obj.specification = STIXCIQIdentity3_0.from_obj(specification) - return return_obj + return obj def to_dict(self): d = super(CIQIdentity3_0Instance, self).to_dict() diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index 8ed12834..5bd3ea48 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -5,8 +5,8 @@ import stix import stix.bindings.incident as incident_binding from stix.common import vocabs -from stix.common import (Identity, Statement, VocabString, InformationSource, - Confidence) +from stix.common import Statement, VocabString, InformationSource, Confidence +from stix.common.identity import Identity, IdentityFactory from stix.common.related import (GenericRelationshipList, RelatedIndicator, RelatedThreatActor, RelatedTTP, RelatedObservable, RelatedIncident, RelatedPackageRefs) @@ -47,7 +47,7 @@ class Incident(stix.BaseCoreComponent): status = fields.TypedField("Status", vocabs.IncidentStatus) time = fields.TypedField("Time", Time) - victims = fields.TypedField("Victim", Identity, multiple=True, key_name="victims") + victims = fields.TypedField("Victim", Identity, factory=IdentityFactory, multiple=True, key_name="victims") attributed_threat_actors = fields.TypedField("Attributed_Threat_Actors", type_="stix.incident.AttributedThreatActors") related_indicators = fields.TypedField("Related_Indicators", type_="stix.incident.RelatedIndicators") related_observables = fields.TypedField("Related_Observables", type_="stix.incident.RelatedObservables") diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index fd20ba35..bca12adc 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -9,8 +9,9 @@ # internal import stix -from stix.common import (Identity, InformationSource, VocabString, Confidence, - RelatedTTP, Statement, CampaignRef) +from stix.common.identity import Identity +from stix.common import (InformationSource, VocabString, Confidence, RelatedTTP, + Statement, CampaignRef) from stix.common.related import (GenericRelationshipList, RelatedCOA, RelatedIndicator, RelatedCampaignRef, RelatedPackageRefs) from stix.common.vocabs import IndicatorType diff --git a/stix/ttp/resource.py b/stix/ttp/resource.py index ce63576e..e468c86a 100644 --- a/stix/ttp/resource.py +++ b/stix/ttp/resource.py @@ -105,8 +105,6 @@ class Personas(stix.EntityList): _binding = ttp_binding _binding_class = _binding.PersonasType _binding_var = "Persona" - _inner_name = "personas" - _dict_as_list = True def _fix_value(self, value): return Identity(name=value) @@ -118,5 +116,3 @@ class Tools(stix.EntityList): _binding = ttp_binding _binding_class = _binding.ToolsType _binding_var = "Tool" - _inner_name = "tools" - _dict_as_list = True From cf5d8263e7086fa498d286c726ac83d1ef4fffa5 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 6 Oct 2015 11:14:28 -0400 Subject: [PATCH 222/438] Added VocabFactory class to vocabs module. Refactored Vocabfield to use new TypedField capabilities. Implemented VocabField throughout stix.common package. --- stix/common/confidence.py | 4 +- stix/common/information_source.py | 4 +- stix/common/names.py | 3 +- stix/common/vocabs.py | 99 +++++++------------------------ 4 files changed, 28 insertions(+), 82 deletions(-) diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 9ffaa159..80907a5b 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -9,7 +9,7 @@ import stix.utils as utils import stix.bindings.stix_common as common_binding -from .vocabs import VocabString +from .vocabs import VocabField from .structured_text import StructuredTextList from .datetimewithprecision import validate_precision @@ -19,7 +19,7 @@ class Confidence(stix.Entity): _binding = common_binding _binding_class = common_binding.ConfidenceType - value = fields.TypedField("Value", VocabString) + value = VocabField("Value") descriptions = fields.TypedField("Description", StructuredTextList) timestamp = fields.DateTimeField("timestamp") timestamp_precision = fields.TypedField("timestamp_precision", preset_hook=validate_precision) diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 8f1d0b75..70b49c40 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -11,7 +11,7 @@ import stix.bindings.stix_common as stix_common_binding # relative -from .vocabs import VocabString +from .vocabs import VocabField from .references import References from .identity import Identity, IdentityFactory from .structured_text import StructuredTextList @@ -26,7 +26,7 @@ class InformationSource(stix.Entity): descriptions = fields.TypedField("Description", StructuredTextList) contributing_sources = fields.TypedField("Contributing_Sources", type_="stix.common.information_source.ContributingSources") time = fields.TypedField("Time", cybox.common.Time) - roles = fields.TypedField("Role", VocabString, multiple=True, key_name="roles") + roles = VocabField("Role", multiple=True, key_name="roles") tools = fields.TypedField("Tools", ToolInformationList) references = fields.TypedField("References", References) diff --git a/stix/common/names.py b/stix/common/names.py index 6136afe5..a65660f0 100644 --- a/stix/common/names.py +++ b/stix/common/names.py @@ -6,7 +6,7 @@ import stix.bindings.stix_common as common_binding # relative -from .vocabs import VocabString +from .vocabs import VocabString, VocabFactory class Names(stix.EntityList): @@ -14,4 +14,5 @@ class Names(stix.EntityList): _binding = common_binding _binding_class = _binding.NamesType _contained_type = VocabString + _entity_factory = VocabFactory _binding_var = 'Name' diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index fb244a92..8ce0b639 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -1,11 +1,12 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields +from mixbox import entities + import stix import stix.bindings.stix_common as stix_common_binding -from mixbox import fields - def validate_value(instance, value): allowed = instance._ALLOWED_VALUES @@ -37,40 +38,22 @@ def __init__(self, *args, **kwargs): """ super(VocabField, self).__init__(*args, **kwargs) + self.factory = VocabFactory # force this factory - if self.type_: - self.__vocab_impl = self.type_ - else: - self.__vocab_impl = VocabString - - # TODO: can we take this out. It shouldn't be necessary since type_ - # should always be a subclass of VocabString. - self.type_ = VocabString # Force this so from_dict/from_obj works. + if self.type_ is None: + self.type_ = VocabString - def _clean(self, value): - """Validate and clean a candidate value for this Vocab. This overrides - the ``_clean()`` method on :class:`.TypedField`. + def check_type(self, value): + return isinstance(value, VocabString) - 1) If the value is ``None``, return ``None`` - 2) If the value is an instance of ``VocabString``, return it. - 3) Attempt to cast the value to the default VocabString type if there - is one, else try to cast it to VocabString. - 4) raise a ValueError - - """ - vocab = self.__vocab_impl - - if value is None: - return None - elif isinstance(value, VocabString): - return value - elif vocab._try_cast: # noqa - return vocab(value) - - error_fmt = "%s must be a %s, not a %s" - error = error_fmt % (self.name, self.type_, type(value)) - raise ValueError(error) +class VocabFactory(entities.EntityFactory): + @classmethod + def entity_class(cls, key): + try: + return stix.lookup_extension(key, default=VocabString) + except ValueError: + return VocabString class VocabString(stix.Entity): @@ -112,13 +95,6 @@ def is_plain(self): self.vocab_reference is None ) - @staticmethod - def lookup_class(xsi_type): - try: - return stix.lookup_extension(xsi_type, default=VocabString) - except ValueError: - return VocabString - def to_dict(self): if self.is_plain(): return self.value @@ -126,47 +102,16 @@ def to_dict(self): @classmethod - def from_obj(cls, cls_obj, partial=None): - if not cls_obj: - return None - - if not partial: - klass = cls.lookup_class(cls_obj.xsi_type) - return klass.from_obj(cls_obj, partial=klass()) - - partial.value = cls_obj.valueOf_ - partial.vocab_name = cls_obj.vocab_name - partial.vocab_reference = cls_obj.vocab_reference - partial.xsi_type = cls_obj.xsi_type - - return partial - - @classmethod - def from_dict(cls, cls_dict, partial=None): + def from_dict(cls, cls_dict): if not cls_dict: - return None - - if not partial: - if isinstance(cls_dict, dict): - get = cls_dict.get - klass = cls.lookup_class(get('xsi:type')) - return klass.from_dict(cls_dict, partial=klass()) - else: - partial = cls() - - # xsi_type should be set automatically by the class's constructor. - - # In case this is a "plain" string, just set it. - if not isinstance(cls_dict, dict): - partial.value = cls_dict + vocab = None + elif not isinstance(cls_dict, dict): + vocab = cls() + vocab.value = cls_dict else: - get = cls_dict.get - partial.value = get('value') - partial.vocab_name = get('vocab_name') - partial.vocab_reference = get('vocab_reference') - partial.xsi_type = get('xsi:type') + vocab = super(VocabString, cls).from_dict(cls_dict) - return partial + return vocab def _get_terms(vocab_class): From f1e757004446f82b038d7133e4b079622964e88b Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 6 Oct 2015 19:01:45 -0400 Subject: [PATCH 223/438] Added xsi_type class attribute to all binding classes which defined xml_type and xmlns_prefix. This needs to match the corresponding API class _XSI_TYPE attribute value. --- stix/bindings/campaign.py | 1 + stix/bindings/course_of_action.py | 1 + stix/bindings/exploit_target.py | 1 + stix/bindings/extensions/address/ciq_address_3_0.py | 1 + stix/bindings/extensions/attack_pattern/capec_2_7.py | 1 + stix/bindings/extensions/identity/ciq_identity_3_0.py | 1 + stix/bindings/extensions/malware/maec_4_1.py | 1 + stix/bindings/extensions/marking/simple_marking.py | 1 + stix/bindings/extensions/marking/terms_of_use_marking.py | 1 + stix/bindings/extensions/marking/tlp.py | 1 + stix/bindings/extensions/structured_coa/generic.py | 1 + stix/bindings/extensions/test_mechanism/generic.py | 2 ++ stix/bindings/extensions/test_mechanism/open_ioc_2010.py | 1 + stix/bindings/extensions/test_mechanism/oval_5_10.py | 1 + stix/bindings/extensions/test_mechanism/snort.py | 1 + stix/bindings/extensions/test_mechanism/yara.py | 1 + stix/bindings/extensions/vulnerability/cvrf_1_1.py | 1 + stix/bindings/incident.py | 1 + stix/bindings/indicator.py | 1 + stix/bindings/report.py | 1 + stix/bindings/threat_actor.py | 1 + stix/bindings/ttp.py | 1 + 22 files changed, 23 insertions(+) diff --git a/stix/bindings/campaign.py b/stix/bindings/campaign.py index a6083434..2ca78168 100644 --- a/stix/bindings/campaign.py +++ b/stix/bindings/campaign.py @@ -447,6 +447,7 @@ class CampaignType(stix_common_binding.CampaignBaseType): xmlns = "http://stix.mitre.org/Campaign-1" xmlns_prefix = "campaign" xml_type = "CampaignType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None, Description=None, Short_Description=None, Names=None, Intended_Effect=None, Status=None, Related_TTPs=None, Related_Incidents=None, Related_Indicators=None, Attribution=None, Associated_Campaigns=None, Confidence=None, Activity=None, Information_Source=None, Handling=None, Related_Packages=None): super(CampaignType, self).__init__(idref=idref, id=id, timestamp=timestamp) diff --git a/stix/bindings/course_of_action.py b/stix/bindings/course_of_action.py index b6ef8862..d58fff71 100644 --- a/stix/bindings/course_of_action.py +++ b/stix/bindings/course_of_action.py @@ -225,6 +225,7 @@ class CourseOfActionType(stix_common_binding.CourseOfActionBaseType): xmlns = "http://stix.mitre.org/CourseOfAction-1" xmlns_prefix = "coa" xml_type = "CourseOfActionType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None, Stage=None, Type=None, Description=None, Short_Description=None, Objective=None, Parameter_Observables=None, Structured_COA=None, Impact=None, Cost=None, Efficacy=None, Information_Source=None, Handling=None, Related_COAs=None, Related_Packages=None): super(CourseOfActionType, self).__init__(idref=idref, id=id, timestamp=timestamp) diff --git a/stix/bindings/exploit_target.py b/stix/bindings/exploit_target.py index c4856181..5edb9870 100644 --- a/stix/bindings/exploit_target.py +++ b/stix/bindings/exploit_target.py @@ -768,6 +768,7 @@ class ExploitTargetType(stix_common_binding.ExploitTargetBaseType): xmlns = "http://stix.mitre.org/ExploitTarget-1" xmlns_prefix = "et" xml_type = "ExploitTargetType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None, Description=None, Short_Description=None, Vulnerability=None, Weakness=None, Configuration=None, Potential_COAs=None, Information_Source=None, Handling=None, Related_Exploit_Targets=None, Related_Packages=None): super(ExploitTargetType, self).__init__(timestamp=timestamp, idref=idref, id=id) diff --git a/stix/bindings/extensions/address/ciq_address_3_0.py b/stix/bindings/extensions/address/ciq_address_3_0.py index cd1e24de..b988cf01 100644 --- a/stix/bindings/extensions/address/ciq_address_3_0.py +++ b/stix/bindings/extensions/address/ciq_address_3_0.py @@ -33,6 +33,7 @@ class CIQAddress3_0InstanceType(stix_common_binding.AddressAbstractType): xmlns = XML_NS xmlns_prefix = "ciqAddress" xml_type = "CIQAddress3.0InstanceType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, Location=None): super(CIQAddress3_0InstanceType, self).__init__() diff --git a/stix/bindings/extensions/attack_pattern/capec_2_7.py b/stix/bindings/extensions/attack_pattern/capec_2_7.py index 6cc3aa0c..dc3171c3 100644 --- a/stix/bindings/extensions/attack_pattern/capec_2_7.py +++ b/stix/bindings/extensions/attack_pattern/capec_2_7.py @@ -32,6 +32,7 @@ class CAPEC2_7InstanceType(ttp_binding.AttackPatternType): xmlns = XML_NS xmlns_prefix = "capecInstance" xml_type = "CAPEC2.7InstanceType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, capec_id=None, Description=None, CAPEC=None): super(CAPEC2_7InstanceType, self).__init__(capec_id=capec_id, Description=Description) diff --git a/stix/bindings/extensions/identity/ciq_identity_3_0.py b/stix/bindings/extensions/identity/ciq_identity_3_0.py index 3c37c4b1..8b351b27 100644 --- a/stix/bindings/extensions/identity/ciq_identity_3_0.py +++ b/stix/bindings/extensions/identity/ciq_identity_3_0.py @@ -33,6 +33,7 @@ class CIQIdentity3_0InstanceType(stix_common_binding.IdentityType): xmlns = XML_NS xmlns_prefix = "ciqIdentity" xml_type = "CIQIdentity3.0InstanceType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, id=None, Name=None, Related_Identities=None, Specification=None, Role=None): super(CIQIdentity3_0InstanceType, self).__init__(idref=idref, id=id, Name=Name, Related_Identities=Related_Identities) diff --git a/stix/bindings/extensions/malware/maec_4_1.py b/stix/bindings/extensions/malware/maec_4_1.py index 552beed1..fce5c888 100644 --- a/stix/bindings/extensions/malware/maec_4_1.py +++ b/stix/bindings/extensions/malware/maec_4_1.py @@ -39,6 +39,7 @@ class MAEC4_1InstanceType(ttp_binding.MalwareInstanceType): xmlns = XML_NS xmlns_prefix = "stix-maec" xml_type = "MAEC4.1InstanceType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, Type=None, Name=None, Description=None, MAEC=None): super(MAEC4_1InstanceType, self).__init__(Type=Type, Name=Name, Description=Description) diff --git a/stix/bindings/extensions/marking/simple_marking.py b/stix/bindings/extensions/marking/simple_marking.py index 839ae146..4f98d790 100644 --- a/stix/bindings/extensions/marking/simple_marking.py +++ b/stix/bindings/extensions/marking/simple_marking.py @@ -33,6 +33,7 @@ class SimpleMarkingStructureType(data_marking_binding.MarkingStructureType): xmlns = XML_NS xmlns_prefix = "simpleMarking" xml_type = "SimpleMarkingStructureType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) subclass = None superclass = data_marking_binding.MarkingStructureType diff --git a/stix/bindings/extensions/marking/terms_of_use_marking.py b/stix/bindings/extensions/marking/terms_of_use_marking.py index d9d99551..a733910a 100644 --- a/stix/bindings/extensions/marking/terms_of_use_marking.py +++ b/stix/bindings/extensions/marking/terms_of_use_marking.py @@ -40,6 +40,7 @@ class TermsOfUseMarkingStructureType(data_marking_binding.MarkingStructureType): xmlns = XML_NS xmlns_prefix = "TOUMarking" xml_type = "TermsOfUseMarkingStructureType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, marking_model_ref=None, marking_model_name=None, id=None, Terms_Of_Use=None): super(TermsOfUseMarkingStructureType, self).__init__(idref=idref, marking_model_ref=marking_model_ref, marking_model_name=marking_model_name, id=id) diff --git a/stix/bindings/extensions/marking/tlp.py b/stix/bindings/extensions/marking/tlp.py index fecade54..8b37293b 100644 --- a/stix/bindings/extensions/marking/tlp.py +++ b/stix/bindings/extensions/marking/tlp.py @@ -33,6 +33,7 @@ class TLPMarkingStructureType(data_marking_binding.MarkingStructureType): xmlns = XML_NS xmlns_prefix = "tlpMarking" xml_type = "TLPMarkingStructureType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) subclass = None superclass = data_marking_binding.MarkingStructureType diff --git a/stix/bindings/extensions/structured_coa/generic.py b/stix/bindings/extensions/structured_coa/generic.py index 3ba383dd..0f9cf9ed 100644 --- a/stix/bindings/extensions/structured_coa/generic.py +++ b/stix/bindings/extensions/structured_coa/generic.py @@ -34,6 +34,7 @@ class GenericStructuredCOAType(StructuredCOAType): xmlns = XML_NS xmlns_prefix = "genericStructuredCOA" xml_type = "GenericStructuredCOAType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, id=None, reference_location=None, Description=None, Type=None, Specification=None): super(GenericStructuredCOAType, self).__init__(idref=idref, id=id) diff --git a/stix/bindings/extensions/test_mechanism/generic.py b/stix/bindings/extensions/test_mechanism/generic.py index ca06cac1..56884273 100644 --- a/stix/bindings/extensions/test_mechanism/generic.py +++ b/stix/bindings/extensions/test_mechanism/generic.py @@ -34,6 +34,8 @@ class GenericTestMechanismType(indicator_binding.TestMechanismType): xmlns = XML_NS xmlns_prefix = "genericTM" xml_type = "GenericTestMechanismType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) + def __init__(self, idref=None, id=None, Efficacy=None, Producer=None, reference_location=None, Description=None, Type=None, Specification=None): super(GenericTestMechanismType, self).__init__(idref=idref, id=id, Efficacy=Efficacy, Producer=Producer) diff --git a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py index 6e1559ec..1e3495b5 100644 --- a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py +++ b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py @@ -33,6 +33,7 @@ class OpenIOC2010TestMechanismType(indicator_binding.TestMechanismType): xmlns = XML_NS xmlns_prefix = "stix-openioc" xml_type = "OpenIOC2010TestMechanismType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, id=None, Efficacy=None, Producer=None, ioc=None): super(OpenIOC2010TestMechanismType, self).__init__(idref=idref, id=id, Efficacy=Efficacy, Producer=Producer) diff --git a/stix/bindings/extensions/test_mechanism/oval_5_10.py b/stix/bindings/extensions/test_mechanism/oval_5_10.py index 565432d2..7c1df922 100644 --- a/stix/bindings/extensions/test_mechanism/oval_5_10.py +++ b/stix/bindings/extensions/test_mechanism/oval_5_10.py @@ -33,6 +33,7 @@ class OVAL5_10TestMechanismType(indicator_binding.TestMechanismType): xmlns = XML_NS xmlns_prefix = "ovalTM" xml_type = "OVAL5.10TestMechanismType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, id=None, Efficacy=None, Producer=None, oval_definitions=None, oval_variables=None): super(OVAL5_10TestMechanismType, self).__init__(idref=idref, id=id, Efficacy=Efficacy, Producer=Producer) diff --git a/stix/bindings/extensions/test_mechanism/snort.py b/stix/bindings/extensions/test_mechanism/snort.py index 53908ddf..51b266f3 100644 --- a/stix/bindings/extensions/test_mechanism/snort.py +++ b/stix/bindings/extensions/test_mechanism/snort.py @@ -33,6 +33,7 @@ class SnortTestMechanismType(indicator_binding.TestMechanismType): xmlns = XML_NS xmlns_prefix = "snortTM" xml_type = "SnortTestMechanismType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, id=None, Efficacy=None, Producer=None, Product_Name=None, Version=None, Rule=None, Event_Filter=None, Rate_Filter=None, Event_Suppression=None): super(SnortTestMechanismType, self).__init__(idref=idref, id=id, Efficacy=Efficacy, Producer=Producer) diff --git a/stix/bindings/extensions/test_mechanism/yara.py b/stix/bindings/extensions/test_mechanism/yara.py index 458c9945..3cd81a99 100644 --- a/stix/bindings/extensions/test_mechanism/yara.py +++ b/stix/bindings/extensions/test_mechanism/yara.py @@ -33,6 +33,7 @@ class YaraTestMechanismType(indicator_binding.TestMechanismType): xmlns = XML_NS xmlns_prefix = "yaraTM" xml_type = "YaraTestMechanismType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, id=None, Efficacy=None, Producer=None, Version=None, Rule=None): super(YaraTestMechanismType, self).__init__(idref=idref, id=id, Efficacy=Efficacy, Producer=Producer) diff --git a/stix/bindings/extensions/vulnerability/cvrf_1_1.py b/stix/bindings/extensions/vulnerability/cvrf_1_1.py index 49bc751b..e192de8e 100644 --- a/stix/bindings/extensions/vulnerability/cvrf_1_1.py +++ b/stix/bindings/extensions/vulnerability/cvrf_1_1.py @@ -34,6 +34,7 @@ class CVRF1_1InstanceType(exploit_target_binding.VulnerabilityType): xmlns = XML_NS xmlns_prefix = "cvrfVuln" xml_type = "CVRF1.1InstanceType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, Description=None, CVE_ID=None, OSVDB_ID=None, CVSS_Score=None, cvrfdoc=None): super(CVRF1_1InstanceType, self).__init__(Description=Description, CVE_ID=CVE_ID, OSVDB_ID=OSVDB_ID, CVSS_Score=CVSS_Score) diff --git a/stix/bindings/incident.py b/stix/bindings/incident.py index 8e177282..a7d1b2ac 100644 --- a/stix/bindings/incident.py +++ b/stix/bindings/incident.py @@ -2150,6 +2150,7 @@ class IncidentType(stix_common_binding.IncidentBaseType): xmlns = "http://stix.mitre.org/Incident-1" xmlns_prefix = "incident" xml_type = "IncidentType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, id=None, timestamp=None, URL=None, version=None, Title=None, External_ID=None, Time=None, Description=None, Short_Description=None, Categories=None, Reporter=None, Responder=None, Coordinator=None, Victim=None, Affected_Assets=None, Impact_Assessment=None, Status=None, Related_Indicators=None, Related_Observables=None, Leveraged_TTPs=None, Attributed_Threat_Actors=None, Intended_Effect=None, Security_Compromise=None, Discovery_Method=None, Related_Incidents=None, COA_Requested=None, COA_Taken=None, Confidence=None, Contact=None, History=None, Information_Source=None, Handling=None, Related_Packages=None): super(IncidentType, self).__init__(timestamp=timestamp, idref=idref, id=id) diff --git a/stix/bindings/indicator.py b/stix/bindings/indicator.py index d6c8b810..e36080c4 100644 --- a/stix/bindings/indicator.py +++ b/stix/bindings/indicator.py @@ -827,6 +827,7 @@ class IndicatorType(stix_common_binding.IndicatorBaseType): xmlns = XML_NS xmlns_prefix = "indicator" xml_type = "IndicatorType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, id=None, timestamp=None, negate=False, version=None, Title=None, Type=None, Alternative_ID=None, Description=None, Short_Description=None, Valid_Time_Position=None, Observable=None, Composite_Indicator_Expression=None, Indicated_TTP=None, Kill_Chain_Phases=None, Test_Mechanisms=None, Likely_Impact=None, Suggested_COAs=None, Handling=None, Confidence=None, Sightings=None, Related_Indicators=None, Related_Campaigns=None, Related_Packages=None, Producer=None): super(IndicatorType, self).__init__(idref=idref, id=id, timestamp=timestamp) diff --git a/stix/bindings/report.py b/stix/bindings/report.py index 9e3fbcc4..b4f831de 100644 --- a/stix/bindings/report.py +++ b/stix/bindings/report.py @@ -568,6 +568,7 @@ class ReportType(common_binding.ReportBaseType): xmlns = XML_NS xmlns_prefix = "report" xml_type = "ReportType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, timestamp=None, idref=None, id=None, version=None, Header=None, Observables=None, Indicators=None, TTPs=None, Exploit_Targets=None, Incidents=None, Courses_Of_Action=None, Campaigns=None, Threat_Actors=None, Related_Reports=None): super(ReportType, self).__init__(timestamp, idref, id, ) diff --git a/stix/bindings/threat_actor.py b/stix/bindings/threat_actor.py index 35be13d7..21c2d585 100644 --- a/stix/bindings/threat_actor.py +++ b/stix/bindings/threat_actor.py @@ -240,6 +240,7 @@ class ThreatActorType(stix_common_binding.ThreatActorBaseType): xmlns = "http://stix.mitre.org/ThreatActor-1" xmlns_prefix = "ta" xml_type = "ThreatActorType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None, Description=None, Short_Description=None, Identity=None, Type=None, Motivation=None, Sophistication=None, Intended_Effect=None, Planning_And_Operational_Support=None, Observed_TTPs=None, Associated_Campaigns=None, Associated_Actors=None, Handling=None, Confidence=None, Information_Source=None, Related_Packages=None): super(ThreatActorType, self).__init__(idref=idref, id=id, timestamp=timestamp) diff --git a/stix/bindings/ttp.py b/stix/bindings/ttp.py index f67ecc0a..73647b80 100644 --- a/stix/bindings/ttp.py +++ b/stix/bindings/ttp.py @@ -1248,6 +1248,7 @@ class TTPType(stix_common_binding.TTPBaseType): xmlns = "http://stix.mitre.org/TTP-1" xmlns_prefix = "ttp" xml_type = "TTPType" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) def __init__(self, idref=None, id=None, timestamp=None, version=None, Title=None, Description=None, Short_Description=None, Intended_Effect=None, Behavior=None, Resources=None, Victim_Targeting=None, Exploit_Targets=None, Related_TTPs=None, Kill_Chain_Phases=None, Information_Source=None, Kill_Chains=None, Handling=None, Related_Packages=None): super(TTPType, self).__init__(idref=idref, id=id, timestamp=timestamp) From 0d77c795760773d6025f0002452f2f377cf88daf Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 6 Oct 2015 19:02:17 -0400 Subject: [PATCH 224/438] Fixed descriptions and short_descriptions NoneType errors in BaseCoreComponent. --- stix/base.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stix/base.py b/stix/base.py index 8cc21763..04c446e3 100644 --- a/stix/base.py +++ b/stix/base.py @@ -379,14 +379,15 @@ class BaseCoreComponent(Cached, Entity): def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): + from stix.common import StructuredTextList super(BaseCoreComponent, self).__init__() self.id_ = id_ or idgen.create_id(self._ID_PREFIX) self.idref = idref self.title = title - self.descriptions = fields.TypedField(description) - self.short_descriptions = fields.TypedField(short_description) + self.descriptions = StructuredTextList(description) + self.short_descriptions = StructuredTextList(short_description) if timestamp: self.timestamp = timestamp From 9db17e878526af5e999f764b726b7df08c06a92f Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Tue, 6 Oct 2015 19:02:39 -0400 Subject: [PATCH 225/438] Update stix.coa package to use Typedfields --- stix/__init__.py | 2 +- stix/campaign/__init__.py | 23 +- stix/coa/__init__.py | 213 ++---------------- stix/coa/objective.py | 121 +--------- stix/coa/structured_coa.py | 74 ++---- stix/common/related.py | 2 + stix/common/statement.py | 5 +- stix/common/structured_text.py | 11 - stix/core/stix_header.py | 6 +- .../structured_coa/generic_structured_coa.py | 108 +-------- stix/test/coa_test.py | 6 +- 11 files changed, 70 insertions(+), 501 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index 4e40df88..63a139ee 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -84,7 +84,7 @@ def lookup_extension(typeinfo, default=None): return default error = "Input %s is missing xml_type attribute. Cannot lookup class." - raise ValueError(error) + raise ValueError(error % type(typeinfo)) # Extension binding classes usually (always?) have an `xmlns_prefix` # class attribute. diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 15d605d2..bccea8f9 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -6,10 +6,9 @@ import stix from stix.utils import deprecated from stix.common import Activity, Confidence, Statement, VocabString -from stix.common.related import ( - GenericRelationshipList, RelatedCampaign, RelatedIncident, RelatedIndicator, - RelatedPackageRefs, RelatedThreatActor, RelatedTTP -) +from stix.common.related import (GenericRelationshipList, RelatedCampaign, + RelatedIncident, RelatedIndicator, RelatedPackageRefs, RelatedThreatActor, + RelatedTTP) from stix.common import vocabs import stix.bindings.campaign as campaign_binding from stix.common.structured_text import StructuredTextList @@ -31,22 +30,6 @@ class Attribution(GenericRelationshipList): _contained_type = RelatedThreatActor _inner_name = "threat_actors" -""" -class Attribution(stix.Entity): - threat_actors = fields.TypedField("Attributed_Threat_Actor", RelatedThreatActor, multiple=True, key_name="threat_actors") - scope = fields.TypedField("scope") - - def __init__(self, scope=None, *args): - self._fields = {} - super(Attribution, self).__init__(*args) - - _namespace = "http://stix.mitre.org/Campaign-1" - _binding = campaign_binding - _binding_class = campaign_binding.AttributionType - _binding_var = "Attributed_Threat_Actor" - _contained_type = RelatedThreatActor - _inner_name = "threat_actors" -""" class RelatedIncidents(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" diff --git a/stix/coa/__init__.py b/stix/coa/__init__.py index 2469d53e..271e2d33 100644 --- a/stix/coa/__init__.py +++ b/stix/coa/__init__.py @@ -2,28 +2,33 @@ # See LICENSE.txt for complete terms. # external +from mixbox import fields from cybox.core import Observables # internal import stix -from stix.common import vocabs, related, VocabString, Statement +from stix.common import vocabs +from stix.common.related import GenericRelationshipList, RelatedPackageRefs, RelatedCOA +from stix.common.vocabs import VocabField +from stix.common.statement import Statement +from stix.common.information_source import InformationSource import stix.bindings.course_of_action as coa_binding # relative from .objective import Objective -from .structured_coa import _BaseStructuredCOA +from .structured_coa import StructuredCOAFactory, _BaseStructuredCOA # Redefines Stage = vocabs.COAStage COAType = vocabs.CourseOfActionType -class RelatedCOAs(related.GenericRelationshipList): +class RelatedCOAs(GenericRelationshipList): _namespace = "http://stix.mitre.org/CourseOfAction-1" _binding = coa_binding _binding_class = coa_binding.RelatedCOAsType _binding_var = "Related_COA" - _contained_type = related.RelatedCOA + _contained_type = RelatedCOA _inner_name = "coas" @@ -51,6 +56,18 @@ class CourseOfAction(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'coa' + stage = VocabField("Stage", Stage) + type_ = VocabField("Type", COAType) + objective = fields.TypedField("Objective", Objective) + parameter_observables = fields.TypedField("Parameter_Observables", Observables) + structured_coa = fields.TypedField("Structured_COA", type_=_BaseStructuredCOA, factory=StructuredCOAFactory) + impact = fields.TypedField("Impact", Statement) + cost = fields.TypedField("Cost", Statement) + efficacy = fields.TypedField("Efficacy", Statement) + related_coas = fields.TypedField("Related_COAs", RelatedCOAs) + related_packages = fields.TypedField("Related_Packages", RelatedPackageRefs) + information_source = fields.TypedField("Information_Source", InformationSource) + def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): @@ -63,194 +80,8 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, short_description=short_description ) - self.stage = None - self.type_ = None - self.objective = None - self.parameter_observables = None - self.structured_coa = None - self.impact = None - self.cost = None - self.efficacy = None self.related_coas = RelatedCOAs() - self.related_packages = related.RelatedPackageRefs() - - @property - def stage(self): - """A :class:`.VocabString` property. If set to a string, an attempt - will be made to convert it to an instance of :class:`.Stage`. - - """ - return self._stage - - @stage.setter - def stage(self, value): - self._set_vocab(Stage, stage=value) - - @property - def type_(self): - """A :class:`.VocabString` property. If set to a string, an attempt - will be made to convert it to an instance of :class:`.COAType`. - - """ - return self._type - - @type_.setter - def type_(self, value): - self._set_vocab(COAType, type=value) - - @property - def objective(self): - """A :class:`.Objective` field. - - """ - return self._objective - - @objective.setter - def objective(self, value): - self._set_var(Objective, try_cast=False, objective=value) - - @property - def impact(self): - """The impact of this COA. This is a :class:`.Statement` property. - - If set to a string, an attempt will be made to convert it into a - :class:`.Statement` object. - - """ - return self._impact - - @impact.setter - def impact(self, value): - self._set_var(Statement, impact=value) - - @property - def cost(self): - """The cost of this COA. This is a :class:`.Statement` property. - - If set to a string, an attempt will be made to convert it into a - :class:`.Statement` object. - - """ - return self._cost - - @cost.setter - def cost(self, value): - self._set_var(Statement, cost=value) - - @property - def efficacy(self): - """The efficacy of this COA. This is a :class:`.Statement` property. - - If set to a string, an attempt will be made to convert it into a - :class:`.Statement` object. - - """ - return self._efficacy - - @efficacy.setter - def efficacy(self, value): - self._set_var(Statement, efficacy=value) - - @property - def structured_coa(self): - """A structured Course of Action extension point. This can be - set to implementations of this extension point, such as - :class:`.GenericStructuredCOA`. - - """ - return self._structured_coa - - @structured_coa.setter - def structured_coa(self, value): - self._set_var(_BaseStructuredCOA, try_cast=False, structured_coa=value) - - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(CourseOfAction, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if self.stage: - return_obj.Stage = self.stage.to_obj(ns_info=ns_info) - if self.type_: - return_obj.Type = self.type_.to_obj(ns_info=ns_info) - if self.objective: - return_obj.Objective = self.objective.to_obj(ns_info=ns_info) - if self.parameter_observables: - return_obj.Parameter_Observables = self.parameter_observables.to_obj(ns_info=ns_info) - if self.impact: - return_obj.Impact = self.impact.to_obj(ns_info=ns_info) - if self.cost: - return_obj.Cost = self.cost.to_obj(ns_info=ns_info) - if self.efficacy: - return_obj.Efficacy = self.efficacy.to_obj(ns_info=ns_info) - if self.related_coas: - return_obj.Related_COAs = self.related_coas.to_obj(ns_info=ns_info) - if self.related_packages: - return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) - if self.structured_coa: - return_obj.Structured_COA = self.structured_coa.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - super(CourseOfAction, cls).from_obj(obj, return_obj=return_obj) - - if isinstance(obj, cls._binding_class): # CourseOfActionType properties - return_obj.title = obj.Title - return_obj.stage = VocabString.from_obj(obj.Stage) - return_obj.type_ = VocabString.from_obj(obj.Type) - return_obj.objective = Objective.from_obj(obj.Objective) - return_obj.parameter_observables = \ - Observables.from_obj(obj.Parameter_Observables) - return_obj.impact = Statement.from_obj(obj.Impact) - return_obj.cost = Statement.from_obj(obj.Cost) - return_obj.efficacy = Statement.from_obj(obj.Efficacy) - return_obj.related_coas = \ - RelatedCOAs.from_obj(obj.Related_COAs) - return_obj.related_packages = \ - related.RelatedPackageRefs.from_obj(obj.Related_Packages) - return_obj.structured_coa = \ - _BaseStructuredCOA.from_obj(obj.Structured_COA) - - return return_obj - - def to_dict(self): - return super(CourseOfAction, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - if not return_obj: - return_obj = cls() - - super(CourseOfAction, cls).from_dict(dict_repr, return_obj=return_obj) - - get = dict_repr.get - return_obj.stage = VocabString.from_dict(get('stage')) - return_obj.type_ = VocabString.from_dict(get('type')) - return_obj.objective = Objective.from_dict(get('objective')) - return_obj.parameter_observables = \ - Observables.from_dict(get('parameter_observables')) - return_obj.impact = Statement.from_dict(get('impact')) - return_obj.cost = Statement.from_dict(get('cost')) - return_obj.efficacy = Statement.from_dict(get('efficacy')) - return_obj.related_coas = \ - RelatedCOAs.from_dict(get('related_coas')) - return_obj.related_packages = \ - related.RelatedPackageRefs.from_dict(get('related_packages')) - return_obj.structured_coa = \ - _BaseStructuredCOA.from_dict(get('structured_coa')) - - return return_obj + self.related_packages = RelatedPackageRefs() # alias for CourseOfAction COA = CourseOfAction diff --git a/stix/coa/objective.py b/stix/coa/objective.py index 0c7a5764..14b097d7 100644 --- a/stix/coa/objective.py +++ b/stix/coa/objective.py @@ -1,6 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + import stix from stix.common import StructuredTextList, Confidence import stix.bindings.course_of_action as coa_binding @@ -10,8 +12,14 @@ class Objective(stix.Entity): _binding = coa_binding _binding_class = coa_binding.ObjectiveType _namespace = "http://stix.mitre.org/CourseOfAction-1" - + + applicability_confidence = fields.TypedField("Applicability_Confidence", type_=Confidence) + descriptions = fields.TypedField("Description", type_=StructuredTextList) + short_descriptions = fields.TypedField("Short_Description", type_=StructuredTextList) + def __init__(self, description=None, short_description=None): + super(Objective, self).__init__() + self.description = description self.short_description = short_description self.applicability_confidence = None @@ -37,36 +45,6 @@ def description(self): def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. @@ -96,35 +74,6 @@ def short_description(self): def short_description(self, value): self.short_descriptions = value - @property - def short_descriptions(self): - """A :class:`.StructuredTextList` object, containing short descriptions - about the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - short descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of :class:`.StructuredTextList` - - """ - return self._short_description - - @short_descriptions.setter - def short_descriptions(self, value): - self._short_description = StructuredTextList(value) - def add_short_description(self, description): """Adds a description to the ``short_descriptions`` collection. @@ -132,55 +81,3 @@ def add_short_description(self, description): """ self.short_descriptions.add(description) - - @property - def applicability_confidence(self): - return self._applicability_confidence - - @applicability_confidence.setter - def applicability_confidence(self, value): - self._set_var(Confidence, try_cast=False, applicability_confidence=value) - - def to_obj(self, return_obj=None, ns_info=None): - super(Objective, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.short_descriptions: - return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) - if self.applicability_confidence: - return_obj.Applicability_Confidence = self.applicability_confidence.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) - return_obj.applicability_confidence = Confidence.from_obj(obj.Applicability_Confidence) - return return_obj - - def to_dict(self): - return super(Objective, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - if not return_obj: - return_obj = cls() - - get = dict_repr.get - return_obj.description = StructuredTextList.from_dict(get('description')) - return_obj.short_description = StructuredTextList.from_dict(get('short_description')) - return_obj.applicability_confidence = Confidence.from_dict(get('applicability_confidence')) - - return return_obj diff --git a/stix/coa/structured_coa.py b/stix/coa/structured_coa.py index 2621e7cb..f69561ae 100644 --- a/stix/coa/structured_coa.py +++ b/stix/coa/structured_coa.py @@ -3,81 +3,43 @@ # external from mixbox.cache import Cached +from mixbox import entities +from mixbox import fields # internal import stix from stix.bindings import course_of_action as coa_binding +class StructuredCOAFactory(entities.EntityFactory): + @classmethod + def entity_class(cls, key): + import stix.extensions.structured_coa.generic_structured_coa # noqa + return stix.lookup_extension(key) + + class _BaseStructuredCOA(Cached, stix.Entity): _namespace = "http://stix.mitre.org/CourseOfAction-1" _binding = coa_binding _binding_class = coa_binding.StructuredCOAType + id_ = fields.IdField("id") + idref = fields.IdrefField("idref") + def __init__(self, id_=None, idref=None): + super(_BaseStructuredCOA, self).__init__() self.id_ = id_ self.idref = idref - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - # Registers the class extension - import stix.extensions.structured_coa.generic_structured_coa # noqa - - if not return_obj: - klass = stix.lookup_extension(obj) - return_obj = klass.from_obj(obj) - else: - return_obj.id_ = obj.id - return_obj.idref = obj.idref - - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - super(_BaseStructuredCOA, self).to_obj( - return_obj=return_obj, - ns_info=ns_info - ) - - if not return_obj: - return_obj = self._binding_class() - - return_obj.id = self.id_ - return_obj.idref = self.idref - return_obj.xsi_type = self._XSI_TYPE - - return return_obj - - @staticmethod - def lookup_class(xsi_type): - if not xsi_type: - raise ValueError("xsi:type is required") - - return stix.lookup_extension(xsi_type) - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - - import stix.extensions.structured_coa.generic_structured_coa # noqa - - if not return_obj: - klass = stix.lookup_extension(d.get('xsi:type')) - return_obj = klass.from_dict(d) - else: - return_obj.id_ = d.get('id') - return_obj.idref = d.get('idref') - - return return_obj - def to_dict(self): d = super(_BaseStructuredCOA, self).to_dict() - d['xsi:type'] = self._XSI_TYPE # added by subclass + d['xsi:type'] = self._XSI_TYPE return d + def to_obj(self, ns_info=None): + obj = super(_BaseStructuredCOA, self).to_obj(ns_info=ns_info) + obj.xsi_type = self._XSI_TYPE + return obj # Backwards compatibility add_extension = stix.add_extension diff --git a/stix/common/related.py b/stix/common/related.py index c992c74b..742bc984 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -140,6 +140,8 @@ class _BaseRelated(GenericRelationship): Subclasses must supply a TypedField named `item`! """ + item = None # override in subclass. + def __init__(self, item=None, confidence=None, information_source=None, relationship=None): diff --git a/stix/common/statement.py b/stix/common/statement.py index 4a44853a..3072b80b 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -9,6 +9,7 @@ import stix.utils as utils import stix.bindings.stix_common as common_binding +from .datetimewithprecision import validate_precision from .confidence import Confidence from .structured_text import StructuredTextList from .vocabs import VocabField, HighMediumLow @@ -20,8 +21,8 @@ class Statement(stix.Entity): _binding_class = common_binding.StatementType # Fields - timestamp = fields.TypedField("timestamp") - timestamp_precision = fields.TypedField("timestamp_precision") + timestamp = fields.DateTimeField("timestamp") + timestamp_precision = fields.TypedField("timestamp_precision", preset_hook=validate_precision) value = VocabField("Value", HighMediumLow) descriptions = fields.TypedField("Description", StructuredTextList) confidence = fields.TypedField("Confidence", Confidence) diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 331d42e7..54ad4c9c 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -125,17 +125,6 @@ def _initialize_inner(self, *args): else: self.add(arg) - @classmethod - def istypeof(cls, obj): - """Check if `cls` is the type of `obj` - - In the normal case, as implemented here, a simple isinstance check is - used. However, there are more complex checks possible. For instance, - EmailAddress.istypeof(obj) checks if obj is an Address object with - a category of Address.CAT_EMAIL - """ - return isinstance(obj, cls) - def with_id(self, id): """Returns a :class:`.StructuredText` object with a matching `id` or ``None`` if not found. diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index 8a4d0a27..70931a9a 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -87,7 +87,7 @@ def add_description(self, description): This is the same as calling "foo.descriptions.add(bar)". """ - deprecated(description) + deprecated.warn(description) self.descriptions.add(description) @property @@ -118,7 +118,7 @@ def add_short_description(self, description): This is the same as calling "foo.short_descriptions.add(bar)". """ - deprecated(description) + deprecated.warn(description) self.short_descriptions.add(description) @@ -130,7 +130,7 @@ def add_package_intent(self, package_intent): will be made to convert it into an instance of :class:`.PackageIntent`. """ - deprecated(package_intent) + deprecated.warn(package_intent) self.package_intents.append(package_intent) def add_profile(self, profile): diff --git a/stix/extensions/structured_coa/generic_structured_coa.py b/stix/extensions/structured_coa/generic_structured_coa.py index 073eef77..82f504a6 100644 --- a/stix/extensions/structured_coa/generic_structured_coa.py +++ b/stix/extensions/structured_coa/generic_structured_coa.py @@ -6,7 +6,8 @@ # internal import stix -from stix.common import EncodedCDATA, StructuredTextList, VocabString +from stix.common import EncodedCDATA, StructuredTextList +from stix.common.vocabs import VocabField from stix.coa.structured_coa import _BaseStructuredCOA # bindings @@ -21,21 +22,13 @@ class GenericStructuredCOA(_BaseStructuredCOA): _XSI_TYPE = "genericStructuredCOA:GenericStructuredCOAType" specification = fields.TypedField("Specification", EncodedCDATA) + descriptions = fields.TypedField("Description", type_=StructuredTextList) + reference_location = fields.TypedField("reference_location") + type_ = VocabField("Type") def __init__(self, id_=None, idref=None): super(GenericStructuredCOA, self).__init__(id_=id_, idref=idref) - self.reference_location = None - self.description = None - self.type_ = None - self.specification = None - - @property - def specification(self): - return self._specification - - @specification.setter - def specification(self, value): - self._set_var(EncodedCDATA, specification=value) + self.descriptions = StructuredTextList() @property def description(self): @@ -52,39 +45,13 @@ def description(self): :class:`.StructuredText` """ - return next(iter(self.descriptions), None) + if self.descriptions is not None: + return next(iter(self.descriptions), None) @description.setter def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. @@ -92,62 +59,3 @@ def add_description(self, description): """ self.descriptions.add(description) - - @property - def type_(self): - return self._type - - @type_.setter - def type_(self, value): - self._set_vocab(type=value) - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - super(GenericStructuredCOA, cls).from_obj(obj, return_obj) - return_obj.reference_location = obj.reference_location - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.type_ = VocabString.from_obj(obj.Type) - return_obj.specification = EncodedCDATA.from_obj(obj.Specification) - - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(GenericStructuredCOA, self).to_obj(return_obj=return_obj, ns_info=ns_info) - if self.reference_location: - return_obj.reference_location = self.reference_location - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.type_: - return_obj.Type = self.type_.to_obj(ns_info=ns_info) - if self.specification: - return_obj.Specification = self.specification.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if not return_obj: - return_obj = cls() - - super(GenericStructuredCOA, cls).from_dict(d, return_obj) - return_obj.reference_location = d.get('reference_location') - return_obj.descriptions = StructuredTextList.from_dict(d.get('description')) - return_obj.type_ = VocabString.from_dict(d.get('type')) - return_obj.specification = EncodedCDATA.from_dict(d.get('specification')) - - return return_obj - - def to_dict(self): - return super(GenericStructuredCOA, self).to_dict() - diff --git a/stix/test/coa_test.py b/stix/test/coa_test.py index b66c6591..58a72ba3 100644 --- a/stix/test/coa_test.py +++ b/stix/test/coa_test.py @@ -13,7 +13,6 @@ import stix.coa.objective as objective - class RelatedCOAsTests(EntityTestCase, unittest.TestCase): klass = coa.RelatedCOAs @@ -98,12 +97,9 @@ def test_add_short_description(self): def test_structured_coa(self): coa_ = coa.CourseOfAction() - def should_fail(): - coa_.structured_coa = "ERROR" - self.assertRaises( TypeError, - should_fail + setattr(coa_, "structured_coa", "ERROR") ) from stix.extensions.structured_coa.generic_structured_coa import GenericStructuredCOA From 085b2d86da3f18113ef77fdc5dd2a901fdf8dd15 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Wed, 7 Oct 2015 13:17:52 -0400 Subject: [PATCH 226/438] A better fix to the missing namespace collect bug. I realized that the super calls to to_obj() should have done the collection, but ns_info hadn't been passed up to that method. --- stix/extensions/identity/ciq_identity_3_0.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index a792c8a4..5c0bbc52 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -66,11 +66,10 @@ def specification(self, value): self._specification = value def to_obj(self, return_obj=None, ns_info=None): - self._collect_ns_info(ns_info) if not return_obj: return_obj = self._binding_class() - super(CIQIdentity3_0Instance, self).to_obj(return_obj) + super(CIQIdentity3_0Instance, self).to_obj(return_obj, ns_info) # return_obj.id = self.id_ # return_obj.idref = self.idref_ From d2fd5f627f3824bf8655a22da419501de009e1c4 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Wed, 7 Oct 2015 14:16:36 -0400 Subject: [PATCH 227/438] Removed NamespaceInfo.finalized_namespaces. It was only used in some test code, which was easy to change. --- stix/test/__init__.py | 2 +- stix/test/utils/nsparser_test.py | 2 +- stix/utils/nsparser.py | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/stix/test/__init__.py b/stix/test/__init__.py index e61d2c37..ee056538 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -110,7 +110,7 @@ def round_trip(o, output=False, list_=False): except KeyError as ex: print str(ex) ns_info.finalize() - print ns_info.finalized_namespaces + print ns_info.binding_namespaces raise if output: diff --git a/stix/test/utils/nsparser_test.py b/stix/test/utils/nsparser_test.py index 1909a732..50d115cb 100644 --- a/stix/test/utils/nsparser_test.py +++ b/stix/test/utils/nsparser_test.py @@ -72,7 +72,7 @@ def test_namespace_collect(self): # finalize the namespace dictionary nsinfo.finalize(ns_dict=NSMAP, schemaloc_dict=SCHEMALOCS) - namespaces = nsinfo.finalized_namespaces.values() + namespaces = nsinfo.binding_namespaces.keys() self.assertTrue(all(ns in namespaces for ns in NSMAP.iterkeys())) diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index fccb927e..52591d72 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -30,7 +30,6 @@ def __init__(self): # Namespaces and schemalocations that will appear in the output # XML document. - self.finalized_namespaces = None self.finalized_schemalocs = None # Namespace dictionary that gets passed to the bindings. @@ -220,8 +219,6 @@ def finalize(self, ns_dict=None, schemaloc_dict=None): self._finalize_namespaces(ns_dict) self._finalize_schemalocs(schemaloc_dict) - self.finalized_namespaces = \ - self._collected_namespaces.get_prefix_uri_map() self.finalized_schemalocs = \ self._collected_namespaces.get_uri_schemaloc_map() self.binding_namespaces = \ From 6b7afa688fa78c83df1db047bcf65051465b1cf0 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Fri, 9 Oct 2015 16:46:01 -0400 Subject: [PATCH 228/438] This branch corresponds to the mixbox 'one_pass_namespaces' branch. Removed NamespaceInfo from python-stix, and made changes as necessary to use the mixbox version of that class. It is renamed in mixbox to NamespaceCollector at present, because I'm afraid there may be another NamespaceInfo class in there before long, and I don't want two classes with the same name. --- stix/base.py | 4 +- stix/test/__init__.py | 5 +- stix/test/utils/nsparser_test.py | 63 +------- stix/utils/__init__.py | 1 + stix/utils/nsparser.py | 248 ------------------------------- 5 files changed, 7 insertions(+), 314 deletions(-) diff --git a/stix/base.py b/stix/base.py index 5393c2d8..50a83cb8 100644 --- a/stix/base.py +++ b/stix/base.py @@ -145,7 +145,7 @@ def to_xml(self, include_namespaces=True, include_schemalocs=False, """ - from .utils import nsparser + from mixbox.entities import NamespaceCollector if (not auto_namespace) and (not ns_dict): raise Exception( @@ -153,7 +153,7 @@ def to_xml(self, include_namespaces=True, include_schemalocs=False, "or missing." ) - ns_info = nsparser.NamespaceInfo() + ns_info = NamespaceCollector() obj = self.to_obj(ns_info=ns_info if auto_namespace else None) diff --git a/stix/test/__init__.py b/stix/test/__init__.py index ee056538..954b4f85 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -9,8 +9,9 @@ import cybox.utils from mixbox.binding_utils import ExternalEncoding +from mixbox.entities import NamespaceCollector -from stix.utils import NamespaceInfo, silence_warnings +from stix.utils import silence_warnings @contextlib.contextmanager @@ -97,7 +98,7 @@ def round_trip(o, output=False, list_=False): o2 = klass.from_dict(d2) # 5. Entity -> Bindings Object - ns_info = NamespaceInfo() + ns_info = NamespaceCollector() xobj = o2.to_obj(ns_info=ns_info) try: diff --git a/stix/test/utils/nsparser_test.py b/stix/test/utils/nsparser_test.py index 50d115cb..f4a305a6 100644 --- a/stix/test/utils/nsparser_test.py +++ b/stix/test/utils/nsparser_test.py @@ -10,72 +10,11 @@ # internal import mixbox.namespaces -import stix from stix.core import STIXPackage -from stix.utils import nsparser, silence_warnings - - -NSMAP = { - "test:a": "a", - "test:b": "b", - "test:c": "c" -} - - -SCHEMALOCS = { - "test:a": "/dev/null", - "test:b": "/dev/null", - "test:c": "/dev/null" -} - - -class A(stix.Entity): - _namespace = nsparser.NS_STIX_OBJECT.name - _XSI_TYPE = "a:AType" - - -class B(A): - _namespace = nsparser.NS_STIXCOMMON_OBJECT.name - _XSI_TYPE = "b:BType" - - -class C(B): - _namespace = nsparser.NS_INDICATOR_OBJECT.name - _XSI_TYPE = "c:CType" +from stix.utils import silence_warnings class NamespaceInfoTests(unittest.TestCase): - def test_nsinfo_collect(self): - """Tests that the NamespaceInfo.collect() method correctly ascends the MRO - of input objects. - - """ - nsinfo = nsparser.NamespaceInfo() - - # Collect classes - nsinfo.collect(C()) - - # Parse collected classes - nsinfo._parse_collected_classes() - - self.assertEqual(len(nsinfo._collected_namespaces), 3) # noqa - - def test_namespace_collect(self): - """Test that NamespaceInfo correctly pulls namespaces from all classes - in an objects MRO. - - """ - nsinfo = nsparser.NamespaceInfo() - - # Collect classes - nsinfo.collect(C()) - - # finalize the namespace dictionary - nsinfo.finalize(ns_dict=NSMAP, schemaloc_dict=SCHEMALOCS) - namespaces = nsinfo.binding_namespaces.keys() - - self.assertTrue(all(ns in namespaces for ns in NSMAP.iterkeys())) - @silence_warnings def test_user_provided_ns(self): diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index 869c030b..737b1b7f 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -4,6 +4,7 @@ import contextlib import functools import keyword +import warnings import lxml.etree diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index 52591d72..86757191 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -1,256 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -import itertools -import warnings - -from mixbox import idgen -from mixbox.entities import Entity import mixbox.namespaces -# internal -import stix - - -class NamespaceInfo(object): - - def __init__(self): - # Namespaces that are "collected" from the Python objects during - # serialization. This will be a (mixbox) NamespaceSet. - self._collected_namespaces = None - - # Namespaces and schemalocations that are attached to STIX/CybOX - # entities when parsed from an external source. - self._input_namespaces = {} - self._input_schemalocs = {} - - # A list of classes that have been visited/seen during the namespace - # collection process. This speeds up the collect() method. - self._collected_classes = set() - - # Namespaces and schemalocations that will appear in the output - # XML document. - self.finalized_schemalocs = None - - # Namespace dictionary that gets passed to the bindings. - self.binding_namespaces = None - - def update(self, ns_info): - self._collected_namespaces.update(ns_info._collected_namespaces) # noqa - self._input_namespaces.update(ns_info._input_namespaces) # noqa - self._input_schemalocs.update(ns_info._input_schemalocs) # noqa - - def _parse_collected_classes(self): - collected = self._collected_classes - entity_klasses = (stix.Entity, Entity) - - # Generator which yields all stix.Entity and mixbox.Entity subclasses - # that were collected. - entity_subclasses = ( - klass for klass in collected if issubclass(klass, entity_klasses) - ) - - alias_to_ns_uri = {} - no_alias_ns_uris = [] - for klass in entity_subclasses: - # Prevents exception being raised if/when - # collections.MutableSequence or another base class appears in the - # MRO. - ns = getattr(klass, "_namespace", None) - if not ns: - continue - - # cybox.objects.* ObjectProperties derivations have an _XSI_NS - # class-level attribute which holds the namespace alias to be - # used for its namespace. - alias = getattr(klass, "_XSI_NS", None) - if alias: - alias_to_ns_uri[alias] = ns - continue - - # Many stix/cybox entity classes have an _XSI_TYPE attribute that - # contains a `prefix:namespace` formatted QNAME for the - # associated xsi:type. - xsi_type = getattr(klass, "_XSI_TYPE", None) - if not xsi_type: - no_alias_ns_uris.append(ns) - continue - - # Attempt to split the xsi:type attribute value into the ns alias - # and the typename. - typeinfo = xsi_type.split(":") - if len(typeinfo) == 2: - alias_to_ns_uri[typeinfo[0]] = ns - else: - no_alias_ns_uris.append(ns) - - # Unrecognized namespace URIs will cause an error at this stage. - self._collected_namespaces = mixbox.namespaces.make_namespace_subset_from_uris( - itertools.chain(alias_to_ns_uri.itervalues(), no_alias_ns_uris) - ) - - # For some reason, prefixes are specified in API class vars and also in - # our big namespace tables. From python-cybox issue #274 [1], I - # conclude that the tables may take priority here. And those are - # already going to be preferred at this point. So the only thing I can - # think to do with class var values is fill in any missing prefixes - # we may have (but I doubt there will be any). - # - # 1. https://github.com/CybOXProject/python-cybox/issues/274 - for prefix, ns_uri in alias_to_ns_uri.iteritems(): - if self._collected_namespaces.preferred_prefix_for_namespace(ns_uri) is None: - self._collected_namespaces.set_preferred_prefix_for_namespace( - ns_uri, prefix, True) - - def _fix_example_namespace(self): - """Attempts to resolve issues where our samples use - 'http://example.com/' for our example namespace but python-stix uses - 'http://example.com' by removing the former. - - """ - example_prefix = 'example' # Example ns prefix - idgen_prefix = idgen.get_id_namespace_prefix() - - # If the ID namespace alias doesn't match the example alias, return. - if idgen_prefix != example_prefix: - return - - # If the example namespace prefix isn't in the parsed namespace - # prefixes, return. - if example_prefix not in self._input_namespaces: - return - - self._input_namespaces[example_prefix] = idgen.EXAMPLE_NAMESPACE.name - - def _finalize_namespaces(self, ns_dict=None): - """Returns a dictionary of namespaces to be exported with an XML - document. - - This loops over all the namespaces that were discovered and built - during the execution of ``collect()`` and - ``_parse_collected_classes()`` and attempts to merge them all. - - Raises: - mixbox.namespaces.DuplicatePrefixError: If namespace prefix was - mapped to more than one namespace. - - """ - - if ns_dict: - # Add the user's entries to our set - for ns, alias in ns_dict.iteritems(): - self._collected_namespaces.add_namespace_uri(ns, alias) - - # Add the ID namespaces - self._collected_namespaces.add_namespace_uri( - idgen.get_id_namespace(), - idgen.get_id_namespace_alias() - ) - - # Remap the example namespace to the one expected by the APIs if the - # sample example namespace is found. - self._fix_example_namespace() - - # Add _input_namespaces - for prefix, uri in self._input_namespaces.iteritems(): - self._collected_namespaces.add_namespace_uri(uri, prefix) - - # Add some default XML namespaces to make sure they're there. - self._collected_namespaces.import_from(mixbox.namespaces.XML_NAMESPACES) - - # python-stix's generateDS-generated binding classes can't handle - # default namespaces. So make sure there are no preferred defaults in - # the set. Get prefixes from the global namespace set if we have to. - for ns_uri in self._collected_namespaces.namespace_uris: - if self._collected_namespaces.preferred_prefix_for_namespace(ns_uri) is None: - prefixes = self._collected_namespaces.get_prefixes(ns_uri) - if len(prefixes) > 0: - prefix = next(iter(prefixes)) - else: - prefix = mixbox.namespaces.lookup_name(ns_uri) - - if prefix is None: - raise mixbox.namespaces.NoPrefixesError(ns_uri) - - self._collected_namespaces.set_preferred_prefix_for_namespace( - ns_uri, prefix, True) - - def _finalize_schemalocs(self, schemaloc_dict=None): - # If schemaloc_dict was passed in, make a copy so we don't mistakenly - # modify the original. - if schemaloc_dict: - schemaloc_dict = dict(schemaloc_dict.iteritems()) - else: - schemaloc_dict = {} - - # Build our schemalocation dictionary! - # - # Initialize it from values found in the parsed, input schemalocations - # (if there are any) and the schemaloc_dict parameter values (if there - # are any). - # - # If there is a schemalocation found in both the parsed schemalocs and - # the schema_loc dict, use the schemaloc_dict value. - for ns, loc in self._input_schemalocs.iteritems(): - if ns not in schemaloc_dict: - schemaloc_dict[ns] = loc - - # Now use the merged dict to update any schema locations we don't - # already have. - for ns, loc in schemaloc_dict.iteritems(): - if self._collected_namespaces.contains_namespace(ns) and \ - self._collected_namespaces.get_schema_location(ns) is None: - self._collected_namespaces.set_schema_location(ns, loc) - - # Warn if we are missing any schemalocations - id_ns = idgen.get_id_namespace() - for ns in self._collected_namespaces.namespace_uris: - if self._collected_namespaces.get_schema_location(ns) is None: - if ns == id_ns or \ - mixbox.namespaces.XML_NAMESPACES.contains_namespace(ns) or \ - ns in schemaloc_dict: - continue - - error = "Unable to map namespace '{0}' to schemaLocation" - warnings.warn(error.format(ns)) - - def finalize(self, ns_dict=None, schemaloc_dict=None): - self._parse_collected_classes() - self._finalize_namespaces(ns_dict) - self._finalize_schemalocs(schemaloc_dict) - - self.finalized_schemalocs = \ - self._collected_namespaces.get_uri_schemaloc_map() - self.binding_namespaces = \ - self._collected_namespaces.get_uri_prefix_map() - - def get_xmlns_string(self, delim): - if self._collected_namespaces is None: - return "" - return self._collected_namespaces.get_xmlns_string( - preferred_prefixes_only=False, delim=delim - ) - - def get_schema_location_string(self, delim): - if self._collected_namespaces is None: - return "" - return self._collected_namespaces.get_schemaloc_string(delim=delim) - - def collect(self, entity): - # Collect all the classes we need to inspect for namespace information - self._collected_classes.update(entity.__class__.__mro__) - - # Collect the input namespaces if this entity came from some external - # source. - if hasattr(entity, "__input_namespaces__"): - self._input_namespaces.update(entity.__input_namespaces__) - - # Collect the input schemalocation information if this entity came - # from some external source. - if hasattr(entity, "__input_schemalocations__"): - self._input_schemalocs.update(entity.__input_schemalocations__) - - Namespace = mixbox.namespaces.Namespace NS_CAMPAIGN_OBJECT = Namespace("http://stix.mitre.org/Campaign-1", "campaign", "http://stix.mitre.org/XMLSchema/campaign/1.2/campaign.xsd") From f919aa183d1a82ba745df6a5640e8a7a83f8e87e Mon Sep 17 00:00:00 2001 From: apsillers Date: Wed, 14 Oct 2015 16:36:20 -0400 Subject: [PATCH 229/438] Change ValidTime to a mixbox Entity --- stix/indicator/valid_time.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stix/indicator/valid_time.py b/stix/indicator/valid_time.py index 12747ebd..83c67c22 100644 --- a/stix/indicator/valid_time.py +++ b/stix/indicator/valid_time.py @@ -5,8 +5,9 @@ import stix from stix.common import DateTimeWithPrecision import stix.bindings.indicator as indicator_binding +from mixbox.entities import Entity -class ValidTime(stix.Entity): +class ValidTime(Entity): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = _binding.ValidTimeType @@ -15,7 +16,7 @@ class ValidTime(stix.Entity): end_time = fields.TypedField("End_Time", DateTimeWithPrecision) def __init__(self, start_time=None, end_time=None): - self._fields = {} + super(ValidTime, self).__init__() self.start_time = start_time self.end_time = end_time From 0dd564fe70f4b3c47bde1bee93bec744d1f1b59d Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 23 Oct 2015 14:35:52 -0400 Subject: [PATCH 230/438] Add super() call to STIXPackage --- stix/core/stix_package.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 3152db84..1deea5a6 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -38,9 +38,9 @@ # binding imports import stix.bindings.stix_core as stix_core_binding +import mixbox.entities - -class STIXPackage(Cached, stix.Entity): +class STIXPackage(Cached, mixbox.entities.Entity): """A STIX Package object. Args: @@ -92,6 +92,8 @@ def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, ttps=None, campaigns=None, related_packages=None, reports=None): + super(STIXPackage, self).__init__() + self.id_ = id_ or idgen.create_id("Package") self.idref = idref self._version = STIXPackage._version From beee89f8a5d880f61370fe36c01daf8b900a1833 Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 23 Oct 2015 14:38:15 -0400 Subject: [PATCH 231/438] Add TypedFields to ThreatActor --- stix/common/related.py | 2 +- stix/common/statement.py | 20 ++- stix/test/threat_actor_test.py | 74 +++++++---- stix/threat_actor/__init__.py | 235 +++------------------------------ 4 files changed, 81 insertions(+), 250 deletions(-) diff --git a/stix/common/related.py b/stix/common/related.py index 742bc984..f3b8ffd4 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -204,7 +204,7 @@ class RelatedThreatActor(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedThreatActorType - item = fields.TypedField("ThreatActor", type_="stix.threat_actor.ThreatActor") + item = fields.TypedField("Threat_Actor", type_="stix.threat_actor.ThreatActor") class RelatedTTP(_BaseRelated): diff --git a/stix/common/statement.py b/stix/common/statement.py index 3072b80b..980c8fcb 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -13,7 +13,7 @@ from .confidence import Confidence from .structured_text import StructuredTextList from .vocabs import VocabField, HighMediumLow - +import mixbox class Statement(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' @@ -67,3 +67,21 @@ def add_description(self, description): """ self.descriptions.add(description) + + +class StatementField(mixbox.fields.TypedField): + def __init__(self, *args, **kwargs): + self._vocab_type = kwargs.pop("vocab_type") + super(StatementField, self).__init__(*args, **kwargs) + self.type_ = Statement + + def _clean(self, value): + if value is None: + return None + elif isinstance(value, Statement): + return value + elif isinstance(value, stix.common.VocabString): + return Statement(value) + else: + vocabklass = self._vocab_type + return Statement(vocabklass(value)) diff --git a/stix/test/threat_actor_test.py b/stix/test/threat_actor_test.py index e4571ccd..36b8dda8 100644 --- a/stix/test/threat_actor_test.py +++ b/stix/test/threat_actor_test.py @@ -15,9 +15,9 @@ class TypesTests(TypedListTestCase, unittest.TestCase): - klass = ta._Types + klass = ta.ThreatActor - _full_dict = [ + _partial_dict = [ { 'value': { "value" : "Hacker", @@ -26,58 +26,74 @@ class TypesTests(TypedListTestCase, unittest.TestCase): }, ] + _full_dict = { + "types": _partial_dict + } class MotivationsTests(TypedListTestCase, unittest.TestCase): - klass = ta._Motivations + klass = ta.ThreatActor - _full_dict = [ - { + _partial_dict = [{ 'value': { "value" : "Ego", "xsi:type" : "stixVocabs:MotivationVocab-1.1" } - }, - ] + }] + + _full_dict = { + "motivations": _partial_dict + } class SophisticationTests(TypedListTestCase, unittest.TestCase): - klass = ta._Sophistications + klass = ta.ThreatActor - _full_dict = [ + _partial_dict = [ { - 'value': { + 'value': { "value" : "Novice", "xsi:type" : "stixVocabs:ThreatActorSophisticationVocab-1.0" - } - }, + } + } ] - + _full_dict = { + "sophistications": _partial_dict + } + class IntendedEffectsTests(TypedListTestCase, unittest.TestCase): - klass = ta._IntendedEffects + klass = ta.ThreatActor - _full_dict = [ + _partial_dict = [ { - 'value': { + 'value': { "value" : "Destruction", "xsi:type" : "stixVocabs:IntendedEffectVocab-1.0" - } + } } ] + + _full_dict = { + "intended_effects": _partial_dict + } class PlanningAndOperationalSupportTests(TypedListTestCase, unittest.TestCase): - klass = ta._PlanningAndOperationalSupports + klass = ta.ThreatActor - _full_dict = [ + _partial_dict = [ { - 'value': { - "value" : "Data Exploitation", - "xsi:type" : 'stixVocabs:PlanningAndOperationalSupportVocab-1.0.1' - } - }, + 'value': { + "value" : "Data Exploitation", + "xsi:type" : 'stixVocabs:PlanningAndOperationalSupportVocab-1.0.1' + } + } ] + _full_dict = { + "planning_and_operational_supports": _partial_dict + } + class ObservedTTPsTests(EntityTestCase, unittest.TestCase): klass = ta.ObservedTTPs @@ -122,11 +138,11 @@ class ThreatActorTests(EntityTestCase, unittest.TestCase): 'description': "This is a long description about a threat actor.", 'short_description': "A bad guy", 'identity': identity_test.IdentityTests._full_dict, - 'types': TypesTests._full_dict, - 'motivations': MotivationsTests._full_dict, - 'sophistications': SophisticationTests._full_dict, - 'intended_effects': IntendedEffectsTests._full_dict, - 'planning_and_operational_supports': PlanningAndOperationalSupportTests._full_dict, + 'types': TypesTests._partial_dict, + 'motivations': MotivationsTests._partial_dict, + 'sophistications': SophisticationTests._partial_dict, + 'intended_effects': IntendedEffectsTests._partial_dict, + 'planning_and_operational_supports': PlanningAndOperationalSupportTests._partial_dict, 'observed_ttps': ObservedTTPsTests._full_dict, 'associated_campaigns': AssocaitedCampaignsTests._full_dict, 'associated_actors': AssociatedActorsTests._full_dict, diff --git a/stix/threat_actor/__init__.py b/stix/threat_actor/__init__.py index 95e12674..c2176cbb 100644 --- a/stix/threat_actor/__init__.py +++ b/stix/threat_actor/__init__.py @@ -8,7 +8,9 @@ GenericRelationshipList, RelatedCampaign, RelatedPackageRefs, RelatedTTP, RelatedThreatActor ) - +from mixbox import fields +from stix.common.statement import StatementField +from stix.common.information_source import InformationSource class ObservedTTPs(GenericRelationshipList): _namespace = 'http://stix.mitre.org/ThreatActor-1' @@ -61,6 +63,19 @@ class ThreatActor(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'threatactor' + identity = fields.TypedField("Identity", Identity) + types = StatementField("Type", Statement, vocab_type=vocabs.ThreatActorType, multiple=True, key_name="types") + motivations = StatementField("Motivation", Statement, vocab_type=vocabs.Motivation, multiple=True, key_name="motivations") + sophistications = StatementField("Sophistication", Statement, vocab_type=vocabs.ThreatActorSophistication, multiple=True, key_name="sophistications") + intended_effects = StatementField("Intended_Effect", Statement, vocab_type=vocabs.IntendedEffect, multiple=True, key_name="intended_effects") + planning_and_operational_supports = StatementField("Planning_And_Operational_Support", Statement, vocab_type=vocabs.PlanningAndOperationalSupport, multiple=True, key_name="planning_and_operational_supports") + confidence = fields.TypedField("Confidence", Confidence) + observed_ttps = fields.TypedField("Observed_TTPs", ObservedTTPs) + associated_campaigns = fields.TypedField("Associated_Campaigns", AssociatedCampaigns) + associated_actors = fields.TypedField("Associated_Actors", AssociatedActors) + related_packages = fields.TypedField("Related_Packages", RelatedPackageRefs) + information_source = fields.TypedField("Information_Source", InformationSource) + def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): @@ -73,43 +88,10 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, short_description=short_description ) - self.identity = None - self.types = None - self.motivations = None - self.sophistications = None - self.intended_effects = None - self.planning_and_operational_supports = None - self.confidence = None self.observed_ttps = ObservedTTPs() self.associated_campaigns = AssociatedCampaigns() self.associated_actors = AssociatedActors() self.related_packages = RelatedPackageRefs() - - @property - def identity(self): - """A :class:`.Identity` field characterizing information about the - threat actor. - - """ - return self._identity - - @identity.setter - def identity(self, value): - self._set_var(Identity, try_cast=False, identity=value) - - @property - def types(self): - """A collection of :class:`.VocabString` objects. Default is - :class:`.ThreatActorType`. - - This behaves like a ``MutableSequence`` type. - - """ - return self._types - - @types.setter - def types(self, value): - self._types = _Types(value) def add_type(self, value): """Adds a :class:`.VocabString` object to the :attr:`types` collection. @@ -119,20 +101,6 @@ def add_type(self, value): """ self.types.append(value) - - @property - def motivations(self): - """A collection of :class:`.VocabString` objects. Default is - :class:`.Motivation`. - - This behaves like a ``MutableSequence`` type. - - """ - return self._motivations - - @motivations.setter - def motivations(self, value): - self._motivations = _Motivations(value) def add_motivation(self, value): """Adds a :class:`.Motivation` object to the :attr:`motivations` @@ -141,20 +109,6 @@ def add_motivation(self, value): """ self.motivations.append(value) - @property - def sophistications(self): - """A collection of :class:`.VocabString` objects. Default is - :class:`.ThreatActorSophistication`. - - This behaves like a ``MutableSequence`` type. - - """ - return self._sophistications - - @sophistications.setter - def sophistications(self, value): - self._sophistications = _Sophistications(value) - def add_sophistication(self, value): """Adds a :class:`.VocabString` object to the :attr:`sophistications` collection. @@ -164,22 +118,6 @@ def add_sophistication(self, value): """ self._sophistications.append(value) - - @property - def intended_effects(self): - """A collection of :class:`.Statement` objects. This behaves like a - ``MutableSequence`` type. - - If set to a string, an attempt will be made to convert it into a - :class:`.Statement` object with its value set to an instance of - :class:`.IntendedEffect`. - - """ - return self._intended_effects - - @intended_effects.setter - def intended_effects(self, value): - self._intended_effects = _IntendedEffects(value) def add_intended_effect(self, value): """Adds a :class:`.Statement` object to the :attr:`intended_effects` @@ -191,20 +129,6 @@ def add_intended_effect(self, value): """ self.intended_effects.append(value) - @property - def planning_and_operational_supports(self): - """A collection of :class:`.VocabString` objects. Default is - :class:`.PlanningAndOperationalSupport`. - - This behaves like a ``MutableSequence`` type. - - """ - return self._planning_and_operational_supports - - @planning_and_operational_supports.setter - def planning_and_operational_supports(self, value): - self._planning_and_operational_supports = _PlanningAndOperationalSupports(value) - def add_planning_and_operational_support(self, value): """Adds a :class:`.VocabString` object to the :attr:`planning_and_operational_supports` collection. @@ -214,130 +138,3 @@ def add_planning_and_operational_support(self, value): """ self.planning_and_operational_supports.append(value) - - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(ThreatActor, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if self.identity: - return_obj.Identity = self.identity.to_obj(ns_info=ns_info) - if self.types: - return_obj.Type = self.types.to_obj(ns_info=ns_info) - if self.motivations: - return_obj.Motivation = self.motivations.to_obj(ns_info=ns_info) - if self.sophistications: - return_obj.Sophistication = self.sophistications.to_obj(ns_info=ns_info) - if self.intended_effects: - return_obj.Intended_Effect = self.intended_effects.to_obj(ns_info=ns_info) - if self.planning_and_operational_supports: - return_obj.Planning_And_Operational_Support = \ - self.planning_and_operational_supports.to_obj(ns_info=ns_info) - if self.observed_ttps: - return_obj.Observed_TTPs = self.observed_ttps.to_obj(ns_info=ns_info) - if self.associated_campaigns: - return_obj.Associated_Campaigns = self.associated_campaigns.to_obj(ns_info=ns_info) - if self.associated_actors: - return_obj.Associated_Actors = self.associated_actors.to_obj(ns_info=ns_info) - if self.confidence: - return_obj.Confidence = self.confidence.to_obj(ns_info=ns_info) - if self.related_packages: - return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - super(ThreatActor, cls).from_obj(obj, return_obj=return_obj) - - if isinstance(obj, cls._binding_class): # ThreatActorType properties - return_obj.identity = Identity.from_obj(obj.Identity) - return_obj.types = _Types.from_obj(obj.Type) - return_obj.motivations = _Motivations.from_obj(obj.Motivation) - return_obj.sophistications = _Sophistications.from_obj(obj.Sophistication) - return_obj.intended_effects = _IntendedEffects.from_obj(obj.Intended_Effect) - return_obj.planning_and_operational_supports = \ - _PlanningAndOperationalSupports.from_obj(obj.Planning_And_Operational_Support) - return_obj.observed_ttps = ObservedTTPs.from_obj(obj.Observed_TTPs) - return_obj.associated_campaigns = AssociatedCampaigns.from_obj(obj.Associated_Campaigns) - return_obj.associated_actors = AssociatedActors.from_obj(obj.Associated_Actors) - return_obj.confidence = Confidence.from_obj(obj.Confidence) - return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) - - return return_obj - - def to_dict(self): - return super(ThreatActor, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - super(ThreatActor, cls).from_dict(dict_repr, return_obj=return_obj) - - get = dict_repr.get - return_obj.identity = Identity.from_dict(get('identity')) - return_obj.types = _Types.from_dict(get('types')) - return_obj.motivations = _Motivations.from_dict(get('motivations')) - return_obj.sophistications = _Sophistications.from_dict(get('sophistications')) - return_obj.intended_effects = _IntendedEffects.from_dict(get('intended_effects')) - return_obj.planning_and_operational_supports = \ - _PlanningAndOperationalSupports.from_dict(get('planning_and_operational_supports')) - return_obj.observed_ttps = ObservedTTPs.from_dict(get('observed_ttps')) - return_obj.associated_campaigns = AssociatedCampaigns.from_dict(get('associated_campaigns')) - return_obj.associated_actors = AssociatedActors.from_dict(get('associated_actors')) - return_obj.confidence = Confidence.from_dict(get('confidence')) - return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) - - return return_obj - - -# NOT ACTUAL STIX TYPES! -class _Sophistications(stix.TypedList): - _contained_type = Statement - - def _fix_value(self, value): - sophistication = vocabs.ThreatActorSophistication(value) - return Statement(value=sophistication) - - -class _Motivations(stix.TypedList): - _contained_type = Statement - - def _fix_value(self, value): - motivation = vocabs.Motivation(value) - return Statement(value=motivation) - - -class _IntendedEffects(stix.TypedList): - _contained_type = Statement - - def _fix_value(self, value): - intended_effect = vocabs.IntendedEffect(value) - return Statement(value=intended_effect) - - -class _PlanningAndOperationalSupports(stix.TypedList): - _contained_type = Statement - - def _fix_value(self, value): - pos = vocabs.PlanningAndOperationalSupport(value) - return Statement(value=pos) - - -class _Types(stix.TypedList): - _contained_type = Statement - - def _fix_value(self, value): - type_ = vocabs.ThreatActorType(value) - return Statement(value=type_) From f0370ac97481fc307e0e7aa29587b5a8393baedf Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 29 Oct 2015 14:14:32 -0400 Subject: [PATCH 232/438] Add Typed Fields to Indicator composition and Sightings --- stix/indicator/indicator.py | 34 +++++------- stix/indicator/sightings.py | 102 ------------------------------------ 2 files changed, 14 insertions(+), 122 deletions(-) diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index bca12adc..e2e4d495 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -2,7 +2,7 @@ # See LICENSE.txt for complete terms. # external -from mixbox import fields +from mixbox import fields, entities from cybox.core import Observable, ObservableComposition from cybox.common import Time @@ -190,7 +190,7 @@ class Indicator(stix.BaseCoreComponent): kill_chain_phases = fields.TypedField("Kill_Chain_Phases", KillChainPhasesReference) valid_time_positions = fields.TypedField("Valid_Time_Position", ValidTime, multiple=True, key_name="valid_time_positions") related_indicators = fields.TypedField("Related_Indicators", RelatedIndicators) - related_campaigns = fields.TypedField("Related_Campaigns", type_="stix.indicator.RelatedCampaigns") + related_campaigns = fields.TypedField("Related_Campaigns", type_="stix.indicator.RelatedCampaignRefs") likely_impact = fields.TypedField("Likely_Impact", Statement) negate = fields.TypedField("negate") related_packages = fields.TypedField("Related_Packages", RelatedPackageRefs) @@ -745,8 +745,8 @@ def add_object(self, object_): self.add_observable(observable) - def to_obj(self, return_obj=None, ns_info=None): - obj = super(Indicator, self).to_obj(return_obj=return_obj, ns_info=ns_info) + def to_obj(self, ns_info=None): + obj = super(Indicator, self).to_obj(ns_info=ns_info) if self.observables: if len(self.observables) > 1: @@ -841,7 +841,7 @@ def from_dict(cls, dict_repr, return_obj=None): return return_obj """ -class CompositeIndicatorExpression(stix.EntityList): +class CompositeIndicatorExpression(entities.EntityList): """Implementation of the STIX ``CompositeIndicatorExpressionType``. The ``CompositeIndicatorExpression`` class implements methods found on @@ -891,26 +891,20 @@ class CompositeIndicatorExpression(stix.EntityList): OP_OR = "OR" OPERATORS = (OP_AND, OP_OR) - def __init__(self, operator="OR", *args): - super(CompositeIndicatorExpression, self).__init__(*args) - self.operator = operator - - @property - def operator(self): - return self._operator - - @operator.setter - def operator(self, value): + def check_operator(self, value): + raise ValueError("always") if not value: raise ValueError("operator must not be None or empty") elif value not in self.OPERATORS: raise ValueError("operator must be one of: %s" % (self.OPERATORS,)) - else: - self._operator = value + + operator = fields.TypedField("operator", preset_hook=check_operator) - def __nonzero__(self): - return super(CompositeIndicatorExpression, self).__nonzero__() + def __init__(self, operator="OR", *args): + super(CompositeIndicatorExpression, self).__init__(*args) + self.operator = operator + """ def to_obj(self, return_obj=None, ns_info=None): list_obj = super(CompositeIndicatorExpression, self).to_obj(return_obj=return_obj, ns_info=ns_info) list_obj.operator = self.operator @@ -943,7 +937,7 @@ def from_dict(cls, dict_repr, return_obj=None): super(CompositeIndicatorExpression, cls).from_dict(dict_repr, return_obj=return_obj) return_obj.operator = dict_repr.get('operator') return return_obj - + """ class RelatedCampaignRefs(GenericRelationshipList): _namespace = "http://stix.mitre.org/Indicator-2" diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index 087ed39c..9b45f11b 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -62,65 +62,6 @@ def add_description(self, description): """ self.descriptions.add(description) - - """ - def to_obj(self, return_obj=None, ns_info=None): - super(Sighting, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - return_obj.timestamp = utils.dates.serialize_value(self.timestamp) - return_obj.timestamp_precision = self.timestamp_precision - return_obj.Reference = self.reference - - if self.source: - return_obj.Source = self.source.to_obj(ns_info=ns_info) - if self.confidence: - return_obj.Confidence = self.confidence.to_obj(ns_info=ns_info) - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.related_observables: - return_obj.Related_Observables = self.related_observables.to_obj(ns_info=ns_info) - - return return_obj - - def to_dict(self): - return super(Sighting, self).to_dict() - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if return_obj is None: - return_obj = cls() - - return_obj.timestamp = obj.timestamp - return_obj.timestamp_precision = obj.timestamp_precision - return_obj.source = InformationSource.from_obj(obj.Source) - return_obj.reference = obj.Reference - return_obj.confidence = Confidence.from_obj(obj.Confidence) - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.related_observables = RelatedObservables.from_obj(obj.Related_Observables) - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if return_obj is None: - return_obj = cls() - - return_obj.timestamp = d.get('timestamp') - return_obj.timestamp_precision = d.get('timestamp_precision') - return_obj.source = InformationSource.from_dict(d.get('source')) - return_obj.reference = d.get('reference') - return_obj.confidence = Confidence.from_dict(d.get('confidence')) - return_obj.descriptions = StructuredTextList.from_dict(d.get('description')) - return_obj.related_observables = RelatedObservables.from_dict(d.get('related_observables')) - return return_obj - """ class Sightings(stix.EntityList): _namespace = "http://stix.mitre.org/Indicator-2" @@ -139,49 +80,6 @@ def __init__(self, sightings_count=None, *args): def __nonzero__(self): return super(Sightings, self).__nonzero__() or bool(self.sightings_count) - """ - @property - def sightings_count(self): - return self._sightings_count - - @sightings_count.setter - def sightings_count(self, value): - self._set_var(int, sightings_count=value) - """ - - def to_obj(self, return_obj=None, ns_info=None): - list_obj = super(Sightings, self).to_obj(return_obj=return_obj, ns_info=ns_info) - list_obj.sightings_count = self.sightings_count - return list_obj - - def to_dict(self): - d = super(Sightings, self).to_dict() - if self.sightings_count: - d['sightings_count'] = self.sightings_count - return d - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if return_obj is None: - return_obj = cls() - - super(Sightings, cls).from_obj(obj, return_obj=return_obj) - return_obj.sightings_count = obj.sightings_count - return return_obj - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - if return_obj is None: - return_obj = cls() - - super(Sightings, cls).from_dict(dict_repr, return_obj=return_obj) - return_obj.sightings_count = dict_repr.get('sightings_count') - return return_obj - class RelatedObservables(GenericRelationshipList): _namespace = "http://stix.mitre.org/Indicator-2" From b876c1e559c7c8cab984fda137815b003728c106 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Sun, 1 Nov 2015 16:02:45 -0500 Subject: [PATCH 233/438] WIP. Began updating python-stix EntityList subclasses to align with mixbox EntityList. --- stix/campaign/__init__.py | 57 ++++++++++++++++++++--------- stix/common/identity.py | 8 ++-- stix/common/information_source.py | 8 ++-- stix/common/kill_chains/__init__.py | 41 +++++++++++++++------ stix/common/names.py | 10 +++-- stix/common/related.py | 41 +++++++++++++++++---- stix/data_marking.py | 12 +----- 7 files changed, 119 insertions(+), 58 deletions(-) diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index bccea8f9..3cd7545e 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -10,43 +10,58 @@ RelatedIncident, RelatedIndicator, RelatedPackageRefs, RelatedThreatActor, RelatedTTP) from stix.common import vocabs +from stix.common.vocabs import VocabField import stix.bindings.campaign as campaign_binding from stix.common.structured_text import StructuredTextList from stix.common.information_source import InformationSource + class AssociatedCampaigns(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" _binding = campaign_binding _binding_class = campaign_binding.AssociatedCampaignsType - _binding_var = "Associated_Campaign" - _contained_type = RelatedCampaign - _inner_name = "campaigns" + + campaign = fields.TypedField("Associated_Campaign", RelatedCampaign, multiple=True, key_name="campaigns") + + @classmethod + def _dict_as_list(cls): + return False + class Attribution(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" _binding = campaign_binding _binding_class = campaign_binding.AttributionType - _binding_var = "Attributed_Threat_Actor" - _contained_type = RelatedThreatActor - _inner_name = "threat_actors" + + threat_actor = fields.TypedField("Attributed_Threat_Actor", RelatedThreatActor, multiple=True, key_name="threat_actors") + + @classmethod + def _dict_as_list(cls): + return False class RelatedIncidents(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" _binding = campaign_binding _binding_class = campaign_binding.RelatedIncidentsType - _binding_var = "Related_Incident" - _contained_type = RelatedIncident - _inner_name = "incidents" + + incident = fields.TypedField("Related_Incident", RelatedIncident, multiple=True, key_name="incidents") + + @classmethod + def _dict_as_list(cls): + return False class RelatedIndicators(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" _binding = campaign_binding _binding_class = campaign_binding.RelatedIndicatorsType - _binding_var = "Related_Indicator" - _contained_type = RelatedIndicator - _inner_name = "indicators" + + indicator = fields.TypedField("Related_Indicator", RelatedIndicator, multiple=True, key_name="indicators") + + @classmethod + def _dict_as_list(cls): + return False def _is_valid(self, value): deprecated.warn(value) @@ -57,18 +72,24 @@ class RelatedTTPs(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" _binding = campaign_binding _binding_class = campaign_binding.RelatedTTPsType - _binding_var = "Related_TTP" - _contained_type = RelatedTTP - _inner_name = "ttps" + + ttp = fields.TypedField("Related_TTP", RelatedTTP, multiple=True, key_name="ttps") + + @classmethod + def _dict_as_list(cls): + return False class Names(stix.EntityList): _namespace = "http://stix.mitre.org/Campaign-1" _binding = campaign_binding _binding_class = campaign_binding.NamesType - _binding_var = "Name" - _contained_type = VocabString - _inner_name = "names" + + name = VocabField("Name", multiple=True, key_name="names") + + @classmethod + def _dict_as_list(cls): + return False class Campaign(stix.BaseCoreComponent): diff --git a/stix/common/identity.py b/stix/common/identity.py index 03e1a2cf..6437fb52 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -46,9 +46,11 @@ class RelatedIdentities(stix.EntityList): _namespace = 'http://stix.mitre.org/common-1' _binding = common_binding _binding_class = common_binding.RelatedIdentitiesType - _binding_var = "Related_Identity" - _contained_type = RelatedIdentity - _inner_name = "identities" + related_identity = fields.TypedField("Related_Identity", RelatedIdentity, multiple=True, key_name="identities") + + @classmethod + def _dict_as_list(cls): + return False # Backwards compatibility diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 70b49c40..955c23fb 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -89,7 +89,9 @@ class ContributingSources(stix.EntityList): _namespace = "http://stix.mitre.org/common-1" _binding = stix_common_binding _binding_class = stix_common_binding.ContributingSourcesType - _binding_var = "Source" - _contained_type = InformationSource - _inner_name = "sources" + source = fields.TypedField("Source", InformationSource, multiple=True, key_name="sources") + + @classmethod + def _dict_as_list(cls): + return False \ No newline at end of file diff --git a/stix/common/kill_chains/__init__.py b/stix/common/kill_chains/__init__.py index f29bffe6..a8b4e8f6 100644 --- a/stix/common/kill_chains/__init__.py +++ b/stix/common/kill_chains/__init__.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. from mixbox import fields +from mixbox import typedlist # internal import stix @@ -48,9 +49,12 @@ class KillChains(stix.EntityList): _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' _binding_class = _binding.KillChainsType - _contained_type = KillChain - _binding_var = "Kill_Chain" - _inner_name = "kill_chains" + + kill_chain = fields.TypedField("Kill_Chain", KillChain, multiple=True, key_name="kill_chains") + + @classmethod + def _dict_as_list(cls): + return False class KillChainPhase(stix.Entity): @@ -99,17 +103,13 @@ def __init__(self, phase_id=None, name=None, ordinality=None, kill_chain_id=None self.kill_chain_name = kill_chain_name -class KillChainPhasesReference(stix.EntityList): - _binding = common_binding - _namespace = 'http://stix.mitre.org/common-1' - _binding_class = _binding.KillChainPhasesReferenceType - _contained_type = KillChainPhaseReference - _binding_var = "Kill_Chain_Phase" - _inner_name = "kill_chain_phases" +class _KillChainPhaseReferenceList(typedlist.TypedList): + def __init__(self, *args): + super(_KillChainPhaseReferenceList, self).__init__(KillChainPhaseReference, True, *args) def _fix_value(self, value): if not isinstance(value, KillChainPhase): - return super(KillChainPhasesReference, self)._fix_value(value) + return super(_KillChainPhaseReferenceList, self)._fix_value(value) if value.phase_id: return KillChainPhaseReference(phase_id=value.phase_id) @@ -117,6 +117,25 @@ def _fix_value(self, value): raise ValueError("KillChainPhase must have a phase_id.") +class _KillChainPhaseReferenceField(fields.TypedField): + def __init__(self, *args, **kwargs): + super(_KillChainPhaseReferenceField, self).__init__(*args, **kwargs) + self.type_ = KillChainPhaseReference + self.listclass = _KillChainPhaseReferenceList + + +class KillChainPhasesReference(stix.EntityList): + _binding = common_binding + _namespace = 'http://stix.mitre.org/common-1' + _binding_class = _binding.KillChainPhasesReferenceType + + kill_chain_phase = _KillChainPhaseReferenceField("Kill_Chain_Phase", multiple=True, key_name="kill_chain_phases") + + @classmethod + def _dict_as_list(cls): + return False + + # NOT AN ACTUAL STIX TYPE! class _KillChainPhases(stix.TypedList): _contained_type = KillChainPhase diff --git a/stix/common/names.py b/stix/common/names.py index a65660f0..47296864 100644 --- a/stix/common/names.py +++ b/stix/common/names.py @@ -1,18 +1,20 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# external +from mixbox import fields + # internal import stix import stix.bindings.stix_common as common_binding # relative -from .vocabs import VocabString, VocabFactory +from .vocabs import VocabField class Names(stix.EntityList): _namespace = 'http://stix.mitre.org/common-1' _binding = common_binding _binding_class = _binding.NamesType - _contained_type = VocabString - _entity_factory = VocabFactory - _binding_var = 'Name' + + name = VocabField("Name", multiple=True) diff --git a/stix/common/related.py b/stix/common/related.py index f3b8ffd4..281484b5 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -1,6 +1,14 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. + +# stdlib +import functools + +# mixbox from mixbox import fields +from mixbox import typedlist + +# cybox from cybox.core import Observable # internal @@ -92,6 +100,12 @@ def __nonzero__(self): class GenericRelationshipList(stix.EntityList): + """Base class for concrete GenericRelationshipList types. + + Note: + Subclasses must supply exactly one multiple TypedField. + """ + _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = _binding.GenericRelationshipListType @@ -107,13 +121,9 @@ def __nonzero__(self): bool(self.scope)) -class RelatedPackageRefs(stix.EntityList): - _namespace = 'http://stix.mitre.org/common-1' - _binding = common_binding - _binding_class = common_binding.RelatedPackageRefsType - _binding_var = "Package_Reference" - _contained_type = RelatedPackageRef - _inner_name = "packages" +class _RelatedPackageList(typedlist.TypedList): + def __init__(self, *args): + super(_RelatedPackageList, self).__init__(RelatedPackageRef, True, *args) def _fix_value(self, value): from stix.core import STIXPackage @@ -128,7 +138,21 @@ def _fix_value(self, value): def _is_valid(self, value): deprecated.warn(value) - return stix.EntityList._is_valid(self, value) + super(_RelatedPackageList, self)._is_valid(self, value) + + +class _RelatedPackageField(fields.TypedField): + def __init__(self, *args, **kwargs): + super(_RelatedPackageField, self).__init__(*args, **kwargs) + self.type_ = RelatedPackageRef + self.listclass = _RelatedPackageList + + +class RelatedPackageRefs(stix.EntityList): + _namespace = 'http://stix.mitre.org/common-1' + _binding = common_binding + _binding_class = common_binding.RelatedPackageRefsType + package = _RelatedPackageField("Package_Reference", multiple=True, key_name="packages") class _BaseRelated(GenericRelationship): @@ -150,6 +174,7 @@ def __init__(self, item=None, confidence=None, information_source, relationship ) + self.item = item diff --git a/stix/data_marking.py b/stix/data_marking.py index f4e03cb3..20978b4f 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -82,21 +82,11 @@ class Marking(stix.EntityList): _binding = stix_data_marking_binding _binding_class = stix_data_marking_binding.MarkingType _namespace = 'http://data-marking.mitre.org/Marking-1' - _contained_type = MarkingSpecification - _binding_var = "Marking" + marking = fields.TypedField("Marking", MarkingSpecification, multiple=True) def __init__(self, markings=None): super(Marking, self).__init__(markings) - @property - def markings(self): - return self._inner - - @markings.setter - def markings(self, value): - self._inner = [] - self.extend(value) - def add_marking(self, value): self.markings.append(value) From 05e8db0bd53e4ecbffb8e3073e558b2b31ba9479 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 2 Nov 2015 08:42:12 -0500 Subject: [PATCH 234/438] Replaced custom multiple fields with standard TypedFields which are passed listfunc arguments. --- stix/common/kill_chains/__init__.py | 16 ++++++++-------- stix/common/related.py | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/stix/common/kill_chains/__init__.py b/stix/common/kill_chains/__init__.py index a8b4e8f6..4ec8e323 100644 --- a/stix/common/kill_chains/__init__.py +++ b/stix/common/kill_chains/__init__.py @@ -86,6 +86,7 @@ def __ne__(self, other): return not self.__eq__(other) def __hash__(self): + # TODO (bworrell): Is all the tuple(sorted(...))) needed? return hash(tuple(sorted(self.to_dict().items()))) @@ -117,19 +118,18 @@ def _fix_value(self, value): raise ValueError("KillChainPhase must have a phase_id.") -class _KillChainPhaseReferenceField(fields.TypedField): - def __init__(self, *args, **kwargs): - super(_KillChainPhaseReferenceField, self).__init__(*args, **kwargs) - self.type_ = KillChainPhaseReference - self.listclass = _KillChainPhaseReferenceList - - class KillChainPhasesReference(stix.EntityList): _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' _binding_class = _binding.KillChainPhasesReferenceType - kill_chain_phase = _KillChainPhaseReferenceField("Kill_Chain_Phase", multiple=True, key_name="kill_chain_phases") + kill_chain_phase = fields.TypedField( + name="Kill_Chain_Phase", + type_=KillChainPhaseReference, + multiple=True, + listfunc=_KillChainPhaseReferenceList, + key_name="kill_chain_phases" + ) @classmethod def _dict_as_list(cls): diff --git a/stix/common/related.py b/stix/common/related.py index 281484b5..ad700469 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -141,18 +141,18 @@ def _is_valid(self, value): super(_RelatedPackageList, self)._is_valid(self, value) -class _RelatedPackageField(fields.TypedField): - def __init__(self, *args, **kwargs): - super(_RelatedPackageField, self).__init__(*args, **kwargs) - self.type_ = RelatedPackageRef - self.listclass = _RelatedPackageList - - class RelatedPackageRefs(stix.EntityList): _namespace = 'http://stix.mitre.org/common-1' _binding = common_binding _binding_class = common_binding.RelatedPackageRefsType - package = _RelatedPackageField("Package_Reference", multiple=True, key_name="packages") + + package = fields.TypedField( + name="Package_Reference", + type_=RelatedPackageRef, + multiple=True, + key_name="packages", + listfunc=_RelatedPackageList + ) class _BaseRelated(GenericRelationship): From c14e08dd6295cf0b52bf0cf453c8e0cb50ac3fe9 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 2 Nov 2015 10:09:59 -0500 Subject: [PATCH 235/438] Added TypedFields to RelatedPackages and RelatedReports. Added _dict_as_list() to GenericRelationshipList so that it is inherited by subclasses. --- stix/campaign/__init__.py | 3 --- stix/common/identity.py | 1 + stix/common/related.py | 38 ++++++++++++++++++++++++++++++++------ 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 3cd7545e..0a897de7 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -59,9 +59,6 @@ class RelatedIndicators(GenericRelationshipList): indicator = fields.TypedField("Related_Indicator", RelatedIndicator, multiple=True, key_name="indicators") - @classmethod - def _dict_as_list(cls): - return False def _is_valid(self, value): deprecated.warn(value) diff --git a/stix/common/identity.py b/stix/common/identity.py index 6437fb52..07278446 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -46,6 +46,7 @@ class RelatedIdentities(stix.EntityList): _namespace = 'http://stix.mitre.org/common-1' _binding = common_binding _binding_class = common_binding.RelatedIdentitiesType + related_identity = fields.TypedField("Related_Identity", RelatedIdentity, multiple=True, key_name="identities") @classmethod diff --git a/stix/common/related.py b/stix/common/related.py index ad700469..e323e811 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -120,6 +120,10 @@ def __nonzero__(self): return (super(GenericRelationshipList, self).__nonzero__() or bool(self.scope)) + @classmethod + def _dict_as_list(cls): + return False + class _RelatedPackageList(typedlist.TypedList): def __init__(self, *args): @@ -182,6 +186,8 @@ class RelatedCampaign(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedCampaignType + + # _BaseRelated requires an "item" field. item = fields.TypedField("Campaign", type_="stix.campaign.Campaign") @@ -189,6 +195,8 @@ class RelatedCOA(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedCourseOfActionType + + # _BaseRelated requires an "item" field. item = fields.TypedField("Course_Of_Action", type_="stix.coa.CourseOfAction") @@ -196,6 +204,8 @@ class RelatedExploitTarget(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedExploitTargetType + + # _BaseRelated requires an "item" field. item = fields.TypedField("Exploit_Target", type_="stix.exploit_target.ExploitTarget") @@ -203,6 +213,8 @@ class RelatedIdentity(_BaseRelated): _namespace = 'http://stix.mitre.org/common-1' _binding = common_binding _binding_class = common_binding.RelatedIdentityType + + # _BaseRelated requires an "item" field. item = fields.TypedField("Identity", type_="stix.common.identity.Identity", factory="stix.common.identity.IdentityFactory") @@ -210,12 +222,16 @@ class RelatedIncident(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedIncidentType + + # _BaseRelated requires an "item" field. item = fields.TypedField("Incident", type_="stix.incident.Incident") class RelatedIndicator(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedIndicatorType + + # _BaseRelated requires an "item" field. item = fields.TypedField("Indicator", type_="stix.indicator.Indicator") @@ -223,12 +239,16 @@ class RelatedObservable(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedObservableType + + # _BaseRelated requires an "item" field. item = fields.TypedField("Observable", type_=Observable) class RelatedThreatActor(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedThreatActorType + + # _BaseRelated requires an "item" field. item = fields.TypedField("Threat_Actor", type_="stix.threat_actor.ThreatActor") @@ -236,6 +256,8 @@ class RelatedTTP(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedTTPType + + # _BaseRelated requires an "item" field. item = fields.TypedField("TTP", type_="stix.ttp.TTP") @@ -243,6 +265,8 @@ class RelatedPackage(_BaseRelated): _namespace = "http://stix.mitre.org/stix-1" _binding = core_binding _binding_class = core_binding.RelatedPackageType + + # _BaseRelated requires an "item" field. item = fields.TypedField("Package", type_="stix.core.STIXPackage", preset_hook=deprecated.field) @@ -250,6 +274,8 @@ class RelatedReport(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = common_binding.RelatedReportType + + # _BaseRelated requires an "item" field. item = fields.TypedField("Report", type_="stix.report.Report") @@ -257,6 +283,8 @@ class RelatedCampaignRef(_BaseRelated): _namespace = "http://stix.mitre.org/common-1" _binding = common_binding _binding_class = _binding.RelatedCampaignReferenceType + + # _BaseRelated requires an "item" field. item = fields.TypedField("Campaign", type_="stix.common.CampaignRef") @@ -264,15 +292,13 @@ class RelatedPackages(GenericRelationshipList): _namespace = 'http://stix.mitre.org/stix-1' _binding = core_binding _binding_class = core_binding.RelatedPackagesType - _binding_var = "Related_Package" - _contained_type = RelatedPackage - _inner_name = "related_packages" + + related_package = fields.TypedField("Related_Package", RelatedPackage, multiple=True, key_name="related_packages") class RelatedReports(GenericRelationshipList): _namespace = 'http://stix.mitre.org/Report-1' _binding = report_binding _binding_class = report_binding.RelatedReportsType - _binding_var = "Related_Report" - _contained_type = RelatedReport - _inner_name = "related_reports" + + related_report = fields.TypedField("Related_Report", RelatedReport, multiple=True, key_name="related_reports") From 053ef50204e7beeb50f2916708c978bf787163c4 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 2 Nov 2015 11:42:16 -0500 Subject: [PATCH 236/438] More EntityList updates across python-stix. TestMecanisms isn't updated yet. Need to test all of this. --- stix/common/kill_chains/__init__.py | 2 +- stix/common/vocabs.py | 21 +++ stix/core/__init__.py | 85 +++++++----- stix/core/ttps.py | 91 ++++--------- stix/incident/__init__.py | 74 +++++++---- stix/indicator/indicator.py | 101 +++++++------- stix/indicator/sightings.py | 21 +-- stix/indicator/test_mechanism.py | 2 + stix/report/__init__.py | 36 ++--- stix/ttp/behavior.py | 22 ++-- stix/ttp/infrastructure.py | 14 +- stix/ttp/resource.py | 195 +++++++++++++++------------- stix/utils/deprecated.py | 9 +- 13 files changed, 344 insertions(+), 329 deletions(-) diff --git a/stix/common/kill_chains/__init__.py b/stix/common/kill_chains/__init__.py index 4ec8e323..b538a4e3 100644 --- a/stix/common/kill_chains/__init__.py +++ b/stix/common/kill_chains/__init__.py @@ -106,7 +106,7 @@ def __init__(self, phase_id=None, name=None, ordinality=None, kill_chain_id=None class _KillChainPhaseReferenceList(typedlist.TypedList): def __init__(self, *args): - super(_KillChainPhaseReferenceList, self).__init__(KillChainPhaseReference, True, *args) + super(_KillChainPhaseReferenceList, self).__init__(type=KillChainPhaseReference, *args) def _fix_value(self, value): if not isinstance(value, KillChainPhase): diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index 8ce0b639..a6b7ed8f 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -1,9 +1,15 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# stdlib +from functools import partial + +# mixbox from mixbox import fields from mixbox import entities +from mixbox import typedlist +# stix import stix import stix.bindings.stix_common as stix_common_binding @@ -22,6 +28,19 @@ def validate_value(instance, value): error = error.format(**locals()) raise ValueError(error) +class VocabList(typedlist.TypedList): + """VocabString fields can be any type of VocabString, though there is often + a preferred/default VocabString type. + + The TypedList will attempt to make sure that every input item is an instance + of the default VocabString and throw an error if it isn't. This sublcass + overrides that behavior and allows any instance of VocabString to be + inserted. + """ + + def _is_valid(self, value): + return isinstance(value, VocabString) + class VocabField(fields.TypedField): """TypedField subclass for VocabString fields.""" @@ -43,6 +62,8 @@ def __init__(self, *args, **kwargs): if self.type_ is None: self.type_ = VocabString + self.listfunc = partial(VocabList, type=self.type_, ignore_none=True) + def check_type(self, value): return isinstance(value, VocabString) diff --git a/stix/core/__init__.py b/stix/core/__init__.py index dcd16eed..08ecc749 100644 --- a/stix/core/__init__.py +++ b/stix/core/__init__.py @@ -1,11 +1,17 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# stdlib +from functools import partial + +# mixbox +from mixbox import fields + # base import import stix # deprecations -from stix.utils import deprecated +from stix.utils.deprecated import IdrefDeprecatedList # component imports from stix.campaign import Campaign @@ -25,84 +31,91 @@ class Campaigns(stix.EntityList): _binding = stix_core_binding _namespace = 'http://stix.mitre.org/stix-1' _binding_class = _binding.CampaignsType - _contained_type = Campaign - _binding_var = "Campaign" - def _is_valid(self, value): - deprecated.idref(value) - return stix.EntityList._is_valid(self, value) + campaign = fields.TypedField( + name="Campaign", + type_=Campaign, + multiple=True, + listfunc=partial(IdrefDeprecatedList, type=Campaign) + ) class CoursesOfAction(stix.EntityList): _binding = stix_core_binding _namespace = 'http://stix.mitre.org/stix-1' _binding_class = _binding.CoursesOfActionType - _contained_type = CourseOfAction - _binding_var = "Course_Of_Action" - def _is_valid(self, value): - deprecated.idref(value) - return stix.EntityList._is_valid(self, value) + course_of_action = fields.TypedField( + name="Course_Of_Action", + type_=CourseOfAction, + multiple=True, + listfunc=partial(IdrefDeprecatedList, type=CourseOfAction) + ) class ExploitTargets(stix.EntityList): _binding = stix_common_binding _namespace = 'http://stix.mitre.org/common-1' _binding_class = _binding.ExploitTargetsType - _contained_type = ExploitTarget - _binding_var = "Exploit_Target" - def _is_valid(self, value): - deprecated.idref(value) - return stix.EntityList._is_valid(self, value) + exploit_target = fields.TypedField( + name="Exploit_Target", + type_=ExploitTarget, + multiple=True, + listfunc=partial(IdrefDeprecatedList, type=ExploitTarget) + ) class Incidents(stix.EntityList): _binding = stix_core_binding _namespace = 'http://stix.mitre.org/stix-1' _binding_class = _binding.IncidentsType - _contained_type = Incident - _binding_var = "Incident" - def _is_valid(self, value): - deprecated.idref(value) - return stix.EntityList._is_valid(self, value) + incident = fields.TypedField( + name="Incident", + type_=Incident, + multiple=True, + listfunc=partial(IdrefDeprecatedList, type=Incident) + ) class Indicators(stix.EntityList): _binding = stix_core_binding _namespace = 'http://stix.mitre.org/stix-1' _binding_class = _binding.IndicatorsType - _contained_type = Indicator - _binding_var = "Indicator" - def _is_valid(self, value): - deprecated.idref(value) - return stix.EntityList._is_valid(self, value) + indicator = fields.TypedField( + name="Indicator", + type_=Indicator, + multiple=True, + listfunc=partial(IdrefDeprecatedList, type=Indicator) + ) class ThreatActors(stix.EntityList): _binding = stix_core_binding _namespace = 'http://stix.mitre.org/stix-1' _binding_class = _binding.ThreatActorsType - _contained_type = ThreatActor - _binding_var = "Threat_Actor" - def _is_valid(self, value): - deprecated.idref(value) - return stix.EntityList._is_valid(self, value) + threat_actor = fields.TypedField( + name="Threat_Actor", + type_=ThreatActor, + multiple=True, + listfunc=partial(IdrefDeprecatedList, type=ThreatActor) + ) class Reports(stix.EntityList): _binding = stix_core_binding _namespace = 'http://stix.mitre.org/stix-1' _binding_class = _binding.ReportsType - _contained_type = Report - _binding_var = "Report" - def _is_valid(self, value): - deprecated.idref(value) - return stix.EntityList._is_valid(self, value) + report = fields.TypedField( + name="Report", + type_=Report, + multiple=True, + listfunc=partial(IdrefDeprecatedList, type=Report) + ) # Namespace flattening diff --git a/stix/core/ttps.py b/stix/core/ttps.py index a355de68..82832e40 100644 --- a/stix/core/ttps.py +++ b/stix/core/ttps.py @@ -1,89 +1,42 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# stdlib +from functools import partial + +# mixbox +from mixbox import entities +from mixbox import fields + +# stix import stix -import stix.utils as utils +from stix import utils from stix.ttp import TTP from stix.common.kill_chains import KillChains from stix.bindings import stix_core as core_binding # deprecation warnings -from stix.utils import deprecated +from stix.utils.deprecated import IdrefDeprecatedList + class TTPs(stix.EntityList): _binding = core_binding _binding_class = _binding.TTPsType _namespace = 'http://stix.mitre.org/stix-1' - _contained_type = TTP - _binding_var = "TTP" - _inner_name = "ttps" - - def __init__(self, ttps=None): - super(TTPs, self).__init__(ttps) - self.kill_chains = KillChains() - def __nonzero__(self): - return super(TTPs, self).__nonzero__() or bool(self.kill_chains) + ttps = fields.TypedField( + name="TTP", + type_=TTP, + multiple=True, + key_name="ttps", + listfunc=partial(IdrefDeprecatedList, type=TTP) + ) - @property - def ttps(self): - return self._inner - - @ttps.setter - def ttps(self, value): - self._inner = [] + kill_chains = fields.TypedField("Kill_Chains", KillChains) - if utils.is_sequence(value): - self.extend(value) - else: - self.append(value) + def __init__(self, ttps=None): + super(TTPs, self).__init__(ttps) + self.kill_chains = KillChains() def add_ttp(self, ttp): self.append(ttp) - - def _is_valid(self, value): - deprecated.idref(value) - return stix.EntityList._is_valid(self, value) - - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(TTPs, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if self.kill_chains: - return_obj.Kill_Chains = self.kill_chains.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): # noqa - if not obj: - return None - - if not return_obj: - return_obj = cls() - - super(TTPs, cls).from_obj(obj, return_obj=return_obj) - - return_obj.kill_chains = KillChains.from_obj(obj.Kill_Chains) - - return return_obj - - def to_dict(self): - return super(TTPs, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): # noqa - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - super(TTPs, cls).from_dict(dict_repr, return_obj) - - get = dict_repr.get - return_obj.kill_chains = KillChains.from_dict(get('kill_chains')) - - return return_obj diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index 5bd3ea48..48c8a27d 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -6,6 +6,7 @@ import stix.bindings.incident as incident_binding from stix.common import vocabs from stix.common import Statement, VocabString, InformationSource, Confidence +from stix.common.vocabs import VocabField from stix.common.identity import Identity, IdentityFactory from stix.common.related import (GenericRelationshipList, RelatedIndicator, RelatedThreatActor, RelatedTTP, RelatedObservable, RelatedIncident, @@ -369,68 +370,91 @@ class AttributedThreatActors(GenericRelationshipList): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.AttributedThreatActorsType - _binding_var = "Threat_Actor" - _contained_type = RelatedThreatActor - _inner_name = "threat_actors" + + threat_actor = fields.TypedField( + name="Threat_Actor", + type_=RelatedThreatActor, + multiple=True, + key_name="threat_actors" + ) class RelatedIndicators(GenericRelationshipList): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.RelatedIndicatorsType - _binding_var = "Related_Indicator" - _contained_type = RelatedIndicator - _inner_name = "indicators" + + indicator = fields.TypedField( + name="Related_Indicator", + type_=RelatedIndicator, + multiple=True, + key_name="indicators" + ) class RelatedObservables(GenericRelationshipList): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.RelatedObservablesType - _binding_var = "Related_Observable" - _contained_type = RelatedObservable - _inner_name = "observables" + + observable = fields.TypedField( + name="Related_Observable", + type_=RelatedObservable, + multiple=True, + key_name="observables" + ) class LeveragedTTPs(GenericRelationshipList): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = _binding.LeveragedTTPsType - _binding_var = "Leveraged_TTP" - _contained_type = RelatedTTP - _inner_name = "ttps" + + ttp = fields.TypedField( + name="Leverated_TTP", + type_=RelatedTTP, + multiple=True, + key_name="ttps" + ) class RelatedIncidents(GenericRelationshipList): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.RelatedIncidentsType - _binding_var = "Related_Incident" - _contained_type = RelatedIncident - _inner_name = "incidents" + + incident = fields.TypedField( + name="Related_Incident", + type_=RelatedIncident, + multiple=True, + key_name="incidents" + ) class IncidentCategories(stix.EntityList): _namespace = "http://stix.mitre.org/Incident-1" - _contained_type = VocabString _binding = incident_binding _binding_class = _binding.CategoriesType - _binding_var = "Category" - _inner_name = "categories" - _dict_as_list = True - def _fix_value(self, value): - return vocabs.IncidentCategory(value) + category = VocabField( + name="Category", + type_=vocabs.IncidentCategory, + multiple=True, + key_name="categories" + ) class AffectedAssets(stix.EntityList): _namespace = "http://stix.mitre.org/Incident-1" - _contained_type = AffectedAsset _binding = incident_binding _binding_class = _binding.AffectedAssetsType - _binding_var = "Affected_Asset" - _inner_name = "affected_assets" - _dict_as_list = True + + affected_asset = fields.TypedField( + name="Affected_Asset", + type_=AffectedAsset, + multiple=True, + key_name="affected_assets" + ) # NOT ACTUAL STIX TYPES! diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index e2e4d495..2531d5c1 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -1,9 +1,12 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# external -from mixbox import fields, entities +# mixbox +from mixbox import fields +from mixbox import entities +from mixbox import typedlist +# cybox from cybox.core import Observable, ObservableComposition from cybox.common import Time @@ -841,6 +844,17 @@ def from_dict(cls, dict_repr, return_obj=None): return return_obj """ +def check_operator(composite_indicator_exp, value): + allowed = CompositeIndicatorExpression.OPERATORS + + if not value: + raise ValueError("operator must not be None or empty") + elif value not in allowed: + raise ValueError("operator must be one of: %s" % allowed) + else: + return + + class CompositeIndicatorExpression(entities.EntityList): """Implementation of the STIX ``CompositeIndicatorExpressionType``. @@ -883,81 +897,56 @@ class CompositeIndicatorExpression(entities.EntityList): _binding = indicator_binding _binding_class = indicator_binding.CompositeIndicatorExpressionType _namespace = 'http://stix.mitre.org/Indicator-2' - _contained_type = Indicator - _binding_var = "Indicator" - _inner_name = "indicators" - + OP_AND = "AND" OP_OR = "OR" OPERATORS = (OP_AND, OP_OR) - - def check_operator(self, value): - raise ValueError("always") - if not value: - raise ValueError("operator must not be None or empty") - elif value not in self.OPERATORS: - raise ValueError("operator must be one of: %s" % (self.OPERATORS,)) - + operator = fields.TypedField("operator", preset_hook=check_operator) - + indicator = fields.TypedField( + name="Indicator", + type_=Indicator, + multiple=True, + key_name="indicators" + ) + + # TODO (bworrell): Change this to *args, **kwargs to get around the weirdness + # that occurs when creating with kwarg and arglist. + # E.g, CompositeIndicatorExpression(operator="AND", arg1, arg2, arg3) + # will raise an error. def __init__(self, operator="OR", *args): super(CompositeIndicatorExpression, self).__init__(*args) self.operator = operator - """ - def to_obj(self, return_obj=None, ns_info=None): - list_obj = super(CompositeIndicatorExpression, self).to_obj(return_obj=return_obj, ns_info=ns_info) - list_obj.operator = self.operator - return list_obj - def to_dict(self): - d = super(CompositeIndicatorExpression, self).to_dict() - if self.operator: - d['operator'] = self.operator - return d +class _RelatedCampaignRefList(typedlist.TypedList): + def __init__(self, *args): + super(_RelatedCampaignRefList, self).__init__(type=RelatedCampaignRef, *args) - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if return_obj is None: - return_obj = cls() - - super(CompositeIndicatorExpression, cls).from_obj(obj, return_obj=return_obj) - return_obj.operator = obj.operator - return return_obj + def _fix_value(self, value): + from stix.campaign import Campaign - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - if return_obj is None: - return_obj = cls() + if isinstance(value, Campaign) and value.id_: + return RelatedCampaignRef(CampaignRef(idref=value.id_)) + return super(_RelatedCampaignRefList, self)._fix_value(value) - super(CompositeIndicatorExpression, cls).from_dict(dict_repr, return_obj=return_obj) - return_obj.operator = dict_repr.get('operator') - return return_obj - """ class RelatedCampaignRefs(GenericRelationshipList): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = _binding.RelatedCampaignReferencesType - _binding_var = 'Related_Campaign' - _contained_type = RelatedCampaignRef - _inner_name = "related_campaigns" + + related_campaign = fields.TypedField( + name="Related_Campaign", + type_=RelatedCampaignRef, + multiple=True, + key_name="related_campaigns", + listfunc=_RelatedCampaignRefList + ) def __init__(self, related_campaign_refs=None, scope=None): super(RelatedCampaignRefs, self).__init__(scope, related_campaign_refs) - def _fix_value(self, value): - from stix.campaign import Campaign - - if isinstance(value, Campaign) and value.id_: - return RelatedCampaignRef(CampaignRef(idref=value.id_)) - else: - return super(RelatedCampaignRefs, self)._fix_value(value) - # NOT ACTUAL STIX TYPES! class IndicatorTypes(stix.TypedList): diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index 9b45f11b..93066c64 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -63,28 +63,31 @@ def add_description(self, description): """ self.descriptions.add(description) + class Sightings(stix.EntityList): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = _binding.SightingsType - _contained_type = Sighting - _binding_var = "Sighting" - _inner_name = "sightings" - + sightings_count = fields.TypedField("sightings_count") - + sighting = fields.TypedField("Sighting", Sighting, multiple=True, key_name="sightings") + def __init__(self, sightings_count=None, *args): super(Sightings, self).__init__(*args) self.sightings_count = sightings_count def __nonzero__(self): - return super(Sightings, self).__nonzero__() or bool(self.sightings_count) + return super(Sightings, self).__nonzero__() or (self.sightings_count is not None) class RelatedObservables(GenericRelationshipList): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = _binding.RelatedObservablesType - _binding_var = "Related_Observable" - _contained_type = RelatedObservable - _inner_name = "observables" + + observable = fields.TypedField( + name="Related_Observable", + type_=RelatedObservable, + multiple=True, + key_name="observables" + ) diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index a63312fe..d96c75da 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -113,5 +113,7 @@ class TestMechanisms(stix.EntityList): _dict_as_list = True + + # Backwards compatibility add_extension = stix.add_extension diff --git a/stix/report/__init__.py b/stix/report/__init__.py index aa6406ac..d4d487e7 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. from mixbox import idgen +from mixbox import fields from mixbox.cache import Cached from cybox.core import Observable, Observables @@ -440,40 +441,32 @@ class Campaigns(stix.EntityList): _binding = report_binding _namespace = 'http://stix.mitre.org/Report-1' _binding_class = _binding.CampaignsType - _contained_type = Campaign - _binding_var = "Campaign" - _inner_name = "campaigns" - _dict_as_list = True + + campaign = fields.TypedField("Campaign", Campaign, multiple=True, key_name="campaigns") class CoursesOfAction(stix.EntityList): _binding = report_binding _namespace = 'http://stix.mitre.org/Report-1' _binding_class = _binding.CoursesOfActionType - _contained_type = CourseOfAction - _binding_var = "Course_Of_Action" - _inner_name = "courses_of_action" - _dict_as_list = True + + course_of_action = fields.TypedField("Course_Of_Action", CourseOfAction, multiple=True, key_name="courses_of_action") class ExploitTargets(stix.EntityList): _binding = stix_common_binding _namespace = 'http://stix.mitre.org/common-1' _binding_class = _binding.ExploitTargetsType - _contained_type = ExploitTarget - _binding_var = "Exploit_Target" - _inner_name = "exploit_targets" - _dict_as_list = True + + exploit_target = fields.TypedField("Exploit_Target", ExploitTarget, multiple=True, key_name="exploit_targets") class Incidents(stix.EntityList): _binding = report_binding _namespace = 'http://stix.mitre.org/Report-1' _binding_class = _binding.IncidentsType - _contained_type = Incident - _binding_var = "Incident" - _inner_name = "incidents" - _dict_as_list = True + + incident = fields.TypedField("Incident", Incident, multiple=True, key_name="incidents") class Indicators(stix.EntityList): @@ -481,16 +474,13 @@ class Indicators(stix.EntityList): _namespace = 'http://stix.mitre.org/Report-1' _binding_class = _binding.IndicatorsType _contained_type = Indicator - _binding_var = "Indicator" - _inner_name = "indicators" - _dict_as_list = True + + indicator = fields.TypedField("Indicator", Indicator, multiple=True, key_name="indicators") class ThreatActors(stix.EntityList): _binding = report_binding _namespace = 'http://stix.mitre.org/Report-1' _binding_class = _binding.ThreatActorsType - _contained_type = ThreatActor - _binding_var = "Threat_Actor" - _inner_name = "threat_actors" - _dict_as_list = True + + threat_actor = fields.TypedField("Threat_Actor", ThreatActor, multiple=True, key_name="threat_actors") diff --git a/stix/ttp/behavior.py b/stix/ttp/behavior.py index f564c5b9..cad5cdc4 100644 --- a/stix/ttp/behavior.py +++ b/stix/ttp/behavior.py @@ -1,5 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. + +# mixbox +from mixbox import fields + +# stix import stix import stix.bindings.ttp as ttp_binding @@ -104,26 +109,21 @@ class Exploits(stix.EntityList): _contained_type = Exploit _binding = ttp_binding _binding_class = _binding.ExploitsType - _binding_var = "Exploit" - _inner_name = "exploits" - _dict_as_list = True + + exploit = fields.TypedField("Exploit", Exploit, multiple=True, key_name="exploits") class MalwareInstances(stix.EntityList): _namespace = "http://stix.mitre.org/TTP-1" - _contained_type = MalwareInstance _binding = ttp_binding _binding_class = _binding.MalwareType - _binding_var = "Malware_Instance" - _inner_name = "malware_instances" - _dict_as_list = True + + malware_instance = fields.TypedField("Malware_Instance", MalwareInstance, multiple=True, key_name="malware_instances") class AttackPatterns(stix.EntityList): _namespace = "http://stix.mitre.org/TTP-1" - _contained_type = AttackPattern _binding = ttp_binding _binding_class = _binding.AttackPatternsType - _binding_var = "Attack_Pattern" - _inner_name = "attack_patterns" - _dict_as_list = True + + attack_pattern = fields.TypedField("Attack_Pattern", AttackPattern, multiple=True, key_name="attack_patterns") diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index b5502868..7aad8773 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -1,8 +1,11 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# external +# mixbox +from mixbox import fields from mixbox.cache import Cached + +# cybox from cybox.core import Observables # internal @@ -276,12 +279,3 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.observable_characterization = Observables.from_dict(dict_repr.get('observable_characterization')) return return_obj - - -class InfraStructureTypes(stix.EntityList): - _namespace = "http://stix.mitre.org/TTP-1" - _contained_type = VocabString - _dict_as_list = True - - def _fix_value(self, value): - return AttackerInfrastructureType(value) diff --git a/stix/ttp/resource.py b/stix/ttp/resource.py index e468c86a..133d007d 100644 --- a/stix/ttp/resource.py +++ b/stix/ttp/resource.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# mixbox +from mixbox import fields +from mixbox import typedlist + # internal import stix from stix.common import ToolInformation, Identity @@ -10,109 +14,124 @@ from .infrastructure import Infrastructure -class Resource(stix.Entity): - _binding = ttp_binding - _binding_class = _binding.ResourceType - _namespace = "http://stix.mitre.org/TTP-1" - - def __init__(self, tools=None, infrastructure=None, personas=None): - self.tools = tools - self.infrastructure = infrastructure - self.personas = personas - - @property - def tools(self): - return self._tools - - @tools.setter - def tools(self, value): - self._tools = Tools(value) - - def add_tool(self, tool): - self.tools.append(tool) +class _IdentityList(typedlist.TypedList): + def __init__(self, *args): + super(_IdentityList, self).__init__(type=Identity, *args) - @property - def infrastructure(self): - return self._infrastructure - - @infrastructure.setter - def infrastructure(self, value): - self._infrastructure = value - - @property - def personas(self): - return self._personas - - @personas.setter - def personas(self, value): - self._personas = Personas(value) - - def add_persona(self, persona): - self.personas.append(persona) - - def to_obj(self, return_obj=None, ns_info=None): - super(Resource, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.tools: - return_obj.Tools = self.tools.to_obj(ns_info=ns_info) - if self.infrastructure: - return_obj.Infrastructure = self.infrastructure.to_obj(ns_info=ns_info) - if self.personas: - return_obj.Personas = self.personas.to_obj(ns_info=ns_info) + def _fix_value(self, value): + return Identity(name=value) - return return_obj - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None +class Personas(stix.EntityList): + _namespace = "http://stix.mitre.org/TTP-1" + _binding = ttp_binding + _binding_class = _binding.PersonasType - if not return_obj: - return_obj = cls() + persona = fields.TypedField("Persona", Identity, multiple=True, listfunc=_IdentityList) - return_obj.infrastructure = Infrastructure.from_obj(obj.Infrastructure) - return_obj.tools = Tools.from_obj(obj.Tools) - return_obj.personas = Personas.from_obj(obj.Personas) - return return_obj +class Tools(stix.EntityList): + _namespace = "http://stix.mitre.org/TTP-1" + _binding = ttp_binding + _binding_class = _binding.ToolsType - def to_dict(self): - return super(Resource, self).to_dict() + tool = fields.TypedField("Tool", ToolInformation, multiple=True) @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None + def _dict_as_list(cls): + return False - if not return_obj: - return_obj = cls() - get = dict_repr.get +class Resource(stix.Entity): + _binding = ttp_binding + _binding_class = _binding.ResourceType + _namespace = "http://stix.mitre.org/TTP-1" - return_obj.tools = Tools.from_dict(get('tools')) - return_obj.infrastructure = Infrastructure.from_dict(get('infrastructure')) - return_obj.personas = Personas.from_dict(get('personas')) + tools = fields.TypedField("Tools", Tools) + infrastructure = fields.TypedField("Infrastructure", Infrastructure) + personas = fields.TypedField("Personas", Personas) - return return_obj + def __init__(self, tools=None, infrastructure=None, personas=None): + super(Resource, self).__init__() + self.tools = tools + self.infrastructure = infrastructure + self.personas = personas -class Personas(stix.EntityList): - _namespace = "http://stix.mitre.org/TTP-1" - _contained_type = Identity - _binding = ttp_binding - _binding_class = _binding.PersonasType - _binding_var = "Persona" + # @property + # def tools(self): + # return self._tools + # + # @tools.setter + # def tools(self, value): + # self._tools = Tools(value) - def _fix_value(self, value): - return Identity(name=value) + def add_tool(self, tool): + self.tools.append(tool) + # @property + # def infrastructure(self): + # return self._infrastructure + # + # @infrastructure.setter + # def infrastructure(self, value): + # self._infrastructure = value + # + # @property + # def personas(self): + # return self._personas + # + # @personas.setter + # def personas(self, value): + # self._personas = Personas(value) -class Tools(stix.EntityList): - _namespace = "http://stix.mitre.org/TTP-1" - _contained_type = ToolInformation - _binding = ttp_binding - _binding_class = _binding.ToolsType - _binding_var = "Tool" + def add_persona(self, persona): + self.personas.append(persona) + # + # def to_obj(self, return_obj=None, ns_info=None): + # super(Resource, self).to_obj(return_obj=return_obj, ns_info=ns_info) + # + # if not return_obj: + # return_obj = self._binding_class() + # + # if self.tools: + # return_obj.Tools = self.tools.to_obj(ns_info=ns_info) + # if self.infrastructure: + # return_obj.Infrastructure = self.infrastructure.to_obj(ns_info=ns_info) + # if self.personas: + # return_obj.Personas = self.personas.to_obj(ns_info=ns_info) + # + # return return_obj + # + # @classmethod + # def from_obj(cls, obj, return_obj=None): + # if not obj: + # return None + # + # if not return_obj: + # return_obj = cls() + # + # return_obj.infrastructure = Infrastructure.from_obj(obj.Infrastructure) + # return_obj.tools = Tools.from_obj(obj.Tools) + # return_obj.personas = Personas.from_obj(obj.Personas) + # + # return return_obj + # + # def to_dict(self): + # return super(Resource, self).to_dict() + # + # @classmethod + # def from_dict(cls, dict_repr, return_obj=None): + # if not dict_repr: + # return None + # + # if not return_obj: + # return_obj = cls() + # + # get = dict_repr.get + # + # return_obj.tools = Tools.from_dict(get('tools')) + # return_obj.infrastructure = Infrastructure.from_dict(get('infrastructure')) + # return_obj.personas = Personas.from_dict(get('personas')) + # + # return return_obj diff --git a/stix/utils/deprecated.py b/stix/utils/deprecated.py index 7283c780..0396844d 100644 --- a/stix/utils/deprecated.py +++ b/stix/utils/deprecated.py @@ -3,7 +3,8 @@ import warnings -from . import is_sequence +from mixbox.datautils import is_sequence +from mixbox.typedlist import TypedList def idref(entity): @@ -45,3 +46,9 @@ def warn(value): fmt = "The use of this field has been deprecated. Received '{0}' object." msg = fmt.format(type(value).__name__) warnings.warn(msg) + + +class IdrefDeprecatedList(TypedList): + def _is_valid(self, value): + idref(value) + return super(IdrefDeprecatedList, self)._is_valid(value) \ No newline at end of file From d881ec1d5a4b458f037b0407f6f0bf25846f51b4 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 2 Nov 2015 12:39:07 -0500 Subject: [PATCH 237/438] Updated GenericRelationshipList subclasses to align with mixbox EntityList requirements. --- stix/coa/__init__.py | 29 ++++++++++++++++++++++++++++ stix/exploit_target/__init__.py | 17 ++++++++-------- stix/exploit_target/vulnerability.py | 7 ++++--- stix/indicator/indicator.py | 12 +++++------- stix/threat_actor/__init__.py | 22 +++++++++++---------- stix/ttp/exploit_targets.py | 7 ++++--- stix/ttp/related_ttps.py | 8 +++++--- stix/ttp/resource.py | 1 - 8 files changed, 67 insertions(+), 36 deletions(-) diff --git a/stix/coa/__init__.py b/stix/coa/__init__.py index 271e2d33..26a0f3f9 100644 --- a/stix/coa/__init__.py +++ b/stix/coa/__init__.py @@ -32,6 +32,35 @@ class RelatedCOAs(GenericRelationshipList): _inner_name = "coas" +class PotentialCOAs(GenericRelationshipList): + """ + A list of ``Potential_COA`` objects, defaults to empty array + """ + _namespace = "http://stix.mitre.org/ExploitTarget-1" + _binding = exploit_target_binding + _binding_class = exploit_target_binding.PotentialCOAsType + + potential_coa = fields.TypedField("Potential_COA", RelatedCOA, multiple=True, key_name="coas") + + def __init__(self, coas=None, scope=None): + super(PotentialCOAs, self).__init__(scope, coas) + + +class RelatedExploitTargets(GenericRelationshipList): + """ + A list of ``RelatedExploitTargets`` objects, defaults to empty array + """ + _namespace = "http://stix.mitre.org/ExploitTarget-1" + _binding = exploit_target_binding + _binding_class = exploit_target_binding.RelatedExploitTargetsType + + related_exploit_target = fields.TypedField("Related_Exploit_Target", RelatedExploitTarget, multiple=True, key_name="related_exploit_targets") + + def __init__(self, related_exploit_targets=None, scope=None): + super(RelatedExploitTargets, self).__init__(scope, related_exploit_targets) + + + class CourseOfAction(stix.BaseCoreComponent): """Implementation of the STIX Course of Action. diff --git a/stix/exploit_target/__init__.py b/stix/exploit_target/__init__.py index bd884578..8fb1429d 100644 --- a/stix/exploit_target/__init__.py +++ b/stix/exploit_target/__init__.py @@ -1,6 +1,9 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# mixbox +from mixbox import fields + # internal import stix import stix.bindings.exploit_target as exploit_target_binding @@ -238,14 +241,11 @@ class PotentialCOAs(GenericRelationshipList): _namespace = "http://stix.mitre.org/ExploitTarget-1" _binding = exploit_target_binding _binding_class = exploit_target_binding.PotentialCOAsType - _binding_var = "Potential_COA" - _contained_type = RelatedCOA - _inner_name = "coas" + + potential_coa = fields.TypedField("Potential_COA", RelatedCOA, multiple=True, key_name="coas") def __init__(self, coas=None, scope=None): - if coas is None: - coas = [] - super(PotentialCOAs, self).__init__(scope, *coas) + super(PotentialCOAs, self).__init__(scope, coas) class RelatedExploitTargets(GenericRelationshipList): @@ -255,9 +255,8 @@ class RelatedExploitTargets(GenericRelationshipList): _namespace = "http://stix.mitre.org/ExploitTarget-1" _binding = exploit_target_binding _binding_class = exploit_target_binding.RelatedExploitTargetsType - _binding_var = "Related_Exploit_Target" - _contained_type = RelatedExploitTarget - _inner_name = "related_exploit_targets" + + related_exploit_target = fields.TypedField("Related_Exploit_Target", RelatedExploitTarget, multiple=True, key_name="related_exploit_targets") def __init__(self, related_exploit_targets=None, scope=None): super(RelatedExploitTargets, self).__init__(scope, related_exploit_targets) diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index 89c0563b..2b7527f6 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -1,6 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + import stix import stix.utils as utils import stix.bindings.exploit_target as exploit_target_binding @@ -385,9 +387,8 @@ class AffectedSoftware(GenericRelationshipList): _binding = exploit_target_binding _binding_class = exploit_target_binding.AffectedSoftwareType _namespace = "http://stix.mitre.org/ExploitTarget-1" - _binding_var = "Affected_Software" - _contained_type = RelatedObservable - _inner_name = "affected_software" + + affected_software = fields.TypedField("Affected_Software", RelatedObservable, multiple=True, key_name="affected_software") # NOT AN ACTUAL STIX TYPE! diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 2531d5c1..eb9b5773 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -79,14 +79,13 @@ class SuggestedCOAs(GenericRelationshipList): or ``"exclusive"``. See :class:`stix.common.related.GenericRelationshipList` documentation for more information. - """ + _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = indicator_binding.SuggestedCOAsType - _binding_var = "Suggested_COA" - _contained_type = RelatedCOA - _inner_name = "suggested_coas" + + suggested_coa = fields.TypedField("Suggested_COA", RelatedCOA, multiple=True, key_name="suggested_coas") def __init__(self, suggested_coas=None, scope=None): super(SuggestedCOAs, self).__init__(scope, suggested_coas) @@ -148,9 +147,8 @@ class RelatedIndicators(GenericRelationshipList): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = indicator_binding.RelatedIndicatorsType - _binding_var = "Related_Indicator" - _contained_type = RelatedIndicator - _inner_name = "related_indicators" + + related_indicator = fields.TypedField("Related_Indicator", RelatedIndicator, multiple=True, key_name="related_indicators") def __init__(self, related_indicators=None, scope=None): super(RelatedIndicators, self).__init__(scope, related_indicators) diff --git a/stix/threat_actor/__init__.py b/stix/threat_actor/__init__.py index c2176cbb..89601068 100644 --- a/stix/threat_actor/__init__.py +++ b/stix/threat_actor/__init__.py @@ -1,6 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +# mixbox +from mixbox import fields + +# internal import stix import stix.bindings.threat_actor as threat_actor_binding from stix.common import vocabs, Confidence, Identity, Statement @@ -8,35 +12,33 @@ GenericRelationshipList, RelatedCampaign, RelatedPackageRefs, RelatedTTP, RelatedThreatActor ) -from mixbox import fields + from stix.common.statement import StatementField from stix.common.information_source import InformationSource + class ObservedTTPs(GenericRelationshipList): _namespace = 'http://stix.mitre.org/ThreatActor-1' _binding = threat_actor_binding _binding_class = threat_actor_binding.ObservedTTPsType - _binding_var = "Observed_TTP" - _contained_type = RelatedTTP - _inner_name = "ttps" + + observed_ttp = fields.TypedField("Observed_TTP", RelatedTTP, multiple=True, key_name="ttps") class AssociatedActors(GenericRelationshipList): _namespace = 'http://stix.mitre.org/ThreatActor-1' _binding = threat_actor_binding _binding_class = threat_actor_binding.AssociatedActorsType - _binding_var = "Associated_Actor" - _contained_type = RelatedThreatActor - _inner_name = "threat_actors" + + associated_actor = fields.TypedField("Associated_Actor", RelatedThreatActor, multiple=True, key_name="threat_actors") class AssociatedCampaigns(GenericRelationshipList): _namespace = 'http://stix.mitre.org/ThreatActor-1' _binding = threat_actor_binding _binding_class = threat_actor_binding.AssociatedCampaignsType - _binding_var = "Associated_Campaign" - _contained_type = RelatedCampaign - _inner_name = "campaigns" + + associated_campaign = fields.TypedField("Associated_Campaigns", RelatedCampaign, multiple=True, key_name="campaigns") class ThreatActor(stix.BaseCoreComponent): diff --git a/stix/ttp/exploit_targets.py b/stix/ttp/exploit_targets.py index 3caf4206..ed7b9fca 100644 --- a/stix/ttp/exploit_targets.py +++ b/stix/ttp/exploit_targets.py @@ -1,6 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + import stix.bindings.ttp as ttp_binding from stix.common.related import GenericRelationshipList, RelatedExploitTarget @@ -9,6 +11,5 @@ class ExploitTargets(GenericRelationshipList): _namespace = "http://stix.mitre.org/TTP-1" _binding = ttp_binding _binding_class = _binding.ExploitTargetsType - _binding_var = "Exploit_Target" - _contained_type = RelatedExploitTarget - _inner_name = "exploit_targets" + + exploit_target = fields.TypedField("Exploit_Target", RelatedExploitTarget, multiple=True, key_name="exploit_targets") diff --git a/stix/ttp/related_ttps.py b/stix/ttp/related_ttps.py index 2dda8cfe..c590ae4f 100644 --- a/stix/ttp/related_ttps.py +++ b/stix/ttp/related_ttps.py @@ -1,6 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + import stix.bindings.ttp as ttp_binding from stix.common.related import GenericRelationshipList, RelatedTTP @@ -9,6 +11,6 @@ class RelatedTTPs(GenericRelationshipList): _namespace = "http://stix.mitre.org/TTP-1" _binding = ttp_binding _binding_class = _binding.RelatedTTPsType - _binding_var = "Related_TTP" - _contained_type = RelatedTTP - _inner_name = "ttps" + + related_ttp = fields.TypedField("Related_TTP", RelatedTTP, multiple=True, key_name="ttps") + diff --git a/stix/ttp/resource.py b/stix/ttp/resource.py index 133d007d..a1ec267a 100644 --- a/stix/ttp/resource.py +++ b/stix/ttp/resource.py @@ -53,7 +53,6 @@ class Resource(stix.Entity): def __init__(self, tools=None, infrastructure=None, personas=None): super(Resource, self).__init__() - self.tools = tools self.infrastructure = infrastructure self.personas = personas From f2e21ba9246da6ae41a06cd0b439146cd9dd09c1 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 2 Nov 2015 12:44:58 -0500 Subject: [PATCH 238/438] Updated MarkingStructure tests. * MarkingStructure is not abstract and does not need an xsi:type value. As such, I removed the unit tests that verified that xsi:type was required. * @id and @idref are not allowed at the same time, so I updated the unit tests to reflect that. --- stix/test/data_marking_test.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/stix/test/data_marking_test.py b/stix/test/data_marking_test.py index 381a6e64..4db86680 100644 --- a/stix/test/data_marking_test.py +++ b/stix/test/data_marking_test.py @@ -12,7 +12,7 @@ class MarkingSpecificationTests(EntityTestCase, unittest.TestCase): klass = dm.MarkingSpecification _full_dict = { 'id': "foo", - 'idref': "foo_ref", + # 'idref': "foo_ref", # Cannot have both @id and @idref set at the same time. 'version': "1234", 'controlled_structure': "some xpath", 'marking_structures': [ @@ -26,21 +26,13 @@ class MarkingSpecificationTests(EntityTestCase, unittest.TestCase): class MarkingStructureTests(unittest.TestCase): - def test_xsi_type_required(self): - d = { - 'marking_model_name': 'TLP', - } - - # If there's not an xsi:type in the dict, this will raise an error. - self.assertRaises(ValueError, dm.MarkingStructure.from_dict, d) - - def test_xsi_type_required(self): + def test_bad_xsi_type(self): d = { 'marking_model_name': 'TLP', 'xsi:type': "UNKNOWN_XSI_TYPE", } - self.assertRaises(ValueError, dm.MarkingStructure.from_dict, d) + self.assertRaises(ValueError, dm.MarkingStructureFactory.from_dict, d) class MarkingTests(EntityTestCase, unittest.TestCase): From 0bde65d529ebaf9b90a4b459f3e3d1c4e41a323e Mon Sep 17 00:00:00 2001 From: apsillers Date: Mon, 2 Nov 2015 13:46:34 -0500 Subject: [PATCH 239/438] WIP TestMechanism --- .../test_mechanism/generic_test_mechanism.py | 21 ++------- stix/indicator/indicator.py | 41 ++--------------- stix/indicator/test_mechanism.py | 46 +++++++++---------- 3 files changed, 30 insertions(+), 78 deletions(-) diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index e8450f1f..6b000fb8 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -88,7 +88,7 @@ def type_(self, value): """ @classmethod - def from_obj(cls, obj, return_obj=None): + def from_obj(cls, obj): if not obj: return None if not return_obj: @@ -102,24 +102,13 @@ def from_obj(cls, obj, return_obj=None): return return_obj - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(GenericTestMechanism, self).to_obj(return_obj=return_obj, ns_info=ns_info) - if self.reference_location: - return_obj.reference_location = self.reference_location - if self.description: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.type_: - return_obj.Type = self.type_.to_obj(ns_info=ns_info) - if self.specification: - return_obj.Specification = self.specification.to_obj(ns_info=ns_info) + def to_obj(self, ns_info=None): + obj = super(GenericTestMechanism, self).to_obj(ns_info=ns_info) - return return_obj + return obj @classmethod - def from_dict(cls, d, return_obj=None): + def from_dict(cls, d): if not d: return None if not return_obj: diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index e2e4d495..84f63229 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -19,7 +19,7 @@ import stix.bindings.indicator as indicator_binding # relative -from .test_mechanism import TestMechanisms +from .test_mechanism import TestMechanisms, TestMechanismFactory from .sightings import Sightings from .valid_time import ValidTime @@ -182,11 +182,11 @@ class Indicator(stix.BaseCoreComponent): indicator_types = fields.TypedField("Type", IndicatorType, multiple=True, key_name="indicator_types") confidence = fields.TypedField("Confidence", Confidence) indicated_ttps = fields.TypedField("Indicated_TTP", RelatedTTP, multiple=True, key_name="indicated_ttps") - test_mechanisms = fields.TypedField("Test_Mechanisms", TestMechanisms) + test_mechanisms = fields.TypedField("Test_Mechanisms", TestMechanisms, factory=TestMechanismFactory) alternative_id = fields.TypedField("Alternative_ID", multiple=True) suggested_coas = fields.TypedField("Suggested_COAs", SuggestedCOAs) sightings = fields.TypedField("Sightings", Sightings) - composite_indicator_expression = fields.TypedField("Composite_Indicator_Expression", ObservableComposition) + composite_indicator_expression = fields.TypedField("Composite_Indicator_Expression", "stix.indicator.CompositeIndicatorExpression") kill_chain_phases = fields.TypedField("Kill_Chain_Phases", KillChainPhasesReference) valid_time_positions = fields.TypedField("Valid_Time_Position", ValidTime, multiple=True, key_name="valid_time_positions") related_indicators = fields.TypedField("Related_Indicators", RelatedIndicators) @@ -892,7 +892,6 @@ class CompositeIndicatorExpression(entities.EntityList): OPERATORS = (OP_AND, OP_OR) def check_operator(self, value): - raise ValueError("always") if not value: raise ValueError("operator must not be None or empty") elif value not in self.OPERATORS: @@ -904,40 +903,6 @@ def __init__(self, operator="OR", *args): super(CompositeIndicatorExpression, self).__init__(*args) self.operator = operator - """ - def to_obj(self, return_obj=None, ns_info=None): - list_obj = super(CompositeIndicatorExpression, self).to_obj(return_obj=return_obj, ns_info=ns_info) - list_obj.operator = self.operator - return list_obj - - def to_dict(self): - d = super(CompositeIndicatorExpression, self).to_dict() - if self.operator: - d['operator'] = self.operator - return d - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if return_obj is None: - return_obj = cls() - - super(CompositeIndicatorExpression, cls).from_obj(obj, return_obj=return_obj) - return_obj.operator = obj.operator - return return_obj - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - if return_obj is None: - return_obj = cls() - - super(CompositeIndicatorExpression, cls).from_dict(dict_repr, return_obj=return_obj) - return_obj.operator = dict_repr.get('operator') - return return_obj - """ class RelatedCampaignRefs(GenericRelationshipList): _namespace = "http://stix.mitre.org/Indicator-2" diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index a63312fe..9ca2e95a 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -2,7 +2,7 @@ # See LICENSE.txt for complete terms. # external -from mixbox import fields +from mixbox import fields, entities from mixbox.cache import Cached # internal @@ -13,7 +13,7 @@ import stix.bindings.indicator as indicator_binding -class _BaseTestMechanism(Cached, stix.Entity): +class _BaseTestMechanism(Cached, entities.Entity): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = indicator_binding.TestMechanismType() @@ -30,16 +30,13 @@ def __init__(self, id_=None, idref=None): self.efficacy = None self.producer = None - + """ @classmethod def from_obj(cls, obj, return_obj=None): if not obj: return None - import stix.extensions.test_mechanism.snort_test_mechanism # noqa - import stix.extensions.test_mechanism.open_ioc_2010_test_mechanism # noqa - import stix.extensions.test_mechanism.yara_test_mechanism # noqa - import stix.extensions.test_mechanism.generic_test_mechanism # noqa + if not return_obj: klass = stix.lookup_extension(obj) @@ -51,23 +48,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.producer = InformationSource.from_obj(obj.Producer) return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - super(_BaseTestMechanism, self).to_obj(return_obj=return_obj, ns_info=ns_info) - if not return_obj: - return_obj = self._binding_class() - - return_obj.id = self.id_ - return_obj.idref = self.idref - # return_obj.xsi_type = self._XSI_TYPE - - if self.efficacy: - return_obj.Efficacy = self.efficacy.to_obj(ns_info=ns_info) - if self.producer: - return_obj.Producer = self.producer.to_obj(ns_info=ns_info) - - return return_obj @staticmethod def lookup_class(xsi_type): @@ -97,12 +78,29 @@ def from_dict(cls, d, return_obj=None): return return_obj + """ + + def to_obj(self, ns_info=None): + obj = super(_BaseTestMechanism, self).to_obj(ns_info=ns_info) + obj.xsi_type = self._XSI_TYPE + + return obj + def to_dict(self): d = super(_BaseTestMechanism, self).to_dict() d['xsi:type'] = self._XSI_TYPE # added by subclass return d +class TestMechanismFactory(entities.EntityFactory): + @classmethod + def entity_class(self, key): + import stix.extensions.test_mechanism.snort_test_mechanism # noqa + import stix.extensions.test_mechanism.open_ioc_2010_test_mechanism # noqa + import stix.extensions.test_mechanism.yara_test_mechanism # noqa + import stix.extensions.test_mechanism.generic_test_mechanism # noqa + stix.lookup_extension(key) + class TestMechanisms(stix.EntityList): _binding = indicator_binding _namespace = 'http://stix.mitre.org/Indicator-2' @@ -111,7 +109,7 @@ class TestMechanisms(stix.EntityList): _binding_var = "Test_Mechanism" _inner_name = "test_mechanisms" _dict_as_list = True - + _entity_factory=TestMechanismFactory # Backwards compatibility add_extension = stix.add_extension From eaa6c689768daf4b34538ebb32aa52bc554a643f Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 2 Nov 2015 13:53:43 -0500 Subject: [PATCH 240/438] Updated YaraTestMechanism to call _BaseTestMechanism correctly. Still need to update to TypedFields. --- .../test_mechanism/yara_test_mechanism.py | 50 +++++++++---------- stix/indicator/test_mechanism.py | 6 ++- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/stix/extensions/test_mechanism/yara_test_mechanism.py b/stix/extensions/test_mechanism/yara_test_mechanism.py index dea407bb..09f4a3cc 100644 --- a/stix/extensions/test_mechanism/yara_test_mechanism.py +++ b/stix/extensions/test_mechanism/yara_test_mechanism.py @@ -35,49 +35,45 @@ def rule(self, value): self._rule = EncodedCDATA(value=value) @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: + def from_obj(cls, cls_obj): + if not cls_obj: return None - if not return_obj: - return_obj = cls() - - super(YaraTestMechanism, cls).from_obj(obj, return_obj) - return_obj.version = obj.Version - return_obj.rule = EncodedCDATA.from_obj(obj.Rule) - - return return_obj + + obj = super(YaraTestMechanism, cls).from_obj(cls_obj) + + obj.version = cls_obj.Version + obj.rule = EncodedCDATA.from_obj(cls_obj.Rule) + + return obj - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(YaraTestMechanism, self).to_obj(return_obj=return_obj, ns_info=ns_info) + def to_obj(self, ns_info=None): + obj = super(YaraTestMechanism, self).to_obj(ns_info=ns_info) if self.version: - return_obj.Version = self.version + obj.Version = self.version if self.rule: - return_obj.Rule = self.rule.to_obj(ns_info=ns_info) + obj.Rule = self.rule.to_obj(ns_info=ns_info) - return return_obj + return obj @classmethod - def from_dict(cls, d, return_obj=None): - if not d: + def from_dict(cls, cls_dict): + if not cls_dict: return None - if not return_obj: - return_obj = cls() - - super(YaraTestMechanism, cls).from_dict(d, return_obj) - return_obj.version = d.get('version') - return_obj.rule = EncodedCDATA.from_dict(d.get('rule')) + + obj = super(YaraTestMechanism, cls).from_dict(cls_dict) + + obj.version = cls_dict.get('version') + obj.rule = EncodedCDATA.from_dict(cls_dict.get('rule')) - return return_obj + return obj def to_dict(self): d = super(YaraTestMechanism, self).to_dict() if self.version: d['version'] = self.version + if self.rule: d['rule'] = self.rule.to_dict() diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index 9ca2e95a..eeebfaf8 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -13,7 +13,7 @@ import stix.bindings.indicator as indicator_binding -class _BaseTestMechanism(Cached, entities.Entity): +class _BaseTestMechanism(Cached, stix.Entity): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = indicator_binding.TestMechanismType() @@ -24,7 +24,8 @@ class _BaseTestMechanism(Cached, entities.Entity): producer = fields.TypedField("Producer", InformationSource) def __init__(self, id_=None, idref=None): - self._fields = {} + super(_BaseTestMechanism, self).__init__() + self.id_ = id_ self.idref = idref self.efficacy = None @@ -101,6 +102,7 @@ def entity_class(self, key): import stix.extensions.test_mechanism.generic_test_mechanism # noqa stix.lookup_extension(key) + class TestMechanisms(stix.EntityList): _binding = indicator_binding _namespace = 'http://stix.mitre.org/Indicator-2' From 07cc98ab89698aea252f6d23da9f46ea8bf9cc45 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 2 Nov 2015 14:03:56 -0500 Subject: [PATCH 241/438] Updated YaraTestMechanism to use TypedFields. --- .../test_mechanism/yara_test_mechanism.py | 68 ++----------------- 1 file changed, 6 insertions(+), 62 deletions(-) diff --git a/stix/extensions/test_mechanism/yara_test_mechanism.py b/stix/extensions/test_mechanism/yara_test_mechanism.py index 09f4a3cc..6682b67b 100644 --- a/stix/extensions/test_mechanism/yara_test_mechanism.py +++ b/stix/extensions/test_mechanism/yara_test_mechanism.py @@ -1,6 +1,8 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + import stix import stix.utils import stix.indicator.test_mechanism @@ -15,67 +17,9 @@ class YaraTestMechanism(_BaseTestMechanism): _binding = yara_tm_binding _binding_class = _binding.YaraTestMechanismType _XSI_TYPE = "yaraTM:YaraTestMechanismType" - - def __init__(self, id_=None, idref=None): - super(YaraTestMechanism, self).__init__(id_=id_, idref=idref) - self.version = None - self.rule = None - - @property - def rule(self): - return self._rule - - @rule.setter - def rule(self, value): - if not value: - self._rule = None - if isinstance(value, EncodedCDATA): - self._rule = value - else: - self._rule = EncodedCDATA(value=value) - - @classmethod - def from_obj(cls, cls_obj): - if not cls_obj: - return None - - obj = super(YaraTestMechanism, cls).from_obj(cls_obj) - - obj.version = cls_obj.Version - obj.rule = EncodedCDATA.from_obj(cls_obj.Rule) - - return obj - - def to_obj(self, ns_info=None): - obj = super(YaraTestMechanism, self).to_obj(ns_info=ns_info) - if self.version: - obj.Version = self.version - if self.rule: - obj.Rule = self.rule.to_obj(ns_info=ns_info) - - return obj - - @classmethod - def from_dict(cls, cls_dict): - if not cls_dict: - return None - - obj = super(YaraTestMechanism, cls).from_dict(cls_dict) - - obj.version = cls_dict.get('version') - obj.rule = EncodedCDATA.from_dict(cls_dict.get('rule')) - - return obj - - def to_dict(self): - d = super(YaraTestMechanism, self).to_dict() - - if self.version: - d['version'] = self.version - - if self.rule: - d['rule'] = self.rule.to_dict() - - return d + version = fields.TypedField("Version") + rule = fields.TypedField("Rule", EncodedCDATA) + def __init__(self, id_=None, idref=None): + super(YaraTestMechanism, self).__init__(id_=id_, idref=idref) From d71721f508bf890b3dde9de4d2566e5f717fbdc5 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 2 Nov 2015 14:36:10 -0500 Subject: [PATCH 242/438] Updated GenericTestMechanism to use TypedFields and updated TestMechanismFactory. --- .../test_mechanism/generic_test_mechanism.py | 81 ++----------------- stix/indicator/indicator.py | 2 +- stix/indicator/test_mechanism.py | 8 +- 3 files changed, 11 insertions(+), 80 deletions(-) diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index 6b000fb8..5acda9f4 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -5,10 +5,12 @@ import stix import stix.indicator.test_mechanism +from stix.common.vocabs import VocabField from stix.common import EncodedCDATA, StructuredTextList, VocabString from stix.indicator.test_mechanism import _BaseTestMechanism import stix.bindings.extensions.test_mechanism.generic as generic_tm_binding + @stix.register_extension class GenericTestMechanism(_BaseTestMechanism): _namespace = "http://stix.mitre.org/extensions/TestMechanism#Generic-1" @@ -16,33 +18,15 @@ class GenericTestMechanism(_BaseTestMechanism): _binding_class = _binding.GenericTestMechanismType _XSI_TYPE = "genericTM:GenericTestMechanismType" - reference_location = fields.TypedField("Reference_Location") + reference_location = fields.TypedField("reference_location") descriptions = fields.TypedField("Description", StructuredTextList) specification = fields.TypedField("Specification", EncodedCDATA) - type_ = fields.TypedField("type", VocabString, key_name="type") + type_ = VocabField("Type") def __init__(self, id_=None, idref=None): super(GenericTestMechanism, self).__init__(id_=id_, idref=idref) - self.reference_location = None - self.description = None - self.type_ = None - self.specification = None - - """ - @property - def specification(self): - return self._specification - - @specification.setter - def specification(self, value): - if not value: - self._specification = None - if isinstance(value, EncodedCDATA): - self._specification = value - else: - self._specification = EncodedCDATA(value=value) - """ - + self.descriptions = StructuredTextList() + @property def description(self): """A single description about the contents or purpose of this object. @@ -71,56 +55,3 @@ def add_description(self, description): """ self.descriptions.add(description) - - """ - @property - def type_(self): - return self._type - - @type_.setter - def type_(self, value): - if not value: - self._type = None - elif isinstance(value, VocabString): - self._type = value - else: - self._type = VocabString(value) - """ - - @classmethod - def from_obj(cls, obj): - if not obj: - return None - if not return_obj: - return_obj = cls() - - super(GenericTestMechanism, cls).from_obj(obj, return_obj) - return_obj.reference_location = obj.reference_location - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.type_ = VocabString.from_obj(obj.Type) - return_obj.specification = EncodedCDATA.from_obj(obj.Specification) - - return return_obj - - def to_obj(self, ns_info=None): - obj = super(GenericTestMechanism, self).to_obj(ns_info=ns_info) - - return obj - - @classmethod - def from_dict(cls, d): - if not d: - return None - if not return_obj: - return_obj = cls() - - super(GenericTestMechanism, cls).from_dict(d, return_obj) - return_obj.reference_location = d.get('reference_location') - return_obj.descriptions = StructuredTextList.from_dict(d.get('description')) - return_obj.type_ = VocabString.from_dict(d.get('type')) - return_obj.specification = EncodedCDATA.from_dict(d.get('specification')) - - return return_obj - - def to_dict(self): - return super(GenericTestMechanism, self).to_dict() diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 84f63229..068393a3 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -182,7 +182,7 @@ class Indicator(stix.BaseCoreComponent): indicator_types = fields.TypedField("Type", IndicatorType, multiple=True, key_name="indicator_types") confidence = fields.TypedField("Confidence", Confidence) indicated_ttps = fields.TypedField("Indicated_TTP", RelatedTTP, multiple=True, key_name="indicated_ttps") - test_mechanisms = fields.TypedField("Test_Mechanisms", TestMechanisms, factory=TestMechanismFactory) + test_mechanisms = fields.TypedField("Test_Mechanisms", TestMechanisms) alternative_id = fields.TypedField("Alternative_ID", multiple=True) suggested_coas = fields.TypedField("Suggested_COAs", SuggestedCOAs) sightings = fields.TypedField("Sightings", Sightings) diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index eeebfaf8..1b4b406f 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -100,7 +100,7 @@ def entity_class(self, key): import stix.extensions.test_mechanism.open_ioc_2010_test_mechanism # noqa import stix.extensions.test_mechanism.yara_test_mechanism # noqa import stix.extensions.test_mechanism.generic_test_mechanism # noqa - stix.lookup_extension(key) + return stix.lookup_extension(key) class TestMechanisms(stix.EntityList): @@ -109,9 +109,9 @@ class TestMechanisms(stix.EntityList): _binding_class = _binding.TestMechanismsType _contained_type = _BaseTestMechanism _binding_var = "Test_Mechanism" - _inner_name = "test_mechanisms" - _dict_as_list = True - _entity_factory=TestMechanismFactory + _entity_factory = TestMechanismFactory + + # Backwards compatibility add_extension = stix.add_extension From acfdfa510ba35502cf34f9be95de59fbc7905b74 Mon Sep 17 00:00:00 2001 From: apsillers Date: Mon, 2 Nov 2015 15:56:38 -0500 Subject: [PATCH 243/438] WIP TypedField updates for various classes --- stix/exploit_target/__init__.py | 4 +- stix/exploit_target/configuration.py | 137 +------- stix/exploit_target/vulnerability.py | 313 ++----------------- stix/exploit_target/weakness.py | 94 +----- stix/extensions/identity/ciq_identity_3_0.py | 2 +- stix/ttp/infrastructure.py | 150 +-------- stix/ttp/resource.py | 3 +- stix/ttp/victim_targeting.py | 14 +- 8 files changed, 68 insertions(+), 649 deletions(-) diff --git a/stix/exploit_target/__init__.py b/stix/exploit_target/__init__.py index bd884578..becbb66b 100644 --- a/stix/exploit_target/__init__.py +++ b/stix/exploit_target/__init__.py @@ -165,7 +165,7 @@ def add_configuration(self, value): """ self.configuration.append(value) - +""" def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() @@ -229,7 +229,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) return return_obj - +""" class PotentialCOAs(GenericRelationshipList): """ diff --git a/stix/exploit_target/configuration.py b/stix/exploit_target/configuration.py index 04400807..b6a1b96c 100644 --- a/stix/exploit_target/configuration.py +++ b/stix/exploit_target/configuration.py @@ -4,9 +4,9 @@ import stix from stix.common import StructuredTextList import stix.bindings.exploit_target as exploit_target_binding +from mixbox import fields, entities - -class Configuration(stix.Entity): +class Configuration(entities.Entity): """Implementation of STIX ``Configuration``. Args: @@ -19,7 +19,12 @@ class Configuration(stix.Entity): _binding_class = _binding.ConfigurationType _namespace = "http://stix.mitre.org/ExploitTarget-1" + descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList") + short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList") + cce_id = fields.TypedField("CCE_ID") + def __init__(self, description=None, short_description=None, cce_id=None): + super(Configuration, self).__init__() self.description = description self.short_description = short_description self.cce_id = cce_id @@ -35,9 +40,7 @@ def description(self): the description with the lowest ordinality value. Returns: - An instance of - :class:`.StructuredText` - + An instance of :class:`.StructuredText` """ return next(iter(self.descriptions), None) @@ -45,41 +48,10 @@ def description(self): def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. This is the same as calling "foo.descriptions.add(bar)". - """ self.descriptions.add(description) @@ -96,7 +68,6 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` - """ return next(iter(self.short_descriptions), None) @@ -104,105 +75,13 @@ def short_description(self): def short_description(self, value): self.short_descriptions = value - @property - def short_descriptions(self): - """A :class:`.StructuredTextList` object, containing short descriptions - about the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - short descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of :class:`.StructuredTextList` - - """ - return self._short_description - - @short_descriptions.setter - def short_descriptions(self, value): - self._short_description = StructuredTextList(value) - def add_short_description(self, description): """Adds a description to the ``short_descriptions`` collection. This is the same as calling "foo.short_descriptions.add(bar)". - """ self.short_descriptions.add(description) - @property - def cce_id(self): - """Common Configuration Enumeration value for this :class:`Configuration`. - - Default Value: ``None`` - - Returns: - A string representing the CCE ID - """ - return self._cce_id - - @cce_id.setter - def cce_id(self, value): - self._cce_id = value - - def to_obj(self, return_obj=None, ns_info=None): - super(Configuration, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.short_descriptions: - return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) - return_obj.CCE_ID = self.cce_id - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.short_description = StructuredTextList.from_obj(obj.Short_Description) - return_obj.cce_id = obj.CCE_ID - - return return_obj - - def to_dict(self): - return super(Configuration, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - get = dict_repr.get - return_obj.descriptions = StructuredTextList.from_dict(get('description')) - return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) - return_obj.cce_id = get('cce_id') - - return return_obj - - # NOT AN ACTUAL STIX TYPE! class _Configurations(stix.TypedList): _contained_type = Configuration diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index 89c0563b..73a4cde1 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -7,9 +7,10 @@ import stix.bindings.stix_common as stix_common_binding from stix.common import DateTimeWithPrecision, StructuredTextList from stix.common.related import GenericRelationshipList, RelatedObservable +from mixbox import entities, fields +from stix.common import References - -class Vulnerability(stix.Entity): +class Vulnerability(entities.Entity): """Implementation of STIX ``Vulnerability``. Args: @@ -22,32 +23,27 @@ class Vulnerability(stix.Entity): _binding_class = _binding.VulnerabilityType _namespace = "http://stix.mitre.org/ExploitTarget-1" + is_known = fields.BooleanField("is_known") + is_publicly_ackowledged = fields.BooleanField("is_publicly_acknowledged") + title = fields.TypedField("title") + descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList") + short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList") + cve_id = fields.TypedField("CVE_ID") + osvdb_id = fields.TypedField("OSVDB_ID") + source = fields.TypedField("source") + cvss_score = fields.TypedField("CVSS_Score", "stix.exploit_target.vulnerability.CVSSVector") + discovered_datetime = fields.TypedField("Discovered_DateTime", DateTimeWithPrecision) + published_datetime = fields.TypedField("Published_DateTime", DateTimeWithPrecision) + affected_software = fields.TypedField("Affected_Software", "stix.exploit_target.vulnerability.AffectedSoftware") + references = fields.TypedField("References", References) + def __init__(self, title=None, description=None, short_description=None): - self.is_known = None - self.is_publicly_acknowledged = None + super(Vulnerability, self).__init__() self.title = title self.description = description self.short_description = short_description - self.cve_id = None - self.osvdb_id = None - self.source = None - self.cvss_score = None - self.discovered_datetime = None - self.published_datetime = None - self.affected_software = AffectedSoftware() self.references = [] - @property - def title(self): - """ - String representing the Vulnerability Title - """ - return self._title - - @title.setter - def title(self, value): - self._title = value - @property def description(self): """A single description about the contents or purpose of this object. @@ -59,9 +55,7 @@ def description(self): the description with the lowest ordinality value. Returns: - An instance of - :class:`.StructuredText` - + An instance of :class:`.StructuredText` """ return next(iter(self.descriptions), None) @@ -69,41 +63,10 @@ def description(self): def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. This is the same as calling "foo.descriptions.add(bar)". - """ self.descriptions.add(description) @@ -120,7 +83,6 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` - """ return next(iter(self.short_descriptions), None) @@ -128,170 +90,19 @@ def short_description(self): def short_description(self, value): self.short_descriptions = value - @property - def short_descriptions(self): - """A :class:`.StructuredTextList` object, containing short descriptions - about the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - short descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of :class:`.StructuredTextList` - - """ - return self._short_description - - @short_descriptions.setter - def short_descriptions(self, value): - self._short_description = StructuredTextList(value) - def add_short_description(self, description): """Adds a description to the ``short_descriptions`` collection. This is the same as calling "foo.short_descriptions.add(bar)". - """ self.short_descriptions.add(description) - @property - def discovered_datetime(self): - """ - Returns: - The time this vulnerability was discovered, represented as - class:`DateTimeWithPrecision` - """ - return self._discovered_datetime - - @discovered_datetime.setter - def discovered_datetime(self, value): - """ - Sets the time this vulnerability was discovered, represented as - class:`DateTimeWithPrecision` - - Default Value: ``None`` - - Returns: - None - - """ - self._set_var(DateTimeWithPrecision, discovered_datetime=value) - - @property - def references(self): - return self._references - - @references.setter - def references(self, value): - self._references = [] - - if not value: - return - elif utils.is_sequence(value): - self._references.extend(x for x in value if x) - else: - self._references.append(value) - def add_reference(self, reference): if not reference: return self.references.append(reference) - def to_obj(self, return_obj=None, ns_info=None): - super(Vulnerability, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - return_obj.Title = self.title - return_obj.CVE_ID = self.cve_id - return_obj.OSVDB_ID = self.osvdb_id - return_obj.Source = self.source - return_obj.is_known = utils.xml_bool(self.is_known) - return_obj.is_publicly_acknowledged = utils.xml_bool(self.is_publicly_acknowledged) - - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.short_descriptions: - return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) - if self.cvss_score: - return_obj.CVSS_Score = self.cvss_score.to_obj(ns_info=ns_info) - if self.discovered_datetime: - return_obj.Discovered_DateTime = self.discovered_datetime.to_obj(ns_info=ns_info) - if self.published_datetime: - return_obj.Published_DateTime = self.published_datetime.to_obj(ns_info=ns_info) - if self.affected_software: - return_obj.Affected_Software = self.affected_software.to_obj(ns_info=ns_info) - if self.references: - return_obj.References = stix_common_binding.ReferencesType(Reference=self.references) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.is_known = utils.xml_bool(obj.is_known) - return_obj.is_publicly_acknowledged = utils.xml_bool(obj.is_publicly_acknowledged) - return_obj.title = obj.Title - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) - return_obj.cve_id = obj.CVE_ID - return_obj.osvdb_id = obj.OSVDB_ID - return_obj.source = obj.Source - return_obj.cvss_score = CVSSVector.from_obj(obj.CVSS_Score) - return_obj.discovered_datetime = DateTimeWithPrecision.from_obj(obj.Discovered_DateTime) - return_obj.published_datetime = DateTimeWithPrecision.from_obj(obj.Published_DateTime) - return_obj.affected_software = AffectedSoftware.from_obj(obj.Affected_Software) - - if obj.References: - return_obj.references = obj.References.Reference - - return return_obj - - def to_dict(self): - return super(Vulnerability, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - if not return_obj: - return_obj = cls() - - get = dict_repr.get - return_obj.is_known = utils.xml_bool(get('is_known')) - return_obj.is_publicly_acknowledged = utils.xml_bool(get('is_publicly_acknowledged')) - return_obj.title = get('title') - return_obj.descriptions = StructuredTextList.from_dict(get('description')) - return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) - return_obj.cve_id = get('cve_id') - return_obj.osvdb_id = get('osvdb_id') - return_obj.source = get('source') - return_obj.cvss_score = CVSSVector.from_dict(get('cvss_score')) - return_obj.discovered_datetime = DateTimeWithPrecision.from_dict(get('discovered_datetime')) - return_obj.published_datetime = DateTimeWithPrecision.from_dict(get('published_datetime')) - return_obj.affected_software = AffectedSoftware.from_dict(get('affected_software')) - return_obj.references = get('references') - - return return_obj - - class CVSSVector(stix.Entity): """ Common Vulnerabilit Scoring System object, representing its component measures @@ -301,84 +112,16 @@ class CVSSVector(stix.Entity): _binding_class = exploit_target_binding.CVSSVectorType _namespace = "http://stix.mitre.org/ExploitTarget-1" - def __init__(self): - self.overall_score = None - self.base_score = None - self.base_vector = None - self.temporal_score = None - self.temporal_vector = None - self.environmental_score = None - self.environmental_vector = None - - def to_obj(self, return_obj=None, ns_info=None): - super(CVSSVector, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - return_obj.Overall_Score = self.overall_score - return_obj.Base_Score = self.base_score - return_obj.Base_Vector = self.base_vector - return_obj.Temporal_Score = self.temporal_score - return_obj.Temporal_Vector = self.temporal_vector - return_obj.Environmental_Score = self.environmental_score - return_obj.Environmental_Vector = self.environmental_vector + overall_score = fields.TypedField("Overall_Score") + base_score = fields.TypedField("Base_Score") + base_vector = fields.TypedField("Base_Vector") + temporal_score = fields.TypedField("Temporal_Score") + temporal_vector = fields.TypedField("Temporal_Vector") + environmental_score = fields.TypedField("Environmental_Score") + environmental_vector = fields.TypedField("Environmental_Vector") - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.overall_score = obj.Overall_Score - return_obj.base_score = obj.Base_Score - return_obj.base_vector = obj.Base_Vector - return_obj.temporal_score = obj.Temporal_Score - return_obj.temporal_vector = obj.Temporal_Vector - return_obj.environmental_score = obj.Environmental_Score - return_obj.environmental_vector = obj.Environmental_Vector - - return return_obj - - def to_dict(self): - d = {} - - if self.overall_score: - d['overall_score'] = self.overall_score - if self.base_score: - d['base_score'] = self.base_score - if self.base_vector: - d['base_vector'] = self.base_vector - if self.temporal_score: - d['temporal_score'] = self.temporal_score - if self.temporal_vector: - d['temporal_vector'] = self.temporal_vector - if self.environmental_score: - d['environmental_score'] = self.environmental_score - if self.environmental_vector: - d['environmental_vector'] = self.environmental_vector - - return d - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - if not return_obj: - return_obj = cls() - - return_obj.overall_score = dict_repr.get('overall_score') - return_obj.base_score = dict_repr.get('base_score') - return_obj.base_vector = dict_repr.get('base_vector') - return_obj.temporal_score = dict_repr.get('temporal_score') - return_obj.temporal_vector = dict_repr.get('temporal_vector') - return_obj.environmental_score = dict_repr.get('environmental_score') - return_obj.environmental_vector = dict_repr.get('environmental_vector') - - return return_obj + def __init__(self): + super(CVSSVector, self).__init__() class AffectedSoftware(GenericRelationshipList): diff --git a/stix/exploit_target/weakness.py b/stix/exploit_target/weakness.py index 1bb9c9e3..fad74b71 100644 --- a/stix/exploit_target/weakness.py +++ b/stix/exploit_target/weakness.py @@ -4,9 +4,9 @@ import stix import stix.bindings.exploit_target as exploit_target_binding from stix.common import StructuredTextList +from mixbox import entities, fields - -class Weakness(stix.Entity): +class Weakness(entities.Entity): """Implementation of STIX ``Weakness``. Args: @@ -18,21 +18,14 @@ class Weakness(stix.Entity): _binding_class = _binding.WeaknessType _namespace = "http://stix.mitre.org/ExploitTarget-1" + descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList") + cwe_id = fields.TypedField("CWE_ID") + def __init__(self, description=None, cwe_id=None): + super(Weakness, self).__init__() self.description = description self.cwe_id = cwe_id - @property - def cwe_id(self): - """ - Common Weakness Enumeration value as a string - """ - return self._cwe_id - - @cwe_id.setter - def cwe_id(self, value): - self._cwe_id = value - @property def description(self): """A single description about the contents or purpose of this object. @@ -44,9 +37,7 @@ def description(self): the description with the lowest ordinality value. Returns: - An instance of - :class:`.StructuredText` - + An instance of :class:`.StructuredText` """ return next(iter(self.descriptions), None) @@ -54,83 +45,12 @@ def description(self): def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. This is the same as calling "foo.descriptions.add(bar)". - """ self.descriptions.add(description) - def to_obj(self, return_obj=None, ns_info=None): - super(Weakness, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - return_obj.CWE_ID = self.cwe_id - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.cwe_id = obj.CWE_ID - - return return_obj - - def to_dict(self): - return super(Weakness, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - if not return_obj: - return_obj = cls() - - return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) - return_obj.cwe_id = dict_repr.get('cwe_id') - - return return_obj - - class _Weaknesses(stix.TypedList): _contained_type = Weakness diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index 12672466..853bdf55 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -112,7 +112,7 @@ def from_dict(cls, dict_repr, return_obj=None): if not return_obj: return_obj = cls() - super(CIQIdentity3_0Instance, cls).from_dict(dict_repr, return_obj) + super(CIQIdentity3_0Instance, cls).from_dict(dict_repr) roles = dict_repr.get('roles', []) specification = dict_repr.get('specification') diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index b5502868..27111299 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -10,79 +10,31 @@ from stix.common import StructuredTextList, VocabString from stix.common.vocabs import AttackerInfrastructureType import stix.bindings.ttp as ttp_binding +from mixbox import fields, entities - -class Infrastructure(Cached, stix.Entity): +class Infrastructure(Cached, entities.Entity): _binding = ttp_binding _binding_class = _binding.InfrastructureType _namespace = "http://stix.mitre.org/TTP-1" - + + + id_ = fields.IdField("id") + idref = fields.IdrefField("idref") + title = fields.TypedField("Title") + descriptions = fields.TypedField("Description", StructuredTextList) + short_descriptions = fields.TypedField("Short_Description", StructuredTextList) + types = fields.TypedField("Types", "stix.ttp.infrastructure.InfraStructureTypes") + observable_characterization = None + + def __init__(self, id_=None, idref=None, title=None, description=None, short_description=None): + super(Infrastructure, self).__init__() self.id_ = id_ self.idref = idref self.title = title self.description = description self.short_description = short_description - self.types = None - self.observable_characterization = None - - @property - def id_(self): - """The ``id_`` property serves as an identifier. - Default Value: ``None`` - - Note: - Both the ``id_`` and ``idref`` properties cannot be set at the - same time. **Setting one will unset the other!** - - Returns: - A string id. - - """ - return self._id - - @id_.setter - def id_(self, value): - if not value: - self._id = None - else: - self._id = value - self.idref = None - - @property - def idref(self): - """The ``idref`` property must be set to the ``id_`` value of another - object instance of the same type. An idref does not need to resolve to - a local object instance. - - Default Value: ``None``. - - Note: - Both the ``id_`` and ``idref`` properties cannot be set at the - same time. **Setting one will unset the other!** - - Returns: - The value of the ``idref`` property - - """ - return self._idref - - @idref.setter - def idref(self, value): - if not value: - self._idref = None - else: - self._idref = value - self.id_ = None # unset id_ if idref is present - - @property - def title(self): - return self._title - - @title.setter - def title(self, value): - self._title = value @property def description(self): @@ -95,9 +47,7 @@ def description(self): the description with the lowest ordinality value. Returns: - An instance of - :class:`.StructuredText` - + An instance of :class:`.StructuredText` """ return next(iter(self.descriptions), None) @@ -105,41 +55,10 @@ def description(self): def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. This is the same as calling "foo.descriptions.add(bar)". - """ self.descriptions.add(description) @@ -156,7 +75,6 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` - """ return next(iter(self.short_descriptions), None) @@ -164,51 +82,13 @@ def short_description(self): def short_description(self, value): self.short_descriptions = value - @property - def short_descriptions(self): - """A :class:`.StructuredTextList` object, containing short descriptions - about the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - short descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of :class:`.StructuredTextList` - - """ - return self._short_description - - @short_descriptions.setter - def short_descriptions(self, value): - self._short_description = StructuredTextList(value) - def add_short_description(self, description): """Adds a description to the ``short_descriptions`` collection. This is the same as calling "foo.short_descriptions.add(bar)". - """ self.short_descriptions.add(description) - @property - def types(self): - return self._types - - @types.setter - def types(self, value): - self._types = InfraStructureTypes(value) - def add_type(self, type_): self.types.append(type_) diff --git a/stix/ttp/resource.py b/stix/ttp/resource.py index e468c86a..94735aad 100644 --- a/stix/ttp/resource.py +++ b/stix/ttp/resource.py @@ -9,8 +9,9 @@ # relative from .infrastructure import Infrastructure +from mixbox import entities, fields -class Resource(stix.Entity): +class Resource(entities.Entity): _binding = ttp_binding _binding_class = _binding.ResourceType _namespace = "http://stix.mitre.org/TTP-1" diff --git a/stix/ttp/victim_targeting.py b/stix/ttp/victim_targeting.py index 738d7e6c..432b33a2 100644 --- a/stix/ttp/victim_targeting.py +++ b/stix/ttp/victim_targeting.py @@ -8,27 +8,23 @@ import stix from stix.common import vocabs, VocabString, Identity import stix.bindings.ttp as ttp_binding - +from mixbox import fields class VictimTargeting(stix.Entity): _binding = ttp_binding _binding_class = _binding.VictimTargetingType _namespace = "http://stix.mitre.org/TTP-1" + identity = fields.TypedField("Identity", Identity) + targeted_systems = fields.TypedField("Targeted_Systems", "stix.ttp.victim_targeting.TargetedSystems") + targeted_information = fields.TypedField("Targeted_Information", "stix.ttp.victim_targeting.TargetedInformation") + def __init__(self): self.identity = None self.targeted_systems = None self.targeted_information = None self.targeted_technical_details = None - @property - def targeted_systems(self): - return self._targeted_systems - - @targeted_systems.setter - def targeted_systems(self, value): - self._targeted_systems = TargetedSystems(value) - def add_targeted_system(self, system): self._targeted_systems.append(system) From aa90e1001ff2a091107b59a520063b8f35e4d0ba Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 2 Nov 2015 21:16:09 -0500 Subject: [PATCH 244/438] Updated VocabField to align with mixbox TypedField. --- stix/common/vocabs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index a6b7ed8f..960c7524 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -59,10 +59,10 @@ def __init__(self, *args, **kwargs): super(VocabField, self).__init__(*args, **kwargs) self.factory = VocabFactory # force this factory - if self.type_ is None: + if self._unresolved_type is None: self.type_ = VocabString - self.listfunc = partial(VocabList, type=self.type_, ignore_none=True) + self._listfunc = partial(VocabList, type=self._unresolved_type) def check_type(self, value): return isinstance(value, VocabString) From c3fedd9b6809a17b23d86b6990b4e7f010238b33 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 2 Nov 2015 21:18:07 -0500 Subject: [PATCH 245/438] Added docstring to IdrefDeprecatedList --- stix/utils/deprecated.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stix/utils/deprecated.py b/stix/utils/deprecated.py index 0396844d..ded2643c 100644 --- a/stix/utils/deprecated.py +++ b/stix/utils/deprecated.py @@ -49,6 +49,10 @@ def warn(value): class IdrefDeprecatedList(TypedList): + """TypedList specialization that raises a UserWarning on ever insert() + call. + """ + def _is_valid(self, value): idref(value) return super(IdrefDeprecatedList, self)._is_valid(value) \ No newline at end of file From b6ba9a84a9e993954e69ed8726c069cec8bfe292 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 2 Nov 2015 22:02:18 -0500 Subject: [PATCH 246/438] Updated TestMechanisms to use new EntityList conventions (multiple field required). --- stix/indicator/test_mechanism.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index 686b92a3..d075ab07 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -107,11 +107,13 @@ class TestMechanisms(stix.EntityList): _binding = indicator_binding _namespace = 'http://stix.mitre.org/Indicator-2' _binding_class = _binding.TestMechanismsType - _contained_type = _BaseTestMechanism - _binding_var = "Test_Mechanism" - _entity_factory = TestMechanismFactory - + test_mechanism = fields.TypedField( + name="Test_Mechanism", + type_=_BaseTestMechanism, + factory=TestMechanismFactory, + multiple=True + ) From f182fa1be9fdbc1d4d3b107ff755f561e44bab08 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Mon, 2 Nov 2015 22:03:13 -0500 Subject: [PATCH 247/438] Added back _RelatedCampaignRefList after it was lost in a merge. Other fixes to make the indicator unit tests pass. --- stix/base.py | 3 -- stix/campaign/__init__.py | 17 --------- stix/coa/__init__.py | 37 ++++---------------- stix/common/related.py | 8 +++-- stix/extensions/identity/ciq_identity_3_0.py | 19 +++++----- stix/indicator/indicator.py | 32 +++++++++++------ stix/test/indicator_test.py | 2 +- stix/utils/deprecated.py | 2 +- 8 files changed, 44 insertions(+), 76 deletions(-) diff --git a/stix/base.py b/stix/base.py index 04c446e3..9e69b320 100644 --- a/stix/base.py +++ b/stix/base.py @@ -203,9 +203,6 @@ def find(self, id_): class EntityList(entities.EntityList, Entity): - _contained_type = _override - _inner_name = None - def to_xml(self, *args, **kwargs): return Entity.to_xml(self, *args, **kwargs) diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 0a897de7..92c2f05f 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -23,10 +23,6 @@ class AssociatedCampaigns(GenericRelationshipList): campaign = fields.TypedField("Associated_Campaign", RelatedCampaign, multiple=True, key_name="campaigns") - @classmethod - def _dict_as_list(cls): - return False - class Attribution(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" @@ -35,10 +31,6 @@ class Attribution(GenericRelationshipList): threat_actor = fields.TypedField("Attributed_Threat_Actor", RelatedThreatActor, multiple=True, key_name="threat_actors") - @classmethod - def _dict_as_list(cls): - return False - class RelatedIncidents(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" @@ -47,10 +39,6 @@ class RelatedIncidents(GenericRelationshipList): incident = fields.TypedField("Related_Incident", RelatedIncident, multiple=True, key_name="incidents") - @classmethod - def _dict_as_list(cls): - return False - class RelatedIndicators(GenericRelationshipList): _namespace = "http://stix.mitre.org/Campaign-1" @@ -59,7 +47,6 @@ class RelatedIndicators(GenericRelationshipList): indicator = fields.TypedField("Related_Indicator", RelatedIndicator, multiple=True, key_name="indicators") - def _is_valid(self, value): deprecated.warn(value) return super(RelatedIndicators, self)._is_valid(value) @@ -72,10 +59,6 @@ class RelatedTTPs(GenericRelationshipList): ttp = fields.TypedField("Related_TTP", RelatedTTP, multiple=True, key_name="ttps") - @classmethod - def _dict_as_list(cls): - return False - class Names(stix.EntityList): _namespace = "http://stix.mitre.org/Campaign-1" diff --git a/stix/coa/__init__.py b/stix/coa/__init__.py index 26a0f3f9..9a70f896 100644 --- a/stix/coa/__init__.py +++ b/stix/coa/__init__.py @@ -27,38 +27,13 @@ class RelatedCOAs(GenericRelationshipList): _namespace = "http://stix.mitre.org/CourseOfAction-1" _binding = coa_binding _binding_class = coa_binding.RelatedCOAsType - _binding_var = "Related_COA" - _contained_type = RelatedCOA - _inner_name = "coas" - - -class PotentialCOAs(GenericRelationshipList): - """ - A list of ``Potential_COA`` objects, defaults to empty array - """ - _namespace = "http://stix.mitre.org/ExploitTarget-1" - _binding = exploit_target_binding - _binding_class = exploit_target_binding.PotentialCOAsType - - potential_coa = fields.TypedField("Potential_COA", RelatedCOA, multiple=True, key_name="coas") - - def __init__(self, coas=None, scope=None): - super(PotentialCOAs, self).__init__(scope, coas) - - -class RelatedExploitTargets(GenericRelationshipList): - """ - A list of ``RelatedExploitTargets`` objects, defaults to empty array - """ - _namespace = "http://stix.mitre.org/ExploitTarget-1" - _binding = exploit_target_binding - _binding_class = exploit_target_binding.RelatedExploitTargetsType - - related_exploit_target = fields.TypedField("Related_Exploit_Target", RelatedExploitTarget, multiple=True, key_name="related_exploit_targets") - - def __init__(self, related_exploit_targets=None, scope=None): - super(RelatedExploitTargets, self).__init__(scope, related_exploit_targets) + related_coa = fields.TypedField( + name="Related_COA", + type_=RelatedCOA, + multiple=True, + key_name="coas" + ) class CourseOfAction(stix.BaseCoreComponent): diff --git a/stix/common/related.py b/stix/common/related.py index e323e811..bb8f1ffe 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -127,7 +127,7 @@ def _dict_as_list(cls): class _RelatedPackageList(typedlist.TypedList): def __init__(self, *args): - super(_RelatedPackageList, self).__init__(RelatedPackageRef, True, *args) + super(_RelatedPackageList, self).__init__(type=RelatedPackageRef, *args) def _fix_value(self, value): from stix.core import STIXPackage @@ -142,7 +142,7 @@ def _fix_value(self, value): def _is_valid(self, value): deprecated.warn(value) - super(_RelatedPackageList, self)._is_valid(self, value) + return super(_RelatedPackageList, self)._is_valid(value) class RelatedPackageRefs(stix.EntityList): @@ -158,6 +158,10 @@ class RelatedPackageRefs(stix.EntityList): listfunc=_RelatedPackageList ) + @classmethod + def _dict_as_list(cls): + return False + class _BaseRelated(GenericRelationship): """A base class for related types. diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index 853bdf55..03497dbd 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -105,25 +105,22 @@ def to_dict(self): return d @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: + def from_dict(cls, cls_dict): + if not cls_dict: return None - if not return_obj: - return_obj = cls() + obj = super(CIQIdentity3_0Instance, cls).from_dict(cls_dict) - super(CIQIdentity3_0Instance, cls).from_dict(dict_repr) - - roles = dict_repr.get('roles', []) - specification = dict_repr.get('specification') + roles = cls_dict.get('roles', []) + specification = cls_dict.get('specification') for role in roles: - return_obj.add_role(role) + obj.add_role(role) if specification: - return_obj.specification = STIXCIQIdentity3_0.from_dict(specification) + obj.specification = STIXCIQIdentity3_0.from_dict(specification) - return return_obj + return obj class STIXCIQIdentity3_0(stix.Entity): diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index d280fc35..11ed79ad 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -17,12 +17,12 @@ Statement, CampaignRef) from stix.common.related import (GenericRelationshipList, RelatedCOA, RelatedIndicator, RelatedCampaignRef, RelatedPackageRefs) -from stix.common.vocabs import IndicatorType +from stix.common.vocabs import VocabField, IndicatorType from stix.common.kill_chains import KillChainPhasesReference import stix.bindings.indicator as indicator_binding # relative -from .test_mechanism import TestMechanisms, TestMechanismFactory +from .test_mechanism import TestMechanisms from .sightings import Sightings from .valid_time import ValidTime @@ -179,8 +179,8 @@ class Indicator(stix.BaseCoreComponent): _ID_PREFIX = "indicator" producer = fields.TypedField("Producer", InformationSource) - observable = fields.TypedField("Observable", Observable, postset_hook = lambda inst,value: inst.set_observables([value])) - indicator_types = fields.TypedField("Type", IndicatorType, multiple=True, key_name="indicator_types") + observable = fields.TypedField("Observable", Observable, postset_hook=lambda inst,value: inst.set_observables([value])) + indicator_types = VocabField("Type", IndicatorType, multiple=True, key_name="indicator_types") confidence = fields.TypedField("Confidence", Confidence) indicated_ttps = fields.TypedField("Indicated_TTP", RelatedTTP, multiple=True, key_name="indicated_ttps") test_mechanisms = fields.TypedField("Test_Mechanisms", TestMechanisms) @@ -196,7 +196,6 @@ class Indicator(stix.BaseCoreComponent): negate = fields.TypedField("negate") related_packages = fields.TypedField("Related_Packages", RelatedPackageRefs) - def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): @@ -789,17 +788,15 @@ def from_obj(cls, obj, return_obj=None): return return_obj """ - + def to_dict(self): keys = ('observables', 'observable_composition_operator', 'negate') #d = utils.to_dict(self, skip=keys) d = super(Indicator, self).to_dict() - if self.negate: - d['negate'] = True - else: - if 'negate' in d: del d['negate'] + if not self.negate: + d.pop("negate", None) if self.observables: if len(self.observables) == 1: @@ -916,6 +913,21 @@ def __init__(self, operator="OR", *args): self.operator = operator +class _RelatedCampaignRefList(typedlist.TypedList): + def __init__(self, *args): + super(_RelatedCampaignRefList, self).__init__(type=RelatedCampaignRef, *args) + + def _fix_value(self, value): + from stix.campaign import Campaign + + if isinstance(value, Campaign) and value.id_: + return RelatedCampaignRef(CampaignRef(idref=value.id_)) + + msg = "Cannot insert object of type '%s' into '%s'" + msg = msg % (type(value), self.__class__.__name__) + raise TypeError(msg) + + class RelatedCampaignRefs(GenericRelationshipList): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding diff --git a/stix/test/indicator_test.py b/stix/test/indicator_test.py index 2aa218f9..f2020a3f 100644 --- a/stix/test/indicator_test.py +++ b/stix/test/indicator_test.py @@ -464,7 +464,7 @@ def test_append_bad_type(self): l = RelatedCampaignRefs() self.assertRaises( - Exception, + TypeError, l.append, Indicator() ) diff --git a/stix/utils/deprecated.py b/stix/utils/deprecated.py index ded2643c..43fb8fc2 100644 --- a/stix/utils/deprecated.py +++ b/stix/utils/deprecated.py @@ -52,7 +52,7 @@ class IdrefDeprecatedList(TypedList): """TypedList specialization that raises a UserWarning on ever insert() call. """ - + def _is_valid(self, value): idref(value) return super(IdrefDeprecatedList, self)._is_valid(value) \ No newline at end of file From 65833661322fb5d767ac674d5dd43ee09f690d4c Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Thu, 5 Nov 2015 16:37:22 -0500 Subject: [PATCH 248/438] Changed the published_datetime field of stix.exploit_target.vulnerability.Vulnerability to be wrapped in a property descriptor, analogously to discovered_datetime. This fixes python-stix issue #276. --- stix/exploit_target/vulnerability.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index 89c0563b..05fe8d63 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -188,6 +188,29 @@ def discovered_datetime(self, value): """ self._set_var(DateTimeWithPrecision, discovered_datetime=value) + @property + def published_datetime(self): + """ + Returns: + The time this vulnerability was published, represented as + class:`DateTimeWithPrecision` + """ + return self._published_datetime + + @published_datetime.setter + def published_datetime(self, value): + """ + Sets the time this vulnerability was published, represented as + class:`DateTimeWithPrecision` + + Default Value: ``None`` + + Returns: + None + + """ + self._set_var(DateTimeWithPrecision, published_datetime=value) + @property def references(self): return self._references From 759094d5c37022faa97c0eb5483f0e228334955c Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 6 Nov 2015 12:58:24 -0500 Subject: [PATCH 249/438] WIP TpyedField updates for TTP, ExploitTarget, and others --- stix/exploit_target/__init__.py | 145 +------------ stix/exploit_target/configuration.py | 4 +- stix/exploit_target/vulnerability.py | 8 +- stix/exploit_target/weakness.py | 2 +- stix/indicator/sightings.py | 2 +- stix/report/header.py | 4 +- stix/threat_actor/__init__.py | 2 +- stix/ttp/__init__.py | 22 +- stix/ttp/attack_pattern.py | 244 ++++++---------------- stix/ttp/behavior.py | 123 +++++------ stix/ttp/exploit.py | 230 ++++++--------------- stix/ttp/infrastructure.py | 136 ++++++------ stix/ttp/malware_instance.py | 299 ++++++++------------------- stix/ttp/resource.py | 2 +- 14 files changed, 352 insertions(+), 871 deletions(-) diff --git a/stix/exploit_target/__init__.py b/stix/exploit_target/__init__.py index e4523368..73668c15 100644 --- a/stix/exploit_target/__init__.py +++ b/stix/exploit_target/__init__.py @@ -16,7 +16,7 @@ from .vulnerability import Vulnerability, _Vulnerabilities # noqa from .weakness import Weakness, _Weaknesses # noqa from .configuration import Configuration, _Configurations # noqa - +from stix.common import InformationSource class ExploitTarget(stix.BaseCoreComponent): """Implementation of STIX Exploit Target. @@ -41,6 +41,14 @@ class ExploitTarget(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'et' + potential_coas = fields.TypedField("Potential_COAs", type_="stix.exploit_target.PotentialCOAs") + related_exploit_targets = fields.TypedField("Related_Exploit_Targets", type_="stix.exploit_target.RelatedExploitTargets") + vulnerabilities = fields.TypedField("Vulnerability", Vulnerability, multiple=True, key_name="vulnerabilities") + weaknesses = fields.TypedField("Weakness", Weakness, multiple=True, key_name="weaknesses") + configuration = fields.TypedField("Configuration", Configuration, multiple=True) + related_packages = fields.TypedField("Related_Packages", RelatedPackageRefs) + information_source = fields.TypedField("Information_Source", InformationSource) + def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): @@ -55,32 +63,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.potential_coas = PotentialCOAs() self.related_exploit_targets = RelatedExploitTargets() - self.vulnerabilities = None - self.weaknesses = None - self.configuration = None self.related_packages = RelatedPackageRefs() - - @property - def vulnerabilities(self): - """A collection of :class:`.Vulnerability` objects. This behaves like - a ``MutableSequence`` type. - - Default Value: ``None`` - - Returns: - A list of :class:`.Vulnerability` - - Raises: - ValueError: If set to a value that is not ``None`` and not an - instance of :class:`.Vulnerability` - - """ - - return self._vulnerabilities - - @vulnerabilities.setter - def vulnerabilities(self, value): - self._vulnerabilities = _Vulnerabilities(value) def add_vulnerability(self, value): """Adds a vulnerability to the :attr:`vulnerabilities` list property. @@ -95,29 +78,7 @@ def add_vulnerability(self, value): ValueError: if the `value` param is of type :class:`.Vulnerability` """ - self.vulnerabilities.append(value) - - @property - def weaknesses(self): - """A collection of :class:`.Weakness` objects. This behaves like - a ``MutableSequence`` type. - - Default Value: ``None`` - - Returns: - A list of :class:`.Weakness` objects. - - Raises: - ValueError: If set to a value that is not ``None`` and not an - instance of :class:`.Weakness` - - """ - return self._weaknesses - - @weaknesses.setter - def weaknesses(self, value): - self._weaknesses = _Weaknesses(value) - + self.vul def add_weakness(self, value): """Adds a weakness to the :attr:`weaknesses` list property. @@ -131,28 +92,6 @@ def add_weakness(self, value): """ self.weaknesses.append(value) - - @property - def configuration(self): - """A list of :class:`.Configuration` objects. This behaves like - a ``MutableSequence`` type. - - Default Value: ``None`` - - Returns: - A list of :class:`.Configuration` objects. - - Raises: - ValueError: If set to a value that is not ``None`` and not an - instance of :class:`.Configuration`. - - """ - - return self._configuration - - @configuration.setter - def configuration(self, value): - self._configuration = _Configurations(value) def add_configuration(self, value): """Adds a configuration to the :attr:`configurations` list property. @@ -168,71 +107,7 @@ def add_configuration(self, value): """ self.configuration.append(value) -""" - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(ExploitTarget, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if self.potential_coas: - return_obj.Potential_COAs = self.potential_coas.to_obj(ns_info=ns_info) - if self.related_exploit_targets: - return_obj.Related_Exploit_Targets = self.related_exploit_targets.to_obj(ns_info=ns_info) - if self.vulnerabilities: - return_obj.Vulnerability = self.vulnerabilities.to_obj(ns_info=ns_info) - if self.weaknesses: - return_obj.Weakness = self.weaknesses.to_obj(ns_info=ns_info) - if self.configuration: - return_obj.Configuration = self.configuration.to_obj(ns_info=ns_info) - if self.related_packages: - return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - super(ExploitTarget, cls).from_obj(obj, return_obj=return_obj) - - if isinstance(obj, cls._binding_class): - return_obj.potential_coas = PotentialCOAs.from_obj(obj.Potential_COAs) - return_obj.related_exploit_targets = RelatedExploitTargets.from_obj(obj.Related_Exploit_Targets) - return_obj.vulnerabilities = _Vulnerabilities.from_obj(obj.Vulnerability) - return_obj.weaknesses = _Weaknesses.from_obj(obj.Weakness) - return_obj.configuration = _Configurations.from_obj(obj.Configuration) - return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) - - return return_obj - - def to_dict(self): - return super(ExploitTarget, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - super(ExploitTarget, cls).from_dict(dict_repr, return_obj=return_obj) - get = dict_repr.get - return_obj.potential_coas = PotentialCOAs.from_dict(get('potential_coas')) - return_obj.related_exploit_targets = RelatedExploitTargets.from_dict(get('related_exploit_targets')) - return_obj.vulnerabilities = _Vulnerabilities.from_dict(get('vulnerabilities')) - return_obj.weaknesses = _Weaknesses.from_dict(get('weaknesses')) - return_obj.configuration = _Configurations.from_dict(get('configuration')) - return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) - - return return_obj -""" class PotentialCOAs(GenericRelationshipList): """ diff --git a/stix/exploit_target/configuration.py b/stix/exploit_target/configuration.py index b6a1b96c..cebaf087 100644 --- a/stix/exploit_target/configuration.py +++ b/stix/exploit_target/configuration.py @@ -42,7 +42,7 @@ def description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions), None) + return next(iter(self.descriptions or []), None) @description.setter def description(self, value): @@ -69,7 +69,7 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.short_descriptions), None) + return next(iter(self.short_descriptions or []), None) @short_description.setter def short_description(self, value): diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index 421b30f2..283018fc 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -27,12 +27,12 @@ class Vulnerability(entities.Entity): is_known = fields.BooleanField("is_known") is_publicly_ackowledged = fields.BooleanField("is_publicly_acknowledged") - title = fields.TypedField("title") + title = fields.TypedField("Title") descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList") short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList") cve_id = fields.TypedField("CVE_ID") osvdb_id = fields.TypedField("OSVDB_ID") - source = fields.TypedField("source") + source = fields.TypedField("Source") cvss_score = fields.TypedField("CVSS_Score", "stix.exploit_target.vulnerability.CVSSVector") discovered_datetime = fields.TypedField("Discovered_DateTime", DateTimeWithPrecision) published_datetime = fields.TypedField("Published_DateTime", DateTimeWithPrecision) @@ -59,7 +59,7 @@ def description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions), None) + return next(iter(self.descriptions or []), None) @description.setter def description(self, value): @@ -86,7 +86,7 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.short_descriptions), None) + return next(iter(self.short_descriptions or []), None) @short_description.setter def short_description(self, value): diff --git a/stix/exploit_target/weakness.py b/stix/exploit_target/weakness.py index fad74b71..57f213b2 100644 --- a/stix/exploit_target/weakness.py +++ b/stix/exploit_target/weakness.py @@ -39,7 +39,7 @@ def description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions), None) + return next(iter(self.descriptions or []), None) @description.setter def description(self, value): diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index 93066c64..704e9c25 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -49,7 +49,7 @@ def description(self): An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions), None) + return next(iter(self.descriptions or []), None) @description.setter def description(self, value): diff --git a/stix/report/header.py b/stix/report/header.py index f95f5dbc..72aa9d49 100644 --- a/stix/report/header.py +++ b/stix/report/header.py @@ -67,7 +67,7 @@ def description(self): :class:`.StructuredText` """ - return next(iter(self.descriptions), None) + return next(iter(self.descriptions or []), None) @description.setter def description(self, value): @@ -96,7 +96,7 @@ def short_description(self): An instance of :class:`.StructuredText` """ - return next(iter(self.short_descriptions), None) + return next(iter(self.short_descriptions or []), None) @short_description.setter def short_description(self, value): diff --git a/stix/threat_actor/__init__.py b/stix/threat_actor/__init__.py index 89601068..3b73901f 100644 --- a/stix/threat_actor/__init__.py +++ b/stix/threat_actor/__init__.py @@ -38,7 +38,7 @@ class AssociatedCampaigns(GenericRelationshipList): _binding = threat_actor_binding _binding_class = threat_actor_binding.AssociatedCampaignsType - associated_campaign = fields.TypedField("Associated_Campaigns", RelatedCampaign, multiple=True, key_name="campaigns") + associated_campaign = fields.TypedField("Associated_Campaign", RelatedCampaign, multiple=True, key_name="campaigns") class ThreatActor(stix.BaseCoreComponent): diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index a74381e5..d3a44cab 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -49,7 +49,7 @@ class TTP(stix.BaseCoreComponent): resources = fields.TypedField("Resources", Resource) victim_targeting = fields.TypedField("Victim_Targeting", VictimTargeting) exploit_targets = fields.TypedField("Exploit_Targets", ExploitTargets) - related_packages = fields.TypedField("Related_Pacakges", RelatedPackageRefs) + related_packages = fields.TypedField("Related_Packages", RelatedPackageRefs) kill_chain_phases = fields.TypedField("Kill_Chain_Phases", KillChainPhasesReference) def __init__(self, id_=None, idref=None, timestamp=None, title=None, @@ -64,13 +64,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, short_description=short_description ) - self.behavior = None - self.related_ttps = None - self.intended_effects = None - self.resources = None - self.victim_targeting = None - self.related_packages = None - self.kill_chain_phases = None + self.related_packages = RelatedPackageRefs() def add_related_ttp(self, value): @@ -134,18 +128,6 @@ def add_kill_chain_phase(self, value): """ self.kill_chain_phases.append(value) - @property - def related_packages(self): - """**DEPRECATED**: A collection of :class:`.RelatedPackageRef` - objects. This behaves like a ``MutableSequence``. - - """ - return self._related_packages - - @related_packages.setter - def related_packages(self, value): - self._related_packages = RelatedPackageRefs(value) - def add_related_package(self, value): """Adds a :class:`.RelatedPackageRef` object to the :attr:`related_packages` collection. diff --git a/stix/ttp/attack_pattern.py b/stix/ttp/attack_pattern.py index 43014d0c..cc039fc4 100644 --- a/stix/ttp/attack_pattern.py +++ b/stix/ttp/attack_pattern.py @@ -11,78 +11,28 @@ # bindings import stix.bindings.ttp as ttp_binding +from mixbox import fields, entities -class AttackPattern(Cached, stix.Entity): +class AttackPattern(Cached, entities.Entity): _binding = ttp_binding _binding_class = _binding.AttackPatternType _namespace = "http://stix.mitre.org/TTP-1" + id_ = fields.IdField("id") + idref = fields.IdrefField("idref") + title = fields.TypedField("Title") + capec_id = fields.TypedField("capec_id") + descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList") + short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList") + def __init__(self, id_=None, idref=None, title=None, description=None, short_description=None): + super(AttackPattern, self).__init__() self.id_ = id_ self.idref = idref - self.capec_id = None self.title = title self.description = description self.short_description = short_description - @property - def id_(self): - """The ``id_`` property serves as an identifier. - - Default Value: ``None`` - - Note: - Both the ``id_`` and ``idref`` properties cannot be set at the - same time. **Setting one will unset the other!** - - Returns: - A string id. - - """ - return self._id - - @id_.setter - def id_(self, value): - if not value: - self._id = None - else: - self._id = value - self.idref = None - - @property - def idref(self): - """The ``idref`` property must be set to the ``id_`` value of another - object instance of the same type. An idref does not need to resolve to - a local object instance. - - Default Value: ``None``. - - Note: - Both the ``id_`` and ``idref`` properties cannot be set at the - same time. **Setting one will unset the other!** - - Returns: - The value of the ``idref`` property - - """ - return self._idref - - @idref.setter - def idref(self, value): - if not value: - self._idref = None - else: - self._idref = value - self.id_ = None # unset id_ if idref is present - - @property - def title(self): - return self._title - - @title.setter - def title(self, value): - self._title = value - @property def description(self): """A single description about the contents or purpose of this object. @@ -94,51 +44,18 @@ def description(self): the description with the lowest ordinality value. Returns: - An instance of - :class:`.StructuredText` - + An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions), None) + return next(iter(self.descriptions or []), None) @description.setter def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. This is the same as calling "foo.descriptions.add(bar)". - """ self.descriptions.add(description) @@ -155,100 +72,69 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` - """ - return next(iter(self.short_descriptions), None) + return next(iter(self.short_descriptions or []), None) @short_description.setter def short_description(self, value): self.short_descriptions = value - @property - def short_descriptions(self): - """A :class:`.StructuredTextList` object, containing short descriptions - about the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - short descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of :class:`.StructuredTextList` - - """ - return self._short_description - - @short_descriptions.setter - def short_descriptions(self, value): - self._short_description = StructuredTextList(value) - def add_short_description(self, description): """Adds a description to the ``short_descriptions`` collection. This is the same as calling "foo.short_descriptions.add(bar)". - """ self.short_descriptions.add(description) - def to_obj(self, return_obj=None, ns_info=None): - super(AttackPattern, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - return_obj.id = self.id_ - return_obj.idref = self.idref - return_obj.capec_id = self.capec_id - return_obj.Title = self.title - - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.short_descriptions: - return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.id_ = obj.id - return_obj.idref = obj.idref - return_obj.capec_id = obj.capec_id - return_obj.title = obj.Title - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) - - return return_obj - - def to_dict(self): - return super(AttackPattern, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - if not return_obj: - return_obj = cls() - - return_obj.id_ = dict_repr.get('id') - return_obj.idref = dict_repr.get('idref') - return_obj.capec_id = dict_repr.get('capec_id') - return_obj.title = dict_repr.get('title') - return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) - return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) - - return return_obj +# def to_obj(self, return_obj=None, ns_info=None): +# super(AttackPattern, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# if not return_obj: +# return_obj = self._binding_class() +# +# return_obj.id = self.id_ +# return_obj.idref = self.idref +# return_obj.capec_id = self.capec_id +# return_obj.Title = self.title +# +# if self.descriptions: +# return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) +# if self.short_descriptions: +# return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) +# +# return return_obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.id_ = obj.id +# return_obj.idref = obj.idref +# return_obj.capec_id = obj.capec_id +# return_obj.title = obj.Title +# return_obj.descriptions = StructuredTextList.from_obj(obj.Description) +# return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) +# +# return return_obj +# +# def to_dict(self): +# return super(AttackPattern, self).to_dict() +# +# @classmethod +# def from_dict(cls, dict_repr, return_obj=None): +# if not dict_repr: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.id_ = dict_repr.get('id') +# return_obj.idref = dict_repr.get('idref') +# return_obj.capec_id = dict_repr.get('capec_id') +# return_obj.title = dict_repr.get('title') +# return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) +# return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) +# +# return return_obj diff --git a/stix/ttp/behavior.py b/stix/ttp/behavior.py index cad5cdc4..a0da9748 100644 --- a/stix/ttp/behavior.py +++ b/stix/ttp/behavior.py @@ -12,96 +12,79 @@ from .exploit import Exploit from .attack_pattern import AttackPattern +from mixbox import entities, fields -class Behavior(stix.Entity): +class Behavior(entities.Entity): _binding = ttp_binding _binding_class = _binding.BehaviorType _namespace = "http://stix.mitre.org/TTP-1" + malware_instances = fields.TypedField("Malware", type_="stix.ttp.behavior.MalwareInstances", key_name="malware_instances") + attack_patterns = fields.TypedField("Attack_Patterns", type_="stix.ttp.behavior.AttackPatterns") + exploits = fields.TypedField("Exploits", type_="stix.ttp.behavior.Exploits") + def __init__(self, malware_instances=None, attack_patterns=None, exploits=None): + super(Behavior, self).__init__() self.malware_instances = malware_instances self.attack_patterns = attack_patterns self.exploits = exploits - @property - def malware_instances(self): - return self._malware_instances - - @malware_instances.setter - def malware_instances(self, value): - self._malware_instances = MalwareInstances(value) def add_malware_instance(self, malware): self.malware_instances.append(malware) - @property - def attack_patterns(self): - return self._attack_patterns - - @attack_patterns.setter - def attack_patterns(self, value): - self._attack_patterns = AttackPatterns(value) - def add_attack_pattern(self, attack_pattern): self.attack_patterns.append(attack_pattern) - @property - def exploits(self): - return self._exploits - - @exploits.setter - def exploits(self, value): - self._exploits = Exploits(value) - def add_exploit(self, exploit): self.exploits.append(exploit) - def to_obj(self, return_obj=None, ns_info=None): - super(Behavior, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.malware_instances: - return_obj.Malware = self.malware_instances.to_obj(ns_info=ns_info) - if self.exploits: - return_obj.Exploits = self.exploits.to_obj(ns_info=ns_info) - if self.attack_patterns: - return_obj.Attack_Patterns = self.attack_patterns.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.malware_instances = MalwareInstances.from_obj(obj.Malware) - return_obj.exploits = Exploits.from_obj(obj.Exploits) - return_obj.attack_patterns = AttackPatterns.from_obj(obj.Attack_Patterns) - - return return_obj - - def to_dict(self): - return super(Behavior, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - if not return_obj: - return_obj = cls() - - get = dict_repr.get - - return_obj.malware_instances = MalwareInstances.from_dict(get('malware_instances')) - return_obj.exploits = Exploits.from_dict(get('exploits')) - return_obj.attack_patterns = AttackPatterns.from_dict(get('attack_patterns')) - - return return_obj +# def to_obj(self, return_obj=None, ns_info=None): +# super(Behavior, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# if not return_obj: +# return_obj = self._binding_class() +# +# if self.malware_instances: +# return_obj.Malware = self.malware_instances.to_obj(ns_info=ns_info) +# if self.exploits: +# return_obj.Exploits = self.exploits.to_obj(ns_info=ns_info) +# if self.attack_patterns: +# return_obj.Attack_Patterns = self.attack_patterns.to_obj(ns_info=ns_info) +# +# return return_obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.malware_instances = MalwareInstances.from_obj(obj.Malware) +# return_obj.exploits = Exploits.from_obj(obj.Exploits) +# return_obj.attack_patterns = AttackPatterns.from_obj(obj.Attack_Patterns) +# +# return return_obj +# +# def to_dict(self): +# return super(Behavior, self).to_dict() +# +# @classmethod +# def from_dict(cls, dict_repr, return_obj=None): +# if not dict_repr: +# return None +# if not return_obj: +# return_obj = cls() +# +# get = dict_repr.get +# +# return_obj.malware_instances = MalwareInstances.from_dict(get('malware_instances')) +# return_obj.exploits = Exploits.from_dict(get('exploits')) +# return_obj.attack_patterns = AttackPatterns.from_dict(get('attack_patterns')) +# +# return return_obj class Exploits(stix.EntityList): diff --git a/stix/ttp/exploit.py b/stix/ttp/exploit.py index 3018efbf..fad7ef09 100644 --- a/stix/ttp/exploit.py +++ b/stix/ttp/exploit.py @@ -11,77 +11,27 @@ # bindings import stix.bindings.ttp as ttp_binding +from mixbox import entities, fields -class Exploit(Cached, stix.Entity): +class Exploit(Cached, entities.Entity): _binding = ttp_binding _binding_class = _binding.ExploitType _namespace = "http://stix.mitre.org/TTP-1" + id_ = fields.IdField("id") + idref = fields.IdrefField("idref") + title = fields.TypedField("Title") + descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList") + short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList") + def __init__(self, id_=None, idref=None, title=None, description=None, short_description=None): + super(Exploit, self).__init__() self.id_ = id_ self.idref = idref self.title = title self.description = description self.short_description = short_description - @property - def id_(self): - """The ``id_`` property serves as an identifier. - - Default Value: ``None`` - - Note: - Both the ``id_`` and ``idref`` properties cannot be set at the - same time. **Setting one will unset the other!** - - Returns: - A string id. - - """ - return self._id - - @id_.setter - def id_(self, value): - if not value: - self._id = None - else: - self._id = value - self.idref = None - - @property - def idref(self): - """The ``idref`` property must be set to the ``id_`` value of another - object instance of the same type. An idref does not need to resolve to - a local object instance. - - Default Value: ``None``. - - Note: - Both the ``id_`` and ``idref`` properties cannot be set at the - same time. **Setting one will unset the other!** - - Returns: - The value of the ``idref`` property - - """ - return self._idref - - @idref.setter - def idref(self, value): - if not value: - self._idref = None - else: - self._idref = value - self.id_ = None # unset id_ if idref is present - - @property - def title(self): - return self._title - - @title.setter - def title(self, value): - self._title = value - @property def description(self): """A single description about the contents or purpose of this object. @@ -93,51 +43,18 @@ def description(self): the description with the lowest ordinality value. Returns: - An instance of - :class:`.StructuredText` - + An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions), None) + return next(iter(self.descriptions or []), None) @description.setter def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. This is the same as calling "foo.descriptions.add(bar)". - """ self.descriptions.add(description) @@ -154,94 +71,63 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` - """ - return next(iter(self.short_descriptions), None) + return next(iter(self.short_descriptions or []), None) @short_description.setter def short_description(self, value): self.short_descriptions = value - @property - def short_descriptions(self): - """A :class:`.StructuredTextList` object, containing short descriptions - about the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - short descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of :class:`.StructuredTextList` - - """ - return self._short_description - - @short_descriptions.setter - def short_descriptions(self, value): - self._short_description = StructuredTextList(value) - def add_short_description(self, description): """Adds a description to the ``short_descriptions`` collection. This is the same as calling "foo.short_descriptions.add(bar)". - """ self.short_descriptions.add(description) - def to_obj(self, return_obj=None, ns_info=None): - super(Exploit, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - return_obj.id = self.id_ - return_obj.Title = self.title - - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.short_description: - return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.id_ = obj.id - return_obj.title = obj.Title - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) - - return return_obj - - def to_dict(self): - return super(Exploit, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - if not return_obj: - return_obj = cls() - - return_obj.id_ = dict_repr.get('id') - return_obj.title = dict_repr.get('title') - return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) - return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) - - return return_obj +# def to_obj(self, return_obj=None, ns_info=None): +# super(Exploit, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# if not return_obj: +# return_obj = self._binding_class() +# +# return_obj.id = self.id_ +# return_obj.Title = self.title +# +# if self.descriptions: +# return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) +# if self.short_description: +# return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) +# +# return return_obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.id_ = obj.id +# return_obj.title = obj.Title +# return_obj.descriptions = StructuredTextList.from_obj(obj.Description) +# return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) +# +# return return_obj +# +# def to_dict(self): +# return super(Exploit, self).to_dict() +# +# @classmethod +# def from_dict(cls, dict_repr, return_obj=None): +# if not dict_repr: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.id_ = dict_repr.get('id') +# return_obj.title = dict_repr.get('title') +# return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) +# return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) +# +# return return_obj diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index 71a034a6..aad8f814 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -26,8 +26,8 @@ class Infrastructure(Cached, entities.Entity): title = fields.TypedField("Title") descriptions = fields.TypedField("Description", StructuredTextList) short_descriptions = fields.TypedField("Short_Description", StructuredTextList) - types = fields.TypedField("Types", "stix.ttp.infrastructure.InfraStructureTypes") - observable_characterization = None + types = fields.TypedField("Type", VocabString, multiple=True, key_name="types") + observable_characterization = fields.TypedField("Observable_Characterization", Observables) def __init__(self, id_=None, idref=None, title=None, description=None, short_description=None): @@ -52,7 +52,7 @@ def description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions), None) + return next(iter(self.descriptions or []), None) @description.setter def description(self, value): @@ -79,7 +79,7 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.short_descriptions), None) + return next(iter(self.short_descriptions or []), None) @short_description.setter def short_description(self, value): @@ -95,67 +95,67 @@ def add_short_description(self, description): def add_type(self, type_): self.types.append(type_) - @property - def observable_characterization(self): - return self._observable_characterization - - @observable_characterization.setter - def observable_characterization(self, value): - self._set_var(Observables, observable_characterization=value) - - def to_obj(self, return_obj=None, ns_info=None): - super(Infrastructure, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - return_obj.id = self.id_ - return_obj.Title = self.title - - if self.description: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.short_description: - return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) - if self.types: - return_obj.Type = [x.to_obj(ns_info=ns_info) for x in self.types] - if self.observable_characterization: - return_obj.Observable_Characterization = self.observable_characterization.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.id_ = obj.id - return_obj.title = obj.Title - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) - return_obj.observable_characterization = Observables.from_obj(obj.Observable_Characterization) - - if obj.Type: - return_obj.types = [VocabString.from_obj(x) for x in obj.Type] - - return return_obj - - def to_dict(self): - return super(Infrastructure, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - if not return_obj: - return_obj = cls() - - return_obj.id_ = dict_repr.get('id') - return_obj.title = dict_repr.get('title') - return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) - return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) - return_obj.types = [VocabString.from_dict(x) for x in dict_repr.get('types', [])] - return_obj.observable_characterization = Observables.from_dict(dict_repr.get('observable_characterization')) - - return return_obj +# def to_obj(self, return_obj=None, ns_info=None): +# super(Infrastructure, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# if not return_obj: +# return_obj = self._binding_class() +# +# return_obj.id = self.id_ +# return_obj.Title = self.title +# +# if self.description: +# return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) +# if self.short_description: +# return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) +# if self.types: +# return_obj.Type = [x.to_obj(ns_info=ns_info) for x in self.types] +# if self.observable_characterization: +# return_obj.Observable_Characterization = self.observable_characterization.to_obj(ns_info=ns_info) +# +# return return_obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.id_ = obj.id +# return_obj.title = obj.Title +# return_obj.descriptions = StructuredTextList.from_obj(obj.Description) +# return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) +# return_obj.observable_characterization = Observables.from_obj(obj.Observable_Characterization) +# +# if obj.Type: +# return_obj.types = [VocabString.from_obj(x) for x in obj.Type] +# +# return return_obj +# +# def to_dict(self): +# return super(Infrastructure, self).to_dict() +# +# @classmethod +# def from_dict(cls, dict_repr, return_obj=None): +# if not dict_repr: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.id_ = dict_repr.get('id') +# return_obj.title = dict_repr.get('title') +# return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) +# return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) +# return_obj.types = [VocabString.from_dict(x) for x in dict_repr.get('types', [])] +# return_obj.observable_characterization = Observables.from_dict(dict_repr.get('observable_characterization')) +# +# return return_obj + +class InfraStructureTypes(stix.EntityList): + _namespace = "http://stix.mitre.org/TTP-1" + _contained_type = VocabString + _dict_as_list = True + + def _fix_value(self, value): + return AttackerInfrastructureType(value) diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index ab4497e0..75d40ca0 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -13,78 +13,28 @@ # bindings import stix.bindings.ttp as ttp_binding +from mixbox import fields, entities class MalwareInstance(Cached, stix.Entity): _binding = ttp_binding _binding_class = _binding.MalwareInstanceType _namespace = "http://stix.mitre.org/TTP-1" + id_ = fields.IdField("id") + idref = fields.IdrefField("idref") + title = fields.TypedField("Title") + descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList") + short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList") + names = fields.TypedField("Name", type_="stix.ttp.malware_instance.MalwareNames", key_name="names") + types = fields.TypedField("Type", type_="stix.ttp.malware_instance.MalwareTypes", key_name="types") + def __init__(self, id_=None, idref=None, title=None, description=None, short_description=None): + super(MalwareInstance, self).__init__() self.id_ = id_ self.idref = idref self.title = title self.description = description self.short_description = short_description - self.names = None - self.types = None - - @property - def id_(self): - """The ``id_`` property serves as an identifier. - - Default Value: ``None`` - - Note: - Both the ``id_`` and ``idref`` properties cannot be set at the - same time. **Setting one will unset the other!** - - Returns: - A string id. - - """ - return self._id - - @id_.setter - def id_(self, value): - if not value: - self._id = None - else: - self._id = value - self.idref = None - - @property - def idref(self): - """The ``idref`` property must be set to the ``id_`` value of another - object instance of the same type. An idref does not need to resolve to - a local object instance. - - Default Value: ``None``. - - Note: - Both the ``id_`` and ``idref`` properties cannot be set at the - same time. **Setting one will unset the other!** - - Returns: - The value of the ``idref`` property - - """ - return self._idref - - @idref.setter - def idref(self, value): - if not value: - self._idref = None - else: - self._idref = value - self.id_ = None # unset id_ if idref is present - - @property - def title(self): - return self._title - - @title.setter - def title(self, value): - self._title = value @property def description(self): @@ -97,57 +47,24 @@ def description(self): the description with the lowest ordinality value. Returns: - An instance of - :class:`.StructuredText` - + An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions), None) + return next(iter(self.descriptions or []), None) @description.setter def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. This is the same as calling "foo.descriptions.add(bar)". - """ self.descriptions.add(description) @property def short_description(self): - """"A single short description about the contents or purpose of this + """A single short description about the contents or purpose of this object. Default Value: ``None`` @@ -158,70 +75,23 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` - """ - return next(iter(self.short_descriptions), None) + return next(iter(self.short_descriptions or []), None) @short_description.setter def short_description(self, value): self.short_descriptions = value - @property - def short_descriptions(self): - """A :class:`.StructuredTextList` object, containing short descriptions - about the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - short descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of :class:`.StructuredTextList` - - """ - return self._short_description - - @short_descriptions.setter - def short_descriptions(self, value): - self._short_description = StructuredTextList(value) - def add_short_description(self, description): """Adds a description to the ``short_descriptions`` collection. This is the same as calling "foo.short_descriptions.add(bar)". - """ self.short_descriptions.add(description) - - @property - def names(self): - return self._names - - @names.setter - def names(self, value): - self._names = MalwareNames(value) - + def add_name(self, name): self._names.append(name) - @property - def types(self): - return self._types - - @types.setter - def types(self, value): - self._types = MalwareTypes(value) - def add_type(self, type_): self._types.append(type_) @@ -232,76 +102,75 @@ def lookup_class(xsi_type): return stix.lookup_extension(xsi_type) - def to_obj(self, return_obj=None, ns_info=None): - super(MalwareInstance, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - return_obj.id = self.id_ - return_obj.Title = self.title - - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.short_descriptions: - return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) - if self.names: - return_obj.Name = self.names.to_obj(ns_info=ns_info) - if self.types: - return_obj.Type = self.types.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - import stix.extensions.malware.maec_4_1_malware # noqa - - if not obj: - return None - - if not return_obj: - klass = stix.lookup_extension(obj, default=cls) - return_obj = klass.from_obj(obj, klass()) - else: - return_obj.id_ = obj.id - return_obj.title = obj.Title - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) - return_obj.names = MalwareNames.from_obj(obj.Name) - return_obj.types = MalwareTypes.from_obj(obj.Type) - - return return_obj - - def to_dict(self): - d = utils.to_dict(self) - - if getattr(self, '_XSI_TYPE', None): - d['xsi:type'] = self._XSI_TYPE - - return d - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - from stix.extensions.malware import maec_4_1_malware # noqa - - if not dict_repr: - return None - - get = dict_repr.get - - if not return_obj: - klass = stix.lookup_extension(get('xsi:type'), cls) - return_obj = klass.from_dict(dict_repr, klass()) - else: - return_obj.id_ = get('id') - return_obj.title = get('title') - return_obj.descriptions = StructuredTextList.from_dict(get('description')) - return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) - return_obj.names = MalwareNames.from_dict(get('names')) - return_obj.types = MalwareTypes.from_dict(get('types')) - - return return_obj - +# def to_obj(self, return_obj=None, ns_info=None): +# super(MalwareInstance, self).to_obj(ns_info=ns_info) +# +# if not return_obj: +# return_obj = self._binding_class() +# +# return_obj.id = self.id_ +# return_obj.Title = self.title +# +# if self.descriptions: +# return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) +# if self.short_descriptions: +# return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) +# if self.names: +# return_obj.Name = self.names.to_obj(ns_info=ns_info) +# if self.types: +# return_obj.Type = self.types.to_obj(ns_info=ns_info) +# +# return return_obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# import stix.extensions.malware.maec_4_1_malware # noqa +# +# if not obj: +# return None +# +# if not return_obj: +# klass = stix.lookup_extension(obj, default=cls) +# return_obj = klass.from_obj(obj, klass()) +# else: +# return_obj.id_ = obj.id +# return_obj.title = obj.Title +# return_obj.descriptions = StructuredTextList.from_obj(obj.Description) +# return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) +# return_obj.names = MalwareNames.from_obj(obj.Name) +# return_obj.types = MalwareTypes.from_obj(obj.Type) +# +# return return_obj +# +# def to_dict(self): +# d = utils.to_dict(self) +# +# if getattr(self, '_XSI_TYPE', None): +# d['xsi:type'] = self._XSI_TYPE +# +# return d +# +# @classmethod +# def from_dict(cls, dict_repr, return_obj=None): +# from stix.extensions.malware import maec_4_1_malware # noqa +# +# if not dict_repr: +# return None +# +# get = dict_repr.get +# +# if not return_obj: +# klass = stix.lookup_extension(get('xsi:type'), cls) +# return_obj = klass.from_dict(dict_repr, klass()) +# else: +# return_obj.id_ = get('id') +# return_obj.title = get('title') +# return_obj.descriptions = StructuredTextList.from_dict(get('description')) +# return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) +# return_obj.names = MalwareNames.from_dict(get('names')) +# return_obj.types = MalwareTypes.from_dict(get('types')) +# +# return return_obj class MalwareNames(stix.TypedList): _contained_type = VocabString diff --git a/stix/ttp/resource.py b/stix/ttp/resource.py index aa6ccbd6..43f338b3 100644 --- a/stix/ttp/resource.py +++ b/stix/ttp/resource.py @@ -40,7 +40,7 @@ class Tools(stix.EntityList): @classmethod def _dict_as_list(cls): - return False + return True class Resource(stix.Entity): From b2ce46b22003cb9da37d00837f920d47f3622cc3 Mon Sep 17 00:00:00 2001 From: apsillers Date: Mon, 9 Nov 2015 07:16:53 -0500 Subject: [PATCH 250/438] Fix Related_TTPs on Campaign --- stix/campaign/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 92c2f05f..fdf0c705 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -108,6 +108,7 @@ class Campaign(stix.BaseCoreComponent): related_incidents = fields.TypedField("Related_Incidents", RelatedIncidents) related_indicators = fields.TypedField("Related_Indicators", RelatedIndicators) related_packages = fields.TypedField("Related_Packages", RelatedPackageRefs) + related_ttps = fields.TypedField("Related_TTPs", RelatedTTPs) information_source = fields.TypedField("Information_Source", InformationSource) def __init__(self, id_=None, idref=None, timestamp=None, title=None, From 1edf3bbb17c1bff1f82ec4b05e5cbefa752924f8 Mon Sep 17 00:00:00 2001 From: apsillers Date: Tue, 10 Nov 2015 14:00:00 -0500 Subject: [PATCH 251/438] Add TypedFields to Indicator classes --- stix/common/vocabs.py | 4 +- stix/incident/__init__.py | 7 +- stix/incident/affected_asset.py | 343 +++++++++-------------- stix/incident/coa.py | 319 +++++++++------------ stix/incident/contributors.py | 7 +- stix/incident/direct_impact_summary.py | 117 ++++---- stix/incident/external_id.py | 107 ++++--- stix/incident/history.py | 240 +++++++--------- stix/incident/impact_assessment.py | 166 +++++------ stix/incident/indirect_impact_summary.py | 135 ++++----- stix/incident/loss_estimation.py | 99 +++---- stix/incident/property_affected.py | 237 +++++++--------- stix/incident/time.py | 226 ++++++--------- stix/incident/total_loss_estimation.py | 98 +++---- 14 files changed, 864 insertions(+), 1241 deletions(-) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index 960c7524..0f7d351b 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -77,7 +77,7 @@ def entity_class(cls, key): return VocabString -class VocabString(stix.Entity): +class VocabString(entities.Entity): _binding = stix_common_binding _binding_class = stix_common_binding.ControlledVocabularyStringType _namespace = 'http://stix.mitre.org/common-1' @@ -95,8 +95,6 @@ def __init__(self, value=None): super(VocabString, self).__init__() self.value = value self.xsi_type = self._XSI_TYPE - self.vocab_name = None - self.vocab_reference = None def __str__(self): return str(self.value) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index 48c8a27d..09e6169d 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -79,6 +79,11 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, description description=description, short_description=short_description ) + self.related_indicators = RelatedIndicators() + self.related_observables = RelatedObservables() + self.related_incidents = RelatedIncidents() + self.related_packages = RelatedPackageRefs() + def add_intended_effect(self, value): """Adds a :class:`.Statement` object to the :attr:`intended_effects` collection. @@ -411,7 +416,7 @@ class LeveragedTTPs(GenericRelationshipList): _binding_class = _binding.LeveragedTTPsType ttp = fields.TypedField( - name="Leverated_TTP", + name="Leveraged_TTP", type_=RelatedTTP, multiple=True, key_name="ttps" diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index 9fd39358..de8fcf44 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -12,30 +12,25 @@ # relative from .property_affected import PropertyAffected +from mixbox import entities, fields -class AffectedAsset(stix.Entity): +class AffectedAsset(entities.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.AffectedAssetType - def __init__(self): - self.type_ = None - self.description = None - self.business_function_or_role = None - self.ownership_class = None - self.management_class = None - self.location_class = None - # self.location = None - self.nature_of_security_effect = None - self.structured_description = None - - @property - def type_(self): - return self._type + descriptions = fields.TypedField("Description", StructuredTextList) + business_function_or_roles = fields.TypedField("Business_Function_Or_Role", StructuredTextList) + ownership_class = fields.TypedField("Ownership_Class", vocabs.OwnershipClass) + management_class = fields.TypedField("Management_Class", vocabs.ManagementClass) + location_class = fields.TypedField("location_Class", vocabs.LocationClass) + # location = fields.TypedField("Location") + nature_of_security_effect = fields.TypedField("Nature_Of_Security_Effect", type_="stix.incident.affected_asset.NatureOfSecurityEffect") + structured_description = fields.TypedField("Structured_Description", Observables) + type_ = fields.TypedField("Type", type_="stix.incident.affected_asset.AssetType", key_name="type") - @type_.setter - def type_(self, value): - self._set_var(AssetType, type=value) + def __init__(self): + super(AffectedAsset, self).__init__() @property def description(self): @@ -58,36 +53,6 @@ def description(self): def description(self, value): self.descriptions = value - @property - def descriptions(self): - """A :class:`.StructuredTextList` object, containing descriptions about - the purpose or intent of this object. - - This is typically used for the purpose of providing multiple - descriptions with different classificaton markings. - - Iterating over this object will yield its contents sorted by their - ``ordinality`` value. - - Default Value: Empty :class:`.StructuredTextList` object. - - Note: - IF this is set to a value that is not an instance of - :class:`.StructuredText`, an effort will ne made to convert it. - If this is set to an iterable, any values contained that are not - an instance of :class:`.StructuredText` will be be converted. - - Returns: - An instance of - :class:`.StructuredTextList` - - """ - return self._description - - @descriptions.setter - def descriptions(self, value): - self._description = StructuredTextList(value) - def add_description(self, description): """Adds a description to the ``descriptions`` collection. @@ -104,192 +69,140 @@ def business_function_or_role(self): def business_function_or_role(self, value): self.business_functions_or_roles = value - @property - def business_functions_or_roles(self): - return self._business_function_or_role - - @business_functions_or_roles.setter - def business_functions_or_roles(self, value): - self._business_function_or_role = StructuredTextList(value) - - @property - def ownership_class(self): - return self._ownership_class - - @ownership_class.setter - def ownership_class(self, value): - self._set_vocab(vocabs.OwnershipClass, ownership_class=value) - - @property - def management_class(self): - return self._management_class - - @management_class.setter - def management_class(self, value): - self._set_vocab(vocabs.ManagementClass, management_class=value) - - @property - def location_class(self): - return self._location_class - - @location_class.setter - def location_class(self, value): - self._set_vocab(vocabs.LocationClass, location_class=value) - - @property - def nature_of_security_effect(self): - return self._nature_of_security_effect - - @nature_of_security_effect.setter - def nature_of_security_effect(self, value): - self._nature_of_security_effect = NatureOfSecurityEffect(value) - def add_property_affected(self, v): self.nature_of_security_effect.append(v) - @property - def structured_description(self): - return self._structured_description - - @structured_description.setter - def structured_description(self, value): - self._set_var(Observables, structured_description=value) - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.type_ = AssetType.from_obj(obj.Type) - return_obj.descriptions = StructuredTextList.from_obj(obj.Description) - return_obj.business_functions_or_roles = StructuredTextList.from_obj(obj.Business_Function_Or_Role) - return_obj.ownership_class = VocabString.from_obj(obj.Ownership_Class) - return_obj.management_class = VocabString.from_obj(obj.Management_Class) - return_obj.location_class = VocabString.from_obj(obj.Location_Class) - # return_obj.location = None - - if obj.Nature_Of_Security_Effect: - n = obj.Nature_Of_Security_Effect - return_obj.nature_of_security_effect = [PropertyAffected.from_obj(x) for x in n.Property_Affected] - - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - super(AffectedAsset, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.type_: - return_obj.Type = self.type_.to_obj(ns_info=ns_info) - if self.descriptions: - return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) - if self.business_functions_or_roles: - return_obj.Business_Function_Or_Role = self.business_functions_or_roles.to_obj(ns_info=ns_info) - if self.ownership_class: - return_obj.Ownership_Class = self.ownership_class.to_obj(ns_info=ns_info) - if self.management_class: - return_obj.Management_Class = self.management_class.to_obj(ns_info=ns_info) - if self.location_class: - return_obj.Location_Class = self.location_class.to_obj(ns_info=ns_info) - # if self.location: - # return_obj.Location = self.location.to_obj(ns_info=ns_info) - if self.nature_of_security_effect: - property_affected_list = [x.to_obj(ns_info=ns_info) for x in self.nature_of_security_effect] - n = self._binding.NatureOfSecurityEffectType(Property_Affected=property_affected_list) - return_obj.Nature_Of_Security_Effect = n - if self.structured_description: - return_obj.Structured_Description = self.structured_description.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if not return_obj: - return_obj = cls() - - get = d.get - return_obj.type_ = AssetType.from_dict(get('type')) - return_obj.descriptions = StructuredTextList.from_dict(get('description')) - return_obj.business_functions_or_roles = StructuredTextList.from_dict(get('business_function_or_role')) - return_obj.ownership_class = VocabString.from_dict(get('ownership_class')) - return_obj.management_class = VocabString.from_dict(get('management_class')) - return_obj.location_class = VocabString.from_dict(get('location_class')) - # return_obj.location = Location.from_dict(get('location')) - return_obj.nature_of_security_effect = NatureOfSecurityEffect.from_dict(get('nature_of_security_effect')) - return_obj.structured_description = Observables.from_dict(get('structured_description')) - return return_obj - - def to_dict(self): - return super(AffectedAsset, self).to_dict() +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.type_ = AssetType.from_obj(obj.Type) +# return_obj.descriptions = StructuredTextList.from_obj(obj.Description) +# return_obj.business_functions_or_roles = StructuredTextList.from_obj(obj.Business_Function_Or_Role) +# return_obj.ownership_class = VocabString.from_obj(obj.Ownership_Class) +# return_obj.management_class = VocabString.from_obj(obj.Management_Class) +# return_obj.location_class = VocabString.from_obj(obj.Location_Class) +# # return_obj.location = None +# +# if obj.Nature_Of_Security_Effect: +# n = obj.Nature_Of_Security_Effect +# return_obj.nature_of_security_effect = [PropertyAffected.from_obj(x) for x in n.Property_Affected] +# +# return return_obj +# +# def to_obj(self, return_obj=None, ns_info=None): +# super(AffectedAsset, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# if not return_obj: +# return_obj = self._binding_class() +# +# if self.type_: +# return_obj.Type = self.type_.to_obj(ns_info=ns_info) +# if self.descriptions: +# return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) +# if self.business_functions_or_roles: +# return_obj.Business_Function_Or_Role = self.business_functions_or_roles.to_obj(ns_info=ns_info) +# if self.ownership_class: +# return_obj.Ownership_Class = self.ownership_class.to_obj(ns_info=ns_info) +# if self.management_class: +# return_obj.Management_Class = self.management_class.to_obj(ns_info=ns_info) +# if self.location_class: +# return_obj.Location_Class = self.location_class.to_obj(ns_info=ns_info) +# # if self.location: +# # return_obj.Location = self.location.to_obj(ns_info=ns_info) +# if self.nature_of_security_effect: +# property_affected_list = [x.to_obj(ns_info=ns_info) for x in self.nature_of_security_effect] +# n = self._binding.NatureOfSecurityEffectType(Property_Affected=property_affected_list) +# return_obj.Nature_Of_Security_Effect = n +# if self.structured_description: +# return_obj.Structured_Description = self.structured_description.to_obj(ns_info=ns_info) +# +# return return_obj +# +# @classmethod +# def from_dict(cls, d, return_obj=None): +# if not d: +# return None +# if not return_obj: +# return_obj = cls() +# +# get = d.get +# return_obj.type_ = AssetType.from_dict(get('type')) +# return_obj.descriptions = StructuredTextList.from_dict(get('description')) +# return_obj.business_functions_or_roles = StructuredTextList.from_dict(get('business_function_or_role')) +# return_obj.ownership_class = VocabString.from_dict(get('ownership_class')) +# return_obj.management_class = VocabString.from_dict(get('management_class')) +# return_obj.location_class = VocabString.from_dict(get('location_class')) +# # return_obj.location = Location.from_dict(get('location')) +# return_obj.nature_of_security_effect = NatureOfSecurityEffect.from_dict(get('nature_of_security_effect')) +# return_obj.structured_description = Observables.from_dict(get('structured_description')) +# return return_obj +# +# def to_dict(self): +# return super(AffectedAsset, self).to_dict() class AssetType(VocabString): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.AssetTypeType + count_affected = fields.TypedField("count_affected") + def __init__(self, value=None, count_affected=None): - self.count_affected = count_affected super(AssetType, self).__init__(value) + self.count_affected = count_affected def is_plain(self): """Override VocabString.is_plain()""" return False - @property - def count_affected(self): - return self._count_affected - - @count_affected.setter - def count_affected(self, value): - self._set_var(int, count_affected=value) - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - super(AssetType, cls).from_obj(obj, return_obj=return_obj) - return_obj.count_affected = obj.count_affected - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(AssetType, self).to_obj(return_obj=return_obj, ns_info=ns_info) - return_obj.count_affected = self.count_affected - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if not return_obj: - return_obj = cls() - - super(AssetType, cls).from_dict(d, return_obj=return_obj) - return_obj.count_affected = d.get('count_affected') - return return_obj - - def to_dict(self): - d = super(AssetType, self).to_dict() - if self.count_affected: - d['count_affected'] = self.count_affected - return d +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# if not return_obj: +# return_obj = cls() +# +# super(AssetType, cls).from_obj(obj, return_obj=return_obj) +# return_obj.count_affected = obj.count_affected +# return return_obj +# +# def to_obj(self, return_obj=None, ns_info=None): +# if not return_obj: +# return_obj = self._binding_class() +# +# super(AssetType, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# return_obj.count_affected = self.count_affected +# return return_obj +# +# @classmethod +# def from_dict(cls, d, return_obj=None): +# if not d: +# return None +# if not return_obj: +# return_obj = cls() +# +# super(AssetType, cls).from_dict(d, return_obj=return_obj) +# return_obj.count_affected = d.get('count_affected') +# return return_obj +# +# def to_dict(self): +# d = super(AssetType, self).to_dict() +# if self.count_affected: +# d['count_affected'] = self.count_affected +# return d class NatureOfSecurityEffect(stix.EntityList): _namespace = "http://stix.mitre.org/Incident-1" - _contained_type = PropertyAffected _binding = incident_binding _binding_class = _binding.NatureOfSecurityEffectType - _binding_var = "Property_Affected" - _inner_name = "nature_of_security_effect" - _dict_as_list = True + + nature_of_security_effect = fields.TypedField("Property_Affected", PropertyAffected, multiple=True, key_name="nature_of_security_effect") + + @classmethod + def _dict_as_list(cls): + return True diff --git a/stix/incident/coa.py b/stix/incident/coa.py index 10828b6d..d7cb215d 100644 --- a/stix/incident/coa.py +++ b/stix/incident/coa.py @@ -11,87 +11,68 @@ # relative from .contributors import Contributors +from mixbox import entities, fields -class COATaken(stix.Entity): +class COATaken(entities.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = _binding.COATakenType + course_of_action = fields.TypedField("Course_Of_Action", CourseOfAction) + contributors = fields.TypedField("Contributors", Contributors) + time = fields.TypedField("Time", type_="stix.incident.coa.COATime") + def __init__(self, course_of_action=None): + super(COATaken, self).__init__() self.time = None self.course_of_action = course_of_action - self.contributors = Contributors() - - @property - def time(self): - return self._time - - @time.setter - def time(self, value): - self._set_var(COATime, try_cast=False, time=value) - - @property - def course_of_action(self): - return self._course_of_action - - @course_of_action.setter - def course_of_action(self, value): - self._set_var(CourseOfAction, try_cast=False, course_of_action=value) - - @property - def contributors(self): - return self._contributors - - @contributors.setter - def contributors(self, value): - self._contributors = Contributors(value) def add_contributor(self, value): self.contributors.append(value) - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.time = COATime.from_obj(obj.Time) - return_obj.contributors = Contributors.from_obj(obj.Contributors) - return_obj.course_of_action = CourseOfAction.from_obj(obj.Course_Of_Action) - - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - super(COATaken, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.time: - return_obj.Time = self.time.to_obj(ns_info=ns_info) - if self.contributors: - return_obj.Contributors = self.contributors.to_obj(ns_info=ns_info) - if self.course_of_action: - return_obj.Course_Of_Action = self.course_of_action.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if not return_obj: - return_obj = cls() - - return_obj.time = COATime.from_dict(d.get('time')) - return_obj.contributors = Contributors.from_dict(d.get('contributors')) - return_obj.course_of_action = CourseOfAction.from_dict(d.get('course_of_action')) - - return return_obj - - def to_dict(self): - return super(COATaken, self).to_dict() +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.time = COATime.from_obj(obj.Time) +# return_obj.contributors = Contributors.from_obj(obj.Contributors) +# return_obj.course_of_action = CourseOfAction.from_obj(obj.Course_Of_Action) +# +# return return_obj +# +# def to_obj(self, return_obj=None, ns_info=None): +# super(COATaken, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# if not return_obj: +# return_obj = self._binding_class() +# +# if self.time: +# return_obj.Time = self.time.to_obj(ns_info=ns_info) +# if self.contributors: +# return_obj.Contributors = self.contributors.to_obj(ns_info=ns_info) +# if self.course_of_action: +# return_obj.Course_Of_Action = self.course_of_action.to_obj(ns_info=ns_info) +# +# return return_obj +# +# @classmethod +# def from_dict(cls, d, return_obj=None): +# if not d: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.time = COATime.from_dict(d.get('time')) +# return_obj.contributors = Contributors.from_dict(d.get('contributors')) +# return_obj.course_of_action = CourseOfAction.from_dict(d.get('course_of_action')) +# +# return return_obj +# +# def to_dict(self): +# return super(COATaken, self).to_dict() class COARequested(COATaken): @@ -99,125 +80,103 @@ class COARequested(COATaken): _binding = incident_binding _binding_class = _binding.COARequestedType + priority = fields.TypedField("priority") + def __init__(self, course_of_action=None): super(COARequested, self).__init__(course_of_action=course_of_action) - self.priority = None - - @property - def priority(self): - return self._priority - - @priority.setter - def priority(self, value): - if value is None: - self._priority = None - else: - self._priority = value - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - super(COARequested, cls).from_obj(obj, return_obj=return_obj) - return_obj.priority = obj.priority - - return return_obj - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(COARequested, self).to_obj(return_obj=return_obj, ns_info=ns_info) - return_obj.priority = self.priority - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if not return_obj: - return_obj = cls() - - super(COARequested, cls).from_dict(d, return_obj=return_obj) - return_obj.priority = d.get('priority') - - return return_obj - - def to_dict(self): - d = utils.to_dict(self) - return d - - -class COATime(stix.Entity): +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# if not return_obj: +# return_obj = cls() +# +# super(COARequested, cls).from_obj(obj, return_obj=return_obj) +# return_obj.priority = obj.priority +# +# return return_obj +# +# def to_obj(self, return_obj=None, ns_info=None): +# if not return_obj: +# return_obj = self._binding_class() +# +# super(COARequested, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# return_obj.priority = self.priority +# +# return return_obj +# +# @classmethod +# def from_dict(cls, d, return_obj=None): +# if not d: +# return None +# if not return_obj: +# return_obj = cls() +# +# super(COARequested, cls).from_dict(d, return_obj=return_obj) +# return_obj.priority = d.get('priority') +# +# return return_obj +# +# def to_dict(self): +# d = utils.to_dict(self) +# return d + + +class COATime(entities.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = _binding.COATimeType + start = fields.TypedField("Start", DateTimeWithPrecision) + end = fields.TypedField("End", DateTimeWithPrecision) + def __init__(self, start=None, end=None): + super(COATime, self).__init__() self.start = start self.end = end - @property - def start(self): - return self._start - - @start.setter - def start(self, value): - self._set_var(DateTimeWithPrecision, start=value) - - @property - def end(self): - return self._end - - @end.setter - def end(self, value): - self._set_var(DateTimeWithPrecision, end=value) - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.start = DateTimeWithPrecision.from_obj(obj.Start) - return_obj.end = DateTimeWithPrecision.from_obj(obj.End) - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(COATime, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if self.start: - return_obj.Start = self.start.to_obj(ns_info=ns_info) - if self.end: - return_obj.End = self.end.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if not return_obj: - return_obj = cls() - - return_obj.start = DateTimeWithPrecision.from_dict(d.get('start')) - return_obj.end = DateTimeWithPrecision.from_dict(d.get('end')) - return return_obj - - def to_dict(self): - d = {} - - if self.start: - d['start'] = self.start.to_dict() - if self.end: - d['end'] = self.end.to_dict() - - return d +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.start = DateTimeWithPrecision.from_obj(obj.Start) +# return_obj.end = DateTimeWithPrecision.from_obj(obj.End) +# return return_obj +# +# def to_obj(self, return_obj=None, ns_info=None): +# if not return_obj: +# return_obj = self._binding_class() +# +# super(COATime, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# if self.start: +# return_obj.Start = self.start.to_obj(ns_info=ns_info) +# if self.end: +# return_obj.End = self.end.to_obj(ns_info=ns_info) +# +# return return_obj + +# @classmethod +# def from_dict(cls, d, return_obj=None): +# if not d: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.start = DateTimeWithPrecision.from_dict(d.get('start')) +# return_obj.end = DateTimeWithPrecision.from_dict(d.get('end')) +# return return_obj +# +# def to_dict(self): +# d = {} +# +# if self.start: +# d['start'] = self.start.to_dict() +# if self.end: +# d['end'] = self.end.to_dict() +# +# return d diff --git a/stix/incident/contributors.py b/stix/incident/contributors.py index d00c33cc..f31dd3a1 100644 --- a/stix/incident/contributors.py +++ b/stix/incident/contributors.py @@ -8,12 +8,11 @@ import stix import stix.utils import stix.bindings.incident as incident_binding - +from mixbox import fields, entities class Contributors(stix.EntityList): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = _binding.ContributorsType - _contained_type = Contributor - _binding_var = "Contributor" - _inner_name = "contributors" + + contributors = fields.TypedField("Contributor", Contributor, multiple=True, key_name="contributors") \ No newline at end of file diff --git a/stix/incident/direct_impact_summary.py b/stix/incident/direct_impact_summary.py index 1f942e56..3f721443 100644 --- a/stix/incident/direct_impact_summary.py +++ b/stix/incident/direct_impact_summary.py @@ -5,81 +5,58 @@ from stix.common import VocabString from stix.common.vocabs import ImpactRating import stix.bindings.incident as incident_binding +from mixbox import fields, entities - -class DirectImpactSummary(stix.Entity): +class DirectImpactSummary(entities.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.DirectImpactSummaryType + asset_losses = fields.TypedField("Asset_Losses", ImpactRating) + business_mission_disruption = fields.TypedField("Business_Mission_Disruption", ImpactRating) + response_and_recovery_costs = fields.TypedField("Response_And_Recovery_Costs", ImpactRating) + def __init__(self): super(DirectImpactSummary, self).__init__() - self.asset_losses = None - self.business_mission_disruption = None - self.response_and_recovery_costs = None - - @property - def asset_losses(self): - return self._asset_losses - - @asset_losses.setter - def asset_losses(self, value): - self._set_vocab(ImpactRating, asset_losses=value) - - @property - def business_mission_disruption(self): - return self._business_mission_disruption - - @business_mission_disruption.setter - def business_mission_disruption(self, value): - self._set_vocab(ImpactRating, business_mission_disruption=value) - - @property - def response_and_recovery_costs(self): - return self._response_and_recovery_costs - - @response_and_recovery_costs.setter - def response_and_recovery_costs(self, value): - self._set_vocab(ImpactRating, response_and_recovery_costs=value) - def to_obj(self, return_obj=None, ns_info=None): - super(DirectImpactSummary, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - obj = self._binding_class() - if self.asset_losses: - obj.Asset_Losses = self.asset_losses.to_obj(ns_info=ns_info) - if self.business_mission_disruption: - obj.Business_Mission_Disruption = self.business_mission_disruption.to_obj(ns_info=ns_info) - if self.response_and_recovery_costs: - obj.Response_And_Recovery_Costs = self.response_and_recovery_costs.to_obj(ns_info=ns_info) - return obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.asset_losses = VocabString.from_obj(obj.Asset_Losses) - return_obj.business_mission_disruption = VocabString.from_obj(obj.Business_Mission_Disruption) - return_obj.response_and_recovery_costs = VocabString.from_obj(obj.Response_And_Recovery_Costs) - return return_obj - - def to_dict(self): - return super(DirectImpactSummary, self).to_dict() - - @classmethod - def from_dict(cls, dict_, return_obj=None): - if not dict_: - return None - - if not return_obj: - return_obj = cls() - - return_obj.asset_losses = VocabString.from_dict(dict_.get('asset_losses')) - return_obj.business_mission_disruption = VocabString.from_dict(dict_.get('business_mission_disruption')) - return_obj.response_and_recovery_costs = VocabString.from_dict(dict_.get('response_and_recovery_costs')) - - return return_obj +# def to_obj(self, return_obj=None, ns_info=None): +# super(DirectImpactSummary, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# obj = self._binding_class() +# if self.asset_losses: +# obj.Asset_Losses = self.asset_losses.to_obj(ns_info=ns_info) +# if self.business_mission_disruption: +# obj.Business_Mission_Disruption = self.business_mission_disruption.to_obj(ns_info=ns_info) +# if self.response_and_recovery_costs: +# obj.Response_And_Recovery_Costs = self.response_and_recovery_costs.to_obj(ns_info=ns_info) +# return obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.asset_losses = VocabString.from_obj(obj.Asset_Losses) +# return_obj.business_mission_disruption = VocabString.from_obj(obj.Business_Mission_Disruption) +# return_obj.response_and_recovery_costs = VocabString.from_obj(obj.Response_And_Recovery_Costs) +# return return_obj +# +# def to_dict(self): +# return super(DirectImpactSummary, self).to_dict() +# +# @classmethod +# def from_dict(cls, dict_, return_obj=None): +# if not dict_: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.asset_losses = VocabString.from_dict(dict_.get('asset_losses')) +# return_obj.business_mission_disruption = VocabString.from_dict(dict_.get('business_mission_disruption')) +# return_obj.response_and_recovery_costs = VocabString.from_dict(dict_.get('response_and_recovery_costs')) +# +# return return_obj diff --git a/stix/incident/external_id.py b/stix/incident/external_id.py index 85eb4cd3..de1c35f5 100644 --- a/stix/incident/external_id.py +++ b/stix/incident/external_id.py @@ -3,73 +3,60 @@ import stix import stix.bindings.incident as incident_binding +from mixbox import fields, entities - -class ExternalID(stix.Entity): +class ExternalID(entities.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.ExternalIDType + value = fields.TypedField("valueOf_", key_name="value") + source = fields.TypedField("source") + def __init__(self, value=None, source=None): super(ExternalID, self).__init__() self.value = value self.source = source - @property - def value(self): - return self._value - - @value.setter - def value(self, value): - self._value = value - - @property - def source(self): - return self._source - - @source.setter - def source(self, value): - self._source = value - - def to_obj(self, return_obj=None, ns_info=None): - super(ExternalID, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - obj = self._binding_class() - obj.valueOf_ = self.value - obj.source = self.source - return obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.value = obj.valueOf_ - return_obj.source = obj.source - return return_obj - - def to_dict(self): - d = { - 'value': self.value, - 'source': self.source - } - return d - - @classmethod - def from_dict(cls, dict_, return_obj=None): - if not dict_: - return None - - if not return_obj: - return_obj = cls() - - if not isinstance(dict_, dict): - return_obj.value = dict_ - else: - return_obj.source = dict_.get('source') - return_obj.value = dict_.get('value') - - return return_obj +# def to_obj(self, return_obj=None, ns_info=None): +# super(ExternalID, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# obj = self._binding_class() +# obj.valueOf_ = self.value +# obj.source = self.source +# return obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.value = obj.valueOf_ +# return_obj.source = obj.source +# return return_obj +# +# def to_dict(self): +# d = { +# 'value': self.value, +# 'source': self.source +# } +# return d +# +# @classmethod +# def from_dict(cls, dict_, return_obj=None): +# if not dict_: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# if not isinstance(dict_, dict): +# return_obj.value = dict_ +# else: +# return_obj.source = dict_.get('source') +# return_obj.value = dict_.get('value') +# +# return return_obj diff --git a/stix/incident/history.py b/stix/incident/history.py index 9650a007..dcf08e6e 100644 --- a/stix/incident/history.py +++ b/stix/incident/history.py @@ -10,158 +10,134 @@ # relative from .coa import COATaken +from mixbox import fields, entities -class JournalEntry(stix.Entity): +def validate_precision(instance, value): + if value and (value not in DATETIME_PRECISION_VALUES): + error = "time_precision must be one of {0}. Received '{1}'" + error = error.format(DATETIME_PRECISION_VALUES, value) + raise ValueError(error) + +class JournalEntry(entities.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.JournalEntryType + value = fields.TypedField("valueOf_", key_name="value") + author = fields.TypedField("author") + time = fields.TypedField("time") #TDOO: utils.dates.parse_value(value) + time_precision = fields.TypedField("time_precision", preset_hook=validate_precision) + def __init__(self, value=None): + super(JournalEntry, self).__init__() self.value = value - self.author = None - self.time = None self.time_precision = 'second' - - @property - def time(self): - return self._time - - @time.setter - def time(self, value): - self._time = utils.dates.parse_value(value) - - @property - def time_precision(self): - return self._time_precision - @time_precision.setter - def time_precision(self, value): - if value and (value not in DATETIME_PRECISION_VALUES): - error = "time_precision must be one of {0}. Received '{1}'" - error = error.format(DATETIME_PRECISION_VALUES, value) - raise ValueError(error) +# def to_obj(self, return_obj=None, ns_info=None): +# super(JournalEntry, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# if not return_obj: +# return_obj = self._binding_class() +# +# return_obj.valueOf_ = self.value +# return_obj.author = self.author +# return_obj.time = utils.dates.serialize_value(self.time) +# return_obj.time_precision = self.time_precision +# +# return return_obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.value = obj.valueOf_ +# return_obj.author = obj.author +# return_obj.time = obj.time +# return_obj.time_precision = obj.time_precision +# +# return return_obj +# +# def to_dict(self): +# return super(JournalEntry, self).to_dict() +# +# @classmethod +# def from_dict(cls, d, return_obj=None): +# if not d: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.value = d.get('value') +# return_obj.author = d.get('author') +# return_obj.time = d.get('time') +# return_obj.time_precision = d.get('time_precision') +# +# return return_obj - self._time_precision = value - - def to_obj(self, return_obj=None, ns_info=None): - super(JournalEntry, self).to_obj(return_obj=return_obj, ns_info=ns_info) - if not return_obj: - return_obj = self._binding_class() - - return_obj.valueOf_ = self.value - return_obj.author = self.author - return_obj.time = utils.dates.serialize_value(self.time) - return_obj.time_precision = self.time_precision - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.value = obj.valueOf_ - return_obj.author = obj.author - return_obj.time = obj.time - return_obj.time_precision = obj.time_precision - - return return_obj - - def to_dict(self): - return super(JournalEntry, self).to_dict() - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - - if not return_obj: - return_obj = cls() - - return_obj.value = d.get('value') - return_obj.author = d.get('author') - return_obj.time = d.get('time') - return_obj.time_precision = d.get('time_precision') - - return return_obj - - -class HistoryItem(stix.Entity): +class HistoryItem(entities.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.HistoryItemType - def __init__(self): - self.action_entry = None - self.journal_entry = None - - @property - def action_entry(self): - return self._action_entry - - @action_entry.setter - def action_entry(self, value): - self._set_var(COATaken, try_cast=False, action_entry=value) - - @property - def journal_entry(self): - return self._journal_entry - - @journal_entry.setter - def journal_entry(self, value): - self._set_var(JournalEntry, journal_entry=value) - - def to_obj(self, return_obj=None, ns_info=None): - super(HistoryItem, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.action_entry: - return_obj.Action_Entry = self.action_entry.to_obj(ns_info=ns_info) - if self.journal_entry: - return_obj.Journal_Entry = self.journal_entry.to_obj(ns_info=ns_info) - - return return_obj + action_entry = fields.TypedField("Action_Entry", COATaken) + journal_entry = fields.TypedField("Journal_Entry", JournalEntry) - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.action_entry = COATaken.from_obj(obj.Action_Entry) - return_obj.journal_entry = JournalEntry.from_obj(obj.Journal_Entry) - - return return_obj - - def to_dict(self): - return super(HistoryItem, self).to_dict() - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - - if not return_obj: - return_obj = cls() + def __init__(self): + super(HistoryItem, self).__init__() - return_obj.action_entry = COATaken.from_dict(d.get('action_entry')) - return_obj.journal_entry = JournalEntry.from_dict(d.get('journal_entry')) - - return return_obj +# def to_obj(self, return_obj=None, ns_info=None): +# super(HistoryItem, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# if not return_obj: +# return_obj = self._binding_class() +# +# if self.action_entry: +# return_obj.Action_Entry = self.action_entry.to_obj(ns_info=ns_info) +# if self.journal_entry: +# return_obj.Journal_Entry = self.journal_entry.to_obj(ns_info=ns_info) +# +# return return_obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.action_entry = COATaken.from_obj(obj.Action_Entry) +# return_obj.journal_entry = JournalEntry.from_obj(obj.Journal_Entry) +# +# return return_obj +# +# def to_dict(self): +# return super(HistoryItem, self).to_dict() +# +# @classmethod +# def from_dict(cls, d, return_obj=None): +# if not d: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.action_entry = COATaken.from_dict(d.get('action_entry')) +# return_obj.journal_entry = JournalEntry.from_dict(d.get('journal_entry')) +# +# return return_obj class History(stix.EntityList): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.HistoryType - _binding_var = "History_Item" - _contained_type = HistoryItem - _inner_name = "history_items" + + history_items = fields.TypedField("History_Item", HistoryItem, multiple=True, key_name="history_items") + \ No newline at end of file diff --git a/stix/incident/impact_assessment.py b/stix/incident/impact_assessment.py index 2f106e30..fa6f3df5 100644 --- a/stix/incident/impact_assessment.py +++ b/stix/incident/impact_assessment.py @@ -11,12 +11,19 @@ from .indirect_impact_summary import IndirectImpactSummary from .total_loss_estimation import TotalLossEstimation +from mixbox import fields, entities -class ImpactAssessment(stix.Entity): +class ImpactAssessment(entities.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.ImpactAssessmentType + direct_impact_summary = fields.TypedField("Direct_Impact_Summary", DirectImpactSummary) + indirect_impact_summary = fields.TypedField("Indirect_Impact_Summary", IndirectImpactSummary) + total_loss_estimation = fields.TypedField("Total_Loss_Estimation", TotalLossEstimation) + impact_qualification = fields.TypedField("Impact_Qualification", vocabs.ImpactQualification) + effects = fields.TypedField("Effects", type_="stix.incident.impact_assessment.Effects") + def __init__(self): super(ImpactAssessment, self).__init__() self.direct_impact_summary = None @@ -26,111 +33,70 @@ def __init__(self): self.effects = None # self.external_impact_assessment_model = None - @property - def effects(self): - return self._effects - - @effects.setter - def effects(self, value): - self._effects = Effects(value) - - def add_effect(self, value): - self.effects.append(value) - - @property - def direct_impact_summary(self): - return self._direct_impact_summary - - @direct_impact_summary.setter - def direct_impact_summary(self, value): - self._set_var(DirectImpactSummary, try_cast=False, direct_impact_summary=value) - - @property - def indirect_impact_summary(self): - return self._indirect_impact_summary - - @indirect_impact_summary.setter - def indirect_impact_summary(self, value): - self._set_var(IndirectImpactSummary, try_cast=False, indirect_impact_summary=value) - - @property - def total_loss_estimation(self): - return self._total_loss_estimation - - @total_loss_estimation.setter - def total_loss_estimation(self, value): - self._set_var(TotalLossEstimation, try_cast=False, total_loss_estimation=value) - - @property - def impact_qualification(self): - return self._impact_qualification - - @impact_qualification.setter - def impact_qualification(self, value): - self._set_vocab(vocabs.ImpactQualification, impact_qualification=value) - - def to_obj(self, return_obj=None, ns_info=None): - super(ImpactAssessment, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - obj = self._binding_class() - - if self.direct_impact_summary: - obj.Direct_Impact_Summary = self.direct_impact_summary.to_obj(ns_info=ns_info) - if self.indirect_impact_summary: - obj.Indirect_Impact_Summary = self.indirect_impact_summary.to_obj(ns_info=ns_info) - if self.total_loss_estimation: - obj.Total_Loss_Estimation = self.total_loss_estimation.to_obj(ns_info=ns_info) - if self.impact_qualification: - obj.Impact_Qualification = self.impact_qualification.to_obj(ns_info=ns_info) - if self.effects: - obj.Effects = self.effects.to_obj(ns_info=ns_info) - - return obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.direct_impact_summary = DirectImpactSummary.from_obj(obj.Direct_Impact_Summary) - return_obj.indirect_impact_summary = IndirectImpactSummary.from_obj(obj.Indirect_Impact_Summary) - return_obj.total_loss_estimation = TotalLossEstimation.from_obj(obj.Total_Loss_Estimation) - return_obj.impact_qualification = VocabString.from_obj(obj.Impact_Qualification) - return_obj.effects = Effects.from_obj(obj.Effects) - - return return_obj - - def to_dict(self): - return super(ImpactAssessment, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - get = dict_repr.get - return_obj.direct_impact_summary = DirectImpactSummary.from_dict(get('direct_impact_summary')) - return_obj.indirect_impact_summary = IndirectImpactSummary.from_dict(get('indirect_impact_summary')) - return_obj.total_loss_estimation = TotalLossEstimation.from_dict(get('total_loss_estimation')) - return_obj.impact_qualification = VocabString.from_dict(get('impact_qualification')) - return_obj.effects = Effects.from_dict(get('effects')) - - return return_obj +# def to_obj(self, return_obj=None, ns_info=None): +# super(ImpactAssessment, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# obj = self._binding_class() +# +# if self.direct_impact_summary: +# obj.Direct_Impact_Summary = self.direct_impact_summary.to_obj(ns_info=ns_info) +# if self.indirect_impact_summary: +# obj.Indirect_Impact_Summary = self.indirect_impact_summary.to_obj(ns_info=ns_info) +# if self.total_loss_estimation: +# obj.Total_Loss_Estimation = self.total_loss_estimation.to_obj(ns_info=ns_info) +# if self.impact_qualification: +# obj.Impact_Qualification = self.impact_qualification.to_obj(ns_info=ns_info) +# if self.effects: +# obj.Effects = self.effects.to_obj(ns_info=ns_info) +# +# return obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.direct_impact_summary = DirectImpactSummary.from_obj(obj.Direct_Impact_Summary) +# return_obj.indirect_impact_summary = IndirectImpactSummary.from_obj(obj.Indirect_Impact_Summary) +# return_obj.total_loss_estimation = TotalLossEstimation.from_obj(obj.Total_Loss_Estimation) +# return_obj.impact_qualification = VocabString.from_obj(obj.Impact_Qualification) +# return_obj.effects = Effects.from_obj(obj.Effects) +# +# return return_obj +# +# def to_dict(self): +# return super(ImpactAssessment, self).to_dict() +# +# @classmethod +# def from_dict(cls, dict_repr, return_obj=None): +# if not dict_repr: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# get = dict_repr.get +# return_obj.direct_impact_summary = DirectImpactSummary.from_dict(get('direct_impact_summary')) +# return_obj.indirect_impact_summary = IndirectImpactSummary.from_dict(get('indirect_impact_summary')) +# return_obj.total_loss_estimation = TotalLossEstimation.from_dict(get('total_loss_estimation')) +# return_obj.impact_qualification = VocabString.from_dict(get('impact_qualification')) +# return_obj.effects = Effects.from_dict(get('effects')) +# +# return return_obj class Effects(stix.EntityList): _namespace = "http://stix.mitre.org/Incident-1" - _contained_type = VocabString _binding = incident_binding _binding_class = _binding.EffectsType - _inner_name = "effects" - _binding_var = "Effect" - _dict_as_list = True + + effects = fields.TypedField("Effect", VocabString, multiple=True, key_name="effects") + + @classmethod + def _dict_as_list(cls): + return True def _fix_value(self, value): return vocabs.IncidentEffect(value=value) diff --git a/stix/incident/indirect_impact_summary.py b/stix/incident/indirect_impact_summary.py index 9c89a945..96ccd848 100644 --- a/stix/incident/indirect_impact_summary.py +++ b/stix/incident/indirect_impact_summary.py @@ -4,94 +4,63 @@ import stix import stix.bindings.incident as incident_binding from stix.common import vocabs, VocabString +from mixbox import entities, fields - -class IndirectImpactSummary(stix.Entity): +class IndirectImpactSummary(entities.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.IndirectImpactSummaryType + loss_of_competitive_advantage = fields.TypedField("Loss_Of_Competitive_Advantage", vocabs.SecurityCompromise) + brand_and_market_damage = fields.TypedField("Brand_And_Market_Damage", vocabs.SecurityCompromise) + increased_operating_costs = fields.TypedField("Increased_Operating_Costs", vocabs.SecurityCompromise) + legal_and_regulatory_costs = fields.TypedField("Legal_And_Regulatory_Costs", vocabs.SecurityCompromise) + def __init__(self): super(IndirectImpactSummary, self).__init__() - self.loss_of_competitive_advantage = None - self.brand_and_market_damage = None - self.increased_operating_costs = None - self.legal_and_regulatory_costs = None - - @property - def loss_of_competitive_advantage(self): - return self._loss_of_competitive_advantage - - @loss_of_competitive_advantage.setter - def loss_of_competitive_advantage(self, value): - self._set_vocab(vocabs.SecurityCompromise, loss_of_competitive_advantage=value) - - @property - def brand_and_market_damage(self): - return self._brand_and_market_damage - - @brand_and_market_damage.setter - def brand_and_market_damage(self, value): - self._set_vocab(vocabs.SecurityCompromise, brand_and_market_damage=value) - - @property - def increased_operating_costs(self): - return self._increased_operating_costs - - @increased_operating_costs.setter - def increased_operating_costs(self, value): - self._set_vocab(vocabs.SecurityCompromise, increased_operating_costs=value) - - @property - def legal_and_regulatory_costs(self): - return self._legal_and_regulatory_costs - - @legal_and_regulatory_costs.setter - def legal_and_regulatory_costs(self, value): - self._set_vocab(vocabs.SecurityCompromise, legal_and_regulatory_costs=value) - - def to_obj(self, return_obj=None, ns_info=None): - super(IndirectImpactSummary, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - obj = self._binding_class() - if self.loss_of_competitive_advantage: - obj.Loss_Of_Competitive_Advantage = self.loss_of_competitive_advantage.to_obj(ns_info=ns_info) - if self.brand_and_market_damage: - obj.Brand_And_Market_Damage = self.brand_and_market_damage.to_obj(ns_info=ns_info) - if self.increased_operating_costs: - obj.Increased_Operating_Costs = self.increased_operating_costs.to_obj(ns_info=ns_info) - if self.legal_and_regulatory_costs: - obj.Legal_And_Regulatory_Costs = self.legal_and_regulatory_costs.to_obj(ns_info=ns_info) - return obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.loss_of_competitive_advantage = VocabString.from_obj(obj.Loss_Of_Competitive_Advantage) - return_obj.brand_and_market_damage = VocabString.from_obj(obj.Brand_And_Market_Damage) - return_obj.increased_operating_costs = VocabString.from_obj(obj.Increased_Operating_Costs) - return_obj.legal_and_regulatory_costs = VocabString.from_obj(obj.Legal_And_Regulatory_Costs) - return return_obj - - def to_dict(self): - return super(IndirectImpactSummary, self).to_dict() - - @classmethod - def from_dict(cls, dict_, return_obj=None): - if not dict_: - return None - - if not return_obj: - return_obj = cls() - - return_obj.loss_of_competitive_advantage = VocabString.from_dict(dict_.get('loss_of_competitive_advantage')) - return_obj.brand_and_market_damage = VocabString.from_dict(dict_.get('brand_and_market_damage')) - return_obj.increased_operating_costs = VocabString.from_dict(dict_.get('increased_operating_costs')) - return_obj.legal_and_regulatory_costs = VocabString.from_dict(dict_.get('legal_and_regulatory_costs')) - return return_obj +# def to_obj(self, return_obj=None, ns_info=None): +# super(IndirectImpactSummary, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# obj = self._binding_class() +# if self.loss_of_competitive_advantage: +# obj.Loss_Of_Competitive_Advantage = self.loss_of_competitive_advantage.to_obj(ns_info=ns_info) +# if self.brand_and_market_damage: +# obj.Brand_And_Market_Damage = self.brand_and_market_damage.to_obj(ns_info=ns_info) +# if self.increased_operating_costs: +# obj.Increased_Operating_Costs = self.increased_operating_costs.to_obj(ns_info=ns_info) +# if self.legal_and_regulatory_costs: +# obj.Legal_And_Regulatory_Costs = self.legal_and_regulatory_costs.to_obj(ns_info=ns_info) +# return obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.loss_of_competitive_advantage = VocabString.from_obj(obj.Loss_Of_Competitive_Advantage) +# return_obj.brand_and_market_damage = VocabString.from_obj(obj.Brand_And_Market_Damage) +# return_obj.increased_operating_costs = VocabString.from_obj(obj.Increased_Operating_Costs) +# return_obj.legal_and_regulatory_costs = VocabString.from_obj(obj.Legal_And_Regulatory_Costs) +# return return_obj +# +# def to_dict(self): +# return super(IndirectImpactSummary, self).to_dict() +# +# @classmethod +# def from_dict(cls, dict_, return_obj=None): +# if not dict_: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.loss_of_competitive_advantage = VocabString.from_dict(dict_.get('loss_of_competitive_advantage')) +# return_obj.brand_and_market_damage = VocabString.from_dict(dict_.get('brand_and_market_damage')) +# return_obj.increased_operating_costs = VocabString.from_dict(dict_.get('increased_operating_costs')) +# return_obj.legal_and_regulatory_costs = VocabString.from_dict(dict_.get('legal_and_regulatory_costs')) +# +# return return_obj diff --git a/stix/incident/loss_estimation.py b/stix/incident/loss_estimation.py index dc9540d3..71db7cfc 100644 --- a/stix/incident/loss_estimation.py +++ b/stix/incident/loss_estimation.py @@ -3,68 +3,53 @@ import stix import stix.bindings.incident as incident_binding +from mixbox import entities, fields - -class LossEstimation(stix.Entity): +class LossEstimation(entities.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.LossEstimationType + iso_currency_code = fields.TypedField("iso_currency_code") + amount = fields.TypedField("amount") + def __init__(self): super(LossEstimation, self).__init__() - self.iso_currency_code = None - self.amount = None - - @property - def amount(self): - return self._amount - - @amount.setter - def amount(self, value): - self._amount = value - - @property - def iso_currency_code(self): - return self._iso_currency_code - - @iso_currency_code.setter - def iso_currency_code(self, value): - self._iso_currency_code = value - - def to_obj(self, return_obj=None, ns_info=None): - super(LossEstimation, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - obj = self._binding_class() - if self.amount: - obj.amount = self.amount - if self.iso_currency_code: - obj.iso_currency_code = self.iso_currency_code - return obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.amount = obj.amount - return_obj.iso_currency_code = obj.iso_currency_code - return return_obj - - def to_dict(self): - return super(LossEstimation, self).to_dict() - - @classmethod - def from_dict(cls, dict_, return_obj=None): - if not dict_: - return None - - if not return_obj: - return_obj = cls() - - return_obj.amount = dict_.get('amount') - return_obj.iso_currency_code = dict_.get('iso_currency_code') - return return_obj +# def to_obj(self, return_obj=None, ns_info=None): +# super(LossEstimation, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# obj = self._binding_class() +# if self.amount: +# obj.amount = self.amount +# if self.iso_currency_code: +# obj.iso_currency_code = self.iso_currency_code +# return obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.amount = obj.amount +# return_obj.iso_currency_code = obj.iso_currency_code +# return return_obj +# +# def to_dict(self): +# return super(LossEstimation, self).to_dict() +# +# @classmethod +# def from_dict(cls, dict_, return_obj=None): +# if not dict_: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.amount = dict_.get('amount') +# return_obj.iso_currency_code = dict_.get('iso_currency_code') +# +# return return_obj diff --git a/stix/incident/property_affected.py b/stix/incident/property_affected.py index 7d735620..41479492 100644 --- a/stix/incident/property_affected.py +++ b/stix/incident/property_affected.py @@ -5,59 +5,62 @@ import stix from stix.common import vocabs, VocabString, StructuredTextList import stix.bindings.incident as incident_binding - +from mixbox import fields, entities class NonPublicDataCompromised(VocabString): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.NonPublicDataCompromisedType + data_encrypted = fields.TypedField("data_encrypted") + def __init__(self, value=None, data_encrypted=None): - self.data_encrypted = data_encrypted super(NonPublicDataCompromised, self).__init__(value) - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - super(NonPublicDataCompromised, cls).from_obj(obj, return_obj=return_obj) - return_obj.data_encrypted = obj.data_encrypted - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() + self.data_encrypted = data_encrypted - super(NonPublicDataCompromised, self).to_obj(return_obj=return_obj, ns_info=ns_info) - return_obj.data_encrypted = self.data_encrypted - return return_obj - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - - if not return_obj: - return_obj = cls() - - super(NonPublicDataCompromised, cls).from_dict(d, return_obj=return_obj) - return_obj.data_encrypted = d.get('data_encrypted') - return return_obj - +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# super(NonPublicDataCompromised, cls).from_obj(obj, return_obj=return_obj) +# return_obj.data_encrypted = obj.data_encrypted +# return return_obj +# +# def to_obj(self, return_obj=None, ns_info=None): +# if not return_obj: +# return_obj = self._binding_class() +# +# super(NonPublicDataCompromised, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# return_obj.data_encrypted = self.data_encrypted +# return return_obj +# +# @classmethod +# def from_dict(cls, d, return_obj=None): +# if not d: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# super(NonPublicDataCompromised, cls).from_dict(d, return_obj=return_obj) +# return_obj.data_encrypted = d.get('data_encrypted') +# return return_obj + def is_plain(self): return False - - def to_dict(self): - d = super(NonPublicDataCompromised, self).to_dict() - - if self.data_encrypted: - d['data_encrypted'] = self.data_encrypted - - return d + +# def to_dict(self): +# d = super(NonPublicDataCompromised, self).to_dict() +# +# if self.data_encrypted: +# d['data_encrypted'] = self.data_encrypted +# +# return d class PropertyAffected(stix.Entity): @@ -65,20 +68,14 @@ class PropertyAffected(stix.Entity): _binding = incident_binding _binding_class = incident_binding.PropertyAffectedType - def __init__(self): - self.property_ = None - self.description_of_effect = None - self.type_of_availability_loss = None - self.duration_of_availability_loss = None - self.non_public_data_compromised = None - - @property - def property_(self): - return self._property + property_ = fields.TypedField("Property", vocabs.LossProperty, key_name="property_") + descriptions_of_effect = fields.TypedField("Description_Of_Effect", StructuredTextList) + type_of_availability_loss = fields.TypedField("Type_Of_Availability_Loss", vocabs.AvailabilityLossType) + duration_of_availability_loss = fields.TypedField("Duration_Of_Availability_Loss", vocabs.LossDuration) + non_public_data_compromised = fields.TypedField("Non_Public_Data_Compromised", NonPublicDataCompromised) - @property_.setter - def property_(self, value): - self._set_vocab(vocabs.LossProperty, property=value) + def __init__(self): + super(PropertyAffected, self).__init__() @property def description_of_effect(self): @@ -106,86 +103,54 @@ def description_of_effect(self): @description_of_effect.setter def description_of_effect(self, value): self.descriptions_of_effect = value - - @property - def descriptions_of_effect(self): - return self._description_of_effect - - @descriptions_of_effect.setter - def descriptions_of_effect(self, value): - self._description_of_effect = StructuredTextList(value) - - @property - def type_of_availability_loss(self): - return self._type_of_availability_loss - - @type_of_availability_loss.setter - def type_of_availability_loss(self, value): - self._set_vocab(vocabs.AvailabilityLossType, type_of_availability_loss=value) - - @property - def duration_of_availability_loss(self): - return self._duration_of_availability_loss - - @duration_of_availability_loss.setter - def duration_of_availability_loss(self, value): - self._set_vocab(vocabs.LossDuration, duration_of_availability_loss=value) - - @property - def non_public_data_compromised(self): - return self._non_public_data_compromised - - @non_public_data_compromised.setter - def non_public_data_compromised(self, value): - self._set_var(NonPublicDataCompromised, non_public_data_compromised=value) - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.property_ = VocabString.from_obj(obj.Property) - return_obj.descriptions_of_effect = StructuredTextList.from_obj(obj.Description_Of_Effect) - return_obj.type_of_availability_loss = VocabString.from_obj(obj.Type_Of_Availability_Loss) - return_obj.duration_of_availability_loss = VocabString.from_obj(obj.Duration_Of_Availability_Loss) - return_obj.non_public_data_compromised = NonPublicDataCompromised.from_obj(obj.Non_Public_Data_Compromised) - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - super(PropertyAffected, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.property_: - return_obj.Property = self.property_.to_obj(ns_info=ns_info) - if self.descriptions_of_effect: - return_obj.Description_Of_Effect = self.descriptions_of_effect.to_obj(ns_info=ns_info) - if self.type_of_availability_loss: - return_obj.Type_Of_Availability_Loss = self.type_of_availability_loss.to_obj(ns_info=ns_info) - if self.duration_of_availability_loss: - return_obj.Duration_Of_Availability_Loss = self.duration_of_availability_loss.to_obj(ns_info=ns_info) - if self.non_public_data_compromised: - return_obj.Non_Public_Data_Compromised = self.non_public_data_compromised.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if not return_obj: - return_obj = cls() - - return_obj.property_ = VocabString.from_dict(d.get('property')) - return_obj.descriptions_of_effect = StructuredTextList.from_dict(d.get('description_of_effect')) - return_obj.type_of_availability_loss = VocabString.from_dict(d.get('type_of_availability_loss')) - return_obj.duration_of_availability_loss = VocabString.from_dict(d.get('duration_of_availability_loss')) - return_obj.non_public_data_compromised = NonPublicDataCompromised.from_dict(d.get('non_public_data_compromised')) - - return return_obj - def to_dict(self): - return super(PropertyAffected, self).to_dict() +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.property_ = VocabString.from_obj(obj.Property) +# return_obj.descriptions_of_effect = StructuredTextList.from_obj(obj.Description_Of_Effect) +# return_obj.type_of_availability_loss = VocabString.from_obj(obj.Type_Of_Availability_Loss) +# return_obj.duration_of_availability_loss = VocabString.from_obj(obj.Duration_Of_Availability_Loss) +# return_obj.non_public_data_compromised = NonPublicDataCompromised.from_obj(obj.Non_Public_Data_Compromised) +# return return_obj +# +# def to_obj(self, return_obj=None, ns_info=None): +# super(PropertyAffected, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# if not return_obj: +# return_obj = self._binding_class() +# +# if self.property_: +# return_obj.Property = self.property_.to_obj(ns_info=ns_info) +# if self.descriptions_of_effect: +# return_obj.Description_Of_Effect = self.descriptions_of_effect.to_obj(ns_info=ns_info) +# if self.type_of_availability_loss: +# return_obj.Type_Of_Availability_Loss = self.type_of_availability_loss.to_obj(ns_info=ns_info) +# if self.duration_of_availability_loss: +# return_obj.Duration_Of_Availability_Loss = self.duration_of_availability_loss.to_obj(ns_info=ns_info) +# if self.non_public_data_compromised: +# return_obj.Non_Public_Data_Compromised = self.non_public_data_compromised.to_obj(ns_info=ns_info) +# +# return return_obj +# +# @classmethod +# def from_dict(cls, d, return_obj=None): +# if not d: +# return None +# if not return_obj: +# return_obj = cls() +# +# return_obj.property_ = VocabString.from_dict(d.get('property')) +# return_obj.descriptions_of_effect = StructuredTextList.from_dict(d.get('description_of_effect')) +# return_obj.type_of_availability_loss = VocabString.from_dict(d.get('type_of_availability_loss')) +# return_obj.duration_of_availability_loss = VocabString.from_dict(d.get('duration_of_availability_loss')) +# return_obj.non_public_data_compromised = NonPublicDataCompromised.from_dict(d.get('non_public_data_compromised')) +# +# return return_obj +# +# def to_dict(self): +# return super(PropertyAffected, self).to_dict() diff --git a/stix/incident/time.py b/stix/incident/time.py index d794b070..3032abdb 100644 --- a/stix/incident/time.py +++ b/stix/incident/time.py @@ -4,19 +4,29 @@ import stix import stix.bindings.incident as incident_binding from stix.common import DateTimeWithPrecision +from mixbox import entities, fields - -class Time(stix.Entity): +class Time(entities.Entity): _binding = incident_binding _binding_class = _binding.TimeType _namespace = "http://stix.mitre.org/Incident-1" + first_malicious_action = fields.TypedField("First_Malicious_Action", DateTimeWithPrecision) + initial_compromise = fields.TypedField("Initial_Compromise", DateTimeWithPrecision) + first_data_exfiltration = fields.TypedField("First_Data_Exfiltration", DateTimeWithPrecision) + incident_discovery = fields.TypedField("Incident_Discovery", DateTimeWithPrecision) + incident_opened = fields.TypedField("Incident_Opened", DateTimeWithPrecision) + containment_achieved = fields.TypedField("Containment_Achieved", DateTimeWithPrecision) + restoration_achieved = fields.TypedField("Restoration_Achieved", DateTimeWithPrecision) + incident_reported = fields.TypedField("Incident_Reported", DateTimeWithPrecision) + incident_closed = fields.TypedField("Incident_Closed", DateTimeWithPrecision) + def __init__(self, first_malicious_action=None, initial_compromise=None, first_data_exfiltration=None, incident_discovery=None, incident_opened=None, containment_achieved=None, restoration_achieved=None, incident_reported=None, incident_closed=None): - + super(Time, self).__init__() self.first_malicious_action = first_malicious_action self.initial_compromise = initial_compromise self.first_data_exfiltration = first_data_exfiltration @@ -27,144 +37,72 @@ def __init__(self, first_malicious_action=None, initial_compromise=None, self.incident_reported = incident_reported self.incident_closed = incident_closed - @property - def first_malicious_action(self): - return self._first_malicious_action - - @first_malicious_action.setter - def first_malicious_action(self, value): - self._set_var(DateTimeWithPrecision, first_malicious_action=value) - - @property - def initial_compromise(self): - return self._initial_compromise - - @initial_compromise.setter - def initial_compromise(self, value): - self._set_var(DateTimeWithPrecision, initial_compromise=value) - - @property - def first_data_exfiltration(self): - return self._first_data_exfiltration - - @first_data_exfiltration.setter - def first_data_exfiltration(self, value): - self._set_var(DateTimeWithPrecision, first_data_exfiltration=value) - - @property - def incident_discovery(self): - return self._incident_discovery - - @incident_discovery.setter - def incident_discovery(self, value): - self._set_var(DateTimeWithPrecision, incident_discovery=value) - - @property - def incident_opened(self): - return self._incident_opened - - @incident_opened.setter - def incident_opened(self, value): - self._set_var(DateTimeWithPrecision, incident_opened=value) - - @property - def containment_achieved(self): - return self._containment_achieved - - @containment_achieved.setter - def containment_achieved(self, value): - self._set_var(DateTimeWithPrecision, containment_achieved=value) - - @property - def restoration_achieved(self): - return self._restoration_achieved - - @restoration_achieved.setter - def restoration_achieved(self, value): - self._set_var(DateTimeWithPrecision, restoration_achieved=value) - - @property - def incident_reported(self): - return self._incident_reported - - @incident_reported.setter - def incident_reported(self, value): - self._set_var(DateTimeWithPrecision, incident_reported=value) - - @property - def incident_closed(self): - return self._incident_closed - - @incident_closed.setter - def incident_closed(self, value): - self._set_var(DateTimeWithPrecision, incident_closed=value) - - def to_obj(self, return_obj=None, ns_info=None): - super(Time, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.first_malicious_action: - return_obj.First_Malicious_Action = self.first_malicious_action.to_obj(ns_info=ns_info) - if self.initial_compromise: - return_obj.Initial_Compromise = self.initial_compromise.to_obj(ns_info=ns_info) - if self.first_data_exfiltration: - return_obj.First_Data_Exfiltration = self.first_data_exfiltration.to_obj(ns_info=ns_info) - if self._incident_discovery: - return_obj.Incident_Discovery = self.incident_discovery.to_obj(ns_info=ns_info) - if self.incident_opened: - return_obj.Incident_Opened = self.incident_opened.to_obj(ns_info=ns_info) - if self.containment_achieved: - return_obj.Containment_Achieved = self.containment_achieved.to_obj(ns_info=ns_info) - if self.restoration_achieved: - return_obj.Restoration_Achieved = self.restoration_achieved.to_obj(ns_info=ns_info) - if self.incident_reported: - return_obj.Incident_Reported = self.incident_reported.to_obj(ns_info=ns_info) - if self.incident_closed: - return_obj.Incident_Closed = self.incident_closed.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.first_malicious_action = DateTimeWithPrecision.from_obj(obj.First_Malicious_Action) - return_obj.initial_compromise = DateTimeWithPrecision.from_obj(obj.Initial_Compromise) - return_obj.first_data_exfiltration = DateTimeWithPrecision.from_obj(obj.First_Data_Exfiltration) - return_obj.incident_discovery = DateTimeWithPrecision.from_obj(obj.Incident_Discovery) - return_obj.incident_opened = DateTimeWithPrecision.from_obj(obj.Incident_Opened) - return_obj.containment_achieved = DateTimeWithPrecision.from_obj(obj.Containment_Achieved) - return_obj.restoration_achieved = DateTimeWithPrecision.from_obj(obj.Restoration_Achieved) - return_obj.incident_reported = DateTimeWithPrecision.from_obj(obj.Incident_Reported) - return_obj.incident_closed = DateTimeWithPrecision.from_obj(obj.Incident_Closed) - - return return_obj - - def to_dict(self): - return super(Time, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - return_obj.first_malicious_action = DateTimeWithPrecision.from_dict(dict_repr.get('first_malicious_action')) - return_obj.initial_compromise = DateTimeWithPrecision.from_dict(dict_repr.get('initial_compromise')) - return_obj.first_data_exfiltration = DateTimeWithPrecision.from_dict(dict_repr.get('first_data_exfiltration')) - return_obj.incident_discovery = DateTimeWithPrecision.from_dict(dict_repr.get('incident_discovery')) - return_obj.incident_opened = DateTimeWithPrecision.from_dict(dict_repr.get('incident_opened')) - return_obj.containment_achieved = DateTimeWithPrecision.from_dict(dict_repr.get('containment_achieved')) - return_obj.restoration_achieved = DateTimeWithPrecision.from_dict(dict_repr.get('restoration_achieved')) - return_obj.incident_reported = DateTimeWithPrecision.from_dict(dict_repr.get('incident_reported')) - return_obj.incident_closed = DateTimeWithPrecision.from_dict(dict_repr.get('incident_closed')) - - return return_obj +# def to_obj(self, return_obj=None, ns_info=None): +# super(Time, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# if not return_obj: +# return_obj = self._binding_class() +# +# if self.first_malicious_action: +# return_obj.First_Malicious_Action = self.first_malicious_action.to_obj(ns_info=ns_info) +# if self.initial_compromise: +# return_obj.Initial_Compromise = self.initial_compromise.to_obj(ns_info=ns_info) +# if self.first_data_exfiltration: +# return_obj.First_Data_Exfiltration = self.first_data_exfiltration.to_obj(ns_info=ns_info) +# if self._incident_discovery: +# return_obj.Incident_Discovery = self.incident_discovery.to_obj(ns_info=ns_info) +# if self.incident_opened: +# return_obj.Incident_Opened = self.incident_opened.to_obj(ns_info=ns_info) +# if self.containment_achieved: +# return_obj.Containment_Achieved = self.containment_achieved.to_obj(ns_info=ns_info) +# if self.restoration_achieved: +# return_obj.Restoration_Achieved = self.restoration_achieved.to_obj(ns_info=ns_info) +# if self.incident_reported: +# return_obj.Incident_Reported = self.incident_reported.to_obj(ns_info=ns_info) +# if self.incident_closed: +# return_obj.Incident_Closed = self.incident_closed.to_obj(ns_info=ns_info) +# +# return return_obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.first_malicious_action = DateTimeWithPrecision.from_obj(obj.First_Malicious_Action) +# return_obj.initial_compromise = DateTimeWithPrecision.from_obj(obj.Initial_Compromise) +# return_obj.first_data_exfiltration = DateTimeWithPrecision.from_obj(obj.First_Data_Exfiltration) +# return_obj.incident_discovery = DateTimeWithPrecision.from_obj(obj.Incident_Discovery) +# return_obj.incident_opened = DateTimeWithPrecision.from_obj(obj.Incident_Opened) +# return_obj.containment_achieved = DateTimeWithPrecision.from_obj(obj.Containment_Achieved) +# return_obj.restoration_achieved = DateTimeWithPrecision.from_obj(obj.Restoration_Achieved) +# return_obj.incident_reported = DateTimeWithPrecision.from_obj(obj.Incident_Reported) +# return_obj.incident_closed = DateTimeWithPrecision.from_obj(obj.Incident_Closed) +# +# return return_obj +# +# def to_dict(self): +# return super(Time, self).to_dict() +# +# @classmethod +# def from_dict(cls, dict_repr, return_obj=None): +# if not dict_repr: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.first_malicious_action = DateTimeWithPrecision.from_dict(dict_repr.get('first_malicious_action')) +# return_obj.initial_compromise = DateTimeWithPrecision.from_dict(dict_repr.get('initial_compromise')) +# return_obj.first_data_exfiltration = DateTimeWithPrecision.from_dict(dict_repr.get('first_data_exfiltration')) +# return_obj.incident_discovery = DateTimeWithPrecision.from_dict(dict_repr.get('incident_discovery')) +# return_obj.incident_opened = DateTimeWithPrecision.from_dict(dict_repr.get('incident_opened')) +# return_obj.containment_achieved = DateTimeWithPrecision.from_dict(dict_repr.get('containment_achieved')) +# return_obj.restoration_achieved = DateTimeWithPrecision.from_dict(dict_repr.get('restoration_achieved')) +# return_obj.incident_reported = DateTimeWithPrecision.from_dict(dict_repr.get('incident_reported')) +# return_obj.incident_closed = DateTimeWithPrecision.from_dict(dict_repr.get('incident_closed')) +# +# return return_obj diff --git a/stix/incident/total_loss_estimation.py b/stix/incident/total_loss_estimation.py index 60a9b061..1fe94779 100644 --- a/stix/incident/total_loss_estimation.py +++ b/stix/incident/total_loss_estimation.py @@ -8,67 +8,53 @@ # relative from .loss_estimation import LossEstimation +from mixbox import entities, fields -class TotalLossEstimation(stix.Entity): +class TotalLossEstimation(entities.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.TotalLossEstimationType + initial_reported_total_loss_estimation = fields.TypedField("Initial_Reported_Total_Loss_Estimation", LossEstimation) + actual_total_loss_estimation = fields.TypedField("Actual_Total_Loss_Estimation", LossEstimation) + def __init__(self): super(TotalLossEstimation, self).__init__() - self.initial_reported_total_loss_estimation = None - self.actual_total_loss_estimation = None - - @property - def initial_reported_total_loss_estimation(self): - return self._initial_reported_total_loss_estimation - - @initial_reported_total_loss_estimation.setter - def initial_reported_total_loss_estimation(self, value): - self._set_var(LossEstimation, initial_reported_total_loss_estimation=value) - - @property - def actual_total_loss_estimation(self): - return self._actual_total_loss_estimation - - @actual_total_loss_estimation.setter - def actual_total_loss_estimation(self, value): - self._set_var(LossEstimation, actual_total_loss_estimation=value) - - def to_obj(self, return_obj=None, ns_info=None): - super(TotalLossEstimation, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - obj = self._binding_class() - if self.initial_reported_total_loss_estimation: - obj.Initial_Reported_Total_Loss_Estimation = self.initial_reported_total_loss_estimation.to_obj(ns_info=ns_info) - if self.actual_total_loss_estimation: - obj.Actual_Total_Loss_Estimation = self.actual_total_loss_estimation.to_obj(ns_info=ns_info) - return obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - return_obj.initial_reported_total_loss_estimation = LossEstimation.from_obj(obj.Initial_Reported_Total_Loss_Estimation) - return_obj.actual_total_loss_estimation = LossEstimation.from_obj(obj.Actual_Total_Loss_Estimation) - return return_obj - - def to_dict(self): - return super(TotalLossEstimation, self).to_dict() - - @classmethod - def from_dict(cls, dict_, return_obj=None): - if not dict_: - return None - - if not return_obj: - return_obj = cls() - - return_obj.initial_reported_total_loss_estimation = LossEstimation.from_dict(dict_.get('initial_reported_total_loss_estimation')) - return_obj.actual_total_loss_estimation = LossEstimation.from_dict(dict_.get('actual_total_loss_estimation')) - return return_obj +# def to_obj(self, return_obj=None, ns_info=None): +# super(TotalLossEstimation, self).to_obj(return_obj=return_obj, ns_info=ns_info) +# +# obj = self._binding_class() +# if self.initial_reported_total_loss_estimation: +# obj.Initial_Reported_Total_Loss_Estimation = self.initial_reported_total_loss_estimation.to_obj(ns_info=ns_info) +# if self.actual_total_loss_estimation: +# obj.Actual_Total_Loss_Estimation = self.actual_total_loss_estimation.to_obj(ns_info=ns_info) +# return obj +# +# @classmethod +# def from_obj(cls, obj, return_obj=None): +# if not obj: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.initial_reported_total_loss_estimation = LossEstimation.from_obj(obj.Initial_Reported_Total_Loss_Estimation) +# return_obj.actual_total_loss_estimation = LossEstimation.from_obj(obj.Actual_Total_Loss_Estimation) +# return return_obj +# +# def to_dict(self): +# return super(TotalLossEstimation, self).to_dict() +# +# @classmethod +# def from_dict(cls, dict_, return_obj=None): +# if not dict_: +# return None +# +# if not return_obj: +# return_obj = cls() +# +# return_obj.initial_reported_total_loss_estimation = LossEstimation.from_dict(dict_.get('initial_reported_total_loss_estimation')) +# return_obj.actual_total_loss_estimation = LossEstimation.from_dict(dict_.get('actual_total_loss_estimation')) +# +# return return_obj From 48888fcd5334c9d1c90d498ee695e0aeb5f6c55e Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 12 Nov 2015 14:22:03 -0500 Subject: [PATCH 252/438] WIP Incident VocabField changes --- stix/incident/__init__.py | 6 ++-- stix/incident/affected_asset.py | 11 +++--- stix/incident/impact_assessment.py | 5 +-- stix/incident/indirect_impact_summary.py | 9 ++--- stix/incident/property_affected.py | 46 ++++-------------------- 5 files changed, 24 insertions(+), 53 deletions(-) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index 09e6169d..f6f78bd4 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -46,7 +46,7 @@ class Incident(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'incident' - status = fields.TypedField("Status", vocabs.IncidentStatus) + status = VocabField("Status", vocabs.IncidentStatus) time = fields.TypedField("Time", Time) victims = fields.TypedField("Victim", Identity, factory=IdentityFactory, multiple=True, key_name="victims") attributed_threat_actors = fields.TypedField("Attributed_Threat_Actors", type_="stix.incident.AttributedThreatActors") @@ -58,13 +58,13 @@ class Incident(stix.BaseCoreComponent): categories = fields.TypedField("Categories", type_="stix.incident.IncidentCategories") intended_effects = fields.TypedField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") leveraged_ttps = fields.TypedField("Leveraged_TTPs", type_="stix.incident.LeveragedTTPs") - discovery_methods = fields.TypedField("Discovery_Method", vocabs.DiscoveryMethod, multiple=True, key_name="discovery_methods") + discovery_methods = VocabField("Discovery_Method", vocabs.DiscoveryMethod, multiple=True, key_name="discovery_methods") reporter = fields.TypedField("Reporter", InformationSource) responders = fields.TypedField("Responder", InformationSource, multiple=True, key_name="responders") coordinators = fields.TypedField("Coordinator", InformationSource, multiple=True, key_name="coordinators") external_ids = fields.TypedField("External_ID", ExternalID, multiple=True, key_name="external_ids") impact_assessment = fields.TypedField("Impact_Assessment", ImpactAssessment) - security_compromise = fields.TypedField("Security_Compromise", vocabs.SecurityCompromise) + security_compromise = VocabField("Security_Compromise", vocabs.SecurityCompromise) confidence = fields.TypedField("Confidence", Confidence) coa_taken = fields.TypedField("COA_Taken", COATaken, multiple=True) coa_requested = fields.TypedField("COA_Requested", COARequested, multiple=True) diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index de8fcf44..96bf7e87 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -7,6 +7,7 @@ # internal import stix from stix.common import vocabs, VocabString, StructuredTextList +from stix.common.vocabs import VocabField import stix.bindings.incident as incident_binding # relative @@ -21,13 +22,13 @@ class AffectedAsset(entities.Entity): descriptions = fields.TypedField("Description", StructuredTextList) business_function_or_roles = fields.TypedField("Business_Function_Or_Role", StructuredTextList) - ownership_class = fields.TypedField("Ownership_Class", vocabs.OwnershipClass) - management_class = fields.TypedField("Management_Class", vocabs.ManagementClass) - location_class = fields.TypedField("location_Class", vocabs.LocationClass) + ownership_class = VocabField("Ownership_Class", vocabs.OwnershipClass) + management_class = VocabField("Management_Class", vocabs.ManagementClass) + location_class = VocabField("location_Class", vocabs.LocationClass) # location = fields.TypedField("Location") - nature_of_security_effect = fields.TypedField("Nature_Of_Security_Effect", type_="stix.incident.affected_asset.NatureOfSecurityEffect") + nature_of_security_effect = VocabField("Nature_Of_Security_Effect", type_="stix.incident.affected_asset.NatureOfSecurityEffect") structured_description = fields.TypedField("Structured_Description", Observables) - type_ = fields.TypedField("Type", type_="stix.incident.affected_asset.AssetType", key_name="type") + type_ = VocabField("Type", type_="stix.incident.affected_asset.AssetType", key_name="type") def __init__(self): super(AffectedAsset, self).__init__() diff --git a/stix/incident/impact_assessment.py b/stix/incident/impact_assessment.py index fa6f3df5..90f8f9bf 100644 --- a/stix/incident/impact_assessment.py +++ b/stix/incident/impact_assessment.py @@ -12,6 +12,7 @@ from .total_loss_estimation import TotalLossEstimation from mixbox import fields, entities +from stix.common.vocabs import VocabField class ImpactAssessment(entities.Entity): _namespace = "http://stix.mitre.org/Incident-1" @@ -21,7 +22,7 @@ class ImpactAssessment(entities.Entity): direct_impact_summary = fields.TypedField("Direct_Impact_Summary", DirectImpactSummary) indirect_impact_summary = fields.TypedField("Indirect_Impact_Summary", IndirectImpactSummary) total_loss_estimation = fields.TypedField("Total_Loss_Estimation", TotalLossEstimation) - impact_qualification = fields.TypedField("Impact_Qualification", vocabs.ImpactQualification) + impact_qualification = VocabField("Impact_Qualification", vocabs.ImpactQualification) effects = fields.TypedField("Effects", type_="stix.incident.impact_assessment.Effects") def __init__(self): @@ -92,7 +93,7 @@ class Effects(stix.EntityList): _binding = incident_binding _binding_class = _binding.EffectsType - effects = fields.TypedField("Effect", VocabString, multiple=True, key_name="effects") + effects = VocabField("Effect", VocabString, multiple=True, key_name="effects") @classmethod def _dict_as_list(cls): diff --git a/stix/incident/indirect_impact_summary.py b/stix/incident/indirect_impact_summary.py index 96ccd848..bd95a4e9 100644 --- a/stix/incident/indirect_impact_summary.py +++ b/stix/incident/indirect_impact_summary.py @@ -4,6 +4,7 @@ import stix import stix.bindings.incident as incident_binding from stix.common import vocabs, VocabString +from stix.common.vocabs import VocabField from mixbox import entities, fields class IndirectImpactSummary(entities.Entity): @@ -11,10 +12,10 @@ class IndirectImpactSummary(entities.Entity): _binding = incident_binding _binding_class = incident_binding.IndirectImpactSummaryType - loss_of_competitive_advantage = fields.TypedField("Loss_Of_Competitive_Advantage", vocabs.SecurityCompromise) - brand_and_market_damage = fields.TypedField("Brand_And_Market_Damage", vocabs.SecurityCompromise) - increased_operating_costs = fields.TypedField("Increased_Operating_Costs", vocabs.SecurityCompromise) - legal_and_regulatory_costs = fields.TypedField("Legal_And_Regulatory_Costs", vocabs.SecurityCompromise) + loss_of_competitive_advantage = VocabField("Loss_Of_Competitive_Advantage", vocabs.SecurityCompromise) + brand_and_market_damage = VocabField("Brand_And_Market_Damage", vocabs.SecurityCompromise) + increased_operating_costs = VocabField("Increased_Operating_Costs", vocabs.SecurityCompromise) + legal_and_regulatory_costs = VocabField("Legal_And_Regulatory_Costs", vocabs.SecurityCompromise) def __init__(self): super(IndirectImpactSummary, self).__init__() diff --git a/stix/incident/property_affected.py b/stix/incident/property_affected.py index 41479492..021a7437 100644 --- a/stix/incident/property_affected.py +++ b/stix/incident/property_affected.py @@ -6,6 +6,7 @@ from stix.common import vocabs, VocabString, StructuredTextList import stix.bindings.incident as incident_binding from mixbox import fields, entities +from stix.common.vocabs import VocabField class NonPublicDataCompromised(VocabString): _namespace = "http://stix.mitre.org/Incident-1" @@ -15,42 +16,9 @@ class NonPublicDataCompromised(VocabString): data_encrypted = fields.TypedField("data_encrypted") def __init__(self, value=None, data_encrypted=None): - super(NonPublicDataCompromised, self).__init__(value) self.data_encrypted = data_encrypted - - -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# super(NonPublicDataCompromised, cls).from_obj(obj, return_obj=return_obj) -# return_obj.data_encrypted = obj.data_encrypted -# return return_obj -# -# def to_obj(self, return_obj=None, ns_info=None): -# if not return_obj: -# return_obj = self._binding_class() -# -# super(NonPublicDataCompromised, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# return_obj.data_encrypted = self.data_encrypted -# return return_obj -# -# @classmethod -# def from_dict(cls, d, return_obj=None): -# if not d: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# super(NonPublicDataCompromised, cls).from_dict(d, return_obj=return_obj) -# return_obj.data_encrypted = d.get('data_encrypted') -# return return_obj - + super(NonPublicDataCompromised, self).__init__(value) + def is_plain(self): return False @@ -68,11 +36,11 @@ class PropertyAffected(stix.Entity): _binding = incident_binding _binding_class = incident_binding.PropertyAffectedType - property_ = fields.TypedField("Property", vocabs.LossProperty, key_name="property_") + property_ = VocabField("Property", vocabs.LossProperty, key_name="property") descriptions_of_effect = fields.TypedField("Description_Of_Effect", StructuredTextList) - type_of_availability_loss = fields.TypedField("Type_Of_Availability_Loss", vocabs.AvailabilityLossType) - duration_of_availability_loss = fields.TypedField("Duration_Of_Availability_Loss", vocabs.LossDuration) - non_public_data_compromised = fields.TypedField("Non_Public_Data_Compromised", NonPublicDataCompromised) + type_of_availability_loss = VocabField("Type_Of_Availability_Loss", vocabs.AvailabilityLossType) + duration_of_availability_loss = VocabField("Duration_Of_Availability_Loss", vocabs.LossDuration) + non_public_data_compromised = VocabField("Non_Public_Data_Compromised", NonPublicDataCompromised) def __init__(self): super(PropertyAffected, self).__init__() From 73300737fe8dada395aff30452e519200d2de20f Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 12 Nov 2015 14:22:27 -0500 Subject: [PATCH 253/438] WIP Misc incidental changes --- stix/campaign/__init__.py | 4 ++-- stix/coa/objective.py | 1 - stix/common/vocabs.py | 2 +- stix/ttp/infrastructure.py | 5 ++++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index fdf0c705..7ebb3c62 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -10,7 +10,7 @@ RelatedIncident, RelatedIndicator, RelatedPackageRefs, RelatedThreatActor, RelatedTTP) from stix.common import vocabs -from stix.common.vocabs import VocabField +from stix.common.vocabs import VocabField, CampaignStatus import stix.bindings.campaign as campaign_binding from stix.common.structured_text import StructuredTextList from stix.common.information_source import InformationSource @@ -102,7 +102,7 @@ class Campaign(stix.BaseCoreComponent): attribution = fields.TypedField("Attribution", Attribution, multiple=True) confidence = fields.TypedField("Confidence", Confidence) # references = fields.TypedField("Reference", multiple=True) - status = fields.TypedField("Status", VocabString) + status = VocabField("Status", CampaignStatus) intended_effects = fields.TypedField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") names = fields.TypedField("Names", Names) related_incidents = fields.TypedField("Related_Incidents", RelatedIncidents) diff --git a/stix/coa/objective.py b/stix/coa/objective.py index 14b097d7..a6fed1ce 100644 --- a/stix/coa/objective.py +++ b/stix/coa/objective.py @@ -22,7 +22,6 @@ def __init__(self, description=None, short_description=None): self.description = description self.short_description = short_description - self.applicability_confidence = None @property def description(self): diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index 0f7d351b..072e63a6 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -77,7 +77,7 @@ def entity_class(cls, key): return VocabString -class VocabString(entities.Entity): +class VocabString(stix.Entity): _binding = stix_common_binding _binding_class = stix_common_binding.ControlledVocabularyStringType _namespace = 'http://stix.mitre.org/common-1' diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index aad8f814..873afe9e 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -155,7 +155,10 @@ def add_type(self, type_): class InfraStructureTypes(stix.EntityList): _namespace = "http://stix.mitre.org/TTP-1" _contained_type = VocabString - _dict_as_list = True + + @classmethod + def _dict_as_list(cls): + return True def _fix_value(self, value): return AttackerInfrastructureType(value) From 01909cc9a4f5990c7d96d3d192007ab4ab2e43b3 Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 12 Nov 2015 17:12:40 -0500 Subject: [PATCH 254/438] Fix VocabField errors and namespace stix/mixbox errors --- stix/incident/__init__.py | 6 +++--- stix/incident/affected_asset.py | 13 ++++++------- stix/incident/coa.py | 4 ++-- stix/incident/direct_impact_summary.py | 2 +- stix/incident/history.py | 4 ++-- stix/incident/impact_assessment.py | 4 ++-- stix/incident/indirect_impact_summary.py | 11 +++++------ stix/incident/property_affected.py | 11 +++++------ stix/incident/time.py | 2 +- stix/incident/total_loss_estimation.py | 2 +- 10 files changed, 28 insertions(+), 31 deletions(-) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index f6f78bd4..09e6169d 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -46,7 +46,7 @@ class Incident(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'incident' - status = VocabField("Status", vocabs.IncidentStatus) + status = fields.TypedField("Status", vocabs.IncidentStatus) time = fields.TypedField("Time", Time) victims = fields.TypedField("Victim", Identity, factory=IdentityFactory, multiple=True, key_name="victims") attributed_threat_actors = fields.TypedField("Attributed_Threat_Actors", type_="stix.incident.AttributedThreatActors") @@ -58,13 +58,13 @@ class Incident(stix.BaseCoreComponent): categories = fields.TypedField("Categories", type_="stix.incident.IncidentCategories") intended_effects = fields.TypedField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") leveraged_ttps = fields.TypedField("Leveraged_TTPs", type_="stix.incident.LeveragedTTPs") - discovery_methods = VocabField("Discovery_Method", vocabs.DiscoveryMethod, multiple=True, key_name="discovery_methods") + discovery_methods = fields.TypedField("Discovery_Method", vocabs.DiscoveryMethod, multiple=True, key_name="discovery_methods") reporter = fields.TypedField("Reporter", InformationSource) responders = fields.TypedField("Responder", InformationSource, multiple=True, key_name="responders") coordinators = fields.TypedField("Coordinator", InformationSource, multiple=True, key_name="coordinators") external_ids = fields.TypedField("External_ID", ExternalID, multiple=True, key_name="external_ids") impact_assessment = fields.TypedField("Impact_Assessment", ImpactAssessment) - security_compromise = VocabField("Security_Compromise", vocabs.SecurityCompromise) + security_compromise = fields.TypedField("Security_Compromise", vocabs.SecurityCompromise) confidence = fields.TypedField("Confidence", Confidence) coa_taken = fields.TypedField("COA_Taken", COATaken, multiple=True) coa_requested = fields.TypedField("COA_Requested", COARequested, multiple=True) diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index 96bf7e87..4e38a0d4 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -7,7 +7,6 @@ # internal import stix from stix.common import vocabs, VocabString, StructuredTextList -from stix.common.vocabs import VocabField import stix.bindings.incident as incident_binding # relative @@ -15,20 +14,20 @@ from mixbox import entities, fields -class AffectedAsset(entities.Entity): +class AffectedAsset(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.AffectedAssetType descriptions = fields.TypedField("Description", StructuredTextList) business_function_or_roles = fields.TypedField("Business_Function_Or_Role", StructuredTextList) - ownership_class = VocabField("Ownership_Class", vocabs.OwnershipClass) - management_class = VocabField("Management_Class", vocabs.ManagementClass) - location_class = VocabField("location_Class", vocabs.LocationClass) + ownership_class = fields.TypedField("Ownership_Class", vocabs.OwnershipClass) + management_class = fields.TypedField("Management_Class", vocabs.ManagementClass) + location_class = fields.TypedField("location_Class", vocabs.LocationClass) # location = fields.TypedField("Location") - nature_of_security_effect = VocabField("Nature_Of_Security_Effect", type_="stix.incident.affected_asset.NatureOfSecurityEffect") + nature_of_security_effect = fields.TypedField("Nature_Of_Security_Effect", type_="stix.incident.affected_asset.NatureOfSecurityEffect") structured_description = fields.TypedField("Structured_Description", Observables) - type_ = VocabField("Type", type_="stix.incident.affected_asset.AssetType", key_name="type") + type_ = fields.TypedField("Type", type_="stix.incident.affected_asset.AssetType", key_name="type") def __init__(self): super(AffectedAsset, self).__init__() diff --git a/stix/incident/coa.py b/stix/incident/coa.py index d7cb215d..e36b8ebe 100644 --- a/stix/incident/coa.py +++ b/stix/incident/coa.py @@ -13,7 +13,7 @@ from mixbox import entities, fields -class COATaken(entities.Entity): +class COATaken(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = _binding.COATakenType @@ -123,7 +123,7 @@ def __init__(self, course_of_action=None): # return d -class COATime(entities.Entity): +class COATime(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = _binding.COATimeType diff --git a/stix/incident/direct_impact_summary.py b/stix/incident/direct_impact_summary.py index 3f721443..2cc91a56 100644 --- a/stix/incident/direct_impact_summary.py +++ b/stix/incident/direct_impact_summary.py @@ -7,7 +7,7 @@ import stix.bindings.incident as incident_binding from mixbox import fields, entities -class DirectImpactSummary(entities.Entity): +class DirectImpactSummary(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.DirectImpactSummaryType diff --git a/stix/incident/history.py b/stix/incident/history.py index dcf08e6e..acdfae84 100644 --- a/stix/incident/history.py +++ b/stix/incident/history.py @@ -18,7 +18,7 @@ def validate_precision(instance, value): error = error.format(DATETIME_PRECISION_VALUES, value) raise ValueError(error) -class JournalEntry(entities.Entity): +class JournalEntry(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.JournalEntryType @@ -80,7 +80,7 @@ def __init__(self, value=None): # return return_obj -class HistoryItem(entities.Entity): +class HistoryItem(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.HistoryItemType diff --git a/stix/incident/impact_assessment.py b/stix/incident/impact_assessment.py index 90f8f9bf..cdc01e93 100644 --- a/stix/incident/impact_assessment.py +++ b/stix/incident/impact_assessment.py @@ -14,7 +14,7 @@ from mixbox import fields, entities from stix.common.vocabs import VocabField -class ImpactAssessment(entities.Entity): +class ImpactAssessment(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.ImpactAssessmentType @@ -22,7 +22,7 @@ class ImpactAssessment(entities.Entity): direct_impact_summary = fields.TypedField("Direct_Impact_Summary", DirectImpactSummary) indirect_impact_summary = fields.TypedField("Indirect_Impact_Summary", IndirectImpactSummary) total_loss_estimation = fields.TypedField("Total_Loss_Estimation", TotalLossEstimation) - impact_qualification = VocabField("Impact_Qualification", vocabs.ImpactQualification) + impact_qualification = fields.TypedField("Impact_Qualification", vocabs.ImpactQualification) effects = fields.TypedField("Effects", type_="stix.incident.impact_assessment.Effects") def __init__(self): diff --git a/stix/incident/indirect_impact_summary.py b/stix/incident/indirect_impact_summary.py index bd95a4e9..b2bfe7ec 100644 --- a/stix/incident/indirect_impact_summary.py +++ b/stix/incident/indirect_impact_summary.py @@ -4,18 +4,17 @@ import stix import stix.bindings.incident as incident_binding from stix.common import vocabs, VocabString -from stix.common.vocabs import VocabField from mixbox import entities, fields -class IndirectImpactSummary(entities.Entity): +class IndirectImpactSummary(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.IndirectImpactSummaryType - loss_of_competitive_advantage = VocabField("Loss_Of_Competitive_Advantage", vocabs.SecurityCompromise) - brand_and_market_damage = VocabField("Brand_And_Market_Damage", vocabs.SecurityCompromise) - increased_operating_costs = VocabField("Increased_Operating_Costs", vocabs.SecurityCompromise) - legal_and_regulatory_costs = VocabField("Legal_And_Regulatory_Costs", vocabs.SecurityCompromise) + loss_of_competitive_advantage = fields.TypedField("Loss_Of_Competitive_Advantage", vocabs.SecurityCompromise) + brand_and_market_damage = fields.TypedField("Brand_And_Market_Damage", vocabs.SecurityCompromise) + increased_operating_costs = fields.TypedField("Increased_Operating_Costs", vocabs.SecurityCompromise) + legal_and_regulatory_costs = fields.TypedField("Legal_And_Regulatory_Costs", vocabs.SecurityCompromise) def __init__(self): super(IndirectImpactSummary, self).__init__() diff --git a/stix/incident/property_affected.py b/stix/incident/property_affected.py index 021a7437..18cf0196 100644 --- a/stix/incident/property_affected.py +++ b/stix/incident/property_affected.py @@ -6,7 +6,6 @@ from stix.common import vocabs, VocabString, StructuredTextList import stix.bindings.incident as incident_binding from mixbox import fields, entities -from stix.common.vocabs import VocabField class NonPublicDataCompromised(VocabString): _namespace = "http://stix.mitre.org/Incident-1" @@ -16,8 +15,8 @@ class NonPublicDataCompromised(VocabString): data_encrypted = fields.TypedField("data_encrypted") def __init__(self, value=None, data_encrypted=None): - self.data_encrypted = data_encrypted super(NonPublicDataCompromised, self).__init__(value) + self.data_encrypted = data_encrypted def is_plain(self): return False @@ -36,11 +35,11 @@ class PropertyAffected(stix.Entity): _binding = incident_binding _binding_class = incident_binding.PropertyAffectedType - property_ = VocabField("Property", vocabs.LossProperty, key_name="property") + property_ = fields.TypedField("Property", vocabs.LossProperty, key_name="property") descriptions_of_effect = fields.TypedField("Description_Of_Effect", StructuredTextList) - type_of_availability_loss = VocabField("Type_Of_Availability_Loss", vocabs.AvailabilityLossType) - duration_of_availability_loss = VocabField("Duration_Of_Availability_Loss", vocabs.LossDuration) - non_public_data_compromised = VocabField("Non_Public_Data_Compromised", NonPublicDataCompromised) + type_of_availability_loss = fields.TypedField("Type_Of_Availability_Loss", vocabs.AvailabilityLossType) + duration_of_availability_loss = fields.TypedField("Duration_Of_Availability_Loss", vocabs.LossDuration) + non_public_data_compromised = fields.TypedField("Non_Public_Data_Compromised", NonPublicDataCompromised) def __init__(self): super(PropertyAffected, self).__init__() diff --git a/stix/incident/time.py b/stix/incident/time.py index 3032abdb..24ec8a64 100644 --- a/stix/incident/time.py +++ b/stix/incident/time.py @@ -6,7 +6,7 @@ from stix.common import DateTimeWithPrecision from mixbox import entities, fields -class Time(entities.Entity): +class Time(stix.Entity): _binding = incident_binding _binding_class = _binding.TimeType _namespace = "http://stix.mitre.org/Incident-1" diff --git a/stix/incident/total_loss_estimation.py b/stix/incident/total_loss_estimation.py index 1fe94779..26132590 100644 --- a/stix/incident/total_loss_estimation.py +++ b/stix/incident/total_loss_estimation.py @@ -10,7 +10,7 @@ from mixbox import entities, fields -class TotalLossEstimation(entities.Entity): +class TotalLossEstimation(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.TotalLossEstimationType From 28f17606c8b4b147c35b75d4ef93afc548666af3 Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 13 Nov 2015 13:15:56 -0500 Subject: [PATCH 255/438] Change History's _dict_as_list to False --- stix/incident/history.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stix/incident/history.py b/stix/incident/history.py index acdfae84..4d3e6ff1 100644 --- a/stix/incident/history.py +++ b/stix/incident/history.py @@ -140,4 +140,8 @@ class History(stix.EntityList): _binding_class = incident_binding.HistoryType history_items = fields.TypedField("History_Item", HistoryItem, multiple=True, key_name="history_items") + + @classmethod + def _dict_as_list(cls): + return False \ No newline at end of file From e16e83c365a43cced0065780bd99963d075cac30 Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 13 Nov 2015 13:16:13 -0500 Subject: [PATCH 256/438] Capitalization typo --- stix/incident/affected_asset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index 4e38a0d4..934e6295 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -23,7 +23,7 @@ class AffectedAsset(stix.Entity): business_function_or_roles = fields.TypedField("Business_Function_Or_Role", StructuredTextList) ownership_class = fields.TypedField("Ownership_Class", vocabs.OwnershipClass) management_class = fields.TypedField("Management_Class", vocabs.ManagementClass) - location_class = fields.TypedField("location_Class", vocabs.LocationClass) + location_class = fields.TypedField("Location_Class", vocabs.LocationClass) # location = fields.TypedField("Location") nature_of_security_effect = fields.TypedField("Nature_Of_Security_Effect", type_="stix.incident.affected_asset.NatureOfSecurityEffect") structured_description = fields.TypedField("Structured_Description", Observables) From 338767f8401c81eed6e33eee32358e8c7e74f99e Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 13 Nov 2015 13:16:27 -0500 Subject: [PATCH 257/438] Add missing fields to Incident --- stix/incident/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index 09e6169d..31c65179 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -69,6 +69,9 @@ class Incident(stix.BaseCoreComponent): coa_taken = fields.TypedField("COA_Taken", COATaken, multiple=True) coa_requested = fields.TypedField("COA_Requested", COARequested, multiple=True) history = fields.TypedField("History", History) + information_source = fields.TypedField("Information_Source", InformationSource) + url = fields.TypedField("URL") + contacts = fields.TypedField("Contact", InformationSource, multiple=True, key_name="contacts") def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): super(Incident, self).__init__( From 9aa861eda927c112f055dc87c99cf8be70772013 Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 13 Nov 2015 13:18:04 -0500 Subject: [PATCH 258/438] Change mixbox Entities back to python-stix Entities --- stix/exploit_target/configuration.py | 2 +- stix/exploit_target/vulnerability.py | 2 +- stix/exploit_target/weakness.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stix/exploit_target/configuration.py b/stix/exploit_target/configuration.py index cebaf087..4ac5476a 100644 --- a/stix/exploit_target/configuration.py +++ b/stix/exploit_target/configuration.py @@ -6,7 +6,7 @@ import stix.bindings.exploit_target as exploit_target_binding from mixbox import fields, entities -class Configuration(entities.Entity): +class Configuration(stix.Entity): """Implementation of STIX ``Configuration``. Args: diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index 283018fc..2cfc82f1 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -12,7 +12,7 @@ from mixbox import entities, fields from stix.common import References -class Vulnerability(entities.Entity): +class Vulnerability(stix.Entity): """Implementation of STIX ``Vulnerability``. Args: diff --git a/stix/exploit_target/weakness.py b/stix/exploit_target/weakness.py index 57f213b2..ab989b9f 100644 --- a/stix/exploit_target/weakness.py +++ b/stix/exploit_target/weakness.py @@ -6,7 +6,7 @@ from stix.common import StructuredTextList from mixbox import entities, fields -class Weakness(entities.Entity): +class Weakness(stix.Entity): """Implementation of STIX ``Weakness``. Args: From 87d56b1de17fc71dcbdd91b14871dea64ef2b2f8 Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 13 Nov 2015 14:34:52 -0500 Subject: [PATCH 259/438] Change mixbox Entities to stix Entities --- stix/core/stix_package.py | 2 +- stix/incident/affected_asset.py | 2 +- stix/incident/external_id.py | 2 +- stix/incident/loss_estimation.py | 2 +- stix/ttp/attack_pattern.py | 2 +- stix/ttp/behavior.py | 4 +--- stix/ttp/exploit.py | 4 ++-- stix/ttp/infrastructure.py | 2 +- 8 files changed, 9 insertions(+), 11 deletions(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 1deea5a6..2549178c 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -40,7 +40,7 @@ import stix.bindings.stix_core as stix_core_binding import mixbox.entities -class STIXPackage(Cached, mixbox.entities.Entity): +class STIXPackage(Cached, stix.Entity): """A STIX Package object. Args: diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index 934e6295..6a87cc2f 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -149,7 +149,7 @@ class AssetType(VocabString): _binding = incident_binding _binding_class = incident_binding.AssetTypeType - count_affected = fields.TypedField("count_affected") + count_affected = fields.IntegerField("count_affected") def __init__(self, value=None, count_affected=None): super(AssetType, self).__init__(value) diff --git a/stix/incident/external_id.py b/stix/incident/external_id.py index de1c35f5..f4adc3f8 100644 --- a/stix/incident/external_id.py +++ b/stix/incident/external_id.py @@ -5,7 +5,7 @@ import stix.bindings.incident as incident_binding from mixbox import fields, entities -class ExternalID(entities.Entity): +class ExternalID(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.ExternalIDType diff --git a/stix/incident/loss_estimation.py b/stix/incident/loss_estimation.py index 71db7cfc..5baf6681 100644 --- a/stix/incident/loss_estimation.py +++ b/stix/incident/loss_estimation.py @@ -5,7 +5,7 @@ import stix.bindings.incident as incident_binding from mixbox import entities, fields -class LossEstimation(entities.Entity): +class LossEstimation(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.LossEstimationType diff --git a/stix/ttp/attack_pattern.py b/stix/ttp/attack_pattern.py index cc039fc4..6080e249 100644 --- a/stix/ttp/attack_pattern.py +++ b/stix/ttp/attack_pattern.py @@ -13,7 +13,7 @@ from mixbox import fields, entities -class AttackPattern(Cached, entities.Entity): +class AttackPattern(Cached, stix.Entity): _binding = ttp_binding _binding_class = _binding.AttackPatternType _namespace = "http://stix.mitre.org/TTP-1" diff --git a/stix/ttp/behavior.py b/stix/ttp/behavior.py index a0da9748..90933f23 100644 --- a/stix/ttp/behavior.py +++ b/stix/ttp/behavior.py @@ -12,9 +12,7 @@ from .exploit import Exploit from .attack_pattern import AttackPattern -from mixbox import entities, fields - -class Behavior(entities.Entity): +class Behavior(stix.Entity): _binding = ttp_binding _binding_class = _binding.BehaviorType _namespace = "http://stix.mitre.org/TTP-1" diff --git a/stix/ttp/exploit.py b/stix/ttp/exploit.py index fad7ef09..ef2ce31c 100644 --- a/stix/ttp/exploit.py +++ b/stix/ttp/exploit.py @@ -11,9 +11,9 @@ # bindings import stix.bindings.ttp as ttp_binding -from mixbox import entities, fields +from mixbox import fields -class Exploit(Cached, entities.Entity): +class Exploit(Cached, stix.Entity): _binding = ttp_binding _binding_class = _binding.ExploitType _namespace = "http://stix.mitre.org/TTP-1" diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index 873afe9e..0740cd0c 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -15,7 +15,7 @@ import stix.bindings.ttp as ttp_binding from mixbox import fields, entities -class Infrastructure(Cached, entities.Entity): +class Infrastructure(Cached, stix.Entity): _binding = ttp_binding _binding_class = _binding.InfrastructureType _namespace = "http://stix.mitre.org/TTP-1" From 1909bf13640db2a7fa3fdfc44410c6818b25ec33 Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 13 Nov 2015 14:44:21 -0500 Subject: [PATCH 260/438] Change Incident test to expect TypeError --- stix/test/incident_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/test/incident_test.py b/stix/test/incident_test.py index 4ba9a3a8..69d4b401 100644 --- a/stix/test/incident_test.py +++ b/stix/test/incident_test.py @@ -537,7 +537,7 @@ def test_add_related_indicator(self): # Test that this fails self.assertRaises( - ValueError, + TypeError, i.add_related_indicator, "THIS SHOULD FAIL" ) From 12798621c7d74f9a03e13710bf89bfe09c566598 Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 13 Nov 2015 14:57:35 -0500 Subject: [PATCH 261/438] Fix tests for test_add_related_indicator/observable TypeErrors --- stix/indicator/indicator.py | 1 + stix/test/incident_test.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 11ed79ad..c95d07f7 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -177,6 +177,7 @@ class Indicator(stix.BaseCoreComponent): _ALL_VERSIONS = ("2.0", "2.0.1", "2.1", "2.1.1", "2.2") _ALLOWED_COMPOSITION_OPERATORS = ('AND', 'OR') _ID_PREFIX = "indicator" + _try_cast = False producer = fields.TypedField("Producer", InformationSource) observable = fields.TypedField("Observable", Observable, postset_hook=lambda inst,value: inst.set_observables([value])) diff --git a/stix/test/incident_test.py b/stix/test/incident_test.py index 69d4b401..c4bde1b5 100644 --- a/stix/test/incident_test.py +++ b/stix/test/incident_test.py @@ -516,7 +516,7 @@ def test_add_related_observable(self): # Test that this fails self.assertRaises( - ValueError, + TypeError, i.add_related_observable, "THIS SHOULD FAIL" ) From c580f809d716a4d0a73f141e516cd150b87e9fbe Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 13 Nov 2015 15:09:59 -0500 Subject: [PATCH 262/438] Add TypedFields to Report class --- stix/report/__init__.py | 276 +++------------------------------------- 1 file changed, 16 insertions(+), 260 deletions(-) diff --git a/stix/report/__init__.py b/stix/report/__init__.py index d4d487e7..fd768187 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -59,11 +59,26 @@ class Report(Cached, stix.Entity): _namespace = 'http://stix.mitre.org/Report-1' _version = "1.0" + id_ = fields.IdField("id") + idref = fields.IdrefField("idref") + timestamp = fields.TypedField("timestamp") + version = fields.TypedField("version") + header = fields.TypedField("Header", Header) + campaigns = fields.TypedField("Campaigns", type_="stix.report.Campaigns") + courses_of_action = fields.TypedField("Courses_of_Action", type_="stix.report.CoursesOfAction") + exploit_targets = fields.TypedField("Exploit_Targets", type_="stix.report.ExploitTargets") + observables = fields.TypedField("Observables", Observables) + indicators = fields.TypedField("Indicators", type_="stix.report.Indicators") + incidents = fields.TypedField("Incidents", type_="stix.report.Incidents") + threat_actors = fields.TypedField("Threat_Actors", type_="stix.report.ThreatActors") + ttps = fields.TypedField("TTPs", type_="stix.report.TTPs") + related_reports = fields.TypedField("Related_Reports", type_="stix.report.RelatedReports") + def __init__(self, id_=None, idref=None, timestamp=None, header=None, courses_of_action=None, exploit_targets=None, indicators=None, observables=None, incidents=None, threat_actors=None, ttps=None, campaigns=None, related_reports=None): - + super(Report, self).__init__() self.id_ = id_ or idgen.create_id("Report") self.idref = idref self.version = self._version @@ -83,73 +98,6 @@ def __init__(self, id_=None, idref=None, timestamp=None, header=None, else: self.timestamp = utils.dates.now() if not idref else None - @property - def id_(self): - """A globally unique identifier for this Report. By default, one - will be generated automatically. - - """ - return self._id - - @id_.setter - def id_(self, value): - if not value: - self._id = None - else: - self._id = value - self.idref = None - - @property - def idref(self): - """A reference to another Report identifier. Setting this will unset - any previous ``id`` values. - - """ - return self._idref - - @idref.setter - def idref(self, value): - if not value: - self._idref = None - else: - self._idref = value - self.id_ = None # unset id_ if idref is present - - @property - def timestamp(self): - """Specifies a timestamp for the definition of this specific Report - object. - - """ - return self._timestamp - - @timestamp.setter - def timestamp(self, value): - self._timestamp = utils.dates.parse_value(value) - - @property - def header(self): - """The :class:`.Header` section for the Report. - - """ - return self._header - - @header.setter - def header(self, value): - self._set_var(Header, try_cast=False, header=value) - - @property - def indicators(self): - """The top-level :class:`.Indicator` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._indicators - - @indicators.setter - def indicators(self, value): - self._indicators = Indicators(value) - def add_indicator(self, indicator): """Adds an :class:`.Indicator` object to the :attr:`indicators` collection. @@ -157,36 +105,12 @@ def add_indicator(self, indicator): """ self.indicators.append(indicator) - @property - def campaigns(self): - """The top-level :class:`.Campaign` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._campaigns - - @campaigns.setter - def campaigns(self, value): - self._campaigns = Campaigns(value) - def add_campaign(self, campaign): """Adds a :class:`Campaign` object to the :attr:`campaigns` collection. """ self.campaigns.append(campaign) - @property - def observables(self): - """The top-level ``Observable`` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._observables - - @observables.setter - def observables(self, value): - self._set_var(Observables, observables=value) - def add_observable(self, observable): """Adds an ``Observable`` object to the :attr:`observables` collection. @@ -199,18 +123,6 @@ def add_observable(self, observable): else: self.observables.add(observable) - @property - def incidents(self): - """The top-level :class:`.Incident` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._incidents - - @incidents.setter - def incidents(self, value): - self._incidents = Incidents(value) - def add_incident(self, incident): """Adds an :class:`.Incident` object to the :attr:`incidents` collection. @@ -218,18 +130,6 @@ def add_incident(self, incident): """ self.incidents.append(incident) - @property - def threat_actors(self): - """The top-level :class:`.ThreatActor` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._threat_actors - - @threat_actors.setter - def threat_actors(self, value): - self._threat_actors = ThreatActors(value) - def add_threat_actor(self, threat_actor): """Adds an :class:`.ThreatActor` object to the :attr:`threat_actors` collection. @@ -237,18 +137,6 @@ def add_threat_actor(self, threat_actor): """ self._threat_actors.append(threat_actor) - @property - def courses_of_action(self): - """The top-level :class:`.CourseOfAction` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._courses_of_action - - @courses_of_action.setter - def courses_of_action(self, value): - self._courses_of_action = CoursesOfAction(value) - def add_course_of_action(self, course_of_action): """Adds an :class:`.CourseOfAction` object to the :attr:`courses_of_action` collection. @@ -256,18 +144,6 @@ def add_course_of_action(self, course_of_action): """ self._courses_of_action.append(course_of_action) - @property - def exploit_targets(self): - """The top-level :class:`.ExploitTarget` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._exploit_targets - - @exploit_targets.setter - def exploit_targets(self, value): - self._exploit_targets = ExploitTargets(value) - def add_exploit_target(self, exploit_target): """Adds an :class:`.ExploitTarget` object to the :attr:`exploit_targets` collection. @@ -275,42 +151,12 @@ def add_exploit_target(self, exploit_target): """ self._exploit_targets.append(exploit_target) - @property - def ttps(self): - """The top-level :class:`.TTP` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._ttps - - @ttps.setter - def ttps(self, value): - if isinstance(value, TTPs): - self._ttps = value - else: - self._ttps = TTPs(value) - def add_ttp(self, ttp): """Adds an :class:`.TTP` object to the :attr:`ttps` collection. """ self.ttps.append(ttp) - @property - def related_reports(self): - """The top-level :class:`.RelatedReports` collection. This behaves like - a ``MutableSequence`` type. - - """ - return self._related_reports - - @related_reports.setter - def related_reports(self, value): - if isinstance(value, RelatedReports): - self._related_reports = value - else: - self._related_reports = RelatedReports(value) - def add_related_report(self, related_report): """Adds an :class:`.RelatedReport` object to the :attr:`related_reports` collection. @@ -347,96 +193,6 @@ def add(self, entity): error = error.format(type(entity)) raise TypeError(error) - def to_obj(self, return_obj=None, ns_info=None): - super(Report, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - return_obj.id = self.id_ - return_obj.idref = self.idref - return_obj.version = self.version - return_obj.timestamp = utils.dates.serialize_value(self.timestamp) - - if self.header: - return_obj.Header = self.header.to_obj(ns_info=ns_info) - if self.campaigns: - return_obj.Campaigns = self.campaigns.to_obj(ns_info=ns_info) - if self.courses_of_action: - return_obj.Courses_Of_Action = self.courses_of_action.to_obj(ns_info=ns_info) - if self.exploit_targets: - return_obj.Exploit_Targets = self.exploit_targets.to_obj(ns_info=ns_info) - if self.indicators: - return_obj.Indicators = self.indicators.to_obj(ns_info=ns_info) - if self.observables: - return_obj.Observables = self.observables.to_obj(ns_info=ns_info) - if self.incidents: - return_obj.Incidents = self.incidents.to_obj(ns_info=ns_info) - if self.threat_actors: - return_obj.Threat_Actors = self.threat_actors.to_obj(ns_info=ns_info) - if self.ttps: - return_obj.TTPs = self.ttps.to_obj(ns_info=ns_info) - if self.related_reports: - return_obj.Related_Reports = self.related_reports.to_obj(ns_info=ns_info) - - return return_obj - - def to_dict(self): - return super(Report, self).to_dict() - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not return_obj: - return_obj = cls() - - # ReportBaseType fields - return_obj.id_ = obj.id - return_obj.idref = obj.idref - return_obj.timestamp = obj.timestamp - - # ReportType fields - if isinstance(obj, cls._binding_class): - return_obj.header = Header.from_obj(obj.Header) - return_obj.campaigns = Campaigns.from_obj(obj.Campaigns) - return_obj.courses_of_action = CoursesOfAction.from_obj(obj.Courses_Of_Action) - return_obj.exploit_targets = ExploitTargets.from_obj(obj.Exploit_Targets) - return_obj.indicators = Indicators.from_obj(obj.Indicators) - return_obj.observables = Observables.from_obj(obj.Observables) - return_obj.incidents = Incidents.from_obj(obj.Incidents) - return_obj.threat_actors = ThreatActors.from_obj(obj.Threat_Actors) - return_obj.ttps = TTPs.from_obj(obj.TTPs) - return_obj.related_reports = RelatedReports.from_obj(obj.Related_Reports) - - # Don't overwrite unless a version is passed in - if obj.version: - return_obj.version = obj.version - - return return_obj - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not return_obj: - return_obj = cls() - - get = dict_repr.get - return_obj.id_ = get('id') - return_obj.idref = get('idref') - return_obj.timestamp = get('timestamp') - return_obj.version = get('version', cls._version) - return_obj.header = Header.from_dict(get('header')) - return_obj.campaigns = Campaigns.from_dict(get('campaigns')) - return_obj.courses_of_action = CoursesOfAction.from_dict(get('courses_of_action')) - return_obj.exploit_targets = ExploitTargets.from_dict(get('exploit_targets')) - return_obj.indicators = Indicators.from_dict(get('indicators')) - return_obj.observables = Observables.from_dict(get('observables')) - return_obj.incidents = Incidents.from_dict(get('incidents')) - return_obj.threat_actors = ThreatActors.from_dict(get('threat_actors')) - return_obj.ttps = TTPs.from_dict(get('ttps')) - return_obj.related_reports = RelatedReports.from_dict(get('related_reports')) - - return return_obj - - class Campaigns(stix.EntityList): _binding = report_binding _namespace = 'http://stix.mitre.org/Report-1' From 3f5da3deeee74aaf418778f6126872f1a0644300 Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 13 Nov 2015 15:50:04 -0500 Subject: [PATCH 263/438] Capitalization typo in Report --- stix/report/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/report/__init__.py b/stix/report/__init__.py index fd768187..e652427b 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -65,7 +65,7 @@ class Report(Cached, stix.Entity): version = fields.TypedField("version") header = fields.TypedField("Header", Header) campaigns = fields.TypedField("Campaigns", type_="stix.report.Campaigns") - courses_of_action = fields.TypedField("Courses_of_Action", type_="stix.report.CoursesOfAction") + courses_of_action = fields.TypedField("Courses_Of_Action", type_="stix.report.CoursesOfAction") exploit_targets = fields.TypedField("Exploit_Targets", type_="stix.report.ExploitTargets") observables = fields.TypedField("Observables", Observables) indicators = fields.TypedField("Indicators", type_="stix.report.Indicators") From 0ad15b0f27e435c2ba0c458111738edd32261152 Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 13 Nov 2015 16:03:06 -0500 Subject: [PATCH 264/438] is_cybox now accounts for the fact that stix entites are mixbox entities --- stix/utils/__init__.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index 869c030b..1b58ae0a 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -136,12 +136,11 @@ def is_stix(entity): def is_cybox(entity): - """Returns true if `entity` is an instance of - :class:`mixbox.entities.Entity`. - """ - # TODO: once all entities subclass from mixbox.entities.Entity, how do we - # do this? - return isinstance(entity, Entity) + """Returns true if `entity` is a Cybox object""" + try: + return entity.__module__.startswith("cybox.") + except AttributeError: + return False def is_entity(entity): From 24c949d2d6754425456505ad05c42cdcd3671ffd Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Fri, 13 Nov 2015 17:33:01 -0500 Subject: [PATCH 265/438] Fix for issue #274: STIXPackage.add() now correctly adds TTPs. --- stix/core/stix_package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 79061ef5..af1a867b 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -374,7 +374,7 @@ def add(self, entity): Incident: self.add_incident, Indicator: self.add_indicator, ThreatActor: self.add_threat_actor, - TTP: self.add_threat_actor, + TTP: self.add_ttp, Report: self.add_report, Observable: self.add_observable, } From 9d292cc852135776738e40a0cfc1872bb291e206 Mon Sep 17 00:00:00 2001 From: apsillers Date: Mon, 16 Nov 2015 20:19:54 -0500 Subject: [PATCH 266/438] Fix add_* methods on STIXPackage --- stix/core/stix_package.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 2549178c..c9d6de21 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -115,12 +115,16 @@ def add_indicator(self, indicator): collection. """ + if self.indicators is None: + self.indicators = Indicators() self.indicators.append(indicator) def add_campaign(self, campaign): """Adds a :class:`Campaign` object to the :attr:`campaigns` collection. """ + if self.campaigns is None: + self.campaigns = Campaigns() self.campaigns.append(campaign) def add_observable(self, observable): @@ -140,6 +144,8 @@ def add_incident(self, incident): collection. """ + if self.incidents is None: + self.incidents = Incidents() self.incidents.append(incident) def add_threat_actor(self, threat_actor): @@ -147,32 +153,42 @@ def add_threat_actor(self, threat_actor): collection. """ - self._threat_actors.append(threat_actor) + if self.threat_actors is None: + self.threat_actors = ThreatActors() + self.threat_actors.append(threat_actor) def add_course_of_action(self, course_of_action): """Adds an :class:`.CourseOfAction` object to the :attr:`courses_of_action` collection. """ - self._courses_of_action.append(course_of_action) + if self.courses_of_action is None: + self.courses_of_action = CoursesOfAction() + self.courses_of_action.append(course_of_action) def add_exploit_target(self, exploit_target): """Adds an :class:`.ExploitTarget` object to the :attr:`exploit_targets` collection. """ - self._exploit_targets.append(exploit_target) + if self.exploit_targets is None: + self.exploit_targets = ExploitTargets() + self.exploit_targets.append(exploit_target) def add_ttp(self, ttp): """Adds an :class:`.TTP` object to the :attr:`ttps` collection. """ + if self.ttps is None: + self.ttps = TTPs() self.ttps.append(ttp) def add_report(self, report): """Adds a :class:`.Report` object to the :attr:`reports` collection. """ + if self.reports is None: + self.reports = Reports() self.reports.append(report) def add_related_package(self, related_package): @@ -180,6 +196,8 @@ def add_related_package(self, related_package): :attr:`related_packages` collection. """ + if self.related_packages is None: + self.related_packages = RelatedPackages() self.related_packages.append(related_package) def add(self, entity): From 7bb6163d8e4f9f505d08ae45db8ba436a0a73ef3 Mon Sep 17 00:00:00 2001 From: apsillers Date: Mon, 16 Nov 2015 20:20:22 -0500 Subject: [PATCH 267/438] Fix description/short_descsription on STIXHeader --- stix/core/stix_header.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index 70931a9a..0caab0f7 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -38,13 +38,12 @@ class STIXHeader(stix.Entity): title = fields.TypedField("Title", preset_hook=deprecated.field) package_intents = VocabField("Package_Intent", PackageIntent, multiple=True, preset_hook=deprecated.field) - descriptions = fields.TypedField("Description", type_=StructuredTextList, preset_hook=deprecated.field) + descriptions = fields.TypedField("Description", type_=StructuredTextList)#, preset_hook=deprecated.field) short_descriptions = fields.TypedField("Short_Description", type_=StructuredTextList, preset_hook=deprecated.field) handling = fields.TypedField("Handling", Marking) information_source = fields.TypedField("Information_Source", InformationSource) profiles = fields.TypedField("Profiles", Profiles) - def __init__(self, package_intents=None, description=None, handling=None, information_source=None, title=None, short_description=None): @@ -78,7 +77,7 @@ def description(self): @description.setter def description(self, value): - self.descriptions = value + self.descriptions = StructuredTextList(value) def add_description(self, description): """**DEPRECATED**. Adds a description to the ``descriptions`` @@ -109,7 +108,7 @@ def short_description(self): @short_description.setter def short_description(self, value): - self.short_descriptions = value + self.short_descriptions = StructuredTextList(value) def add_short_description(self, description): """**DEPRECATED**. Adds a description to the ``short_descriptions`` From 9b5fa978e147bc72415cc40a164c06a7009b42c5 Mon Sep 17 00:00:00 2001 From: apsillers Date: Tue, 17 Nov 2015 08:41:10 -0500 Subject: [PATCH 268/438] Update SnortTestMechanism to typed fields --- .../test_mechanism/snort_test_mechanism.py | 126 ++---------------- 1 file changed, 9 insertions(+), 117 deletions(-) diff --git a/stix/extensions/test_mechanism/snort_test_mechanism.py b/stix/extensions/test_mechanism/snort_test_mechanism.py index efd12c77..8dc58daa 100644 --- a/stix/extensions/test_mechanism/snort_test_mechanism.py +++ b/stix/extensions/test_mechanism/snort_test_mechanism.py @@ -5,7 +5,7 @@ from stix.common import EncodedCDATA from stix.indicator import test_mechanism import stix.bindings.extensions.test_mechanism.snort as snort_tm_binding - +from mixbox import fields @stix.register_extension class SnortTestMechanism(test_mechanism._BaseTestMechanism): @@ -14,121 +14,13 @@ class SnortTestMechanism(test_mechanism._BaseTestMechanism): _binding_class = _binding.SnortTestMechanismType _XSI_TYPE = "snortTM:SnortTestMechanismType" + product_name = fields.TypedField("Product_Name", EncodedCDATA) + version = fields.TypedField("Version", EncodedCDATA) + rules = fields.TypedField("Rule", EncodedCDATA, multiple=True, key_name="rules") + event_filters = fields.TypedField("Event_Filter", EncodedCDATA, multiple=True, key_name="event_filters") + rate_filters = fields.TypedField("Rate_Filter", EncodedCDATA, multiple=True, key_name="rate_filters") + event_suppressions = fields.TypedField("Event_Suppression", EncodedCDATA, multiple=True, key_name="event_suppressions") + def __init__(self, id_=None, idref=None): super(SnortTestMechanism, self).__init__(id_=id_, idref=idref) - self.product_name = None - self.version = None - self.rules = None - self.event_filters = None - self.rate_filters = None - self.event_suppressions = None - - @property - def rules(self): - return self._rules - - @rules.setter - def rules(self, value): - self._rules = _EncodedCDATAs(value) - - def add_rule(self, rule): - self.rules.append(rule) - - @property - def event_filters(self): - return self._event_filters - - @event_filters.setter - def event_filters(self, value): - self._event_filters = _EncodedCDATAs(value) - - def add_event_filter(self, item): - self.event_filters.append(item) - - @property - def rate_filters(self): - return self._rate_filters - - @rate_filters.setter - def rate_filters(self, value): - self._rate_filters = _EncodedCDATAs(value) - - def add_rate_filter(self, item): - self.rate_filters.append(item) - - @property - def event_suppressions(self): - return self._event_suppressions - - @event_suppressions.setter - def event_suppressions(self, value): - self._event_suppressions = _EncodedCDATAs(value) - - def add_event_suppression(self, item): - self.event_suppressions.append(item) - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - super(SnortTestMechanism, cls).from_obj(obj, return_obj) - return_obj.product_name = obj.Product_Name - return_obj.version = obj.Version - return_obj.rules = _EncodedCDATAs.from_obj(obj.Rule) - return_obj.event_filters = _EncodedCDATAs.from_obj(obj.Event_Filter) - return_obj.rate_filters = _EncodedCDATAs.from_obj(obj.Rate_Filter) - return_obj.event_suppressions = _EncodedCDATAs.from_obj(obj.Event_Suppression) - - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(SnortTestMechanism, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - return_obj.Product_Name = self.product_name - return_obj.Version = self.version - - if self.rules: - return_obj.Rule = self.rules.to_obj(ns_info=ns_info) - if self.event_filters: - return_obj.Event_Filter = self.event_filters.to_obj(ns_info=ns_info) - if self.rate_filters: - return_obj.Rate_Filter = self.rate_filters.to_obj(ns_info=ns_info) - if self.event_suppressions: - return_obj.Event_Suppression = self.event_suppressions.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if not return_obj: - return_obj = cls() - - super(SnortTestMechanism, cls).from_dict(d, return_obj) - - get = d.get - return_obj.product_name = get('product_name') - return_obj.version = get('version') - return_obj.rules = _EncodedCDATAs.from_dict(get('rules')) - return_obj.event_filters = _EncodedCDATAs.from_dict(get('event_filters')) - return_obj.rate_filters = _EncodedCDATAs.from_dict(get('rate_filters')) - return_obj.event_suppressions = _EncodedCDATAs.from_dict(get('event_suppressions')) - - return return_obj - - def to_dict(self): - return super(SnortTestMechanism, self).to_dict() - - -# Not an actual STIX data type! -class _EncodedCDATAs(stix.TypedList): - _contained_type = EncodedCDATA - - + \ No newline at end of file From c4f254a481d49a45b10590a980a22c95d814511d Mon Sep 17 00:00:00 2001 From: apsillers Date: Wed, 18 Nov 2015 17:28:10 -0500 Subject: [PATCH 269/438] Change TypedFields to VocabFields for properties with type vocab.* --- stix/incident/__init__.py | 218 ++++------------------- stix/incident/affected_asset.py | 115 +----------- stix/incident/impact_assessment.py | 55 +----- stix/incident/indirect_impact_summary.py | 54 +----- stix/incident/property_affected.py | 65 +------ 5 files changed, 51 insertions(+), 456 deletions(-) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index 31c65179..c8d22b7f 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -46,7 +46,7 @@ class Incident(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'incident' - status = fields.TypedField("Status", vocabs.IncidentStatus) + status = vocabs.VocabField("Status", vocabs.IncidentStatus) time = fields.TypedField("Time", Time) victims = fields.TypedField("Victim", Identity, factory=IdentityFactory, multiple=True, key_name="victims") attributed_threat_actors = fields.TypedField("Attributed_Threat_Actors", type_="stix.incident.AttributedThreatActors") @@ -58,13 +58,13 @@ class Incident(stix.BaseCoreComponent): categories = fields.TypedField("Categories", type_="stix.incident.IncidentCategories") intended_effects = fields.TypedField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") leveraged_ttps = fields.TypedField("Leveraged_TTPs", type_="stix.incident.LeveragedTTPs") - discovery_methods = fields.TypedField("Discovery_Method", vocabs.DiscoveryMethod, multiple=True, key_name="discovery_methods") + discovery_methods = vocabs.VocabField("Discovery_Method", vocabs.DiscoveryMethod, multiple=True, key_name="discovery_methods") reporter = fields.TypedField("Reporter", InformationSource) responders = fields.TypedField("Responder", InformationSource, multiple=True, key_name="responders") coordinators = fields.TypedField("Coordinator", InformationSource, multiple=True, key_name="coordinators") external_ids = fields.TypedField("External_ID", ExternalID, multiple=True, key_name="external_ids") impact_assessment = fields.TypedField("Impact_Assessment", ImpactAssessment) - security_compromise = fields.TypedField("Security_Compromise", vocabs.SecurityCompromise) + security_compromise = vocabs.VocabField("Security_Compromise", vocabs.SecurityCompromise) confidence = fields.TypedField("Confidence", Confidence) coa_taken = fields.TypedField("COA_Taken", COATaken, multiple=True) coa_requested = fields.TypedField("COA_Requested", COARequested, multiple=True) @@ -234,146 +234,6 @@ def add_related_observable(self, value): def add_related_package(self, value): self.related_packages.append(value) - # def to_obj(self, return_obj=None, ns_info=None): - # if not return_obj: - # return_obj = self._binding_class() - # - # super(Incident, self).to_obj(return_obj=return_obj, ns_info=ns_info) - # - # if self.time: - # return_obj.Time = self.time.to_obj(ns_info=ns_info) - # if self.victims: - # return_obj.Victim = self.victims.to_obj(ns_info=ns_info) - # if self.attributed_threat_actors: - # return_obj.Attributed_Threat_Actors = self.attributed_threat_actors.to_obj(ns_info=ns_info) - # if self.related_indicators: - # return_obj.Related_Indicators = self.related_indicators.to_obj(ns_info=ns_info) - # if self.related_observables: - # return_obj.Related_Observables = self.related_observables.to_obj(ns_info=ns_info) - # if self.related_incidents: - # return_obj.Related_Incidents = self.related_incidents.to_obj(ns_info=ns_info) - # if self.categories: - # return_obj.Categories = self.categories.to_obj(ns_info=ns_info) - # if self.intended_effects: - # return_obj.Intended_Effect = self.intended_effects.to_obj(ns_info=ns_info) - # if self.leveraged_ttps: - # return_obj.Leveraged_TTPs = self.leveraged_ttps.to_obj(ns_info=ns_info) - # if self.affected_assets: - # return_obj.Affected_Assets = self.affected_assets.to_obj(ns_info=ns_info) - # if self.discovery_methods: - # return_obj.Discovery_Method = self.discovery_methods.to_obj(ns_info=ns_info) - # if self.reporter: - # return_obj.Reporter = self.reporter.to_obj(ns_info=ns_info) - # if self.responders: - # return_obj.Responder = self.responders.to_obj(ns_info=ns_info) - # if self.coordinators: - # return_obj.Coordinator = self.coordinators.to_obj(ns_info=ns_info) - # if self.external_ids: - # return_obj.External_ID = self.external_ids.to_obj(ns_info=ns_info) - # if self.impact_assessment: - # return_obj.Impact_Assessment = self.impact_assessment.to_obj(ns_info=ns_info) - # if self.security_compromise: - # return_obj.Security_Compromise = self.security_compromise.to_obj(ns_info=ns_info) - # if self.confidence: - # return_obj.Confidence = self.confidence.to_obj(ns_info=ns_info) - # if self.coa_taken: - # return_obj.COA_Taken = self.coa_taken.to_obj(ns_info=ns_info) - # if self.coa_requested: - # return_obj.COA_Requested = self.coa_requested.to_obj(ns_info=ns_info) - # if self.status: - # return_obj.Status = self.status.to_obj(ns_info=ns_info) - # if self.history: - # return_obj.History = self.history.to_obj(ns_info=ns_info) - # if self.related_packages: - # return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) - # if self.contacts: - # return_obj.Contact = self.contacts.to_obj(ns_info=ns_info) - # if self.url: - # return_obj.URL = self.url - # - # return return_obj - # - # @classmethod - # def from_obj(cls, obj, return_obj=None): - # if not obj: - # return None - # - # if not return_obj: - # return_obj = cls() - # - # super(Incident, cls).from_obj(obj, return_obj=return_obj) - # - # if isinstance(obj, cls._binding_class): - # return_obj.time = Time.from_obj(obj.Time) - # return_obj.victims = _Victims.from_obj(obj.Victim) - # return_obj.categories = IncidentCategories.from_obj(obj.Categories) - # return_obj.intended_effects = _IntendedEffects.from_obj(obj.Intended_Effect) - # return_obj.affected_assets = AffectedAssets.from_obj(obj.Affected_Assets) - # return_obj.discovery_methods = DiscoveryMethods.from_obj(obj.Discovery_Method) - # return_obj.coa_taken = _COAsTaken.from_obj(obj.COA_Taken) - # return_obj.coa_requested = _COAsRequested.from_obj(obj.COA_Requested) - # return_obj.confidence = Confidence.from_obj(obj.Confidence) - # return_obj.attributed_threat_actors = AttributedThreatActors.from_obj(obj.Attributed_Threat_Actors) - # return_obj.related_indicators = RelatedIndicators.from_obj(obj.Related_Indicators) - # return_obj.related_observables = RelatedObservables.from_obj(obj.Related_Observables) - # return_obj.leveraged_ttps = LeveragedTTPs.from_obj(obj.Leveraged_TTPs) - # return_obj.related_incidents = RelatedIncidents.from_obj(obj.Related_Incidents) - # return_obj.status = VocabString.from_obj(obj.Status) - # return_obj.history = History.from_obj(obj.History) - # return_obj.responders = _InformationSources.from_obj(obj.Responder) - # return_obj.coordinators = _InformationSources.from_obj(obj.Coordinator) - # return_obj.external_ids = _ExternalIDs.from_obj(obj.External_ID) - # return_obj.reporter = InformationSource.from_obj(obj.Reporter) - # return_obj.impact_assessment = ImpactAssessment.from_obj(obj.Impact_Assessment) - # return_obj.security_compromise = VocabString.from_obj(obj.Security_Compromise) - # return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) - # return_obj.contacts = _InformationSources.from_obj(obj.Contact) - # return_obj.url = obj.URL - # - # return return_obj - # - # def to_dict(self): - # return super(Incident, self).to_dict() - # - # @classmethod - # def from_dict(cls, dict_repr, return_obj=None): - # if not dict_repr: - # return None - # - # if not return_obj: - # return_obj = cls() - # - # super(Incident, cls).from_dict(dict_repr, return_obj=return_obj) - # - # get = dict_repr.get - # return_obj.time = Time.from_dict(get('time')) - # return_obj.victims = _Victims.from_dict(get('victims')) - # return_obj.categories = IncidentCategories.from_dict(get('categories')) - # return_obj.attributed_threat_actors = AttributedThreatActors.from_dict(get('attributed_threat_actors')) - # return_obj.related_indicators = RelatedIndicators.from_dict(get('related_indicators')) - # return_obj.related_observables = RelatedObservables.from_dict(get('related_observables')) - # return_obj.related_incidents = RelatedIncidents.from_dict(get('related_incidents')) - # return_obj.intended_effects = _IntendedEffects.from_list(get('intended_effects')) - # return_obj.leveraged_ttps = LeveragedTTPs.from_dict(get('leveraged_ttps')) - # return_obj.affected_assets = AffectedAssets.from_dict(get('affected_assets')) - # return_obj.discovery_methods = DiscoveryMethods.from_dict(get('discovery_methods')) - # return_obj.reporter = InformationSource.from_dict(get('reporter')) - # return_obj.responders = _InformationSources.from_dict(get('responders')) - # return_obj.coordinators = _InformationSources.from_dict(get('coordinators')) - # return_obj.external_ids = _ExternalIDs.from_dict(get('external_ids')) - # return_obj.impact_assessment = ImpactAssessment.from_dict(get('impact_assessment')) - # return_obj.security_compromise = VocabString.from_dict(get('security_compromise')) - # return_obj.confidence = Confidence.from_dict(get('confidence')) - # return_obj.coa_taken = _COAsTaken.from_dict(get('coa_taken')) - # return_obj.coa_requested = _COAsRequested.from_dict(get('coa_requested')) - # return_obj.status = VocabString.from_dict(get('status')) - # return_obj.history = History.from_dict(get('history')) - # return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) - # return_obj.contacts = _InformationSources.from_dict(get('contacts')) - # return_obj.url = get('url') - # - # return return_obj - class AttributedThreatActors(GenericRelationshipList): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding @@ -466,39 +326,39 @@ class AffectedAssets(stix.EntityList): # NOT ACTUAL STIX TYPES! - -class DiscoveryMethods(stix.TypedList): - _contained_type = VocabString - - def _fix_value(self, value): - return vocabs.DiscoveryMethod(value) - - -class _COAsTaken(stix.TypedList): - _contained_type = COATaken - - -class _COAsRequested(stix.TypedList): - _contained_type = COARequested - - -class _ExternalIDs(stix.TypedList): - _contained_type = ExternalID - - -class _InformationSources(stix.TypedList): - _contained_type = InformationSource - - -class _Victims(stix.TypedList): - _contained_type = Identity - - def _fix_value(self, value): - return Identity(name=value) - - -class _IntendedEffects(stix.TypedList): - _contained_type = Statement - - def _fix_value(self, value): - return Statement(value=vocabs.IntendedEffect(value)) +# +# class DiscoveryMethods(stix.TypedList): +# _contained_type = VocabString +# +# def _fix_value(self, value): +# return vocabs.DiscoveryMethod(value) +# +# +# class _COAsTaken(stix.TypedList): +# _contained_type = COATaken +# +# +# class _COAsRequested(stix.TypedList): +# _contained_type = COARequested +# +# +# class _ExternalIDs(stix.TypedList): +# _contained_type = ExternalID +# +# +# class _InformationSources(stix.TypedList): +# _contained_type = InformationSource +# +# +# class _Victims(stix.TypedList): +# _contained_type = Identity +# +# def _fix_value(self, value): +# return Identity(name=value) +# +# +# class _IntendedEffects(stix.TypedList): +# _contained_type = Statement +# +# def _fix_value(self, value): +# return Statement(value=vocabs.IntendedEffect(value)) diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index 6a87cc2f..4a75d4a2 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -21,9 +21,9 @@ class AffectedAsset(stix.Entity): descriptions = fields.TypedField("Description", StructuredTextList) business_function_or_roles = fields.TypedField("Business_Function_Or_Role", StructuredTextList) - ownership_class = fields.TypedField("Ownership_Class", vocabs.OwnershipClass) - management_class = fields.TypedField("Management_Class", vocabs.ManagementClass) - location_class = fields.TypedField("Location_Class", vocabs.LocationClass) + ownership_class = vocabs.VocabField("Ownership_Class", vocabs.OwnershipClass) + management_class = vocabs.VocabField("Management_Class", vocabs.ManagementClass) + location_class = vocabs.VocabField("Location_Class", vocabs.LocationClass) # location = fields.TypedField("Location") nature_of_security_effect = fields.TypedField("Nature_Of_Security_Effect", type_="stix.incident.affected_asset.NatureOfSecurityEffect") structured_description = fields.TypedField("Structured_Description", Observables) @@ -71,78 +71,7 @@ def business_function_or_role(self, value): def add_property_affected(self, v): self.nature_of_security_effect.append(v) - -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.type_ = AssetType.from_obj(obj.Type) -# return_obj.descriptions = StructuredTextList.from_obj(obj.Description) -# return_obj.business_functions_or_roles = StructuredTextList.from_obj(obj.Business_Function_Or_Role) -# return_obj.ownership_class = VocabString.from_obj(obj.Ownership_Class) -# return_obj.management_class = VocabString.from_obj(obj.Management_Class) -# return_obj.location_class = VocabString.from_obj(obj.Location_Class) -# # return_obj.location = None -# -# if obj.Nature_Of_Security_Effect: -# n = obj.Nature_Of_Security_Effect -# return_obj.nature_of_security_effect = [PropertyAffected.from_obj(x) for x in n.Property_Affected] -# -# return return_obj -# -# def to_obj(self, return_obj=None, ns_info=None): -# super(AffectedAsset, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# if not return_obj: -# return_obj = self._binding_class() -# -# if self.type_: -# return_obj.Type = self.type_.to_obj(ns_info=ns_info) -# if self.descriptions: -# return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) -# if self.business_functions_or_roles: -# return_obj.Business_Function_Or_Role = self.business_functions_or_roles.to_obj(ns_info=ns_info) -# if self.ownership_class: -# return_obj.Ownership_Class = self.ownership_class.to_obj(ns_info=ns_info) -# if self.management_class: -# return_obj.Management_Class = self.management_class.to_obj(ns_info=ns_info) -# if self.location_class: -# return_obj.Location_Class = self.location_class.to_obj(ns_info=ns_info) -# # if self.location: -# # return_obj.Location = self.location.to_obj(ns_info=ns_info) -# if self.nature_of_security_effect: -# property_affected_list = [x.to_obj(ns_info=ns_info) for x in self.nature_of_security_effect] -# n = self._binding.NatureOfSecurityEffectType(Property_Affected=property_affected_list) -# return_obj.Nature_Of_Security_Effect = n -# if self.structured_description: -# return_obj.Structured_Description = self.structured_description.to_obj(ns_info=ns_info) -# -# return return_obj -# -# @classmethod -# def from_dict(cls, d, return_obj=None): -# if not d: -# return None -# if not return_obj: -# return_obj = cls() -# -# get = d.get -# return_obj.type_ = AssetType.from_dict(get('type')) -# return_obj.descriptions = StructuredTextList.from_dict(get('description')) -# return_obj.business_functions_or_roles = StructuredTextList.from_dict(get('business_function_or_role')) -# return_obj.ownership_class = VocabString.from_dict(get('ownership_class')) -# return_obj.management_class = VocabString.from_dict(get('management_class')) -# return_obj.location_class = VocabString.from_dict(get('location_class')) -# # return_obj.location = Location.from_dict(get('location')) -# return_obj.nature_of_security_effect = NatureOfSecurityEffect.from_dict(get('nature_of_security_effect')) -# return_obj.structured_description = Observables.from_dict(get('structured_description')) -# return return_obj -# -# def to_dict(self): -# return super(AffectedAsset, self).to_dict() + class AssetType(VocabString): _namespace = "http://stix.mitre.org/Incident-1" @@ -159,42 +88,6 @@ def is_plain(self): """Override VocabString.is_plain()""" return False -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# if not return_obj: -# return_obj = cls() -# -# super(AssetType, cls).from_obj(obj, return_obj=return_obj) -# return_obj.count_affected = obj.count_affected -# return return_obj -# -# def to_obj(self, return_obj=None, ns_info=None): -# if not return_obj: -# return_obj = self._binding_class() -# -# super(AssetType, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# return_obj.count_affected = self.count_affected -# return return_obj -# -# @classmethod -# def from_dict(cls, d, return_obj=None): -# if not d: -# return None -# if not return_obj: -# return_obj = cls() -# -# super(AssetType, cls).from_dict(d, return_obj=return_obj) -# return_obj.count_affected = d.get('count_affected') -# return return_obj -# -# def to_dict(self): -# d = super(AssetType, self).to_dict() -# if self.count_affected: -# d['count_affected'] = self.count_affected -# return d - class NatureOfSecurityEffect(stix.EntityList): _namespace = "http://stix.mitre.org/Incident-1" diff --git a/stix/incident/impact_assessment.py b/stix/incident/impact_assessment.py index cdc01e93..c6f0f78a 100644 --- a/stix/incident/impact_assessment.py +++ b/stix/incident/impact_assessment.py @@ -22,7 +22,7 @@ class ImpactAssessment(stix.Entity): direct_impact_summary = fields.TypedField("Direct_Impact_Summary", DirectImpactSummary) indirect_impact_summary = fields.TypedField("Indirect_Impact_Summary", IndirectImpactSummary) total_loss_estimation = fields.TypedField("Total_Loss_Estimation", TotalLossEstimation) - impact_qualification = fields.TypedField("Impact_Qualification", vocabs.ImpactQualification) + impact_qualification = vocabs.VocabField("Impact_Qualification", vocabs.ImpactQualification) effects = fields.TypedField("Effects", type_="stix.incident.impact_assessment.Effects") def __init__(self): @@ -34,59 +34,6 @@ def __init__(self): self.effects = None # self.external_impact_assessment_model = None -# def to_obj(self, return_obj=None, ns_info=None): -# super(ImpactAssessment, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# obj = self._binding_class() -# -# if self.direct_impact_summary: -# obj.Direct_Impact_Summary = self.direct_impact_summary.to_obj(ns_info=ns_info) -# if self.indirect_impact_summary: -# obj.Indirect_Impact_Summary = self.indirect_impact_summary.to_obj(ns_info=ns_info) -# if self.total_loss_estimation: -# obj.Total_Loss_Estimation = self.total_loss_estimation.to_obj(ns_info=ns_info) -# if self.impact_qualification: -# obj.Impact_Qualification = self.impact_qualification.to_obj(ns_info=ns_info) -# if self.effects: -# obj.Effects = self.effects.to_obj(ns_info=ns_info) -# -# return obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.direct_impact_summary = DirectImpactSummary.from_obj(obj.Direct_Impact_Summary) -# return_obj.indirect_impact_summary = IndirectImpactSummary.from_obj(obj.Indirect_Impact_Summary) -# return_obj.total_loss_estimation = TotalLossEstimation.from_obj(obj.Total_Loss_Estimation) -# return_obj.impact_qualification = VocabString.from_obj(obj.Impact_Qualification) -# return_obj.effects = Effects.from_obj(obj.Effects) -# -# return return_obj -# -# def to_dict(self): -# return super(ImpactAssessment, self).to_dict() -# -# @classmethod -# def from_dict(cls, dict_repr, return_obj=None): -# if not dict_repr: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# get = dict_repr.get -# return_obj.direct_impact_summary = DirectImpactSummary.from_dict(get('direct_impact_summary')) -# return_obj.indirect_impact_summary = IndirectImpactSummary.from_dict(get('indirect_impact_summary')) -# return_obj.total_loss_estimation = TotalLossEstimation.from_dict(get('total_loss_estimation')) -# return_obj.impact_qualification = VocabString.from_dict(get('impact_qualification')) -# return_obj.effects = Effects.from_dict(get('effects')) -# -# return return_obj - class Effects(stix.EntityList): _namespace = "http://stix.mitre.org/Incident-1" diff --git a/stix/incident/indirect_impact_summary.py b/stix/incident/indirect_impact_summary.py index b2bfe7ec..0e2b0903 100644 --- a/stix/incident/indirect_impact_summary.py +++ b/stix/incident/indirect_impact_summary.py @@ -11,56 +11,10 @@ class IndirectImpactSummary(stix.Entity): _binding = incident_binding _binding_class = incident_binding.IndirectImpactSummaryType - loss_of_competitive_advantage = fields.TypedField("Loss_Of_Competitive_Advantage", vocabs.SecurityCompromise) - brand_and_market_damage = fields.TypedField("Brand_And_Market_Damage", vocabs.SecurityCompromise) - increased_operating_costs = fields.TypedField("Increased_Operating_Costs", vocabs.SecurityCompromise) - legal_and_regulatory_costs = fields.TypedField("Legal_And_Regulatory_Costs", vocabs.SecurityCompromise) + loss_of_competitive_advantage = vocabs.VocabField("Loss_Of_Competitive_Advantage", vocabs.SecurityCompromise) + brand_and_market_damage = vocabs.VocabField("Brand_And_Market_Damage", vocabs.SecurityCompromise) + increased_operating_costs = vocabs.VocabField("Increased_Operating_Costs", vocabs.SecurityCompromise) + legal_and_regulatory_costs = vocabs.VocabField("Legal_And_Regulatory_Costs", vocabs.SecurityCompromise) def __init__(self): super(IndirectImpactSummary, self).__init__() - -# def to_obj(self, return_obj=None, ns_info=None): -# super(IndirectImpactSummary, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# obj = self._binding_class() -# if self.loss_of_competitive_advantage: -# obj.Loss_Of_Competitive_Advantage = self.loss_of_competitive_advantage.to_obj(ns_info=ns_info) -# if self.brand_and_market_damage: -# obj.Brand_And_Market_Damage = self.brand_and_market_damage.to_obj(ns_info=ns_info) -# if self.increased_operating_costs: -# obj.Increased_Operating_Costs = self.increased_operating_costs.to_obj(ns_info=ns_info) -# if self.legal_and_regulatory_costs: -# obj.Legal_And_Regulatory_Costs = self.legal_and_regulatory_costs.to_obj(ns_info=ns_info) -# return obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.loss_of_competitive_advantage = VocabString.from_obj(obj.Loss_Of_Competitive_Advantage) -# return_obj.brand_and_market_damage = VocabString.from_obj(obj.Brand_And_Market_Damage) -# return_obj.increased_operating_costs = VocabString.from_obj(obj.Increased_Operating_Costs) -# return_obj.legal_and_regulatory_costs = VocabString.from_obj(obj.Legal_And_Regulatory_Costs) -# return return_obj -# -# def to_dict(self): -# return super(IndirectImpactSummary, self).to_dict() -# -# @classmethod -# def from_dict(cls, dict_, return_obj=None): -# if not dict_: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.loss_of_competitive_advantage = VocabString.from_dict(dict_.get('loss_of_competitive_advantage')) -# return_obj.brand_and_market_damage = VocabString.from_dict(dict_.get('brand_and_market_damage')) -# return_obj.increased_operating_costs = VocabString.from_dict(dict_.get('increased_operating_costs')) -# return_obj.legal_and_regulatory_costs = VocabString.from_dict(dict_.get('legal_and_regulatory_costs')) -# -# return return_obj diff --git a/stix/incident/property_affected.py b/stix/incident/property_affected.py index 18cf0196..7933cc47 100644 --- a/stix/incident/property_affected.py +++ b/stix/incident/property_affected.py @@ -20,14 +20,6 @@ def __init__(self, value=None, data_encrypted=None): def is_plain(self): return False - -# def to_dict(self): -# d = super(NonPublicDataCompromised, self).to_dict() -# -# if self.data_encrypted: -# d['data_encrypted'] = self.data_encrypted -# -# return d class PropertyAffected(stix.Entity): @@ -35,10 +27,10 @@ class PropertyAffected(stix.Entity): _binding = incident_binding _binding_class = incident_binding.PropertyAffectedType - property_ = fields.TypedField("Property", vocabs.LossProperty, key_name="property") + property_ = vocabs.VocabField("Property", vocabs.LossProperty, key_name="property") descriptions_of_effect = fields.TypedField("Description_Of_Effect", StructuredTextList) - type_of_availability_loss = fields.TypedField("Type_Of_Availability_Loss", vocabs.AvailabilityLossType) - duration_of_availability_loss = fields.TypedField("Duration_Of_Availability_Loss", vocabs.LossDuration) + type_of_availability_loss = vocabs.VocabField("Type_Of_Availability_Loss", vocabs.AvailabilityLossType) + duration_of_availability_loss = vocabs.VocabField("Duration_Of_Availability_Loss", vocabs.LossDuration) non_public_data_compromised = fields.TypedField("Non_Public_Data_Compromised", NonPublicDataCompromised) def __init__(self): @@ -70,54 +62,3 @@ def description_of_effect(self): @description_of_effect.setter def description_of_effect(self, value): self.descriptions_of_effect = value - -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.property_ = VocabString.from_obj(obj.Property) -# return_obj.descriptions_of_effect = StructuredTextList.from_obj(obj.Description_Of_Effect) -# return_obj.type_of_availability_loss = VocabString.from_obj(obj.Type_Of_Availability_Loss) -# return_obj.duration_of_availability_loss = VocabString.from_obj(obj.Duration_Of_Availability_Loss) -# return_obj.non_public_data_compromised = NonPublicDataCompromised.from_obj(obj.Non_Public_Data_Compromised) -# return return_obj -# -# def to_obj(self, return_obj=None, ns_info=None): -# super(PropertyAffected, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# if not return_obj: -# return_obj = self._binding_class() -# -# if self.property_: -# return_obj.Property = self.property_.to_obj(ns_info=ns_info) -# if self.descriptions_of_effect: -# return_obj.Description_Of_Effect = self.descriptions_of_effect.to_obj(ns_info=ns_info) -# if self.type_of_availability_loss: -# return_obj.Type_Of_Availability_Loss = self.type_of_availability_loss.to_obj(ns_info=ns_info) -# if self.duration_of_availability_loss: -# return_obj.Duration_Of_Availability_Loss = self.duration_of_availability_loss.to_obj(ns_info=ns_info) -# if self.non_public_data_compromised: -# return_obj.Non_Public_Data_Compromised = self.non_public_data_compromised.to_obj(ns_info=ns_info) -# -# return return_obj -# -# @classmethod -# def from_dict(cls, d, return_obj=None): -# if not d: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.property_ = VocabString.from_dict(d.get('property')) -# return_obj.descriptions_of_effect = StructuredTextList.from_dict(d.get('description_of_effect')) -# return_obj.type_of_availability_loss = VocabString.from_dict(d.get('type_of_availability_loss')) -# return_obj.duration_of_availability_loss = VocabString.from_dict(d.get('duration_of_availability_loss')) -# return_obj.non_public_data_compromised = NonPublicDataCompromised.from_dict(d.get('non_public_data_compromised')) -# -# return return_obj -# -# def to_dict(self): -# return super(PropertyAffected, self).to_dict() From bb33e263c5029fdcbcf713ecf93e82e30bd0ff12 Mon Sep 17 00:00:00 2001 From: apsillers Date: Wed, 18 Nov 2015 19:02:31 -0500 Subject: [PATCH 270/438] Make package use `version` instead of `_version` --- stix/core/stix_package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index c9d6de21..44b92f89 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -96,7 +96,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, self.id_ = id_ or idgen.create_id("Package") self.idref = idref - self._version = STIXPackage._version + self.version = STIXPackage._version self.stix_header = stix_header self.campaigns = campaigns self.courses_of_action = courses_of_action From 4f2a2f646e8b8156cf8963a2b56401da33382ef5 Mon Sep 17 00:00:00 2001 From: apsillers Date: Wed, 18 Nov 2015 19:03:49 -0500 Subject: [PATCH 271/438] Clean up underscore classes, comment blocks, VocabFields --- stix/campaign/__init__.py | 129 +------------- stix/common/activity.py | 1 - stix/common/campaign_reference.py | 1 - stix/common/information_source.py | 3 +- stix/core/stix_header.py | 2 +- stix/exploit_target/__init__.py | 2 +- stix/exploit_target/configuration.py | 14 +- .../structured_coa/generic_structured_coa.py | 2 +- .../test_mechanism/generic_test_mechanism.py | 2 + stix/incident/__init__.py | 42 +---- stix/incident/coa.py | 126 -------------- stix/incident/direct_impact_summary.py | 42 ----- stix/incident/external_id.py | 43 ----- stix/incident/history.py | 88 ---------- stix/incident/loss_estimation.py | 38 ----- stix/incident/time.py | 70 -------- stix/incident/total_loss_estimation.py | 38 ----- stix/indicator/indicator.py | 159 +----------------- stix/indicator/test_mechanism.py | 50 ------ stix/test/campaign_test.py | 12 +- stix/test/encoding_test.py | 1 + stix/test/exploit_target_test.py | 4 +- stix/test/incident_test.py | 8 - stix/ttp/__init__.py | 87 +--------- stix/ttp/attack_pattern.py | 53 ------ stix/ttp/behavior.py | 47 ------ stix/ttp/exploit.py | 47 ------ stix/ttp/infrastructure.py | 56 ------ stix/ttp/malware_instance.py | 83 +-------- stix/ttp/resource.py | 78 --------- stix/ttp/victim_targeting.py | 90 +--------- 31 files changed, 40 insertions(+), 1378 deletions(-) diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 7ebb3c62..fd644cc5 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -6,6 +6,7 @@ import stix from stix.utils import deprecated from stix.common import Activity, Confidence, Statement, VocabString +from stix.common.statement import StatementField from stix.common.related import (GenericRelationshipList, RelatedCampaign, RelatedIncident, RelatedIndicator, RelatedPackageRefs, RelatedThreatActor, RelatedTTP) @@ -103,7 +104,7 @@ class Campaign(stix.BaseCoreComponent): confidence = fields.TypedField("Confidence", Confidence) # references = fields.TypedField("Reference", multiple=True) status = VocabField("Status", CampaignStatus) - intended_effects = fields.TypedField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") + intended_effects = StatementField("Intended_Effect", Statement, vocab_type=vocabs.IntendedEffect, multiple=True, key_name="intended_effects") names = fields.TypedField("Names", Names) related_incidents = fields.TypedField("Related_Incidents", RelatedIncidents) related_indicators = fields.TypedField("Related_Indicators", RelatedIndicators) @@ -157,7 +158,6 @@ def description(self): @description.setter def description(self, value): - from stix.common.structured_text import StructuredTextList self.descriptions = StructuredTextList(value) def add_description(self, description): @@ -167,128 +167,3 @@ def add_description(self, description): """ self.descriptions.add(description) - - #@property - #def status(self): - # """The status of the Campaign. This is a :class:`VocabString` field. - - # If set to a string, an attempt will be made to convert it to a - # :class:`.CampaignStatus` object. - - # """ - # return self._status - - #@status.setter - #def status(self, value): - # self._set_vocab(vocabs.CampaignStatus, status=value) - - - -""" def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(Campaign, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if self.names: - return_obj.Names = self.names.to_obj(ns_info=ns_info) - if self.intended_effects: - return_obj.Intended_Effect = self.intended_effects.to_obj(ns_info=ns_info) - if self.status: - return_obj.Status = self.status.to_obj(ns_info=ns_info) - if self.related_ttps: - return_obj.Related_TTPs = self.related_ttps.to_obj(ns_info=ns_info) - if self.related_incidents: - return_obj.Related_Incidents = self.related_incidents.to_obj(ns_info=ns_info) - if self.related_indicators: - return_obj.Related_Indicators = self.related_indicators.to_obj(ns_info=ns_info) - if self.attribution: - return_obj.Attribution = self.attribution.to_obj(ns_info=ns_info) - if self.associated_campaigns: - return_obj.Associated_Campaigns = self.associated_campaigns.to_obj(ns_info=ns_info) - if self.confidence: - return_obj.Confidence = self.confidence.to_obj(ns_info=ns_info) - if self.activity: - return_obj.Activity = self.activity.to_obj(ns_info=ns_info) - if self.related_packages: - return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - super(Campaign, cls).from_obj(obj, return_obj=return_obj) - - if isinstance(obj, cls._binding_class): - return_obj.names = Names.from_obj(obj.Names) - return_obj.intended_effects = \ - _IntendedEffects.from_obj(obj.Intended_Effect) - return_obj.status = VocabString.from_obj(obj.Status) - return_obj.related_ttps = RelatedTTPs.from_obj(obj.Related_TTPs) - return_obj.related_incidents = \ - RelatedIncidents.from_obj(obj.Related_Incidents) - return_obj.related_indicators = \ - RelatedIndicators.from_obj(obj.Related_Indicators) - return_obj.attribution = _AttributionList.from_obj(obj.Attribution) - return_obj.associated_campaigns = \ - AssociatedCampaigns.from_obj(obj.Associated_Campaigns) - return_obj.confidence = Confidence.from_obj(obj.Confidence) - return_obj.activity = _Activities.from_obj(obj.Activity) - return_obj.related_packages = \ - RelatedPackageRefs.from_obj(obj.Related_Packages) - - return return_obj - - def to_dict(self): - return super(Campaign, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - super(Campaign, cls).from_dict(dict_repr, return_obj=return_obj) - - get = dict_repr.get # PEP 8 line lengths - return_obj.names = Names.from_dict(get('names')) - return_obj.intended_effects = \ - _IntendedEffects.from_dict(get('intended_effects')) - return_obj.status = VocabString.from_dict(get('status')) - return_obj.related_ttps = \ - RelatedTTPs.from_dict(get('related_ttps')) - return_obj.related_incidents = \ - RelatedIncidents.from_dict(get('related_incidents')) - return_obj.related_indicators = \ - RelatedIndicators.from_dict(get('related_indicators')) - return_obj.attribution = _AttributionList.from_list(get('attribution')) - return_obj.associated_campaigns = \ - AssociatedCampaigns.from_dict(get('associated_campaigns')) - return_obj.confidence = \ - Confidence.from_dict(get('confidence')) - return_obj.activity = _Activities.from_dict(get('activity')) - return_obj.related_packages = \ - RelatedPackageRefs.from_dict(get('related_packages')) - - return return_obj -""" - -# Not Actual STIX Types! -#class _Activities(stix.TypedList): -# _contained_type = Activity - - -class _IntendedEffects(stix.TypedList): - _contained_type = Statement - - def _fix_value(self, value): - intended_effect = vocabs.IntendedEffect(value) - return Statement(value=intended_effect) diff --git a/stix/common/activity.py b/stix/common/activity.py index 1ed5c2ab..7d82741d 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -21,7 +21,6 @@ class Activity(stix.Entity): def __init__(self): super(Activity, self).__init__() - self.date_time = None self.descriptions = StructuredTextList() @property diff --git a/stix/common/campaign_reference.py b/stix/common/campaign_reference.py index fc116ee5..3a9e7a38 100644 --- a/stix/common/campaign_reference.py +++ b/stix/common/campaign_reference.py @@ -26,7 +26,6 @@ def __init__(self, idref=None, timestamp=None): self.idref = idref self.timestamp = timestamp - self.names = None def add_name(self, name): self.names.append(name) diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 955c23fb..006ca08b 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -94,4 +94,5 @@ class ContributingSources(stix.EntityList): @classmethod def _dict_as_list(cls): - return False \ No newline at end of file + return False + \ No newline at end of file diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index 0caab0f7..869ae504 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -38,7 +38,7 @@ class STIXHeader(stix.Entity): title = fields.TypedField("Title", preset_hook=deprecated.field) package_intents = VocabField("Package_Intent", PackageIntent, multiple=True, preset_hook=deprecated.field) - descriptions = fields.TypedField("Description", type_=StructuredTextList)#, preset_hook=deprecated.field) + descriptions = fields.TypedField("Description", type_=StructuredTextList, preset_hook=deprecated.field) short_descriptions = fields.TypedField("Short_Description", type_=StructuredTextList, preset_hook=deprecated.field) handling = fields.TypedField("Handling", Marking) information_source = fields.TypedField("Information_Source", InformationSource) diff --git a/stix/exploit_target/__init__.py b/stix/exploit_target/__init__.py index 73668c15..8be95051 100644 --- a/stix/exploit_target/__init__.py +++ b/stix/exploit_target/__init__.py @@ -15,7 +15,7 @@ # relative from .vulnerability import Vulnerability, _Vulnerabilities # noqa from .weakness import Weakness, _Weaknesses # noqa -from .configuration import Configuration, _Configurations # noqa +from .configuration import Configuration # noqa from stix.common import InformationSource class ExploitTarget(stix.BaseCoreComponent): diff --git a/stix/exploit_target/configuration.py b/stix/exploit_target/configuration.py index 4ac5476a..e1d2c3bb 100644 --- a/stix/exploit_target/configuration.py +++ b/stix/exploit_target/configuration.py @@ -42,7 +42,9 @@ def description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions or []), None) + if self.descriptions is None: + return None + return next(iter(self.descriptions), None) @description.setter def description(self, value): @@ -53,6 +55,8 @@ def add_description(self, description): This is the same as calling "foo.descriptions.add(bar)". """ + if self.descriptions is None: + self.descriptions = StructuredTextList() self.descriptions.add(description) @property @@ -69,7 +73,9 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.short_descriptions or []), None) + if self.short_descriptions is None: + self.short_descriptions = StructuredTextList() + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): @@ -81,7 +87,3 @@ def add_short_description(self, description): This is the same as calling "foo.short_descriptions.add(bar)". """ self.short_descriptions.add(description) - -# NOT AN ACTUAL STIX TYPE! -class _Configurations(stix.TypedList): - _contained_type = Configuration diff --git a/stix/extensions/structured_coa/generic_structured_coa.py b/stix/extensions/structured_coa/generic_structured_coa.py index 82f504a6..83c2b8a1 100644 --- a/stix/extensions/structured_coa/generic_structured_coa.py +++ b/stix/extensions/structured_coa/generic_structured_coa.py @@ -50,7 +50,7 @@ def description(self): @description.setter def description(self, value): - self.descriptions = value + self.descriptions = StructuredTextList(value) def add_description(self, description): """Adds a description to the ``descriptions`` collection. diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index 5acda9f4..dd3a816b 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -54,4 +54,6 @@ def add_description(self, description): This is the same as calling "foo.descriptions.add(bar)". """ + if self.descriptions is None: + self.descriptions = StructuredTextList() self.descriptions.add(description) diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index c8d22b7f..b4397aa1 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -7,6 +7,7 @@ from stix.common import vocabs from stix.common import Statement, VocabString, InformationSource, Confidence from stix.common.vocabs import VocabField +from stix.common.statement import StatementField from stix.common.identity import Identity, IdentityFactory from stix.common.related import (GenericRelationshipList, RelatedIndicator, RelatedThreatActor, RelatedTTP, RelatedObservable, RelatedIncident, @@ -56,7 +57,7 @@ class Incident(stix.BaseCoreComponent): related_packages = fields.TypedField("Related_Packages", RelatedPackageRefs) affected_assets = fields.TypedField("Affected_Assets", type_="stix.incident.AffectedAssets") categories = fields.TypedField("Categories", type_="stix.incident.IncidentCategories") - intended_effects = fields.TypedField("Intended_Effect", Statement, multiple=True, key_name="intended_effects") + intended_effects = StatementField("Intended_Effect", Statement, vocab_type=vocabs.IntendedEffect, multiple=True, key_name="intended_effects") leveraged_ttps = fields.TypedField("Leveraged_TTPs", type_="stix.incident.LeveragedTTPs") discovery_methods = vocabs.VocabField("Discovery_Method", vocabs.DiscoveryMethod, multiple=True, key_name="discovery_methods") reporter = fields.TypedField("Reporter", InformationSource) @@ -323,42 +324,3 @@ class AffectedAssets(stix.EntityList): multiple=True, key_name="affected_assets" ) - - -# NOT ACTUAL STIX TYPES! -# -# class DiscoveryMethods(stix.TypedList): -# _contained_type = VocabString -# -# def _fix_value(self, value): -# return vocabs.DiscoveryMethod(value) -# -# -# class _COAsTaken(stix.TypedList): -# _contained_type = COATaken -# -# -# class _COAsRequested(stix.TypedList): -# _contained_type = COARequested -# -# -# class _ExternalIDs(stix.TypedList): -# _contained_type = ExternalID -# -# -# class _InformationSources(stix.TypedList): -# _contained_type = InformationSource -# -# -# class _Victims(stix.TypedList): -# _contained_type = Identity -# -# def _fix_value(self, value): -# return Identity(name=value) -# -# -# class _IntendedEffects(stix.TypedList): -# _contained_type = Statement -# -# def _fix_value(self, value): -# return Statement(value=vocabs.IntendedEffect(value)) diff --git a/stix/incident/coa.py b/stix/incident/coa.py index e36b8ebe..93a6313a 100644 --- a/stix/incident/coa.py +++ b/stix/incident/coa.py @@ -30,50 +30,6 @@ def __init__(self, course_of_action=None): def add_contributor(self, value): self.contributors.append(value) -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.time = COATime.from_obj(obj.Time) -# return_obj.contributors = Contributors.from_obj(obj.Contributors) -# return_obj.course_of_action = CourseOfAction.from_obj(obj.Course_Of_Action) -# -# return return_obj -# -# def to_obj(self, return_obj=None, ns_info=None): -# super(COATaken, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# if not return_obj: -# return_obj = self._binding_class() -# -# if self.time: -# return_obj.Time = self.time.to_obj(ns_info=ns_info) -# if self.contributors: -# return_obj.Contributors = self.contributors.to_obj(ns_info=ns_info) -# if self.course_of_action: -# return_obj.Course_Of_Action = self.course_of_action.to_obj(ns_info=ns_info) -# -# return return_obj -# -# @classmethod -# def from_dict(cls, d, return_obj=None): -# if not d: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.time = COATime.from_dict(d.get('time')) -# return_obj.contributors = Contributors.from_dict(d.get('contributors')) -# return_obj.course_of_action = CourseOfAction.from_dict(d.get('course_of_action')) -# -# return return_obj -# -# def to_dict(self): -# return super(COATaken, self).to_dict() - class COARequested(COATaken): namespace = "http://stix.mitre.org/Incident-1" @@ -85,43 +41,6 @@ class COARequested(COATaken): def __init__(self, course_of_action=None): super(COARequested, self).__init__(course_of_action=course_of_action) -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# if not return_obj: -# return_obj = cls() -# -# super(COARequested, cls).from_obj(obj, return_obj=return_obj) -# return_obj.priority = obj.priority -# -# return return_obj -# -# def to_obj(self, return_obj=None, ns_info=None): -# if not return_obj: -# return_obj = self._binding_class() -# -# super(COARequested, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# return_obj.priority = self.priority -# -# return return_obj -# -# @classmethod -# def from_dict(cls, d, return_obj=None): -# if not d: -# return None -# if not return_obj: -# return_obj = cls() -# -# super(COARequested, cls).from_dict(d, return_obj=return_obj) -# return_obj.priority = d.get('priority') -# -# return return_obj -# -# def to_dict(self): -# d = utils.to_dict(self) -# return d - class COATime(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" @@ -135,48 +54,3 @@ def __init__(self, start=None, end=None): super(COATime, self).__init__() self.start = start self.end = end - -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.start = DateTimeWithPrecision.from_obj(obj.Start) -# return_obj.end = DateTimeWithPrecision.from_obj(obj.End) -# return return_obj -# -# def to_obj(self, return_obj=None, ns_info=None): -# if not return_obj: -# return_obj = self._binding_class() -# -# super(COATime, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# if self.start: -# return_obj.Start = self.start.to_obj(ns_info=ns_info) -# if self.end: -# return_obj.End = self.end.to_obj(ns_info=ns_info) -# -# return return_obj - -# @classmethod -# def from_dict(cls, d, return_obj=None): -# if not d: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.start = DateTimeWithPrecision.from_dict(d.get('start')) -# return_obj.end = DateTimeWithPrecision.from_dict(d.get('end')) -# return return_obj -# -# def to_dict(self): -# d = {} -# -# if self.start: -# d['start'] = self.start.to_dict() -# if self.end: -# d['end'] = self.end.to_dict() -# -# return d diff --git a/stix/incident/direct_impact_summary.py b/stix/incident/direct_impact_summary.py index 2cc91a56..e7a18471 100644 --- a/stix/incident/direct_impact_summary.py +++ b/stix/incident/direct_impact_summary.py @@ -18,45 +18,3 @@ class DirectImpactSummary(stix.Entity): def __init__(self): super(DirectImpactSummary, self).__init__() - -# def to_obj(self, return_obj=None, ns_info=None): -# super(DirectImpactSummary, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# obj = self._binding_class() -# if self.asset_losses: -# obj.Asset_Losses = self.asset_losses.to_obj(ns_info=ns_info) -# if self.business_mission_disruption: -# obj.Business_Mission_Disruption = self.business_mission_disruption.to_obj(ns_info=ns_info) -# if self.response_and_recovery_costs: -# obj.Response_And_Recovery_Costs = self.response_and_recovery_costs.to_obj(ns_info=ns_info) -# return obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.asset_losses = VocabString.from_obj(obj.Asset_Losses) -# return_obj.business_mission_disruption = VocabString.from_obj(obj.Business_Mission_Disruption) -# return_obj.response_and_recovery_costs = VocabString.from_obj(obj.Response_And_Recovery_Costs) -# return return_obj -# -# def to_dict(self): -# return super(DirectImpactSummary, self).to_dict() -# -# @classmethod -# def from_dict(cls, dict_, return_obj=None): -# if not dict_: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.asset_losses = VocabString.from_dict(dict_.get('asset_losses')) -# return_obj.business_mission_disruption = VocabString.from_dict(dict_.get('business_mission_disruption')) -# return_obj.response_and_recovery_costs = VocabString.from_dict(dict_.get('response_and_recovery_costs')) -# -# return return_obj diff --git a/stix/incident/external_id.py b/stix/incident/external_id.py index f4adc3f8..b9391240 100644 --- a/stix/incident/external_id.py +++ b/stix/incident/external_id.py @@ -17,46 +17,3 @@ def __init__(self, value=None, source=None): super(ExternalID, self).__init__() self.value = value self.source = source - -# def to_obj(self, return_obj=None, ns_info=None): -# super(ExternalID, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# obj = self._binding_class() -# obj.valueOf_ = self.value -# obj.source = self.source -# return obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.value = obj.valueOf_ -# return_obj.source = obj.source -# return return_obj -# -# def to_dict(self): -# d = { -# 'value': self.value, -# 'source': self.source -# } -# return d -# -# @classmethod -# def from_dict(cls, dict_, return_obj=None): -# if not dict_: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# if not isinstance(dict_, dict): -# return_obj.value = dict_ -# else: -# return_obj.source = dict_.get('source') -# return_obj.value = dict_.get('value') -# -# return return_obj diff --git a/stix/incident/history.py b/stix/incident/history.py index 4d3e6ff1..1baf87cf 100644 --- a/stix/incident/history.py +++ b/stix/incident/history.py @@ -32,52 +32,6 @@ def __init__(self, value=None): super(JournalEntry, self).__init__() self.value = value self.time_precision = 'second' - -# def to_obj(self, return_obj=None, ns_info=None): -# super(JournalEntry, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# if not return_obj: -# return_obj = self._binding_class() -# -# return_obj.valueOf_ = self.value -# return_obj.author = self.author -# return_obj.time = utils.dates.serialize_value(self.time) -# return_obj.time_precision = self.time_precision -# -# return return_obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.value = obj.valueOf_ -# return_obj.author = obj.author -# return_obj.time = obj.time -# return_obj.time_precision = obj.time_precision -# -# return return_obj -# -# def to_dict(self): -# return super(JournalEntry, self).to_dict() -# -# @classmethod -# def from_dict(cls, d, return_obj=None): -# if not d: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.value = d.get('value') -# return_obj.author = d.get('author') -# return_obj.time = d.get('time') -# return_obj.time_precision = d.get('time_precision') -# -# return return_obj class HistoryItem(stix.Entity): @@ -90,48 +44,6 @@ class HistoryItem(stix.Entity): def __init__(self): super(HistoryItem, self).__init__() - -# def to_obj(self, return_obj=None, ns_info=None): -# super(HistoryItem, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# if not return_obj: -# return_obj = self._binding_class() -# -# if self.action_entry: -# return_obj.Action_Entry = self.action_entry.to_obj(ns_info=ns_info) -# if self.journal_entry: -# return_obj.Journal_Entry = self.journal_entry.to_obj(ns_info=ns_info) -# -# return return_obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.action_entry = COATaken.from_obj(obj.Action_Entry) -# return_obj.journal_entry = JournalEntry.from_obj(obj.Journal_Entry) -# -# return return_obj -# -# def to_dict(self): -# return super(HistoryItem, self).to_dict() -# -# @classmethod -# def from_dict(cls, d, return_obj=None): -# if not d: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.action_entry = COATaken.from_dict(d.get('action_entry')) -# return_obj.journal_entry = JournalEntry.from_dict(d.get('journal_entry')) -# -# return return_obj class History(stix.EntityList): diff --git a/stix/incident/loss_estimation.py b/stix/incident/loss_estimation.py index 5baf6681..294c027a 100644 --- a/stix/incident/loss_estimation.py +++ b/stix/incident/loss_estimation.py @@ -15,41 +15,3 @@ class LossEstimation(stix.Entity): def __init__(self): super(LossEstimation, self).__init__() - -# def to_obj(self, return_obj=None, ns_info=None): -# super(LossEstimation, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# obj = self._binding_class() -# if self.amount: -# obj.amount = self.amount -# if self.iso_currency_code: -# obj.iso_currency_code = self.iso_currency_code -# return obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.amount = obj.amount -# return_obj.iso_currency_code = obj.iso_currency_code -# return return_obj -# -# def to_dict(self): -# return super(LossEstimation, self).to_dict() -# -# @classmethod -# def from_dict(cls, dict_, return_obj=None): -# if not dict_: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.amount = dict_.get('amount') -# return_obj.iso_currency_code = dict_.get('iso_currency_code') -# -# return return_obj diff --git a/stix/incident/time.py b/stix/incident/time.py index 24ec8a64..f566b897 100644 --- a/stix/incident/time.py +++ b/stix/incident/time.py @@ -36,73 +36,3 @@ def __init__(self, first_malicious_action=None, initial_compromise=None, self.restoration_achieved = restoration_achieved self.incident_reported = incident_reported self.incident_closed = incident_closed - -# def to_obj(self, return_obj=None, ns_info=None): -# super(Time, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# if not return_obj: -# return_obj = self._binding_class() -# -# if self.first_malicious_action: -# return_obj.First_Malicious_Action = self.first_malicious_action.to_obj(ns_info=ns_info) -# if self.initial_compromise: -# return_obj.Initial_Compromise = self.initial_compromise.to_obj(ns_info=ns_info) -# if self.first_data_exfiltration: -# return_obj.First_Data_Exfiltration = self.first_data_exfiltration.to_obj(ns_info=ns_info) -# if self._incident_discovery: -# return_obj.Incident_Discovery = self.incident_discovery.to_obj(ns_info=ns_info) -# if self.incident_opened: -# return_obj.Incident_Opened = self.incident_opened.to_obj(ns_info=ns_info) -# if self.containment_achieved: -# return_obj.Containment_Achieved = self.containment_achieved.to_obj(ns_info=ns_info) -# if self.restoration_achieved: -# return_obj.Restoration_Achieved = self.restoration_achieved.to_obj(ns_info=ns_info) -# if self.incident_reported: -# return_obj.Incident_Reported = self.incident_reported.to_obj(ns_info=ns_info) -# if self.incident_closed: -# return_obj.Incident_Closed = self.incident_closed.to_obj(ns_info=ns_info) -# -# return return_obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.first_malicious_action = DateTimeWithPrecision.from_obj(obj.First_Malicious_Action) -# return_obj.initial_compromise = DateTimeWithPrecision.from_obj(obj.Initial_Compromise) -# return_obj.first_data_exfiltration = DateTimeWithPrecision.from_obj(obj.First_Data_Exfiltration) -# return_obj.incident_discovery = DateTimeWithPrecision.from_obj(obj.Incident_Discovery) -# return_obj.incident_opened = DateTimeWithPrecision.from_obj(obj.Incident_Opened) -# return_obj.containment_achieved = DateTimeWithPrecision.from_obj(obj.Containment_Achieved) -# return_obj.restoration_achieved = DateTimeWithPrecision.from_obj(obj.Restoration_Achieved) -# return_obj.incident_reported = DateTimeWithPrecision.from_obj(obj.Incident_Reported) -# return_obj.incident_closed = DateTimeWithPrecision.from_obj(obj.Incident_Closed) -# -# return return_obj -# -# def to_dict(self): -# return super(Time, self).to_dict() -# -# @classmethod -# def from_dict(cls, dict_repr, return_obj=None): -# if not dict_repr: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.first_malicious_action = DateTimeWithPrecision.from_dict(dict_repr.get('first_malicious_action')) -# return_obj.initial_compromise = DateTimeWithPrecision.from_dict(dict_repr.get('initial_compromise')) -# return_obj.first_data_exfiltration = DateTimeWithPrecision.from_dict(dict_repr.get('first_data_exfiltration')) -# return_obj.incident_discovery = DateTimeWithPrecision.from_dict(dict_repr.get('incident_discovery')) -# return_obj.incident_opened = DateTimeWithPrecision.from_dict(dict_repr.get('incident_opened')) -# return_obj.containment_achieved = DateTimeWithPrecision.from_dict(dict_repr.get('containment_achieved')) -# return_obj.restoration_achieved = DateTimeWithPrecision.from_dict(dict_repr.get('restoration_achieved')) -# return_obj.incident_reported = DateTimeWithPrecision.from_dict(dict_repr.get('incident_reported')) -# return_obj.incident_closed = DateTimeWithPrecision.from_dict(dict_repr.get('incident_closed')) -# -# return return_obj diff --git a/stix/incident/total_loss_estimation.py b/stix/incident/total_loss_estimation.py index 26132590..d7b73dfe 100644 --- a/stix/incident/total_loss_estimation.py +++ b/stix/incident/total_loss_estimation.py @@ -20,41 +20,3 @@ class TotalLossEstimation(stix.Entity): def __init__(self): super(TotalLossEstimation, self).__init__() - -# def to_obj(self, return_obj=None, ns_info=None): -# super(TotalLossEstimation, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# obj = self._binding_class() -# if self.initial_reported_total_loss_estimation: -# obj.Initial_Reported_Total_Loss_Estimation = self.initial_reported_total_loss_estimation.to_obj(ns_info=ns_info) -# if self.actual_total_loss_estimation: -# obj.Actual_Total_Loss_Estimation = self.actual_total_loss_estimation.to_obj(ns_info=ns_info) -# return obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.initial_reported_total_loss_estimation = LossEstimation.from_obj(obj.Initial_Reported_Total_Loss_Estimation) -# return_obj.actual_total_loss_estimation = LossEstimation.from_obj(obj.Actual_Total_Loss_Estimation) -# return return_obj -# -# def to_dict(self): -# return super(TotalLossEstimation, self).to_dict() -# -# @classmethod -# def from_dict(cls, dict_, return_obj=None): -# if not dict_: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.initial_reported_total_loss_estimation = LossEstimation.from_dict(dict_.get('initial_reported_total_loss_estimation')) -# return_obj.actual_total_loss_estimation = LossEstimation.from_dict(dict_.get('actual_total_loss_estimation')) -# -# return return_obj diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index c95d07f7..cabe88fa 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -209,26 +209,19 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, short_description=short_description ) - self.producer = None self.observables = None self.indicator_types = IndicatorTypes() - self.confidence = None - #self.indicated_ttps = _IndicatedTTPs() self.test_mechanisms = TestMechanisms() self.alternative_id = None self.suggested_coas = SuggestedCOAs() self.sightings = Sightings() self.composite_indicator_expression = None self.kill_chain_phases = KillChainPhasesReference() - #self.valid_time_positions = _ValidTimePositions() self.related_indicators = None self.related_campaigns = RelatedCampaignRefs() self.observable_composition_operator = "OR" - self.likely_impact = None - self.negate = None self.related_packages = RelatedPackageRefs() - @property def observables(self): """A list of ``cybox.core.Observable`` instances. This can be set to @@ -290,35 +283,7 @@ def add_observable(self, observable): instance of ``cybox.core.Observable``. """ - self.observables.append(observable) - - """ - @property - def alternative_id(self): - ""An alternative identifi er for this :class:`Indicator` - - This property can be set to a single string identifier or a list of - identifiers. If set to a single object, the object will be inserted - into an empty list internally. - - Default Value: Empty ``list`` - - Returns: - A list of alternative ids. - - "" - return self._alternative_id - - @alternative_id.setter - def alternative_id(self, value): - self._alternative_id = [] - if not value: - return - elif utils.is_sequence(value): - self._alternative_id.extend(x for x in value if x) - else: - self._alternative_id.append(value) - """ + self.observables.append(observable) def add_alternative_id(self, value): """Adds an alternative id to the ``alternative_id`` list property. @@ -335,30 +300,6 @@ def add_alternative_id(self, value): return self.alternative_id.append(value) - - """ - @property - def valid_time_positions(self): - ""A list of valid time positions for this :class:`Indicator`. - - This property can be set to a single instance or a list of - :class:`stix.indicator.valid_time.ValidTime` instances. If set to a - single instance, that object is converted into a list containing - one item. - - Default Value: Empty ``list`` - - Returns: - A list of - :class:`stix.indicator.valid_time.ValidTime` instances. - - "" - return self._valid_time_positions - - @valid_time_positions.setter - def valid_time_positions(self, value): - self._valid_time_positions = _ValidTimePositions(value) - """ def add_valid_time_position(self, value): """Adds an valid time position to the ``valid_time_positions`` property @@ -377,36 +318,6 @@ def add_valid_time_position(self, value): """ self.valid_time_positions.append(value) - """ - @property - def indicator_types(self): - ""A list of indicator types for this :class:`Indicator`. - - This property can be set to lists or single instances of ``str`` - or :class:`stix.common.vocabs.VocabString` or an instance - of :class:`IndicatorTypes`. - - Note: - If an instance of ``str`` is passed in (or a ``list`` containing - ``str`` values) an attempt will be made to convert that string - value to an instance of :class:`stix.common.vocabs.IndicatorType`. - - Default Value: An empty ``IndicatorTypes`` instance. - - See Also: - Documentation for :class:`IndicatorTypes`. - - Returns: - An instance of ``IndicatorTypes``. - - "" - return self._indicator_types - - @indicator_types.setter - def indicator_types(self, value): - self._indicator_types = IndicatorTypes(value) - """ - def add_indicator_type(self, value): """Adds a value to the ``indicator_types`` list property. @@ -744,7 +655,6 @@ def add_object(self, object_): observable = Observable(object_) self.add_observable(observable) - def to_obj(self, ns_info=None): obj = super(Indicator, self).to_obj(ns_info=ns_info) @@ -758,38 +668,6 @@ def to_obj(self, ns_info=None): return obj - """ - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - super(Indicator, cls).from_obj(obj, return_obj=return_obj) - - if isinstance(obj, cls._binding_class): - return_obj.negate = obj.negate - return_obj.producer = InformationSource.from_obj(obj.Producer) - return_obj.confidence = Confidence.from_obj(obj.Confidence) - return_obj.sightings = Sightings.from_obj(obj.Sightings) - return_obj.composite_indicator_expression = CompositeIndicatorExpression.from_obj(obj.Composite_Indicator_Expression) - return_obj.kill_chain_phases = KillChainPhasesReference.from_obj(obj.Kill_Chain_Phases) - return_obj.related_indicators = RelatedIndicators.from_obj(obj.Related_Indicators) - return_obj.likely_impact = Statement.from_obj(obj.Likely_Impact) - return_obj.indicator_types = IndicatorTypes.from_obj(obj.Type) - return_obj.test_mechanisms = TestMechanisms.from_obj(obj.Test_Mechanisms) - return_obj.suggested_coas = SuggestedCOAs.from_obj(obj.Suggested_COAs) - return_obj.alternative_id = obj.Alternative_ID - return_obj.indicated_ttps = _IndicatedTTPs.from_obj(obj.Indicated_TTP) - return_obj.valid_time_positions = _ValidTimePositions.from_obj(obj.Valid_Time_Position) - return_obj.observable = Observable.from_obj(obj.Observable) - return_obj.related_campaigns = RelatedCampaignRefs.from_obj(obj.Related_Campaigns) - return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) - - return return_obj - """ - def to_dict(self): keys = ('observables', 'observable_composition_operator', 'negate') #d = utils.to_dict(self, skip=keys) @@ -808,37 +686,6 @@ def to_dict(self): return d - """ - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - if not return_obj: - return_obj = cls() - - super(Indicator, cls).from_dict(dict_repr, return_obj=return_obj) - - get = dict_repr.get - return_obj.negate = get('negate') - return_obj.alternative_id = get('alternative_id') - return_obj.indicated_ttps = _IndicatedTTPs.from_dict(get('indicated_ttps')) - return_obj.test_mechanisms = TestMechanisms.from_list(get('test_mechanisms')) - return_obj.suggested_coas = SuggestedCOAs.from_dict(get('suggested_coas')) - return_obj.sightings = Sightings.from_dict(get('sightings')) - return_obj.composite_indicator_expression = CompositeIndicatorExpression.from_dict(get('composite_indicator_expression')) - return_obj.kill_chain_phases = KillChainPhasesReference.from_dict(get('kill_chain_phases')) - return_obj.related_indicators = RelatedIndicators.from_dict(get('related_indicators')) - return_obj.likely_impact = Statement.from_dict(get('likely_impact')) - return_obj.indicator_types = IndicatorTypes.from_list(get('indicator_types')) - return_obj.confidence = Confidence.from_dict(get('confidence')) - return_obj.valid_time_positions = _ValidTimePositions.from_dict(get('valid_time_positions')) - return_obj.observable = Observable.from_dict(get('observable')) - return_obj.producer = InformationSource.from_dict(get('producer')) - return_obj.related_campaigns = RelatedCampaignRefs.from_dict(get('related_campaigns')) - return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) - - return return_obj - """ def check_operator(composite_indicator_exp, value): allowed = CompositeIndicatorExpression.OPERATORS @@ -991,9 +838,5 @@ def _fix_value(self, value): return IndicatorType(value) -class _IndicatedTTPs(stix.TypedList): - _contained_type = RelatedTTP - - class _Observables(stix.TypedList): _contained_type = Observable diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index d075ab07..ce69d20d 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -30,56 +30,6 @@ def __init__(self, id_=None, idref=None): self.idref = idref self.efficacy = None self.producer = None - - """ - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - - - if not return_obj: - klass = stix.lookup_extension(obj) - return_obj = klass.from_obj(obj) - else: - return_obj.id_ = obj.id - return_obj.idref = obj.idref - return_obj.efficacy = Statement.from_obj(obj.Efficacy) - return_obj.producer = InformationSource.from_obj(obj.Producer) - - return return_obj - - - @staticmethod - def lookup_class(xsi_type): - if not xsi_type: - raise ValueError("xsi:type is required") - - return stix.lookup_extension(xsi_type) - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - - import stix.extensions.test_mechanism.snort_test_mechanism # noqa - import stix.extensions.test_mechanism.open_ioc_2010_test_mechanism # noqa - import stix.extensions.test_mechanism.yara_test_mechanism # noqa - import stix.extensions.test_mechanism.generic_test_mechanism # noqa - - if not return_obj: - klass = stix.lookup_extension(d.get('xsi:type')) - return_obj = klass.from_dict(d) - else: - return_obj.id_ = d.get('id') - return_obj.idref = d.get('idref') - return_obj.efficacy = Statement.from_dict(d.get('efficacy')) - return_obj.producer = InformationSource.from_dict(d.get('producer')) - - return return_obj - - """ def to_obj(self, ns_info=None): obj = super(_BaseTestMechanism, self).to_obj(ns_info=ns_info) diff --git a/stix/test/campaign_test.py b/stix/test/campaign_test.py index 16e2c8a2..e7d9ab74 100644 --- a/stix/test/campaign_test.py +++ b/stix/test/campaign_test.py @@ -29,13 +29,17 @@ class NamesTests(EntityTestCase, unittest.TestCase): ] } + class IntendedEffectsTests(TypedListTestCase, unittest.TestCase): - klass = campaign._IntendedEffects + klass = campaign.Campaign - _full_dict = [ + _partial_dict = [ statement_test.StatementTests._full_dict ] - + + _full_dict = { + 'intended_effects': _partial_dict, + } class RelatedTTPsTest(EntityTestCase, unittest.TestCase): klass = campaign.RelatedTTPs @@ -114,7 +118,7 @@ class CampaignTest(EntityTestCase, unittest.TestCase): 'description': 'A pretty novice set of actors.', 'short_description': 'novices', 'names': NamesTests._full_dict, - 'intended_effects': IntendedEffectsTests._full_dict, + 'intended_effects': IntendedEffectsTests._partial_dict, 'status': { 'value': "Ongoing", 'xsi:type':'stixVocabs:CampaignStatusVocab-1.0' diff --git a/stix/test/encoding_test.py b/stix/test/encoding_test.py index 0ff7c7a2..e84d67db 100644 --- a/stix/test/encoding_test.py +++ b/stix/test/encoding_test.py @@ -128,6 +128,7 @@ def test_to_xml_utf16_encoded(self): s = STIXHeader() s.title = UNICODE_STR xml = s.to_xml(encoding=encoding) + print xml self.assertTrue(UNICODE_STR in xml.decode(encoding)) @silence_warnings diff --git a/stix/test/exploit_target_test.py b/stix/test/exploit_target_test.py index 2395fa4e..e2e94ec5 100644 --- a/stix/test/exploit_target_test.py +++ b/stix/test/exploit_target_test.py @@ -120,9 +120,11 @@ class ConfigurationTests(EntityTestCase, unittest.TestCase): class ConfigurationsTests(TypedListTestCase, unittest.TestCase): klass = configuration._Configurations - _full_dict = [ + _inner_dict = { + "configuration": [ ConfigurationTests._full_dict ] + } class ExploitTargetTests(EntityTestCase, unittest.TestCase): diff --git a/stix/test/incident_test.py b/stix/test/incident_test.py index c4bde1b5..dbff65a7 100644 --- a/stix/test/incident_test.py +++ b/stix/test/incident_test.py @@ -409,14 +409,6 @@ class RelatedIncidentsTests(EntityTestCase, unittest.TestCase): } -class IntendedEffectsTests(TypedListTestCase, unittest.TestCase): - klass = incident._IntendedEffects - - _full_dict = [ - statement_test.StatementTests._full_dict - ] - - class DiscoveryMethodsTests(TypedListTestCase, unittest.TestCase): klass = incident.DiscoveryMethods diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index d3a44cab..4c671274 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -7,9 +7,9 @@ import stix.bindings.ttp as ttp_binding from stix.common import vocabs from stix.common import Statement -from stix.common.vocabs import IntendedEffect from stix.common.kill_chains import KillChainPhasesReference from stix.common.related import RelatedPackageRefs +from stix.common.statement import StatementField from stix.ttp.related_ttps import RelatedTTPs from stix.ttp.exploit_targets import ExploitTargets @@ -45,7 +45,7 @@ class TTP(stix.BaseCoreComponent): behavior = fields.TypedField("Behavior", Behavior) related_ttps = fields.TypedField("Related_TTPs", RelatedTTPs) - intended_effects = fields.TypedField("Intended_Effect", IntendedEffect, multiple=True) + intended_effects = StatementField("Intended_Effect", Statement, vocab_type=vocabs.IntendedEffect, multiple=True) resources = fields.TypedField("Resources", Resource) victim_targeting = fields.TypedField("Victim_Targeting", VictimTargeting) exploit_targets = fields.TypedField("Exploit_Targets", ExploitTargets) @@ -139,89 +139,6 @@ def add_related_package(self, value): """ self.related_packages.append(value) - """ - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(TTP, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if self.behavior: - return_obj.Behavior = self.behavior.to_obj(ns_info=ns_info) - if self.related_ttps: - return_obj.Related_TTPs = self.related_ttps.to_obj(ns_info=ns_info) - if self.exploit_targets: - return_obj.Exploit_Targets = self.exploit_targets.to_obj(ns_info=ns_info) - if self.intended_effects: - return_obj.Intended_Effect = self.intended_effects.to_obj(ns_info=ns_info) - if self.resources: - return_obj.Resources = self.resources.to_obj(ns_info=ns_info) - if self.victim_targeting: - return_obj.Victim_Targeting = self.victim_targeting.to_obj(ns_info=ns_info) - if self.kill_chain_phases: - return_obj.Kill_Chain_Phases = self.kill_chain_phases.to_obj(ns_info=ns_info) - if self.related_packages: - return_obj.Related_Packages = self.related_packages.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - - if not return_obj: - return_obj = cls() - - super(TTP, cls).from_obj(obj, return_obj=return_obj) - - if isinstance(obj, cls._binding_class): - return_obj.behavior = Behavior.from_obj(obj.Behavior) - return_obj.related_ttps = RelatedTTPs.from_obj(obj.Related_TTPs) - return_obj.exploit_targets = ExploitTargets.from_obj(obj.Exploit_Targets) - return_obj.resources = Resource.from_obj(obj.Resources) - return_obj.victim_targeting = VictimTargeting.from_obj(obj.Victim_Targeting) - return_obj.intended_effects = _IntendedEffects.from_obj(obj.Intended_Effect) - return_obj.kill_chain_phases = KillChainPhasesReference.from_obj(obj.Kill_Chain_Phases) - return_obj.related_packages = RelatedPackageRefs.from_obj(obj.Related_Packages) - - return return_obj - - def to_dict(self): - return super(TTP, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - super(TTP, cls).from_dict(dict_repr, return_obj=return_obj) - - get = dict_repr.get - return_obj.behavior = Behavior.from_dict(get('behavior')) - return_obj.related_ttps = RelatedTTPs.from_dict(get('related_ttps')) - return_obj.exploit_targets = ExploitTargets.from_dict(get('exploit_targets')) - return_obj.intended_effects = _IntendedEffects.from_dict(get('intended_effects')) - return_obj.resources = Resource.from_dict(get('resources')) - return_obj.victim_targeting = VictimTargeting.from_dict(get('victim_targeting')) - return_obj.related_packages = RelatedPackageRefs.from_dict(get('related_packages')) - return_obj.kill_chain_phases = KillChainPhasesReference.from_dict(get('kill_chain_phases')) - - return return_obj - """ - -# NOT ACTUAL STIX TYPE -class _IntendedEffects(stix.TypedList): - _contained_type = Statement - - def _fix_value(self, value): - intended_effect = vocabs.IntendedEffect(value) - return Statement(value=intended_effect) - - # Avoid circular imports from .related_ttps import RelatedTTPs from .exploit_targets import ExploitTargets diff --git a/stix/ttp/attack_pattern.py b/stix/ttp/attack_pattern.py index 6080e249..a292ef69 100644 --- a/stix/ttp/attack_pattern.py +++ b/stix/ttp/attack_pattern.py @@ -85,56 +85,3 @@ def add_short_description(self, description): This is the same as calling "foo.short_descriptions.add(bar)". """ self.short_descriptions.add(description) - -# def to_obj(self, return_obj=None, ns_info=None): -# super(AttackPattern, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# if not return_obj: -# return_obj = self._binding_class() -# -# return_obj.id = self.id_ -# return_obj.idref = self.idref -# return_obj.capec_id = self.capec_id -# return_obj.Title = self.title -# -# if self.descriptions: -# return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) -# if self.short_descriptions: -# return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) -# -# return return_obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.id_ = obj.id -# return_obj.idref = obj.idref -# return_obj.capec_id = obj.capec_id -# return_obj.title = obj.Title -# return_obj.descriptions = StructuredTextList.from_obj(obj.Description) -# return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) -# -# return return_obj -# -# def to_dict(self): -# return super(AttackPattern, self).to_dict() -# -# @classmethod -# def from_dict(cls, dict_repr, return_obj=None): -# if not dict_repr: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.id_ = dict_repr.get('id') -# return_obj.idref = dict_repr.get('idref') -# return_obj.capec_id = dict_repr.get('capec_id') -# return_obj.title = dict_repr.get('title') -# return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) -# return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) -# -# return return_obj diff --git a/stix/ttp/behavior.py b/stix/ttp/behavior.py index 90933f23..c6d887d2 100644 --- a/stix/ttp/behavior.py +++ b/stix/ttp/behavior.py @@ -37,53 +37,6 @@ def add_attack_pattern(self, attack_pattern): def add_exploit(self, exploit): self.exploits.append(exploit) -# def to_obj(self, return_obj=None, ns_info=None): -# super(Behavior, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# if not return_obj: -# return_obj = self._binding_class() -# -# if self.malware_instances: -# return_obj.Malware = self.malware_instances.to_obj(ns_info=ns_info) -# if self.exploits: -# return_obj.Exploits = self.exploits.to_obj(ns_info=ns_info) -# if self.attack_patterns: -# return_obj.Attack_Patterns = self.attack_patterns.to_obj(ns_info=ns_info) -# -# return return_obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# -# if not return_obj: -# return_obj = cls() -# -# return_obj.malware_instances = MalwareInstances.from_obj(obj.Malware) -# return_obj.exploits = Exploits.from_obj(obj.Exploits) -# return_obj.attack_patterns = AttackPatterns.from_obj(obj.Attack_Patterns) -# -# return return_obj -# -# def to_dict(self): -# return super(Behavior, self).to_dict() -# -# @classmethod -# def from_dict(cls, dict_repr, return_obj=None): -# if not dict_repr: -# return None -# if not return_obj: -# return_obj = cls() -# -# get = dict_repr.get -# -# return_obj.malware_instances = MalwareInstances.from_dict(get('malware_instances')) -# return_obj.exploits = Exploits.from_dict(get('exploits')) -# return_obj.attack_patterns = AttackPatterns.from_dict(get('attack_patterns')) -# -# return return_obj - class Exploits(stix.EntityList): _namespace = "http://stix.mitre.org/TTP-1" diff --git a/stix/ttp/exploit.py b/stix/ttp/exploit.py index ef2ce31c..d7e5aa13 100644 --- a/stix/ttp/exploit.py +++ b/stix/ttp/exploit.py @@ -84,50 +84,3 @@ def add_short_description(self, description): This is the same as calling "foo.short_descriptions.add(bar)". """ self.short_descriptions.add(description) - -# def to_obj(self, return_obj=None, ns_info=None): -# super(Exploit, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# if not return_obj: -# return_obj = self._binding_class() -# -# return_obj.id = self.id_ -# return_obj.Title = self.title -# -# if self.descriptions: -# return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) -# if self.short_description: -# return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) -# -# return return_obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.id_ = obj.id -# return_obj.title = obj.Title -# return_obj.descriptions = StructuredTextList.from_obj(obj.Description) -# return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) -# -# return return_obj -# -# def to_dict(self): -# return super(Exploit, self).to_dict() -# -# @classmethod -# def from_dict(cls, dict_repr, return_obj=None): -# if not dict_repr: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.id_ = dict_repr.get('id') -# return_obj.title = dict_repr.get('title') -# return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) -# return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) -# -# return return_obj diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index 0740cd0c..6bbd09b8 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -95,62 +95,6 @@ def add_short_description(self, description): def add_type(self, type_): self.types.append(type_) -# def to_obj(self, return_obj=None, ns_info=None): -# super(Infrastructure, self).to_obj(return_obj=return_obj, ns_info=ns_info) -# -# if not return_obj: -# return_obj = self._binding_class() -# -# return_obj.id = self.id_ -# return_obj.Title = self.title -# -# if self.description: -# return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) -# if self.short_description: -# return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) -# if self.types: -# return_obj.Type = [x.to_obj(ns_info=ns_info) for x in self.types] -# if self.observable_characterization: -# return_obj.Observable_Characterization = self.observable_characterization.to_obj(ns_info=ns_info) -# -# return return_obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# if not obj: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.id_ = obj.id -# return_obj.title = obj.Title -# return_obj.descriptions = StructuredTextList.from_obj(obj.Description) -# return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) -# return_obj.observable_characterization = Observables.from_obj(obj.Observable_Characterization) -# -# if obj.Type: -# return_obj.types = [VocabString.from_obj(x) for x in obj.Type] -# -# return return_obj -# -# def to_dict(self): -# return super(Infrastructure, self).to_dict() -# -# @classmethod -# def from_dict(cls, dict_repr, return_obj=None): -# if not dict_repr: -# return None -# if not return_obj: -# return_obj = cls() -# -# return_obj.id_ = dict_repr.get('id') -# return_obj.title = dict_repr.get('title') -# return_obj.descriptions = StructuredTextList.from_dict(dict_repr.get('description')) -# return_obj.short_descriptions = StructuredTextList.from_dict(dict_repr.get('short_description')) -# return_obj.types = [VocabString.from_dict(x) for x in dict_repr.get('types', [])] -# return_obj.observable_characterization = Observables.from_dict(dict_repr.get('observable_characterization')) -# -# return return_obj class InfraStructureTypes(stix.EntityList): _namespace = "http://stix.mitre.org/TTP-1" diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index 75d40ca0..0cfe4e3c 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -25,8 +25,8 @@ class MalwareInstance(Cached, stix.Entity): title = fields.TypedField("Title") descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList") short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList") - names = fields.TypedField("Name", type_="stix.ttp.malware_instance.MalwareNames", key_name="names") - types = fields.TypedField("Type", type_="stix.ttp.malware_instance.MalwareTypes", key_name="types") + names = vocabs.VocabField("Name", type_=VocabString, multiple=True, key_name="names") + types = vocabs.VocabField("Type", type_=vocabs.MalwareType, multiple=True, key_name="types") def __init__(self, id_=None, idref=None, title=None, description=None, short_description=None): super(MalwareInstance, self).__init__() @@ -102,85 +102,6 @@ def lookup_class(xsi_type): return stix.lookup_extension(xsi_type) -# def to_obj(self, return_obj=None, ns_info=None): -# super(MalwareInstance, self).to_obj(ns_info=ns_info) -# -# if not return_obj: -# return_obj = self._binding_class() -# -# return_obj.id = self.id_ -# return_obj.Title = self.title -# -# if self.descriptions: -# return_obj.Description = self.descriptions.to_obj(ns_info=ns_info) -# if self.short_descriptions: -# return_obj.Short_Description = self.short_descriptions.to_obj(ns_info=ns_info) -# if self.names: -# return_obj.Name = self.names.to_obj(ns_info=ns_info) -# if self.types: -# return_obj.Type = self.types.to_obj(ns_info=ns_info) -# -# return return_obj -# -# @classmethod -# def from_obj(cls, obj, return_obj=None): -# import stix.extensions.malware.maec_4_1_malware # noqa -# -# if not obj: -# return None -# -# if not return_obj: -# klass = stix.lookup_extension(obj, default=cls) -# return_obj = klass.from_obj(obj, klass()) -# else: -# return_obj.id_ = obj.id -# return_obj.title = obj.Title -# return_obj.descriptions = StructuredTextList.from_obj(obj.Description) -# return_obj.short_descriptions = StructuredTextList.from_obj(obj.Short_Description) -# return_obj.names = MalwareNames.from_obj(obj.Name) -# return_obj.types = MalwareTypes.from_obj(obj.Type) -# -# return return_obj -# -# def to_dict(self): -# d = utils.to_dict(self) -# -# if getattr(self, '_XSI_TYPE', None): -# d['xsi:type'] = self._XSI_TYPE -# -# return d -# -# @classmethod -# def from_dict(cls, dict_repr, return_obj=None): -# from stix.extensions.malware import maec_4_1_malware # noqa -# -# if not dict_repr: -# return None -# -# get = dict_repr.get -# -# if not return_obj: -# klass = stix.lookup_extension(get('xsi:type'), cls) -# return_obj = klass.from_dict(dict_repr, klass()) -# else: -# return_obj.id_ = get('id') -# return_obj.title = get('title') -# return_obj.descriptions = StructuredTextList.from_dict(get('description')) -# return_obj.short_descriptions = StructuredTextList.from_dict(get('short_description')) -# return_obj.names = MalwareNames.from_dict(get('names')) -# return_obj.types = MalwareTypes.from_dict(get('types')) -# -# return return_obj - -class MalwareNames(stix.TypedList): - _contained_type = VocabString - - -class MalwareTypes(stix.TypedList): - _contained_type = VocabString - - def _fix_value(self, value): - return vocabs.MalwareType(value) # Backwards compatibility diff --git a/stix/ttp/resource.py b/stix/ttp/resource.py index 43f338b3..2b8240e2 100644 --- a/stix/ttp/resource.py +++ b/stix/ttp/resource.py @@ -57,81 +57,3 @@ def __init__(self, tools=None, infrastructure=None, personas=None): self.tools = tools self.infrastructure = infrastructure self.personas = personas - - # @property - # def tools(self): - # return self._tools - # - # @tools.setter - # def tools(self, value): - # self._tools = Tools(value) - - def add_tool(self, tool): - self.tools.append(tool) - - # @property - # def infrastructure(self): - # return self._infrastructure - # - # @infrastructure.setter - # def infrastructure(self, value): - # self._infrastructure = value - # - # @property - # def personas(self): - # return self._personas - # - # @personas.setter - # def personas(self, value): - # self._personas = Personas(value) - - def add_persona(self, persona): - self.personas.append(persona) - # - # def to_obj(self, return_obj=None, ns_info=None): - # super(Resource, self).to_obj(return_obj=return_obj, ns_info=ns_info) - # - # if not return_obj: - # return_obj = self._binding_class() - # - # if self.tools: - # return_obj.Tools = self.tools.to_obj(ns_info=ns_info) - # if self.infrastructure: - # return_obj.Infrastructure = self.infrastructure.to_obj(ns_info=ns_info) - # if self.personas: - # return_obj.Personas = self.personas.to_obj(ns_info=ns_info) - # - # return return_obj - # - # @classmethod - # def from_obj(cls, obj, return_obj=None): - # if not obj: - # return None - # - # if not return_obj: - # return_obj = cls() - # - # return_obj.infrastructure = Infrastructure.from_obj(obj.Infrastructure) - # return_obj.tools = Tools.from_obj(obj.Tools) - # return_obj.personas = Personas.from_obj(obj.Personas) - # - # return return_obj - # - # def to_dict(self): - # return super(Resource, self).to_dict() - # - # @classmethod - # def from_dict(cls, dict_repr, return_obj=None): - # if not dict_repr: - # return None - # - # if not return_obj: - # return_obj = cls() - # - # get = dict_repr.get - # - # return_obj.tools = Tools.from_dict(get('tools')) - # return_obj.infrastructure = Infrastructure.from_dict(get('infrastructure')) - # return_obj.personas = Personas.from_dict(get('personas')) - # - # return return_obj diff --git a/stix/ttp/victim_targeting.py b/stix/ttp/victim_targeting.py index 432b33a2..2eff70a4 100644 --- a/stix/ttp/victim_targeting.py +++ b/stix/ttp/victim_targeting.py @@ -16,97 +16,15 @@ class VictimTargeting(stix.Entity): _namespace = "http://stix.mitre.org/TTP-1" identity = fields.TypedField("Identity", Identity) - targeted_systems = fields.TypedField("Targeted_Systems", "stix.ttp.victim_targeting.TargetedSystems") - targeted_information = fields.TypedField("Targeted_Information", "stix.ttp.victim_targeting.TargetedInformation") + + targeted_systems = vocabs.VocabField("Targeted_Systems", vocabs.SystemType, multiple=True) + targeted_information = vocabs.VocabField("Targeted_Information", vocabs.InformationType, multiple=True) def __init__(self): - self.identity = None - self.targeted_systems = None - self.targeted_information = None - self.targeted_technical_details = None + super(VictimTargeting, self).__init__() def add_targeted_system(self, system): self._targeted_systems.append(system) - @property - def targeted_information(self): - return self._targeted_information - - @targeted_information.setter - def targeted_information(self, value): - self._targeted_information = TargetedInformation(value) - def add_targeted_information(self, targeted_information): self._targeted_information.append(targeted_information) - - @property - def targeted_technical_details(self): - return self._targeted_technical_details - - @targeted_technical_details.setter - def targeted_technical_details(self, value): - self._set_var(Observables, targeted_technical_details=value) - - def to_obj(self, return_obj=None, ns_info=None): - super(VictimTargeting, self).to_obj(return_obj=return_obj, ns_info=ns_info) - - if not return_obj: - return_obj = self._binding_class() - - if self.identity: - return_obj.Identity = self.identity.to_obj(ns_info=ns_info) - if self.targeted_information: - return_obj.Targeted_Information = self.targeted_information.to_obj(ns_info=ns_info) - if self.targeted_systems: - return_obj.Targeted_Systems = self.targeted_systems.to_obj(ns_info=ns_info) - if self.targeted_technical_details: - return_obj.Targeted_Technical_Details = self.targeted_technical_details.to_obj(ns_info=ns_info) - - return return_obj - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - return_obj.identity = Identity.from_obj(obj.Identity) - return_obj.targeted_technical_details = Observables.from_obj(obj.Targeted_Technical_Details) - return_obj.targeted_systems = TargetedSystems.from_obj(obj.Targeted_Systems) - return_obj.targeted_information = TargetedInformation.from_obj(obj.Targeted_Information) - - return return_obj - - def to_dict(self): - return super(VictimTargeting, self).to_dict() - - @classmethod - def from_dict(cls, dict_repr, return_obj=None): - if not dict_repr: - return None - - if not return_obj: - return_obj = cls() - - get = dict_repr.get - return_obj.identity = Identity.from_dict(get('identity')) - return_obj.targeted_systems = TargetedSystems.from_dict(get('targeted_systems')) - return_obj.targeted_information = TargetedInformation.from_dict(get('targeted_information')) - return_obj.targeted_technical_details = Observables.from_dict(get('targeted_technical_details')) - - return return_obj - - -class TargetedSystems(stix.TypedList): - _contained_type = VocabString - - def _fix_value(self, value): - return vocabs.SystemType(value) - - -class TargetedInformation(stix.TypedList): - _contained_type = VocabString - - def _fix_value(self, value): - return vocabs.InformationType(value) From cb7cbd871c4ca8140183adbffb4cc7f769239020 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 19 Nov 2015 16:15:00 -0500 Subject: [PATCH 272/438] Added DeprecatedList class to depreacted module. Implemented deprecation warning in insert() rather than _is_valid() --- stix/utils/deprecated.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/stix/utils/deprecated.py b/stix/utils/deprecated.py index 43fb8fc2..66025ace 100644 --- a/stix/utils/deprecated.py +++ b/stix/utils/deprecated.py @@ -49,10 +49,19 @@ def warn(value): class IdrefDeprecatedList(TypedList): - """TypedList specialization that raises a UserWarning on ever insert() - call. + """TypedList specialization that raises a UserWarning if an inserted value + contains an idref. """ - def _is_valid(self, value): + def insert(self, idx, value): idref(value) - return super(IdrefDeprecatedList, self)._is_valid(value) \ No newline at end of file + super(IdrefDeprecatedList, self).insert(idx, value) + + +class DeprecatedList(TypedList): + """TypedList specialization that raises a UserWarning if a non-None + value is inserted. + """ + def insert(self, idx, value): + warn(value) + super(DeprecatedList, self).insert(idx, value) From 52cfc6b40e49ed8f576016ba2d88a793ef549e94 Mon Sep 17 00:00:00 2001 From: Bryan Worrell Date: Thu, 19 Nov 2015 16:15:30 -0500 Subject: [PATCH 273/438] Updated campaign.RelatedIndicators to use DeprecatedList. This fixes a unittest failure. --- stix/campaign/__init__.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index fd644cc5..5ef089e9 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -1,11 +1,12 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from functools import partial + from mixbox import fields import stix -from stix.utils import deprecated -from stix.common import Activity, Confidence, Statement, VocabString +from stix.common import Activity, Confidence, Statement from stix.common.statement import StatementField from stix.common.related import (GenericRelationshipList, RelatedCampaign, RelatedIncident, RelatedIndicator, RelatedPackageRefs, RelatedThreatActor, @@ -15,6 +16,7 @@ import stix.bindings.campaign as campaign_binding from stix.common.structured_text import StructuredTextList from stix.common.information_source import InformationSource +from stix.utils.deprecated import DeprecatedList class AssociatedCampaigns(GenericRelationshipList): @@ -46,11 +48,13 @@ class RelatedIndicators(GenericRelationshipList): _binding = campaign_binding _binding_class = campaign_binding.RelatedIndicatorsType - indicator = fields.TypedField("Related_Indicator", RelatedIndicator, multiple=True, key_name="indicators") - - def _is_valid(self, value): - deprecated.warn(value) - return super(RelatedIndicators, self)._is_valid(value) + indicator = fields.TypedField( + name="Related_Indicator", + type_=RelatedIndicator, + multiple=True, + key_name="indicators", + listfunc=partial(DeprecatedList, type=RelatedIndicator) + ) class RelatedTTPs(GenericRelationshipList): From 0b6038997eacdd524cb3129d1e37fd57573a589c Mon Sep 17 00:00:00 2001 From: rroberge Date: Mon, 23 Nov 2015 17:39:23 -0500 Subject: [PATCH 274/438] Updated front page link from mitre.org to github url In the Read Me file --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index fa18e658..26a2dd91 100644 --- a/README.rst +++ b/README.rst @@ -5,7 +5,7 @@ A python library for parsing, manipulating, and generating STIX v1.2 content. :Source: https://github.com/STIXProject/python-stix :Documentation: http://stix.readthedocs.org -:Information: http://stix.mitre.org +:Information: https://stixproject.github.io/ |travis badge| |landscape.io badge| |version badge| |downloads badge| From 81494fa91714023b4c7f742259eafcde745b8ced Mon Sep 17 00:00:00 2001 From: apsillers Date: Mon, 23 Nov 2015 18:18:05 -0500 Subject: [PATCH 275/438] Change descriptions/short_descriptions getters on Cached classes --- stix/ttp/attack_pattern.py | 8 ++++++-- stix/ttp/exploit.py | 8 ++++++-- stix/ttp/infrastructure.py | 8 ++++++-- stix/ttp/malware_instance.py | 8 ++++++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/stix/ttp/attack_pattern.py b/stix/ttp/attack_pattern.py index a292ef69..1716a6d6 100644 --- a/stix/ttp/attack_pattern.py +++ b/stix/ttp/attack_pattern.py @@ -46,7 +46,9 @@ def description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions or []), None) + if self.descriptions is None: + self.descriptions = StructuredTextList() + return next(iter(self.descriptions), None) @description.setter def description(self, value): @@ -73,7 +75,9 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.short_descriptions or []), None) + if self.short_descriptions is None: + self.short_descriptions = StructuredTextList() + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): diff --git a/stix/ttp/exploit.py b/stix/ttp/exploit.py index d7e5aa13..874082d2 100644 --- a/stix/ttp/exploit.py +++ b/stix/ttp/exploit.py @@ -45,7 +45,9 @@ def description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions or []), None) + if self.descriptions is None: + self.descriptions = StructuredTextList() + return next(iter(self.descriptions), None) @description.setter def description(self, value): @@ -72,7 +74,9 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.short_descriptions or []), None) + if self.short_descriptions is None: + self.short_descriptions = StructuredTextList() + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index 6bbd09b8..6bda4923 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -52,7 +52,9 @@ def description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions or []), None) + if self.descriptions is None: + self.descriptions = StructuredTextList() + return next(iter(self.descriptions), None) @description.setter def description(self, value): @@ -79,7 +81,9 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.short_descriptions or []), None) + if self.short_descriptions is None: + self.short_descriptions = StructuredTextList() + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index 0cfe4e3c..f8acf339 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -49,7 +49,9 @@ def description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.descriptions or []), None) + if self.descriptions is None: + self.descriptions = StructuredTextList() + return next(iter(self.descriptions), None) @description.setter def description(self, value): @@ -76,7 +78,9 @@ def short_description(self): Returns: An instance of :class:`.StructuredText` """ - return next(iter(self.short_descriptions or []), None) + if self.short_descriptions is None: + self.short_descriptions = [] + return next(iter(self.short_descriptions), None) @short_description.setter def short_description(self, value): From e95fbc47b2ade80b443c53210dda85bd7ccf18ea Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 10 Dec 2015 14:07:22 -0500 Subject: [PATCH 276/438] Add TypedFields to MAECInstance --- stix/extensions/malware/maec_4_1_malware.py | 87 ++++++++++++--------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index 4bf7b044..d80e7286 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -15,7 +15,7 @@ import stix.ttp.malware_instance from stix.ttp.malware_instance import MalwareInstance import stix.bindings.extensions.malware.maec_4_1 as ext_binding - +from mixbox import fields _MIN_PYTHON_MAEC_VERSION = '4.1.0.12' @@ -81,6 +81,20 @@ def is_maec(obj): return isinstance(obj, maecPackage) +def validate_maec_input(instance, value): + if value is None: + return + elif _MAEC_INSTALLED and is_maec(value): + return + elif mixbox.xml.is_element(value) or mixbox.xml.is_etree(value): + return + else: + error = ( + "Cannot set maec to '{0}'. Expected 'lxml.etree._Element' or " + "'maec.package.package.Package'." + ) + error = error.format(type(value)) + raise ValueError(error) @stix.register_extension class MAECInstance(MalwareInstance): @@ -91,34 +105,13 @@ class MAECInstance(MalwareInstance): _XSI_TYPE = "stix-maec:MAEC4.1InstanceType" _TAG_MAEC = "{%s}MAEC" % _namespace + maec = fields.TypedField("MAEC", preset_hook=validate_maec_input) + def __init__(self, maec=None): super(MAECInstance, self).__init__() self.__input_namespaces__ = {} self.__input_schemalocations__ = {} self.maec = maec - - @property - def maec(self): - return self._maec - - @maec.setter - def maec(self, value): - if value is None: - self._maec = None - elif _MAEC_INSTALLED and is_maec(value): - self._maec = value - elif mixbox.xml.is_element(value) or mixbox.xml.is_etree(value): - tree = mixbox.xml.get_etree(value) - root = mixbox.xml.get_etree_root(tree) - self._parse_etree(root) - self._maec = root - else: - error = ( - "Cannot set maec to '{0}'. Expected 'lxml.etree._Element' or " - "'maec.package.package.Package'." - ) - error = error.format(type(value)) - raise ValueError(error) def _parse_etree(self, root): node_tag = root.tag @@ -152,18 +145,18 @@ def _collect_namespaces(self, node): self.__input_namespaces__ = dict(node.nsmap.iteritems()) @classmethod - def from_obj(cls, obj, return_obj=None): + def from_obj(cls, obj): if not obj: return None - if not return_obj: - return_obj = cls() - - super(MAECInstance, cls).from_obj(obj, return_obj) + return_obj = cls() + if _MAEC_INSTALLED: - return_obj.maec = maecPackage.from_obj(obj.MAEC) + obj.MAEC = maecPackage.from_obj(obj.MAEC) else: - return_obj.maec = obj.MAEC + obj.MAEC = obj.MAEC + + super(MAECInstance, cls).from_obj(obj) return return_obj @@ -171,7 +164,13 @@ def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() - super(MAECInstance, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(MAECInstance, self).to_obj(ns_info=ns_info) + + if mixbox.xml.is_element(self.maec) or mixbox.xml.is_etree(self.maec): + tree = mixbox.xml.get_etree(self.maec) + root = mixbox.xml.get_etree_root(tree) + self._parse_etree(root) + self.maec = root if _MAEC_INSTALLED and isinstance(self.maec, maecPackage): return_obj.MAEC = self.maec.to_obj(ns_info=ns_info) @@ -195,18 +194,21 @@ def from_dict(cls, d, return_obj=None): if not d: return None - if not return_obj: - return_obj = cls() - - super(MAECInstance, cls).from_dict(d, return_obj) - with utils.ignored(KeyError): maec = d['maec'] + + print "FROM_DICT", maec + if isinstance(maec, dict): - return_obj.maec = cls._maec_from_dict(maec) + d['maec'] = cls._maec_from_dict(maec) else: parser = mixbox.xml.get_xml_parser() - return_obj.maec = etree.parse(StringIO(maec), parser=parser) + try: + d['maec'] = etree.parse(StringIO(maec), parser=parser) + except: + pass + + return_obj = super(MAECInstance, cls).from_dict(d) return return_obj @@ -214,6 +216,13 @@ def to_dict(self): d = super(MAECInstance, self).to_dict() if self.maec is not None: + if mixbox.xml.is_element(self.maec) or mixbox.xml.is_etree(self.maec): + tree = mixbox.xml.get_etree(self.maec) + root = mixbox.xml.get_etree_root(tree) + self._parse_etree(root) + self.maec = root + + if _MAEC_INSTALLED and isinstance(self.maec, maecPackage): d['maec'] = self.maec.to_dict() else: From 4e8b1195e56f4bbe83962ccc4d7d51b7efe3426a Mon Sep 17 00:00:00 2001 From: apsillers Date: Wed, 30 Dec 2015 11:52:58 -0500 Subject: [PATCH 277/438] Update MAECInstance ot use TypedFields --- stix/extensions/malware/maec_4_1_malware.py | 461 ++++++++++---------- 1 file changed, 230 insertions(+), 231 deletions(-) diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index d80e7286..4a0b6b21 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -1,231 +1,230 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. -# See LICENSE.txt for complete terms. - -# stdlib -from StringIO import StringIO -from distutils.version import LooseVersion - -# external -from lxml import etree -import mixbox.xml - -# internal -import stix -import stix.utils as utils -import stix.ttp.malware_instance -from stix.ttp.malware_instance import MalwareInstance -import stix.bindings.extensions.malware.maec_4_1 as ext_binding -from mixbox import fields - -_MIN_PYTHON_MAEC_VERSION = '4.1.0.12' - - -class UnsupportedVersion(Exception): - def __init__(self, message, expected, found): - super(UnsupportedVersion, self).__init__(message) - self.expected = expected - self.found = found - - -def _check_maec_version(): - """Checks that the installed python-maec has a version greater than or - equal to the minimum supported version. - - Note: - We do this rather than having a python-maec dependency requirement - listed in setup.py because MAEC is used as an extension to STIX and - not a core component to STIX (like CybOX). - - Raises: - ImportError: If python-maec is not installed. - UnsupportedVersion: If the python-maec installation does not satisfy - the version requirements. - - """ - import maec - - found = maec.__version__ - expected = _MIN_PYTHON_MAEC_VERSION - - if LooseVersion(found) >= LooseVersion(expected): - return - - fmt = ("Unsupported python-maec version installed: '%s'. Minimum version " - "is '%s'.") - error = fmt % (found, expected) - raise UnsupportedVersion(error, expected=expected, found=found) - - -try: - # Check that the correct version of python-maec is installed. - _check_maec_version() - - # Import maecPackage into global space - from maec.package.package import Package as maecPackage - - _MAEC_INSTALLED = True -except ImportError: - maecPackage, Package = None, None - _MAEC_INSTALLED = False - - -def is_maec(obj): - """Checks if the input object is python-maec object. - - Returns: - True if python-maec is ins - - """ - if not _MAEC_INSTALLED: - return False - - return isinstance(obj, maecPackage) - -def validate_maec_input(instance, value): - if value is None: - return - elif _MAEC_INSTALLED and is_maec(value): - return - elif mixbox.xml.is_element(value) or mixbox.xml.is_etree(value): - return - else: - error = ( - "Cannot set maec to '{0}'. Expected 'lxml.etree._Element' or " - "'maec.package.package.Package'." - ) - error = error.format(type(value)) - raise ValueError(error) - -@stix.register_extension -class MAECInstance(MalwareInstance): - _binding = ext_binding - _binding_class = _binding.MAEC4_1InstanceType - _namespace = 'http://stix.mitre.org/extensions/Malware#MAEC4.1-1' - _xml_ns_prefix = "stix-maec" - _XSI_TYPE = "stix-maec:MAEC4.1InstanceType" - _TAG_MAEC = "{%s}MAEC" % _namespace - - maec = fields.TypedField("MAEC", preset_hook=validate_maec_input) - - def __init__(self, maec=None): - super(MAECInstance, self).__init__() - self.__input_namespaces__ = {} - self.__input_schemalocations__ = {} - self.maec = maec - - def _parse_etree(self, root): - node_tag = root.tag - - if node_tag != self._TAG_MAEC: - self._cast_maec(root) - - self._collect_namespaces(root) - self._collect_schemalocs(root) - - def _cast_maec(self, node): - ns_maec = "http://maec.mitre.org/XMLSchema/maec-package-2" - node_ns = etree.QName(node).namespace - - if node_ns == ns_maec: - etree.register_namespace(self._xml_ns_prefix, self._namespace) - node.tag = self._TAG_MAEC - else: - error = "Cannot set maec. Expected tag '{0}' found '{1}'." - error = error.format(self._TAG_MAEC, node.tag) - raise ValueError(error) - - def _collect_schemalocs(self, node): - try: - schemaloc = mixbox.xml.get_schemaloc_pairs(node) - self.__input_schemalocations__ = dict(schemaloc) - except KeyError: - self.__input_schemalocations__ = {} - - def _collect_namespaces(self, node): - self.__input_namespaces__ = dict(node.nsmap.iteritems()) - - @classmethod - def from_obj(cls, obj): - if not obj: - return None - - return_obj = cls() - - if _MAEC_INSTALLED: - obj.MAEC = maecPackage.from_obj(obj.MAEC) - else: - obj.MAEC = obj.MAEC - - super(MAECInstance, cls).from_obj(obj) - - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(MAECInstance, self).to_obj(ns_info=ns_info) - - if mixbox.xml.is_element(self.maec) or mixbox.xml.is_etree(self.maec): - tree = mixbox.xml.get_etree(self.maec) - root = mixbox.xml.get_etree_root(tree) - self._parse_etree(root) - self.maec = root - - if _MAEC_INSTALLED and isinstance(self.maec, maecPackage): - return_obj.MAEC = self.maec.to_obj(ns_info=ns_info) - else: - return_obj.MAEC = self.maec - - return return_obj - - @classmethod - def _maec_from_dict(cls, d): - if _MAEC_INSTALLED: - return maecPackage.from_dict(d) - - raise ValueError( - "Unable to parse 'maec' value in dictionary. Please " - "install python-maec to parse dictionary value." - ) - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - - with utils.ignored(KeyError): - maec = d['maec'] - - print "FROM_DICT", maec - - if isinstance(maec, dict): - d['maec'] = cls._maec_from_dict(maec) - else: - parser = mixbox.xml.get_xml_parser() - try: - d['maec'] = etree.parse(StringIO(maec), parser=parser) - except: - pass - - return_obj = super(MAECInstance, cls).from_dict(d) - - return return_obj - - def to_dict(self): - d = super(MAECInstance, self).to_dict() - - if self.maec is not None: - if mixbox.xml.is_element(self.maec) or mixbox.xml.is_etree(self.maec): - tree = mixbox.xml.get_etree(self.maec) - root = mixbox.xml.get_etree_root(tree) - self._parse_etree(root) - self.maec = root - - - if _MAEC_INSTALLED and isinstance(self.maec, maecPackage): - d['maec'] = self.maec.to_dict() - else: - d['maec'] = etree.tostring(self.maec) - - return d +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +# stdlib +from StringIO import StringIO +from distutils.version import LooseVersion + +# external +from lxml import etree +import mixbox.xml + +# internal +import stix +import stix.utils as utils +import stix.ttp.malware_instance +from stix.ttp.malware_instance import MalwareInstance +import stix.bindings.extensions.malware.maec_4_1 as ext_binding +from mixbox import fields +from stix.bindings.extensions.malware.maec_4_1 import maec_installed +from lxml.etree import _ElementTree + +_MIN_PYTHON_MAEC_VERSION = '4.1.0.12' + + +class UnsupportedVersion(Exception): + def __init__(self, message, expected, found): + super(UnsupportedVersion, self).__init__(message) + self.expected = expected + self.found = found + + +def _check_maec_version(): + """Checks that the installed python-maec has a version greater than or + equal to the minimum supported version. + + Note: + We do this rather than having a python-maec dependency requirement + listed in setup.py because MAEC is used as an extension to STIX and + not a core component to STIX (like CybOX). + + Raises: + ImportError: If python-maec is not installed. + UnsupportedVersion: If the python-maec installation does not satisfy + the version requirements. + + """ + import maec + + found = maec.__version__ + expected = _MIN_PYTHON_MAEC_VERSION + + if LooseVersion(found) >= LooseVersion(expected): + return + + fmt = ("Unsupported python-maec version installed: '%s'. Minimum version " + "is '%s'.") + error = fmt % (found, expected) + raise UnsupportedVersion(error, expected=expected, found=found) + + +try: + # Check that the correct version of python-maec is installed. + _check_maec_version() + + # Import maecPackage into global space + from maec.package.package import Package as maecPackage + + _MAEC_INSTALLED = True +except ImportError: + maecPackage, Package = None, None + _MAEC_INSTALLED = False + + +def is_maec(obj): + """Checks if the input object is python-maec object. + + Returns: + True if python-maec is ins + + """ + if not _MAEC_INSTALLED: + return False + + return isinstance(obj, maecPackage) + +def validate_maec_input(instance, value): + if value is None: + return + elif _MAEC_INSTALLED and is_maec(value): + return + elif mixbox.xml.is_element(value) or mixbox.xml.is_etree(value): + return + else: + error = ( + "Cannot set maec to '{0}'. Expected 'lxml.etree._Element' or " + "'maec.package.package.Package'." + ) + error = error.format(type(value)) + raise ValueError(error) + +@stix.register_extension +class MAECInstance(MalwareInstance): + _binding = ext_binding + _binding_class = _binding.MAEC4_1InstanceType + _namespace = 'http://stix.mitre.org/extensions/Malware#MAEC4.1-1' + _xml_ns_prefix = "stix-maec" + _XSI_TYPE = "stix-maec:MAEC4.1InstanceType" + _TAG_MAEC = "{%s}MAEC" % _namespace + + maec = fields.TypedField("MAEC", preset_hook=validate_maec_input) + + def __init__(self, maec=None): + super(MAECInstance, self).__init__() + self.__input_namespaces__ = {} + self.__input_schemalocations__ = {} + self.maec = maec + + def _parse_etree(self, root): + node_tag = root.tag + + if node_tag != self._TAG_MAEC: + self._cast_maec(root) + + self._collect_namespaces(root) + self._collect_schemalocs(root) + + def _cast_maec(self, node): + ns_maec = "http://maec.mitre.org/XMLSchema/maec-package-2" + node_ns = etree.QName(node).namespace + + if node_ns == ns_maec: + etree.register_namespace(self._xml_ns_prefix, self._namespace) + node.tag = self._TAG_MAEC + else: + error = "Cannot set maec. Expected tag '{0}' found '{1}'." + error = error.format(self._TAG_MAEC, node.tag) + raise ValueError(error) + + def _collect_schemalocs(self, node): + try: + schemaloc = mixbox.xml.get_schemaloc_pairs(node) + self.__input_schemalocations__ = dict(schemaloc) + except KeyError: + self.__input_schemalocations__ = {} + + def _collect_namespaces(self, node): + self.__input_namespaces__ = dict(node.nsmap.iteritems()) + + @classmethod + def from_obj(cls, obj): + if not obj: + return None + + return_obj = cls() + + if _MAEC_INSTALLED: + obj.MAEC = maecPackage.from_obj(obj.MAEC) + else: + obj.MAEC = obj.MAEC + + super(MAECInstance, cls).from_obj(obj) + + return return_obj + + def to_obj(self, return_obj=None, ns_info=None): + if not return_obj: + return_obj = self._binding_class() + + super(MAECInstance, self).to_obj(ns_info=ns_info) + + if mixbox.xml.is_element(self.maec) or mixbox.xml.is_etree(self.maec): + tree = mixbox.xml.get_etree(self.maec) + root = mixbox.xml.get_etree_root(tree) + self._parse_etree(root) + self.maec = root + + if _MAEC_INSTALLED and isinstance(self.maec, maecPackage): + return_obj.MAEC = self.maec.to_obj(ns_info=ns_info) + else: + return_obj.MAEC = self.maec + + return return_obj + + @classmethod + def _maec_from_dict(cls, d): + if _MAEC_INSTALLED: + return maecPackage.from_dict(d) + + raise ValueError( + "Unable to parse 'maec' value in dictionary. Please " + "install python-maec to parse dictionary value." + ) + + @classmethod + def from_dict(cls, d, return_obj=None): + if not d: + return None + + d = d.copy() + + maec = d.get('maec') + + if maec is None: + pass + elif isinstance(maec, dict): + d['maec'] = cls._maec_from_dict(maec) + elif isinstance(maec, basestring): + d['maec'] = mixbox.xml.get_etree_root(StringIO(maec)) + else: + raise TypeError("Unknown type for 'maec' entry.") + + return_obj = super(MAECInstance, cls).from_dict(d) + + return return_obj + + def to_dict(self): + d = super(MAECInstance, self).to_dict() + + if self.maec is not None: + if mixbox.xml.is_element(self.maec) or mixbox.xml.is_etree(self.maec): + tree = mixbox.xml.get_etree(self.maec) + root = mixbox.xml.get_etree_root(tree) + self._parse_etree(root) + self.maec = root + d['maec'] = etree.tostring(self.maec) + elif _MAEC_INSTALLED and isinstance(self.maec, maecPackage): + d['maec'] = self.maec.to_dict() + else: + d['maec'] = self.maec.to_dict() + return d From 295d155112112e9a9308cd1ba1195314f3328b2c Mon Sep 17 00:00:00 2001 From: apsillers Date: Wed, 30 Dec 2015 11:55:31 -0500 Subject: [PATCH 278/438] Fix logic for MAECInstance's ElementTree to_dict path --- stix/extensions/malware/maec_4_1_malware.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index 4a0b6b21..12f447a9 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -222,9 +222,9 @@ def to_dict(self): root = mixbox.xml.get_etree_root(tree) self._parse_etree(root) self.maec = root - d['maec'] = etree.tostring(self.maec) - elif _MAEC_INSTALLED and isinstance(self.maec, maecPackage): + + if _MAEC_INSTALLED and isinstance(self.maec, maecPackage): d['maec'] = self.maec.to_dict() else: - d['maec'] = self.maec.to_dict() + d['maec'] = etree.tostring(self.maec) return d From b7eb15906e295b9fc051b03f4b717374757b35f3 Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 31 Dec 2015 19:18:36 -0500 Subject: [PATCH 279/438] Add XSI_TYPE to MAECInstance dict --- stix/extensions/malware/maec_4_1_malware.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index 12f447a9..cb088205 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -227,4 +227,8 @@ def to_dict(self): d['maec'] = self.maec.to_dict() else: d['maec'] = etree.tostring(self.maec) + + if self._XSI_TYPE: + d['xsi:type'] = self._XSI_TYPE + return d From 0fcab99caab0bbc8355ba73f917857ed2dea1df1 Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 31 Dec 2015 19:19:10 -0500 Subject: [PATCH 280/438] Add TypedField to IOC Text Mechanism --- .../open_ioc_2010_test_mechanism.py | 223 +++++++++--------- 1 file changed, 109 insertions(+), 114 deletions(-) diff --git a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py index f7ae9eff..3d285c4d 100644 --- a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py +++ b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py @@ -1,114 +1,109 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. -# See LICENSE.txt for complete terms. - -# stdlib -from StringIO import StringIO - -# external -from lxml import etree -import mixbox.xml - -# internal -import stix -from stix.indicator.test_mechanism import _BaseTestMechanism -import stix.bindings.extensions.test_mechanism.open_ioc_2010 as open_ioc_tm_binding - - -@stix.register_extension -class OpenIOCTestMechanism(_BaseTestMechanism): - _namespace = "http://stix.mitre.org/extensions/TestMechanism#OpenIOC2010-1" - _binding = open_ioc_tm_binding - _binding_class = _binding.OpenIOC2010TestMechanismType - _xml_ns_prefix = "stix-openioc" - _XSI_TYPE = "stix-openioc:OpenIOC2010TestMechanismType" - _TAG_IOC = "{%s}ioc" % _namespace - - def __init__(self, id_=None, idref=None): - super(OpenIOCTestMechanism, self).__init__(id_=id_, idref=idref) - self.ioc = None - self.__input_namespaces__ = {} - self.__input_schemalocations__ = {} - - @property - def ioc(self): - return self._ioc - - @ioc.setter - def ioc(self, value): - if value is None: - self._ioc = None - return - - tree = mixbox.xml.get_etree(value) - root = mixbox.xml.get_etree_root(tree) - - if root.tag != self._TAG_IOC: - self._cast_ioc(root) - - self._collect_namespaces(root) - self._collect_schemalocs(root) - self._ioc = tree - - def _collect_schemalocs(self, node): - try: - schemaloc = mixbox.xml.get_schemaloc_pairs(node) - self.__input_schemalocations__ = dict(schemaloc) - except KeyError: - self.__input_schemalocations__ = {} - - def _collect_namespaces(self, node): - self.__input_namespaces__ = dict(node.nsmap.iteritems()) - - def _cast_ioc(self, node): - ns_ioc = "http://schemas.mandiant.com/2010/ioc" - node_ns = etree.QName(node).namespace - - if node_ns == ns_ioc: - etree.register_namespace(self._xml_ns_prefix, self._namespace) - node.tag = self._TAG_IOC - else: - error = "Cannot set ioc. Expected tag '{0}' found '{1}'." - error = error.format(self._TAG_IOC, node.tag) - raise ValueError(error) - - @classmethod - def from_obj(cls, obj, return_obj=None): - if not obj: - return None - if not return_obj: - return_obj = cls() - - super(OpenIOCTestMechanism, cls).from_obj(obj, return_obj) - return_obj.ioc = obj.ioc - return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - - super(OpenIOCTestMechanism, self).to_obj(return_obj=return_obj, ns_info=ns_info) - return_obj.ioc = self.ioc - return return_obj - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - if not return_obj: - return_obj = cls() - - super(OpenIOCTestMechanism, cls).from_dict(d, return_obj) - if 'ioc' in d: - parser = mixbox.xml.get_xml_parser() - return_obj.ioc = etree.parse(StringIO(d['ioc']), parser=parser) - - return return_obj - - def to_dict(self): - d = super(OpenIOCTestMechanism, self).to_dict() - - if self.ioc: - d['ioc'] = etree.tostring(self.ioc) - - return d - +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +# stdlib +from StringIO import StringIO + +# external +from lxml import etree +import mixbox.xml +from mixbox.fields import TypedField + +# internal +import stix +from stix.indicator.test_mechanism import _BaseTestMechanism +import stix.bindings.extensions.test_mechanism.open_ioc_2010 as open_ioc_tm_binding +from mixbox.cache import instanceof + + +@stix.register_extension +class OpenIOCTestMechanism(_BaseTestMechanism): + _namespace = "http://stix.mitre.org/extensions/TestMechanism#OpenIOC2010-1" + _binding = open_ioc_tm_binding + _binding_class = _binding.OpenIOC2010TestMechanismType + _xml_ns_prefix = "stix-openioc" + _XSI_TYPE = "stix-openioc:OpenIOC2010TestMechanismType" + _TAG_IOC = "{%s}ioc" % _namespace + + ioc = TypedField("ioc") + + def __init__(self, id_=None, idref=None): + super(OpenIOCTestMechanism, self).__init__(id_=id_, idref=idref) + self.ioc = None + self.__input_namespaces__ = {} + self.__input_schemalocations__ = {} + + def _collect_schemalocs(self, node): + try: + schemaloc = mixbox.xml.get_schemaloc_pairs(node) + self.__input_schemalocations__ = dict(schemaloc) + except KeyError: + self.__input_schemalocations__ = {} + + def _collect_namespaces(self, node): + self.__input_namespaces__ = dict(node.nsmap.iteritems()) + + def _cast_ioc(self, node): + ns_ioc = "http://schemas.mandiant.com/2010/ioc" + node_ns = etree.QName(node).namespace + + if node_ns == ns_ioc: + etree.register_namespace(self._xml_ns_prefix, self._namespace) + node.tag = self._TAG_IOC + else: + error = "Cannot set ioc. Expected tag '{0}' found '{1}'." + error = error.format(self._TAG_IOC, node.tag) + raise ValueError(error) + + def _processed_ioc(self): + if self.ioc is None: + return None + + tree = mixbox.xml.get_etree(self.ioc) + root = mixbox.xml.get_etree_root(tree) + + if root.tag != self._TAG_IOC: + self._cast_ioc(root) + + self._collect_namespaces(root) + self._collect_schemalocs(root) + return tree + + @classmethod + def from_obj(cls, obj): + if not obj: + return None + + return_obj = super(OpenIOCTestMechanism, cls).from_obj(obj) + return_obj.ioc = obj.ioc + return return_obj + + def to_obj(self, return_obj=None, ns_info=None): + if not return_obj: + return_obj = self._binding_class() + + super(OpenIOCTestMechanism, self).to_obj(ns_info=ns_info) + return_obj.ioc = self._processed_ioc() + return return_obj + + @classmethod + def from_dict(cls, d): + if not d: + return None + + return_obj = super(OpenIOCTestMechanism, cls).from_dict(d) + + if 'ioc' in d: + parser = mixbox.xml.get_xml_parser() + return_obj.ioc = etree.parse(StringIO(d['ioc']), parser=parser) + + return return_obj + + def to_dict(self): + d = super(OpenIOCTestMechanism, self).to_dict() + + if self.ioc: + d['ioc'] = etree.tostring(self._processed_ioc()) + + return d + From 6de788310789e72e81dcd13623724f61f3a5ba5e Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 31 Dec 2015 19:19:56 -0500 Subject: [PATCH 281/438] MalwareInstance factory --- stix/ttp/behavior.py | 126 +++++++++---------- stix/ttp/malware_instance.py | 229 ++++++++++++++++++----------------- 2 files changed, 180 insertions(+), 175 deletions(-) diff --git a/stix/ttp/behavior.py b/stix/ttp/behavior.py index c6d887d2..4d9928d4 100644 --- a/stix/ttp/behavior.py +++ b/stix/ttp/behavior.py @@ -1,63 +1,63 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. -# See LICENSE.txt for complete terms. - -# mixbox -from mixbox import fields - -# stix -import stix -import stix.bindings.ttp as ttp_binding - -from .malware_instance import MalwareInstance -from .exploit import Exploit -from .attack_pattern import AttackPattern - -class Behavior(stix.Entity): - _binding = ttp_binding - _binding_class = _binding.BehaviorType - _namespace = "http://stix.mitre.org/TTP-1" - - malware_instances = fields.TypedField("Malware", type_="stix.ttp.behavior.MalwareInstances", key_name="malware_instances") - attack_patterns = fields.TypedField("Attack_Patterns", type_="stix.ttp.behavior.AttackPatterns") - exploits = fields.TypedField("Exploits", type_="stix.ttp.behavior.Exploits") - - def __init__(self, malware_instances=None, attack_patterns=None, exploits=None): - super(Behavior, self).__init__() - self.malware_instances = malware_instances - self.attack_patterns = attack_patterns - self.exploits = exploits - - - def add_malware_instance(self, malware): - self.malware_instances.append(malware) - - def add_attack_pattern(self, attack_pattern): - self.attack_patterns.append(attack_pattern) - - def add_exploit(self, exploit): - self.exploits.append(exploit) - - -class Exploits(stix.EntityList): - _namespace = "http://stix.mitre.org/TTP-1" - _contained_type = Exploit - _binding = ttp_binding - _binding_class = _binding.ExploitsType - - exploit = fields.TypedField("Exploit", Exploit, multiple=True, key_name="exploits") - - -class MalwareInstances(stix.EntityList): - _namespace = "http://stix.mitre.org/TTP-1" - _binding = ttp_binding - _binding_class = _binding.MalwareType - - malware_instance = fields.TypedField("Malware_Instance", MalwareInstance, multiple=True, key_name="malware_instances") - - -class AttackPatterns(stix.EntityList): - _namespace = "http://stix.mitre.org/TTP-1" - _binding = ttp_binding - _binding_class = _binding.AttackPatternsType - - attack_pattern = fields.TypedField("Attack_Pattern", AttackPattern, multiple=True, key_name="attack_patterns") +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +# mixbox +from mixbox import fields + +# stix +import stix +import stix.bindings.ttp as ttp_binding + +from .malware_instance import MalwareInstance, MalwareInstanceFactory +from .exploit import Exploit +from .attack_pattern import AttackPattern + +class Behavior(stix.Entity): + _binding = ttp_binding + _binding_class = _binding.BehaviorType + _namespace = "http://stix.mitre.org/TTP-1" + + malware_instances = fields.TypedField("Malware", type_="stix.ttp.behavior.MalwareInstances", key_name="malware_instances") + attack_patterns = fields.TypedField("Attack_Patterns", type_="stix.ttp.behavior.AttackPatterns") + exploits = fields.TypedField("Exploits", type_="stix.ttp.behavior.Exploits") + + def __init__(self, malware_instances=None, attack_patterns=None, exploits=None): + super(Behavior, self).__init__() + self.malware_instances = malware_instances + self.attack_patterns = attack_patterns + self.exploits = exploits + + + def add_malware_instance(self, malware): + self.malware_instances.append(malware) + + def add_attack_pattern(self, attack_pattern): + self.attack_patterns.append(attack_pattern) + + def add_exploit(self, exploit): + self.exploits.append(exploit) + + +class Exploits(stix.EntityList): + _namespace = "http://stix.mitre.org/TTP-1" + _contained_type = Exploit + _binding = ttp_binding + _binding_class = _binding.ExploitsType + + exploit = fields.TypedField("Exploit", Exploit, multiple=True, key_name="exploits") + + +class MalwareInstances(stix.EntityList): + _namespace = "http://stix.mitre.org/TTP-1" + _binding = ttp_binding + _binding_class = _binding.MalwareType + + malware_instance = fields.TypedField("Malware_Instance", MalwareInstance, multiple=True, factory=MalwareInstanceFactory, key_name="malware_instances") + + +class AttackPatterns(stix.EntityList): + _namespace = "http://stix.mitre.org/TTP-1" + _binding = ttp_binding + _binding_class = _binding.AttackPatternsType + + attack_pattern = fields.TypedField("Attack_Pattern", AttackPattern, multiple=True, key_name="attack_patterns") diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index f8acf339..5e550ea6 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -1,112 +1,117 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. -# See LICENSE.txt for complete terms. - -# external -from mixbox.cache import Cached - -# internal -import stix -import stix.utils as utils -from stix.common import vocabs -from stix.common import StructuredTextList, VocabString - -# bindings -import stix.bindings.ttp as ttp_binding - -from mixbox import fields, entities - -class MalwareInstance(Cached, stix.Entity): - _binding = ttp_binding - _binding_class = _binding.MalwareInstanceType - _namespace = "http://stix.mitre.org/TTP-1" - - id_ = fields.IdField("id") - idref = fields.IdrefField("idref") - title = fields.TypedField("Title") - descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList") - short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList") - names = vocabs.VocabField("Name", type_=VocabString, multiple=True, key_name="names") - types = vocabs.VocabField("Type", type_=vocabs.MalwareType, multiple=True, key_name="types") - - def __init__(self, id_=None, idref=None, title=None, description=None, short_description=None): - super(MalwareInstance, self).__init__() - self.id_ = id_ - self.idref = idref - self.title = title - self.description = description - self.short_description = short_description - - @property - def description(self): - """A single description about the contents or purpose of this object. - - Default Value: ``None`` - - Note: - If this object has more than one description set, this will return - the description with the lowest ordinality value. - - Returns: - An instance of :class:`.StructuredText` - """ - if self.descriptions is None: - self.descriptions = StructuredTextList() - return next(iter(self.descriptions), None) - - @description.setter - def description(self, value): - self.descriptions = value - - def add_description(self, description): - """Adds a description to the ``descriptions`` collection. - - This is the same as calling "foo.descriptions.add(bar)". - """ - self.descriptions.add(description) - - @property - def short_description(self): - """A single short description about the contents or purpose of this - object. - - Default Value: ``None`` - - Note: - If this object has more than one short description set, this will - return the description with the lowest ordinality value. - - Returns: - An instance of :class:`.StructuredText` - """ - if self.short_descriptions is None: - self.short_descriptions = [] - return next(iter(self.short_descriptions), None) - - @short_description.setter - def short_description(self, value): - self.short_descriptions = value - - def add_short_description(self, description): - """Adds a description to the ``short_descriptions`` collection. - - This is the same as calling "foo.short_descriptions.add(bar)". - """ - self.short_descriptions.add(description) - - def add_name(self, name): - self._names.append(name) - - def add_type(self, type_): - self._types.append(type_) - - @staticmethod - def lookup_class(xsi_type): - if not xsi_type: - raise ValueError("xsi:type is required") - - return stix.lookup_extension(xsi_type) - - - -# Backwards compatibility -add_extension = stix.add_extension +# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +# external +from mixbox.cache import Cached + +# internal +import stix +import stix.utils as utils +from stix.common import vocabs +from stix.common import StructuredTextList, VocabString + +# bindings +import stix.bindings.ttp as ttp_binding + +from mixbox import fields, entities + +class MalwareInstance(Cached, stix.Entity): + _binding = ttp_binding + _binding_class = _binding.MalwareInstanceType + _namespace = "http://stix.mitre.org/TTP-1" + _XSI_TYPE = None # defined by subclasses + + id_ = fields.IdField("id") + idref = fields.IdrefField("idref") + title = fields.TypedField("Title") + descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList") + short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList") + names = vocabs.VocabField("Name", type_=VocabString, multiple=True, key_name="names") + types = vocabs.VocabField("Type", type_=vocabs.MalwareType, multiple=True, key_name="types") + + def __init__(self, id_=None, idref=None, title=None, description=None, short_description=None): + super(MalwareInstance, self).__init__() + self.id_ = id_ + self.idref = idref + self.title = title + self.description = description + self.short_description = short_description + + @property + def description(self): + """A single description about the contents or purpose of this object. + + Default Value: ``None`` + + Note: + If this object has more than one description set, this will return + the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + """ + if self.descriptions is None: + self.descriptions = StructuredTextList() + return next(iter(self.descriptions), None) + + @description.setter + def description(self, value): + self.descriptions = value + + def add_description(self, description): + """Adds a description to the ``descriptions`` collection. + + This is the same as calling "foo.descriptions.add(bar)". + """ + self.descriptions.add(description) + + @property + def short_description(self): + """A single short description about the contents or purpose of this + object. + + Default Value: ``None`` + + Note: + If this object has more than one short description set, this will + return the description with the lowest ordinality value. + + Returns: + An instance of :class:`.StructuredText` + """ + if self.short_descriptions is None: + self.short_descriptions = [] + return next(iter(self.short_descriptions), None) + + @short_description.setter + def short_description(self, value): + self.short_descriptions = value + + def add_short_description(self, description): + """Adds a description to the ``short_descriptions`` collection. + + This is the same as calling "foo.short_descriptions.add(bar)". + """ + self.short_descriptions.add(description) + + def add_name(self, name): + self._names.append(name) + + def add_type(self, type_): + self._types.append(type_) + + @staticmethod + def lookup_class(xsi_type): + if not xsi_type: + raise ValueError("xsi:type is required") + + return stix.lookup_extension(xsi_type) + + +class MalwareInstanceFactory(entities.EntityFactory): + @classmethod + def entity_class(cls, key): + val = stix.lookup_extension(key, default=MalwareInstance) + +# Backwards compatibility +add_extension = stix.add_extension From cab4b4f6e1574a4a043ce4ea334b6ddf50ec2301 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas Date: Thu, 28 Jan 2016 09:47:13 -0500 Subject: [PATCH 282/438] Strong bindings in extensions and emit() in data marking class --- stix/bindings/extensions/address/ciq_address_3_0.py | 1 + stix/bindings/extensions/attack_pattern/capec_2_7.py | 1 + stix/bindings/extensions/identity/ciq_identity_3_0.py | 1 + stix/bindings/extensions/malware/maec_4_1.py | 1 + stix/bindings/extensions/marking/simple_marking.py | 1 + stix/bindings/extensions/marking/terms_of_use_marking.py | 1 + stix/bindings/extensions/marking/tlp.py | 1 + stix/bindings/extensions/structured_coa/generic.py | 1 + stix/bindings/extensions/test_mechanism/generic.py | 1 + stix/bindings/extensions/test_mechanism/open_ioc_2010.py | 1 + stix/bindings/extensions/test_mechanism/oval_5_10.py | 1 + stix/bindings/extensions/test_mechanism/snort.py | 1 + stix/bindings/extensions/test_mechanism/yara.py | 1 + stix/bindings/extensions/vulnerability/cvrf_1_1.py | 1 + stix/data_marking.py | 3 ++- 15 files changed, 16 insertions(+), 1 deletion(-) diff --git a/stix/bindings/extensions/address/ciq_address_3_0.py b/stix/bindings/extensions/address/ciq_address_3_0.py index cd1e24de..972a713f 100644 --- a/stix/bindings/extensions/address/ciq_address_3_0.py +++ b/stix/bindings/extensions/address/ciq_address_3_0.py @@ -91,6 +91,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CIQAddr lwrite(etree_.tostring(self.Location, pretty_print=pretty_print)) #self.Location.export(lwrite, level, nsmap, namespace_, name_='Location', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/extensions/attack_pattern/capec_2_7.py b/stix/bindings/extensions/attack_pattern/capec_2_7.py index 6cc3aa0c..40b44762 100644 --- a/stix/bindings/extensions/attack_pattern/capec_2_7.py +++ b/stix/bindings/extensions/attack_pattern/capec_2_7.py @@ -90,6 +90,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CAPEC2. lwrite(etree_.tostring(self.CAPEC, pretty_print=pretty_print)) #self.CAPEC.export(lwrite, level, nsmap, namespace_, name_='CAPEC', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/extensions/identity/ciq_identity_3_0.py b/stix/bindings/extensions/identity/ciq_identity_3_0.py index 3c37c4b1..e7605230 100644 --- a/stix/bindings/extensions/identity/ciq_identity_3_0.py +++ b/stix/bindings/extensions/identity/ciq_identity_3_0.py @@ -105,6 +105,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CIQIden showIndent(lwrite, level, pretty_print) lwrite('<%s:Role>%s%s' % (nsmap[namespace_], quote_xml(Role_), nsmap[namespace_], eol_)) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/extensions/malware/maec_4_1.py b/stix/bindings/extensions/malware/maec_4_1.py index 552beed1..8c8fe0ec 100644 --- a/stix/bindings/extensions/malware/maec_4_1.py +++ b/stix/bindings/extensions/malware/maec_4_1.py @@ -94,6 +94,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='MAEC4.1 showIndent(lwrite, level, pretty_print) lwrite(etree_.tostring(self.MAEC, pretty_print=pretty_print)) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/extensions/marking/simple_marking.py b/stix/bindings/extensions/marking/simple_marking.py index 839ae146..63f229b9 100644 --- a/stix/bindings/extensions/marking/simple_marking.py +++ b/stix/bindings/extensions/marking/simple_marking.py @@ -91,6 +91,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='SimpleM showIndent(lwrite, level, pretty_print) lwrite('<%s:Statement>%s%s' % (nsmap[namespace_], quote_xml(self.Statement), nsmap[namespace_], eol_)) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/extensions/marking/terms_of_use_marking.py b/stix/bindings/extensions/marking/terms_of_use_marking.py index d9d99551..9fed0f1d 100644 --- a/stix/bindings/extensions/marking/terms_of_use_marking.py +++ b/stix/bindings/extensions/marking/terms_of_use_marking.py @@ -93,6 +93,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TermsOf showIndent(lwrite, level, pretty_print) lwrite('<%s:Terms_Of_Use>%s%s' % (nsmap[namespace_], quote_xml(self.Terms_Of_Use), nsmap[namespace_], eol_)) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/extensions/marking/tlp.py b/stix/bindings/extensions/marking/tlp.py index fecade54..ef57ec7e 100644 --- a/stix/bindings/extensions/marking/tlp.py +++ b/stix/bindings/extensions/marking/tlp.py @@ -87,6 +87,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TLPMark super(TLPMarkingStructureType, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) pass def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/extensions/structured_coa/generic.py b/stix/bindings/extensions/structured_coa/generic.py index 3ba383dd..2db4c2c5 100644 --- a/stix/bindings/extensions/structured_coa/generic.py +++ b/stix/bindings/extensions/structured_coa/generic.py @@ -112,6 +112,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Generic if self.Specification is not None: self.Specification.export(lwrite, level, nsmap, namespace_, name_='Specification', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/extensions/test_mechanism/generic.py b/stix/bindings/extensions/test_mechanism/generic.py index ca06cac1..d49ae519 100644 --- a/stix/bindings/extensions/test_mechanism/generic.py +++ b/stix/bindings/extensions/test_mechanism/generic.py @@ -112,6 +112,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='Generic if self.Specification is not None: self.Specification.export(lwrite, level, nsmap, namespace_, name_='Specification', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py index 6e1559ec..fde66eea 100644 --- a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py +++ b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py @@ -90,6 +90,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='OpenIOC lwrite(etree_.tostring(self.ioc, pretty_print=pretty_print)) #self.ioc.export(lwrite, level, nsmap, namespace_, name_='ioc', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/extensions/test_mechanism/oval_5_10.py b/stix/bindings/extensions/test_mechanism/oval_5_10.py index 565432d2..5675bebe 100644 --- a/stix/bindings/extensions/test_mechanism/oval_5_10.py +++ b/stix/bindings/extensions/test_mechanism/oval_5_10.py @@ -98,6 +98,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='OVAL5.1 lwrite(etree_.tostring(self.oval_variables, pretty_print=pretty_print)) #self.oval_variables.export(lwrite, level, nsmap, namespace_, name_='oval_variables', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/extensions/test_mechanism/snort.py b/stix/bindings/extensions/test_mechanism/snort.py index 53908ddf..b0d0eaad 100644 --- a/stix/bindings/extensions/test_mechanism/snort.py +++ b/stix/bindings/extensions/test_mechanism/snort.py @@ -140,6 +140,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='SnortTe for Event_Suppression_ in self.Event_Suppression: Event_Suppression_.export(lwrite, level, nsmap, namespace_, name_='Event_Suppression', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/extensions/test_mechanism/yara.py b/stix/bindings/extensions/test_mechanism/yara.py index 458c9945..b0d2031d 100644 --- a/stix/bindings/extensions/test_mechanism/yara.py +++ b/stix/bindings/extensions/test_mechanism/yara.py @@ -95,6 +95,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='YaraTes if self.Rule is not None: self.Rule.export(lwrite, level, nsmap, namespace_, name_='Rule', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/bindings/extensions/vulnerability/cvrf_1_1.py b/stix/bindings/extensions/vulnerability/cvrf_1_1.py index 49bc751b..85e8b64f 100644 --- a/stix/bindings/extensions/vulnerability/cvrf_1_1.py +++ b/stix/bindings/extensions/vulnerability/cvrf_1_1.py @@ -91,6 +91,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CVRF1.1 lwrite(etree_.tostring(self.cvrfdoc, pretty_print=pretty_print)) #self.cvrfdoc.export(lwrite, level, nsmap, namespace_, name_='cvrfdoc', pretty_print=pretty_print) def build(self, node): + self.__sourcenode__ = node already_processed = set() self.buildAttributes(node, node.attrib, already_processed) for child in node: diff --git a/stix/data_marking.py b/stix/data_marking.py index 73bacf67..2a0ad8b7 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -57,7 +57,7 @@ def from_obj(cls, obj, return_obj=None): return_obj = cls() return_obj.markings = _MarkingSpecifications.from_obj(obj.Marking) - + signals.emit("Entity.created.from_obj", return_obj, obj) return return_obj @classmethod @@ -241,6 +241,7 @@ def from_obj(cls, obj, return_obj=None): klass = stix.lookup_extension(obj, default=cls) m = klass.from_obj(obj, return_obj=klass()) + signals.emit("Entity.created.from_obj", return_obj, obj) return m @classmethod From a8d784e33e0e84b32b628f0f6d5776fc0b277754 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas Date: Fri, 5 Feb 2016 08:57:16 -0500 Subject: [PATCH 283/438] Utils: attr_name() return correct property --- stix/utils/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index 1b58ae0a..784ad396 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -191,6 +191,9 @@ def attr_name(name): 'title """ + if hasattr(name, "_key_name"): + return name.key_name + name = name.lower() if name.startswith("_"): From 0bcb5e4de8977ccafcb16d609e82eb52cbf98c5f Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas Date: Sat, 13 Feb 2016 15:39:01 -0500 Subject: [PATCH 284/438] attr_name() return correct value if typefield is present --- stix/utils/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index 1b58ae0a..eb4df100 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -18,7 +18,7 @@ CDATA_START = "" -CONFLICTING_NAMES = keyword.kwlist + ['id', 'type', 'range'] +CONFLICTING_NAMES = keyword.kwlist + ['id', 'type', 'range', 'object'] @contextlib.contextmanager @@ -191,6 +191,9 @@ def attr_name(name): 'title """ + if hasattr(name, "_key_name"): + name = name.key_name + name = name.lower() if name.startswith("_"): From c257136632f2e034fb666fad4e0ba209da41fdc6 Mon Sep 17 00:00:00 2001 From: apsillers Date: Wed, 24 Feb 2016 11:27:46 -0500 Subject: [PATCH 285/438] Fix MalwareInstanceFactory.entity_class --- stix/ttp/malware_instance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index 5e550ea6..7be67952 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -111,7 +111,7 @@ def lookup_class(xsi_type): class MalwareInstanceFactory(entities.EntityFactory): @classmethod def entity_class(cls, key): - val = stix.lookup_extension(key, default=MalwareInstance) + return stix.lookup_extension(key, default=MalwareInstance) # Backwards compatibility add_extension = stix.add_extension From 2f1bc392d874ef052e5b4130bf56db0d3926a6f2 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas Date: Thu, 3 Mar 2016 10:59:30 -0500 Subject: [PATCH 286/438] Fixed Typos --- stix/data_marking.py | 2 +- stix/exploit_target/vulnerability.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stix/data_marking.py b/stix/data_marking.py index 20978b4f..983788f5 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -32,7 +32,7 @@ class MarkingStructure(Cached, stix.Entity): id_ = fields.IdField("id") idref = fields.IdrefField("idref") marking_model_name = fields.TypedField("marking_model_name") - marking_mode_ref = fields.TypedField("marking_model_ref") + marking_model_ref = fields.TypedField("marking_model_ref") def __init__(self): super(MarkingStructure, self).__init__() diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index 2cfc82f1..ebf199c4 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -26,7 +26,7 @@ class Vulnerability(stix.Entity): _namespace = "http://stix.mitre.org/ExploitTarget-1" is_known = fields.BooleanField("is_known") - is_publicly_ackowledged = fields.BooleanField("is_publicly_acknowledged") + is_publicly_acknowledged = fields.BooleanField("is_publicly_acknowledged") title = fields.TypedField("Title") descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList") short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList") From b0a7930c8354f51efeb67ba613e6d08b6ff01497 Mon Sep 17 00:00:00 2001 From: apsillers Date: Wed, 23 Mar 2016 10:36:50 -0400 Subject: [PATCH 287/438] Update Entity::from_list to handle string-list input --- stix/common/vocabs.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index 072e63a6..d0ed3bff 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -69,6 +69,8 @@ def check_type(self, value): class VocabFactory(entities.EntityFactory): + _convert_strings = True + @classmethod def entity_class(cls, key): try: From 4fa18e0ab2dfe1aa6f0b543238a6dcf7b7ca1a1f Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 25 Mar 2016 10:09:35 -0400 Subject: [PATCH 288/438] Make TypedCollection.from_dict treat empty list and None differently --- stix/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stix/base.py b/stix/base.py index 9e69b320..d119f923 100644 --- a/stix/base.py +++ b/stix/base.py @@ -266,7 +266,7 @@ def to_list(self): @classmethod def from_obj(cls, obj_list, contained_type=None): - if not obj_list: + if obj_list is None: return None if not contained_type: @@ -367,7 +367,7 @@ class BaseCoreComponent(Cached, Entity): title = fields.TypedField("Title") id_ = fields.IdField("id") idref = fields.IdrefField("idref") - descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList") + descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList", ) short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList") version = fields.TypedField("version", preset_hook=_validate_version) timestamp = fields.DateTimeField("timestamp") From 33c0b5c07866b3b40cfb9586a4b74c53062ec7ba Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 25 Mar 2016 15:21:49 -0400 Subject: [PATCH 289/438] Fix TTPs type in Report --- stix/report/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/report/__init__.py b/stix/report/__init__.py index e652427b..24daeb0c 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -71,7 +71,7 @@ class Report(Cached, stix.Entity): indicators = fields.TypedField("Indicators", type_="stix.report.Indicators") incidents = fields.TypedField("Incidents", type_="stix.report.Incidents") threat_actors = fields.TypedField("Threat_Actors", type_="stix.report.ThreatActors") - ttps = fields.TypedField("TTPs", type_="stix.report.TTPs") + ttps = fields.TypedField("TTPs", type_="stix.core.ttps.TTPs") related_reports = fields.TypedField("Related_Reports", type_="stix.report.RelatedReports") def __init__(self, id_=None, idref=None, timestamp=None, header=None, From 8b2edb3e7fe2761ccc2df0d6547d8b8a606abfcd Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 25 Mar 2016 15:48:03 -0400 Subject: [PATCH 290/438] Add None-checking to Report's `add` methods --- stix/report/__init__.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/stix/report/__init__.py b/stix/report/__init__.py index 24daeb0c..5dc948e0 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -103,12 +103,16 @@ def add_indicator(self, indicator): collection. """ + if self.indicators is None: + self.indicators = Indicators() self.indicators.append(indicator) def add_campaign(self, campaign): """Adds a :class:`Campaign` object to the :attr:`campaigns` collection. """ + if self.campaigns is None: + self.campaigns = Campaigns() self.campaigns.append(campaign) def add_observable(self, observable): @@ -128,6 +132,8 @@ def add_incident(self, incident): collection. """ + if self.incidents is None: + self.incidents = Incidents() self.incidents.append(incident) def add_threat_actor(self, threat_actor): @@ -135,6 +141,8 @@ def add_threat_actor(self, threat_actor): collection. """ + if self.threat_actors is None: + self.threat_actors = ThreatActors() self._threat_actors.append(threat_actor) def add_course_of_action(self, course_of_action): @@ -142,19 +150,25 @@ def add_course_of_action(self, course_of_action): :attr:`courses_of_action` collection. """ - self._courses_of_action.append(course_of_action) + if self.courses_of_action is None: + self.courses_of_action = CoursesOfAction() + self.courses_of_action.append(course_of_action) def add_exploit_target(self, exploit_target): """Adds an :class:`.ExploitTarget` object to the :attr:`exploit_targets` collection. """ - self._exploit_targets.append(exploit_target) + if self.exploit_targets is None: + self.exploit_targets = ExploitTargets() + self.exploit_targets.append(exploit_target) def add_ttp(self, ttp): """Adds an :class:`.TTP` object to the :attr:`ttps` collection. """ + if self.ttps is None: + self.ttps = TTPs() self.ttps.append(ttp) def add_related_report(self, related_report): @@ -162,6 +176,8 @@ def add_related_report(self, related_report): :attr:`related_reports` collection. """ + if self.related_reports is None: + self.related_reports = RelatedReports() self.related_reports.append(related_report) def add(self, entity): From 5e7ca60d0aaf490a34514bbb07bdd01702b50268 Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 31 Mar 2016 13:01:00 -0400 Subject: [PATCH 291/438] Add default values to STIXPackage fields --- stix/core/stix_package.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 44b92f89..983143a6 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -98,16 +98,16 @@ def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, self.idref = idref self.version = STIXPackage._version self.stix_header = stix_header - self.campaigns = campaigns - self.courses_of_action = courses_of_action - self.exploit_targets = exploit_targets - self.observables = observables - self.indicators = indicators - self.incidents = incidents - self.threat_actors = threat_actors - self.ttps = ttps + self.campaigns = campaigns or Campaigns() + self.courses_of_action = courses_of_action or CoursesOfAction() + self.exploit_targets = exploit_targets or ExploitTargets() + self.observables = observables or Observables() + self.indicators = indicators or Indicators() + self.incidents = incidents or Incidents() + self.threat_actors = threat_actors or ThreatActors() + self.ttps = ttps or TTPs() self.related_packages = related_packages - self.reports = reports + self.reports = reports or Reports() self.timestamp = timestamp def add_indicator(self, indicator): From be5a2f53bcf5531418f28dfa185a332fd6ecddcf Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 31 Mar 2016 13:01:27 -0400 Subject: [PATCH 292/438] Revert simplification for testing framework --- stix/test/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stix/test/__init__.py b/stix/test/__init__.py index 13f40bf0..a3f5fac3 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -45,8 +45,8 @@ def inner(*args, **kwargs): def round_trip_dict(cls, dict_): - #obj = cls.object_from_dict(dict_) - #dict2 = cls.dict_from_object(obj) + obj = cls.object_from_dict(dict_) + dict2 = cls.dict_from_object(obj) api_obj = cls.from_dict(dict_) dict2 = cls.to_dict(api_obj) From 787b65bc0383324ffe66f27404fee50664398665 Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 31 Mar 2016 13:03:51 -0400 Subject: [PATCH 293/438] Import MAEC extension package in _lookup_extension --- stix/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stix/__init__.py b/stix/__init__.py index 63a139ee..7578b28e 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -45,6 +45,8 @@ def _lookup_extension(xsi_type): ValueError: If no class has been registered for the `xsi_type`. """ + import stix.extensions.malware.maec_4_1_malware + if xsi_type in _EXTENSION_MAP: return _EXTENSION_MAP[xsi_type] @@ -131,3 +133,4 @@ def supported_stix_version(): """ return ('1.1.1', '1.2') + From fbdea36b3acff649e8303af620d47c83b80966d8 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Thu, 31 Mar 2016 19:43:09 -0400 Subject: [PATCH 294/438] Fixes for exploit_target and incident nose tests. --- stix/test/exploit_target_test.py | 12 +--- stix/test/incident_test.py | 94 +++++++------------------------- 2 files changed, 22 insertions(+), 84 deletions(-) diff --git a/stix/test/exploit_target_test.py b/stix/test/exploit_target_test.py index e2e94ec5..89fe3b8a 100644 --- a/stix/test/exploit_target_test.py +++ b/stix/test/exploit_target_test.py @@ -117,16 +117,6 @@ class ConfigurationTests(EntityTestCase, unittest.TestCase): } -class ConfigurationsTests(TypedListTestCase, unittest.TestCase): - klass = configuration._Configurations - - _inner_dict = { - "configuration": [ - ConfigurationTests._full_dict - ] - } - - class ExploitTargetTests(EntityTestCase, unittest.TestCase): klass = et.ExploitTarget _full_dict = { @@ -139,7 +129,7 @@ class ExploitTargetTests(EntityTestCase, unittest.TestCase): 'short_description': "an ExploitTarget", 'vulnerabilities': VulnerabilitiesTests._full_dict, 'weaknesses': WeaknessesTests._full_dict, - 'configuration': ConfigurationsTests._full_dict, + 'configuration': [ConfigurationTests._full_dict], 'potential_coas': PotentialCOAsTests._full_dict, 'information_source': information_source_test.InformationSourceTests._full_dict, 'handling': data_marking_test.MarkingTests._full_dict, diff --git a/stix/test/incident_test.py b/stix/test/incident_test.py index dbff65a7..adfbfb9f 100644 --- a/stix/test/incident_test.py +++ b/stix/test/incident_test.py @@ -7,10 +7,11 @@ from stix.core import STIXPackage from cybox.common import StructuredText -from stix.test import EntityTestCase, TypedListTestCase, assert_warnings +from stix.test import EntityTestCase, assert_warnings from stix.test import data_marking_test from stix.test.common import ( - confidence_test, information_source_test, statement_test, related_test + confidence_test, information_source_test, related_test, identity_test, + statement_test ) import stix.common.vocabs as vocabs @@ -66,14 +67,6 @@ class COATakenTest(EntityTestCase, unittest.TestCase): } -class COAsTakenTest(TypedListTestCase, unittest.TestCase): - klass = incident._COAsTaken - - _full_dict = [ - COATakenTest._full_dict, - ] - - class COARequestedTest(EntityTestCase, unittest.TestCase): klass = incident.COARequested @@ -91,15 +84,6 @@ class COARequestedTest(EntityTestCase, unittest.TestCase): } -class COAsRequestedTest(TypedListTestCase, unittest.TestCase): - klass = incident._COAsRequested - - _full_dict = [ - COARequestedTest._full_dict, - ] - - - class JournalEntryTest(EntityTestCase, unittest.TestCase): klass = history.JournalEntry @@ -163,28 +147,13 @@ class LeveragedTTPsTest(EntityTestCase, unittest.TestCase): } -class ExternalIDsTest(TypedListTestCase, unittest.TestCase): - klass = incident._ExternalIDs - - _full_dict = [ - { - 'source': 'foo', - 'value': '478392-feb3ca-98a9ef-984392742' - }, - { - 'source': 'bar', - 'value': '478392-feb3ca-98a9ef-984392742' - }, - ] - - -class VictimsTest(TypedListTestCase, unittest.TestCase): - klass = incident._Victims +class ExternalIDTest(EntityTestCase, unittest.TestCase): + klass = incident.ExternalID - _full_dict = [ - {'name': 'Spooderman'}, - {'name': 'Spooderman'} - ] + _full_dict = { + 'source': 'foo', + 'value': '478392-feb3ca-98a9ef-984392742' + } class TimeTest(EntityTestCase, unittest.TestCase): @@ -214,19 +183,6 @@ class CategoriesTest(EntityTestCase, unittest.TestCase): ] -class InformationSourcesTest(TypedListTestCase, unittest.TestCase): - klass = incident._InformationSources - - _full_dict = [ - { - 'description': 'Test', - 'identity': { - 'name': 'Spooderman' - } - }, - ] - - class TotalLossEstimationTest(EntityTestCase, unittest.TestCase): klass = impact_assessment.TotalLossEstimation @@ -409,17 +365,6 @@ class RelatedIncidentsTests(EntityTestCase, unittest.TestCase): } -class DiscoveryMethodsTests(TypedListTestCase, unittest.TestCase): - klass = incident.DiscoveryMethods - - _full_dict = [ - { - 'value': 'Unknown', - 'xsi:type': 'stixVocabs:LocationClassVocab-1.0' - } - ] - - class IncidentTest(EntityTestCase, unittest.TestCase): klass = incident.Incident _full_dict = { @@ -430,19 +375,19 @@ class IncidentTest(EntityTestCase, unittest.TestCase): 'description': 'The Datacenter was broken into.', 'short_description': 'Short Description Title', 'handling': data_marking_test.MarkingTests._full_dict, - 'external_ids': ExternalIDsTest._full_dict, + 'external_ids': [ExternalIDTest._full_dict], 'attributed_threat_actors': AttributedThreatActorsTest._full_dict, 'categories': CategoriesTest._full_dict, - 'coa_taken': COAsTakenTest._full_dict, - 'coa_requested': COAsRequestedTest._full_dict, - 'coordinators': InformationSourcesTest._full_dict, + 'coa_taken': [COATakenTest._full_dict], + 'coa_requested': [COARequestedTest._full_dict], + 'coordinators': [information_source_test.InformationSourceTests._full_dict], 'impact_assessment': ImpactAssessmentTest._full_dict, 'leveraged_ttps': LeveragedTTPsTest._full_dict, 'related_indicators': RelatedIndicatorsTest._full_dict, 'reporter': information_source_test.InformationSourceTests._full_dict, - 'responders': InformationSourcesTest._full_dict, + 'responders': [information_source_test.InformationSourceTests._full_dict], 'time': TimeTest._full_dict, - 'victims': VictimsTest._full_dict, + 'victims': [identity_test.IdentityTests._full_dict], 'information_source': information_source_test.InformationSourceTests._full_dict, 'security_compromise': { "value": "Suspected", @@ -456,11 +401,14 @@ class IncidentTest(EntityTestCase, unittest.TestCase): 'affected_assets': AffectedAssetsTest._full_dict, 'related_observables': RelatedObservablesTest._full_dict, 'related_incidents': RelatedIncidentsTests._full_dict, - 'intended_effects': IntendedEffectsTests._full_dict, - 'discovery_methods': DiscoveryMethodsTests._full_dict, + 'intended_effects': [statement_test.StatementTests._full_dict], + 'discovery_methods': [{ + "value": "Security Alarm", + "xsi:type": "stixVocabs:DiscoveryMethodVocab-2.0" + }], 'confidence': confidence_test.ConfidenceTests._full_dict, 'related_packages': related_test.RelatedPackageRefsTests._full_dict, - 'contacts': InformationSourcesTest._full_dict, + 'contacts': [information_source_test.InformationSourceTests._full_dict], 'url': 'http://www.example.com/' } From e686d5d89cbcfc543cbb0d9bbc3dd7c777bba9ec Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Thu, 31 Mar 2016 19:47:25 -0400 Subject: [PATCH 295/438] Fixed some nonsensical if statements in nose test code, like if type(self) == type(SomeType): Which is testing against the type of a type... not what was intended! --- stix/test/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stix/test/__init__.py b/stix/test/__init__.py index a3f5fac3..612746af 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -140,7 +140,7 @@ def setUp(self): @silence_warnings def test_round_trip_full_dict(self): # Don't run this test on the base class - if type(self) == type(EntityTestCase): + if type(self) is EntityTestCase: return dict2 = round_trip_dict(self.klass, self._full_dict) @@ -159,7 +159,7 @@ def _combine(self, d): @silence_warnings def test_round_trip_full(self): # Don't run this test on the base class - if type(self) == type(EntityTestCase): + if type(self) is EntityTestCase: return ent = self.klass.from_dict(self._full_dict) @@ -181,7 +181,7 @@ class TypedListTestCase(object): @silence_warnings def test_round_trip_rt(self): - if type(self) == type(TypedListTestCase): + if type(self) is TypedListTestCase: return obj = self.klass.from_dict(self._full_dict) From edc7e54fd70593b21177fca894e3f436ac495b4e Mon Sep 17 00:00:00 2001 From: Christos Kontas Date: Tue, 12 Apr 2016 16:11:45 +0200 Subject: [PATCH 296/438] docs: fix wrong permissions of files Usually it doesn't harm for text files to have executable permissions, especially when they contain nothing more than text. Still, it is better to be defensive on similar cases. --- docs/api/common/kill_chains.rst | 0 docs/api/extensions/malware/maec_4_1_malware.rst | 0 docs/api/extensions/structured_coa/generic.rst | 0 docs/api/incident/affected_asset.rst | 0 docs/api/incident/property_affected.rst | 0 docs/api/indicator/sightings.rst | 0 docs/api/indicator/valid_time.rst | 0 docs/api/utils/utils.rst | 0 docs/examples/index.rst | 0 examples/sample.xml | 0 10 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 docs/api/common/kill_chains.rst mode change 100755 => 100644 docs/api/extensions/malware/maec_4_1_malware.rst mode change 100755 => 100644 docs/api/extensions/structured_coa/generic.rst mode change 100755 => 100644 docs/api/incident/affected_asset.rst mode change 100755 => 100644 docs/api/incident/property_affected.rst mode change 100755 => 100644 docs/api/indicator/sightings.rst mode change 100755 => 100644 docs/api/indicator/valid_time.rst mode change 100755 => 100644 docs/api/utils/utils.rst mode change 100755 => 100644 docs/examples/index.rst mode change 100755 => 100644 examples/sample.xml diff --git a/docs/api/common/kill_chains.rst b/docs/api/common/kill_chains.rst old mode 100755 new mode 100644 diff --git a/docs/api/extensions/malware/maec_4_1_malware.rst b/docs/api/extensions/malware/maec_4_1_malware.rst old mode 100755 new mode 100644 diff --git a/docs/api/extensions/structured_coa/generic.rst b/docs/api/extensions/structured_coa/generic.rst old mode 100755 new mode 100644 diff --git a/docs/api/incident/affected_asset.rst b/docs/api/incident/affected_asset.rst old mode 100755 new mode 100644 diff --git a/docs/api/incident/property_affected.rst b/docs/api/incident/property_affected.rst old mode 100755 new mode 100644 diff --git a/docs/api/indicator/sightings.rst b/docs/api/indicator/sightings.rst old mode 100755 new mode 100644 diff --git a/docs/api/indicator/valid_time.rst b/docs/api/indicator/valid_time.rst old mode 100755 new mode 100644 diff --git a/docs/api/utils/utils.rst b/docs/api/utils/utils.rst old mode 100755 new mode 100644 diff --git a/docs/examples/index.rst b/docs/examples/index.rst old mode 100755 new mode 100644 diff --git a/examples/sample.xml b/examples/sample.xml old mode 100755 new mode 100644 From 0fefd686bcc8a087246281891659f16e835e484b Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Wed, 13 Apr 2016 19:25:45 -0400 Subject: [PATCH 297/438] Fixes to get this example working. The change to stix/exploit_target/vulnerability.py in how the descriptions and short_descriptions fields are initialized, was borrowed from BaseCoreComponent (stix/base.py). It seemed to fix the problem. Dunno why the same fields were initialized differently in different places... --- examples/vuln_affected_software.py | 3 ++- stix/exploit_target/vulnerability.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/vuln_affected_software.py b/examples/vuln_affected_software.py index 6743e5ae..0fb90ad6 100644 --- a/examples/vuln_affected_software.py +++ b/examples/vuln_affected_software.py @@ -16,7 +16,7 @@ # python-stix from stix.core import STIXPackage from stix.exploit_target import ExploitTarget -from stix.exploit_target.vulnerability import Vulnerability +from stix.exploit_target.vulnerability import Vulnerability, AffectedSoftware # Build a Product Object that characterizes our affected software @@ -32,6 +32,7 @@ # RelatedObservable instances. This wraps our Observable in a # RelatedObservable layer. vuln = Vulnerability() +vuln.affected_software = AffectedSoftware() vuln.affected_software.append(observable) # Create the Exploit Target diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index ebf199c4..7691716d 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -42,8 +42,8 @@ class Vulnerability(stix.Entity): def __init__(self, title=None, description=None, short_description=None): super(Vulnerability, self).__init__() self.title = title - self.description = description - self.short_description = short_description + self.descriptions = StructuredTextList(description) + self.short_descriptions = StructuredTextList(short_description) self.references = [] @property From 7b5f445f48f2547fe056cb8a286b741e722d8ca5 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Thu, 14 Apr 2016 16:45:23 -0400 Subject: [PATCH 298/438] Fix to get the example working again. --- examples/custom_vocabstring.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/custom_vocabstring.py b/examples/custom_vocabstring.py index b14d19db..a0b06260 100644 --- a/examples/custom_vocabstring.py +++ b/examples/custom_vocabstring.py @@ -9,6 +9,8 @@ # builtin from StringIO import StringIO +import mixbox.namespaces + # python-stix modules from stix.core import STIXPackage from stix.common import vocabs @@ -38,6 +40,11 @@ class CustomVocab(vocabs.VocabString): _XSI_TYPE = 'customVocabs:CustomVocab-1.0' _ALLOWED_VALUES = ('FOO', 'BAR') +# Register the namespace of the CustomVocab +mixbox.namespaces.register_namespace( + mixbox.namespaces.Namespace( + 'http://customvocabs.com/vocabs-1', 'customVocabs')) + # Register our Custom Vocabulary class so parsing and serialization works vocabs.add_vocab(CustomVocab) From f740961e6864017799753acec4f126181a19e143 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Thu, 14 Apr 2016 17:54:09 -0400 Subject: [PATCH 299/438] Fix _RelatedCampaignRefList so you can add a CampaignRef to it (will get wrapped in a RelatedCampaignRef). This fixes the vuln_affected_software.py example. --- stix/indicator/indicator.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index cabe88fa..a44766f4 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -770,6 +770,8 @@ def _fix_value(self, value): if isinstance(value, Campaign) and value.id_: return RelatedCampaignRef(CampaignRef(idref=value.id_)) + elif isinstance(value, CampaignRef): + return RelatedCampaignRef(value) msg = "Cannot insert object of type '%s' into '%s'" msg = msg % (type(value), self.__class__.__name__) From b27653bd7098dfc8f227aff7012c19bff37f6dce Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Tue, 19 Apr 2016 17:33:12 -0400 Subject: [PATCH 300/438] Fixed a cyclic import problem --- stix/report/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stix/report/__init__.py b/stix/report/__init__.py index 5dc948e0..d2d63a7f 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -14,7 +14,6 @@ # components from stix.campaign import Campaign from stix.coa import CourseOfAction -from stix.core.ttps import TTPs from stix.exploit_target import ExploitTarget from stix.indicator import Indicator from stix.incident import Incident @@ -256,3 +255,5 @@ class ThreatActors(stix.EntityList): _binding_class = _binding.ThreatActorsType threat_actor = fields.TypedField("Threat_Actor", ThreatActor, multiple=True, key_name="threat_actors") + +from stix.core.ttps import TTPs From 111c35e928255ad3b7279b1f346ea94aad4a2a7a Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas Date: Fri, 22 Apr 2016 15:17:32 -0400 Subject: [PATCH 301/438] Added field to properly provide values to binding object. --- stix/common/structured_text.py | 1 + 1 file changed, 1 insertion(+) diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 54ad4c9c..48fa215a 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -108,6 +108,7 @@ class StructuredTextList(stix.TypedCollection, collections.Sequence): :class:`.StructuredText` objects or sequences of objects. """ + _treat_none_as_empty_list = True _contained_type = StructuredText _try_cast = True From e5082931e0e1c622163b8a477c6dc7a2c2317851 Mon Sep 17 00:00:00 2001 From: apsillers Date: Wed, 27 Apr 2016 16:13:40 -0400 Subject: [PATCH 302/438] Nominal fixes for typedfield compatibility --- stix/extensions/identity/ciq_identity_3_0.py | 38 ++++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index 03497dbd..857b827b 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -82,8 +82,8 @@ def to_obj(self, ns_info=None): def from_obj(cls, cls_obj): obj = super(CIQIdentity3_0Instance, cls).from_obj(cls_obj) - roles = obj.Role - specification = obj.Specification + roles = cls_obj.Role + specification = cls_obj.Specification if roles: for role in roles: @@ -332,7 +332,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_obj(self, return_obj=None, ns_info=None): - super(STIXCIQIdentity3_0, self).to_obj(return_obj=return_obj, ns_info=ns_info) + #super(STIXCIQIdentity3_0, self).to_obj(ns_info=ns_info) if not return_obj: root_tag = STIXCIQIdentity3_0.XML_TAG @@ -456,7 +456,7 @@ def free_text_address(self, value): self._set_var(FreeTextAddress, free_text_address=value) def to_obj(self, return_obj=None, ns_info=None): - super(Address, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(Address, self).to_obj(ns_info=ns_info) if not return_obj: return_obj = et.Element(self.XML_TAG) @@ -559,7 +559,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_obj(self, return_obj=None, ns_info=None): - super(AdministrativeArea, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(AdministrativeArea, self).to_obj(ns_info=ns_info) if not return_obj: return_obj = et.Element(self.XML_TAG) @@ -631,7 +631,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_obj(self, return_obj=None, ns_info=None): - super(Country, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(Country, self).to_obj(ns_info=ns_info) if not return_obj: return_obj = et.Element(self.XML_TAG) @@ -666,7 +666,7 @@ def __init__(self, value=None): self.value = value def to_obj(self, return_obj=None, ns_info=None): - super(NameElement, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(NameElement, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) return_obj.text = self.value @@ -739,7 +739,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_obj(self, return_obj=None, ns_info=None): - super(FreeTextAddress, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(FreeTextAddress, self).to_obj(ns_info=ns_info) if not return_obj: return_obj = et.Element(self.XML_TAG) @@ -815,7 +815,7 @@ def add_organisation_name(self, value): raise ValueError('value must be instance of OrganisationName') def to_obj(self, return_obj=None, ns_info=None): - super(PartyName, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(PartyName, self).to_obj(ns_info=ns_info) if not return_obj: root_tag = PartyName.XML_TAG @@ -924,7 +924,7 @@ def value(self, value): self._value = value def to_obj(self, return_obj=None, ns_info=None): - super(NameLine, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(NameLine, self).to_obj(ns_info=ns_info) if not return_obj: root_tag = NameLine.XML_TAG @@ -993,7 +993,7 @@ def add_name_element(self, value): raise ValueError('value must be instance of PersonNameElement') def to_obj(self, return_obj=None, ns_info=None): - super(PersonName, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(PersonName, self).to_obj(ns_info=ns_info) if not return_obj: root_tag = PersonName.XML_TAG @@ -1099,7 +1099,7 @@ def add_subdivision_name(self, value): self.subdivision_names.append(value) def to_obj(self, return_obj=None, ns_info=None): - super(OrganisationName, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(OrganisationName, self).to_obj(ns_info=ns_info) if not return_obj: root_tag = OrganisationName.XML_TAG @@ -1198,7 +1198,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_obj(self, return_obj=None, ns_info=None): - super(_BaseNameElement, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(_BaseNameElement, self).to_obj(ns_info=ns_info) return_obj.text = self.value return return_obj @@ -1403,7 +1403,7 @@ def type(self, value): self._type = value def to_obj(self, return_obj=None, ns_info=None): - super(SubDivisionName, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(SubDivisionName, self).to_obj(ns_info=ns_info) if not return_obj: root_tag = SubDivisionName.XML_TAG @@ -1457,7 +1457,7 @@ def __init__(self, value=None): self.value = value def to_obj(self, return_obj=None, ns_info=None): - super(Language, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(Language, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) return_obj.text = self.value @@ -1497,7 +1497,7 @@ def __init__(self, value=None, type_=None): self.value = value def to_obj(self, return_obj=None, ns_info=None): - super(ElectronicAddressIdentifier, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(ElectronicAddressIdentifier, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) return_obj.text = self.value @@ -1548,7 +1548,7 @@ def __init__(self, industry_type=None): self.industry_type = industry_type def to_obj(self, return_obj=None, ns_info=None): - super(OrganisationInfo, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(OrganisationInfo, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) if self.industry_type: @@ -1594,7 +1594,7 @@ def __init__(self, value=None, type_=None): self.type_ = type_ def to_obj(self, return_obj=None, ns_info=None): - super(FreeTextLine, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(FreeTextLine, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) if self.type_: @@ -1778,7 +1778,7 @@ def type_(self, value): self._type = value def to_obj(self, return_obj=None, ns_info=None): - super(ContactNumberElement, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(ContactNumberElement, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) if self.type_: From 25eb534d3ba8cf827690159b32eeebae4ad08d5b Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 28 Apr 2016 12:18:13 -0400 Subject: [PATCH 303/438] Fix Statement's description field --- stix/common/statement.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/common/statement.py b/stix/common/statement.py index 980c8fcb..a36984a5 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -35,7 +35,7 @@ def __init__(self, value=None, timestamp=None, description=None, self.timestamp = timestamp or utils.dates.now() self.timestamp_precision = "second" self.value = value - self.description = description + self.description = StructuredTextList(description) self.source = source self.confidence = None From e1f13aa6fbee100e743b52abecbfb7309c7b069a Mon Sep 17 00:00:00 2001 From: apsillers Date: Thu, 28 Apr 2016 12:53:54 -0400 Subject: [PATCH 304/438] StructuredTextList fixes --- stix/coa/objective.py | 4 ++-- stix/common/statement.py | 2 +- stix/common/tools.py | 2 +- stix/exploit_target/weakness.py | 2 +- stix/incident/affected_asset.py | 2 ++ stix/incident/property_affected.py | 1 + stix/report/header.py | 4 ++-- stix/ttp/malware_instance.py | 4 ++-- 8 files changed, 12 insertions(+), 9 deletions(-) diff --git a/stix/coa/objective.py b/stix/coa/objective.py index a6fed1ce..09c708a6 100644 --- a/stix/coa/objective.py +++ b/stix/coa/objective.py @@ -20,8 +20,8 @@ class Objective(stix.Entity): def __init__(self, description=None, short_description=None): super(Objective, self).__init__() - self.description = description - self.short_description = short_description + self.description = StructuredTextList(description) + self.short_description = StructuredTextList(short_description) @property def description(self): diff --git a/stix/common/statement.py b/stix/common/statement.py index a36984a5..8d04884f 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -35,7 +35,7 @@ def __init__(self, value=None, timestamp=None, description=None, self.timestamp = timestamp or utils.dates.now() self.timestamp_precision = "second" self.value = value - self.description = StructuredTextList(description) + self.descriptions = StructuredTextList(description) self.source = source self.confidence = None diff --git a/stix/common/tools.py b/stix/common/tools.py index 6ec44a4d..2865098c 100644 --- a/stix/common/tools.py +++ b/stix/common/tools.py @@ -24,7 +24,7 @@ class ToolInformation(stix.Entity, cybox.common.ToolInformation): def __init__(self, title=None, short_description=None, tool_name=None, tool_vendor=None): super(ToolInformation, self).__init__(tool_name=tool_name, tool_vendor=tool_vendor) self.title = title - self.short_description = short_description + self.short_description = StructuredTextList(short_description) @property def short_description(self): diff --git a/stix/exploit_target/weakness.py b/stix/exploit_target/weakness.py index ab989b9f..db9f4ecc 100644 --- a/stix/exploit_target/weakness.py +++ b/stix/exploit_target/weakness.py @@ -23,7 +23,7 @@ class Weakness(stix.Entity): def __init__(self, description=None, cwe_id=None): super(Weakness, self).__init__() - self.description = description + self.description = StructuredTextList(description) self.cwe_id = cwe_id @property diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index 4a75d4a2..36b882c4 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -31,6 +31,8 @@ class AffectedAsset(stix.Entity): def __init__(self): super(AffectedAsset, self).__init__() + self.description = StructuredTextList() + self.business_function_or_role = StructuredTextList() @property def description(self): diff --git a/stix/incident/property_affected.py b/stix/incident/property_affected.py index 7933cc47..50ec2453 100644 --- a/stix/incident/property_affected.py +++ b/stix/incident/property_affected.py @@ -35,6 +35,7 @@ class PropertyAffected(stix.Entity): def __init__(self): super(PropertyAffected, self).__init__() + self.descriptions_of_effect = StructuredTextList() @property def description_of_effect(self): diff --git a/stix/report/header.py b/stix/report/header.py index 72aa9d49..2506af22 100644 --- a/stix/report/header.py +++ b/stix/report/header.py @@ -47,8 +47,8 @@ def __init__(self, title=None, description=None, short_description=None, self.intents = intents self.title = title - self.description = description - self.short_description = short_description + self.description = StructuredTextList(description) + self.short_description = StructuredTextList(short_description) self.handling = handling self.information_source = information_source diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index 3d26df13..b864ced0 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -34,8 +34,8 @@ def __init__(self, id_=None, idref=None, title=None, description=None, short_des self.id_ = id_ self.idref = idref self.title = title - self.description = description - self.short_description = short_description + self.description = StructuredTextList(description) + self.short_description = StructuredTextList(short_description) @property def description(self): From 1119f4dd239d2c1f851bbe26160c949786764a5a Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 29 Apr 2016 08:36:34 -0400 Subject: [PATCH 305/438] Fix various add_* methods --- stix/common/statement.py | 3 ++- stix/incident/__init__.py | 16 ++++++++++++++-- stix/indicator/indicator.py | 2 +- stix/report/__init__.py | 4 ++-- stix/threat_actor/__init__.py | 2 +- stix/ttp/__init__.py | 3 +++ stix/ttp/behavior.py | 6 +++--- stix/ttp/victim_targeting.py | 4 ++-- 8 files changed, 28 insertions(+), 12 deletions(-) diff --git a/stix/common/statement.py b/stix/common/statement.py index 8d04884f..241d7b66 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -14,6 +14,7 @@ from .structured_text import StructuredTextList from .vocabs import VocabField, HighMediumLow import mixbox +from stix.common.vocabs import VocabString class Statement(stix.Entity): _namespace = 'http://stix.mitre.org/common-1' @@ -23,7 +24,7 @@ class Statement(stix.Entity): # Fields timestamp = fields.DateTimeField("timestamp") timestamp_precision = fields.TypedField("timestamp_precision", preset_hook=validate_precision) - value = VocabField("Value", HighMediumLow) + value = VocabField("Value", VocabString) descriptions = fields.TypedField("Description", StructuredTextList) confidence = fields.TypedField("Confidence", Confidence) source = fields.TypedField("Source", type_="stix.common.InformationSource") diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index b4397aa1..49df7e51 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -87,6 +87,9 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, description self.related_observables = RelatedObservables() self.related_incidents = RelatedIncidents() self.related_packages = RelatedPackageRefs() + self.categories = IncidentCategories() + self.affected_assets = AffectedAssets() + self.leveraged_ttps = LeveragedTTPs() def add_intended_effect(self, value): """Adds a :class:`.Statement` object to the :attr:`intended_effects` @@ -98,13 +101,19 @@ def add_intended_effect(self, value): """ self.intended_effects.append(value) + def add_leveraged_ttps(self, ttp): + """Adds a :class:`.RelatedTTP` value to the :attr:`leveraged_ttps` + collection. + + """ + self.leveraged_ttps.append(ttp) def add_victim(self, victim): """Adds a :class:`.IdentityType` value to the :attr:`victims` collection. """ - self._victims.append(victim) + self.victims.append(victim) def add_category(self, category): """Adds a :class:`.VocabString` object to the :attr:`categories` @@ -175,7 +184,7 @@ def add_related_indicator(self, value): The `indicator` parameter must be an instance of :class:`.RelatedIndicator` or :class:`Indicator`. - If the `indicator` parameter is ``None``, no item wil be added to the + If the `indicator` parameter is ``None``, no item will be added to the ``related_indicators`` list property. Calling this method is the same as calling ``append()`` on the @@ -234,6 +243,9 @@ def add_related_observable(self, value): def add_related_package(self, value): self.related_packages.append(value) + + def add_related_incidents(self, value): + self.related_incidents.append(value) class AttributedThreatActors(GenericRelationshipList): _namespace = "http://stix.mitre.org/Incident-1" diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index a44766f4..aed2f481 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -209,7 +209,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, short_description=short_description ) - self.observables = None + self.observables = [] self.indicator_types = IndicatorTypes() self.test_mechanisms = TestMechanisms() self.alternative_id = None diff --git a/stix/report/__init__.py b/stix/report/__init__.py index d2d63a7f..d58d4d52 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -142,7 +142,7 @@ def add_threat_actor(self, threat_actor): """ if self.threat_actors is None: self.threat_actors = ThreatActors() - self._threat_actors.append(threat_actor) + self.threat_actors.append(threat_actor) def add_course_of_action(self, course_of_action): """Adds an :class:`.CourseOfAction` object to the @@ -196,7 +196,7 @@ def add(self, entity): Incident: self.add_incident, Indicator: self.add_indicator, ThreatActor: self.add_threat_actor, - TTP: self.add_threat_actor, + TTP: self.add_ttp, Observable: self.add_observable, } diff --git a/stix/threat_actor/__init__.py b/stix/threat_actor/__init__.py index 3b73901f..01e63d9b 100644 --- a/stix/threat_actor/__init__.py +++ b/stix/threat_actor/__init__.py @@ -119,7 +119,7 @@ def add_sophistication(self, value): instance of :class:`.ThreatActorSophistication`. """ - self._sophistications.append(value) + self.sophistications.append(value) def add_intended_effect(self, value): """Adds a :class:`.Statement` object to the :attr:`intended_effects` diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index 4c671274..8aae2cf9 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -65,6 +65,9 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, ) self.related_packages = RelatedPackageRefs() + self.exploit_targets = ExploitTargets() + self.related_ttps = RelatedTTPs() + self.kill_chain_phases = KillChainPhasesReference() def add_related_ttp(self, value): diff --git a/stix/ttp/behavior.py b/stix/ttp/behavior.py index d1582e46..5d53e643 100644 --- a/stix/ttp/behavior.py +++ b/stix/ttp/behavior.py @@ -23,9 +23,9 @@ class Behavior(stix.Entity): def __init__(self, malware_instances=None, attack_patterns=None, exploits=None): super(Behavior, self).__init__() - self.malware_instances = malware_instances - self.attack_patterns = attack_patterns - self.exploits = exploits + self.malware_instances = malware_instances or MalwareInstances() + self.attack_patterns = attack_patterns or AttackPatterns() + self.exploits = exploits or Exploits() def add_malware_instance(self, malware): diff --git a/stix/ttp/victim_targeting.py b/stix/ttp/victim_targeting.py index 2eff70a4..eeb4bef6 100644 --- a/stix/ttp/victim_targeting.py +++ b/stix/ttp/victim_targeting.py @@ -24,7 +24,7 @@ def __init__(self): super(VictimTargeting, self).__init__() def add_targeted_system(self, system): - self._targeted_systems.append(system) + self.targeted_systems.append(system) def add_targeted_information(self, targeted_information): - self._targeted_information.append(targeted_information) + self.targeted_information.append(targeted_information) From dc0a494ec33fbaf509da0c7bb1d10754f498bc29 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas Date: Fri, 29 Apr 2016 10:49:03 -0400 Subject: [PATCH 306/438] Behavior changes to Observable/Observables in Indicator. --- stix/indicator/indicator.py | 156 ++++++++++++++++++++++-------------- 1 file changed, 96 insertions(+), 60 deletions(-) diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index aed2f481..1711eac5 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -19,6 +19,7 @@ RelatedIndicator, RelatedCampaignRef, RelatedPackageRefs) from stix.common.vocabs import VocabField, IndicatorType from stix.common.kill_chains import KillChainPhasesReference +from stix import utils import stix.bindings.indicator as indicator_binding # relative @@ -180,7 +181,7 @@ class Indicator(stix.BaseCoreComponent): _try_cast = False producer = fields.TypedField("Producer", InformationSource) - observable = fields.TypedField("Observable", Observable, postset_hook=lambda inst,value: inst.set_observables([value])) + observable = fields.TypedField("Observable", Observable) indicator_types = VocabField("Type", IndicatorType, multiple=True, key_name="indicator_types") confidence = fields.TypedField("Confidence", Confidence) indicated_ttps = fields.TypedField("Indicated_TTP", RelatedTTP, multiple=True, key_name="indicated_ttps") @@ -209,7 +210,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, short_description=short_description ) - self.observables = [] + self.observable = None self.indicator_types = IndicatorTypes() self.test_mechanisms = TestMechanisms() self.alternative_id = None @@ -228,51 +229,95 @@ def observables(self): a single object instance or a list of objects. Note: - If the input value or values are not instance(s) of - ``cybox.core.Observable``, an attempt will be made to - convert the value to an instance of ``cybox.core.Observable``. + If only one Observable is set, this property will return a list + with the ``observable`` property. - Default Value: Empty ``list`` + If multiple ``cybox.core.Observable`` this property will return + Observables under the ``cybox.core.ObservableComposition``. + + Access to the top level ``cybox.core.Observable`` is made via + ``observable`` property. + + Default Value: + Empty ``list``. Returns: A ``list`` of ``cybox.core.Observable`` instances. + """ + if not self.observable: + return [] + elif self.observable.observable_composition: + return self.observable.observable_composition.observables + + return [] + + @observables.setter + def observables(self, value): + """ + The method will automatically create a top ``cybox.core.Observable`` and + append all ``cybox.core.Observable`` using ``observable_composition`` + property when a ``list`` is given with length greater than 1. + + Note: + The top level ``cybox.core.Observable`` will set the ``operator`` + property for the ``cybox.core.ObservableComposition`` via the + ``observable_composition_operator`` property. The value of + ``operator`` can be changed via ``observable_composition_operator`` + property. By default, the composition layer will be set to ``"OR"``. + + Args: + value: A ``list`` of ``cybox.core.Observable`` instances or a single + ``cybox.core.Observable`` instance. + Raises: ValueError: If set to a value that cannot be converted to an instance of ``cybox.core.Observable``. - """ - return self._observables + if not value: + return - @observables.setter - def observables(self, value): - # this code causes infinite recursion; observables sets observable which sets obesrvables... - #try: - # self.observable = value[0] - #except TypeError: - # self.observable = value - self._observables = _Observables(value) + if isinstance(value, Observable): + self.observable = value + + elif utils.is_sequence(value): + if len(value) == 1: + self.observable = value + return + + observable_comp = ObservableComposition() + observable_comp.operator = self.observable_composition_operator + + for element in value: + observable_comp.add(element) + + self.observable = Observable() + self.observable.observable_composition = observable_comp def set_observables(self, value): self.observables = value def add_observable(self, observable): - """Adds an observable to the ``observables`` list property of the + """Adds an observable to the ``observable`` property of the :class:`Indicator`. If the `observable` parameter is ``None``, no item will be added - to the ``observables`` list. + to the ``observable`` property. Note: The STIX Language dictates that an :class:`Indicator` can have only - one ``Observable`` under it. Because of this, the ``to_xml()`` - method will convert the ``observables`` list into an - ``cybox.core.ObservableComposition`` instance, in which each item - in the ``observables`` list will be added to the composition. By + one ``Observable`` under it. Because of this, when a user adds + another ``Observable`` a new, empty ``Observable`` will be crated + and append the existing and new ``observable`` using the + ``ObservableComposition`` property. To access the top level + ``Observable`` can be achieved by the ``observable`` property .By default, the ``operator`` of the composition layer will be set to ``"OR"``. The ``operator`` value can be changed via the ``observable_composition_operator`` property. + Setting ``observable`` or ``observables`` with re-initialize the + property and lose all ``Observable`` in the composition layer. + Args: observable: An instance of ``cybox.core.Observable`` or an object type that can be converted into one. @@ -283,8 +328,29 @@ def add_observable(self, observable): instance of ``cybox.core.Observable``. """ - self.observables.append(observable) - + if not observable: + return + + # Sets the first observable. + elif not self.observable: + self.observable = observable + + # When another is inserted. A "root" Observable is created and the + # user's Observables are appended to the composition. + elif not self.observable.observable_composition: + observable_comp = ObservableComposition() + observable_comp.operator = self.observable_composition_operator + + observable_comp.add(self.observable) + observable_comp.add(observable) + + self.observable = Observable() + self.observable.observable_composition = observable_comp + + # Keep appending to "root" Observable. + else: + self.observable.observable_composition.add(observable) + def add_alternative_id(self, value): """Adds an alternative id to the ``alternative_id`` list property. @@ -300,7 +366,7 @@ def add_alternative_id(self, value): return self.alternative_id.append(value) - + def add_valid_time_position(self, value): """Adds an valid time position to the ``valid_time_positions`` property list. @@ -340,7 +406,6 @@ def add_indicator_type(self, value): """ self.indicator_types.append(value) - def add_indicated_ttp(self, v): """Adds an Indicated TTP to the ``indicated_ttps`` list property of this :class:`Indicator`. @@ -367,7 +432,6 @@ def add_indicated_ttp(self, v): """ self.indicated_ttps.append(v) - def add_test_mechanism(self, tm): """Adds an Test Mechanism to the ``test_mechanisms`` list property of this :class:`Indicator`. @@ -467,6 +531,10 @@ def observable_composition_operator(self): def observable_composition_operator(self, value): if value in self._ALLOWED_COMPOSITION_OPERATORS: self._observable_composition_operator = value + + if self.observable and self.observable.observable_composition: + self.observable.observable_composition.operator = value + return error = "observable_composition_operator must one of {0}" @@ -655,37 +723,7 @@ def add_object(self, object_): observable = Observable(object_) self.add_observable(observable) - - def to_obj(self, ns_info=None): - obj = super(Indicator, self).to_obj(ns_info=ns_info) - - if self.observables: - if len(self.observables) > 1: - root_observable = self._merge_observables(self.observables) - else: - root_observable = self.observables[0] - obj.Observable = root_observable.to_obj(ns_info=ns_info) - - return obj - - def to_dict(self): - keys = ('observables', 'observable_composition_operator', 'negate') - #d = utils.to_dict(self, skip=keys) - - d = super(Indicator, self).to_dict() - - if not self.negate: - d.pop("negate", None) - - if self.observables: - if len(self.observables) == 1: - d['observable'] = self.observables[0].to_dict() - else: - composite_observable = self._merge_observables(self.observables) - d['observable'] = composite_observable.to_dict() - - return d - + def check_operator(composite_indicator_exp, value): allowed = CompositeIndicatorExpression.OPERATORS @@ -770,8 +808,6 @@ def _fix_value(self, value): if isinstance(value, Campaign) and value.id_: return RelatedCampaignRef(CampaignRef(idref=value.id_)) - elif isinstance(value, CampaignRef): - return RelatedCampaignRef(value) msg = "Cannot insert object of type '%s' into '%s'" msg = msg % (type(value), self.__class__.__name__) From bd55ccdcb83a951374612bd00c7c71b7464c5bed Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 29 Apr 2016 13:39:24 -0400 Subject: [PATCH 307/438] Fix add_vulnerability --- stix/exploit_target/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stix/exploit_target/__init__.py b/stix/exploit_target/__init__.py index 8be95051..9d27d0b6 100644 --- a/stix/exploit_target/__init__.py +++ b/stix/exploit_target/__init__.py @@ -78,7 +78,8 @@ def add_vulnerability(self, value): ValueError: if the `value` param is of type :class:`.Vulnerability` """ - self.vul + self.vulnerabilities.append(value) + def add_weakness(self, value): """Adds a weakness to the :attr:`weaknesses` list property. From b4f756057c1913be81b666154be4bb357003ad67 Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 29 Apr 2016 13:49:25 -0400 Subject: [PATCH 308/438] Fix add_related_indicator --- stix/indicator/indicator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 1711eac5..9e92675a 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -218,7 +218,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, title=None, self.sightings = Sightings() self.composite_indicator_expression = None self.kill_chain_phases = KillChainPhasesReference() - self.related_indicators = None + self.related_indicators = RelatedIndicators() self.related_campaigns = RelatedCampaignRefs() self.observable_composition_operator = "OR" self.related_packages = RelatedPackageRefs() From 473b084a4f539ea41a45fe5e830f77ca8a8d4bc7 Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 29 Apr 2016 14:20:04 -0400 Subject: [PATCH 309/438] Fix description/short_description bugs --- stix/common/confidence.py | 2 +- stix/core/stix_header.py | 4 ++-- stix/exploit_target/configuration.py | 4 ++-- stix/ttp/attack_pattern.py | 4 ++-- stix/ttp/exploit.py | 4 ++-- stix/ttp/infrastructure.py | 6 +++--- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/stix/common/confidence.py b/stix/common/confidence.py index 80907a5b..d5c1d946 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -31,7 +31,7 @@ def __init__(self, value=None, timestamp=None, description=None, source=None): self.timestamp = timestamp or utils.dates.now() self.timestamp_precision = "second" self.value = value - self.description = description + self.description = StructuredTextList(description) self.source = source # TODO: support confidence_assertion_chain diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index 869ae504..fb4c2917 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -51,8 +51,8 @@ def __init__(self, package_intents=None, description=None, handling=None, self.package_intents = package_intents self.title = title - self.description = description - self.short_description = short_description + self.description = StructuredTextList(description) + self.short_description = StructuredTextList(short_description) self.handling = handling self.information_source = information_source self.profiles = None diff --git a/stix/exploit_target/configuration.py b/stix/exploit_target/configuration.py index e1d2c3bb..44c0e867 100644 --- a/stix/exploit_target/configuration.py +++ b/stix/exploit_target/configuration.py @@ -25,8 +25,8 @@ class Configuration(stix.Entity): def __init__(self, description=None, short_description=None, cce_id=None): super(Configuration, self).__init__() - self.description = description - self.short_description = short_description + self.description = StructuredTextList(description) + self.short_description = StructuredTextList(short_description) self.cce_id = cce_id @property diff --git a/stix/ttp/attack_pattern.py b/stix/ttp/attack_pattern.py index 1716a6d6..52471374 100644 --- a/stix/ttp/attack_pattern.py +++ b/stix/ttp/attack_pattern.py @@ -30,8 +30,8 @@ def __init__(self, id_=None, idref=None, title=None, description=None, short_des self.id_ = id_ self.idref = idref self.title = title - self.description = description - self.short_description = short_description + self.description = StructuredTextList(description) + self.short_description = StructuredTextList(short_description) @property def description(self): diff --git a/stix/ttp/exploit.py b/stix/ttp/exploit.py index 874082d2..72bb87d1 100644 --- a/stix/ttp/exploit.py +++ b/stix/ttp/exploit.py @@ -29,8 +29,8 @@ def __init__(self, id_=None, idref=None, title=None, description=None, short_des self.id_ = id_ self.idref = idref self.title = title - self.description = description - self.short_description = short_description + self.description = StructuredTextList(description) + self.short_description = StructuredTextList(short_description) @property def description(self): diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index 6bda4923..f35e9ec0 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -35,8 +35,8 @@ def __init__(self, id_=None, idref=None, title=None, description=None, short_des self.id_ = id_ self.idref = idref self.title = title - self.description = description - self.short_description = short_description + self.description = StructuredTextList(description) + self.short_description = StructuredTextList(short_description) @property @@ -58,7 +58,7 @@ def description(self): @description.setter def description(self, value): - self.descriptions = value + self.descriptions = StructuredTextList(value) def add_description(self, description): """Adds a description to the ``descriptions`` collection. From 6d5c8598d6bfabb7f4384525a991b8433a8e0064 Mon Sep 17 00:00:00 2001 From: apsillers Date: Fri, 29 Apr 2016 15:13:30 -0400 Subject: [PATCH 310/438] Add inofrmation_source to TTP --- stix/ttp/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index 8aae2cf9..83f6e679 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -17,6 +17,7 @@ from .behavior import Behavior from .resource import Resource from .victim_targeting import VictimTargeting +from stix.common.information_source import InformationSource class TTP(stix.BaseCoreComponent): @@ -51,6 +52,7 @@ class TTP(stix.BaseCoreComponent): exploit_targets = fields.TypedField("Exploit_Targets", ExploitTargets) related_packages = fields.TypedField("Related_Packages", RelatedPackageRefs) kill_chain_phases = fields.TypedField("Kill_Chain_Phases", KillChainPhasesReference) + information_source = fields.TypedField("Information_Source", InformationSource) def __init__(self, id_=None, idref=None, timestamp=None, title=None, description=None, short_description=None): From 32cb130c012aeaa44428954726323a8685417eaa Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas Date: Tue, 3 May 2016 08:28:18 -0400 Subject: [PATCH 311/438] fix add_marking() --- stix/data_marking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/data_marking.py b/stix/data_marking.py index 983788f5..c88f0370 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -88,7 +88,7 @@ def __init__(self, markings=None): super(Marking, self).__init__(markings) def add_marking(self, value): - self.markings.append(value) + self.marking.append(value) # Backwards compatibility From 281b1f08e7b66a2fde4e9de03e21fd9372c53945 Mon Sep 17 00:00:00 2001 From: apsillers Date: Wed, 4 May 2016 12:00:56 -0400 Subject: [PATCH 312/438] Update version for new namespace/typedfield work --- stix/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/version.py b/stix/version.py index 87535902..8b906dce 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.1.dev2" +__version__ = "1.2.0.2" From 130f0391304cf0de97ee4e82cf4875dcf5074c23 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 16 May 2016 14:04:44 -0400 Subject: [PATCH 313/438] Fix add_name() and add_type() methods in Malware Instance. --- stix/ttp/malware_instance.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index b864ced0..bf976aff 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -15,6 +15,7 @@ from mixbox import fields, entities + class MalwareInstance(Cached, stix.Entity): _binding = ttp_binding _binding_class = _binding.MalwareInstanceType @@ -95,10 +96,10 @@ def add_short_description(self, description): self.short_descriptions.add(description) def add_name(self, name): - self._names.append(name) + self.names.append(name) def add_type(self, type_): - self._types.append(type_) + self.types.append(type_) @staticmethod def lookup_class(xsi_type): From e349d5fb90ee1c361a816a93fbb0fff50ae715c3 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Mon, 27 Jun 2016 13:15:59 -0400 Subject: [PATCH 314/438] Replace pypip badges with shield.io pypip.in is down ( badges/pypipins#37 ) --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 26a2dd91..947cb436 100644 --- a/README.rst +++ b/README.rst @@ -15,9 +15,9 @@ A python library for parsing, manipulating, and generating STIX v1.2 content. .. |landscape.io badge| image:: https://landscape.io/github/STIXProject/python-stix/master/landscape.png :target: https://landscape.io/github/STIXProject/python-stix/master :alt: Code Health -.. |version badge| image:: https://pypip.in/v/stix/badge.png +.. |version badge| image:: https://img.shields.io/pypi/v/stix.png?maxAge=2592000 :target: https://pypi.python.org/pypi/stix/ -.. |downloads badge| image:: https://pypip.in/d/stix/badge.png +.. |downloads badge| image:: https://img.shields.io/pypi/dm/stix.png?maxAge=2592000 :target: https://pypi.python.org/pypi/stix/ From 86d87835b0a6c2912aa89c1082cf3edaa03ca587 Mon Sep 17 00:00:00 2001 From: "joe.walton" Date: Tue, 28 Jun 2016 09:29:32 +0100 Subject: [PATCH 315/438] update to_dict and from_dict to include organisation_info --- stix/extensions/identity/ciq_identity_3_0.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index e20e6185..52178179 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -406,6 +406,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj = cls() return_obj.party_name = PartyName.from_dict(dict_repr.get('party_name')) + return_obj.organisation_info = OrganisationInfo.from_dict(dict_repr.get('organisation_info')) return_obj.languages = [Language.from_dict(x) for x in dict_repr.get('languages', [])] return_obj.addresses = [Address.from_dict(x) for x in dict_repr.get('addresses', [])] return_obj.electronic_address_identifiers = [ElectronicAddressIdentifier.from_dict(x) for x in dict_repr.get('electronic_address_identifiers', [])] @@ -420,6 +421,8 @@ def to_dict(self): if self.party_name: d['party_name'] = self.party_name.to_dict() + if self.organisation_info: + d['organisation_info'] = self.organisation_info.to_dict() if self.languages: d['languages'] = [x.to_dict() for x in self.languages] if self.addresses: From feff79c2211f82487c5aaddabadfb1486cf6a002 Mon Sep 17 00:00:00 2001 From: "joe.walton" Date: Tue, 5 Jul 2016 15:54:24 +0100 Subject: [PATCH 316/438] add test data for organisation info --- stix/test/extensions/identity/ciq_identity_3_0_test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stix/test/extensions/identity/ciq_identity_3_0_test.py b/stix/test/extensions/identity/ciq_identity_3_0_test.py index f56bb6f2..882e496c 100644 --- a/stix/test/extensions/identity/ciq_identity_3_0_test.py +++ b/stix/test/extensions/identity/ciq_identity_3_0_test.py @@ -47,6 +47,9 @@ class CIQIdentity3_0InstanceTests(EntityTestCase, unittest.TestCase): } ] }, + 'organisation_info': { + 'industry_type': 'test industry' + }, 'languages': [ {'value': 'test language'} ], From 18f1dbd9db42c636e6f5fc73fbe3656c60ff889a Mon Sep 17 00:00:00 2001 From: clenk Date: Tue, 12 Jul 2016 08:16:25 -0400 Subject: [PATCH 317/438] Initial Python 3 support --- stix/__init__.py | 6 ++- stix/bindings/campaign.py | 4 +- stix/bindings/course_of_action.py | 4 +- stix/bindings/data_marking.py | 4 +- stix/bindings/exploit_target.py | 6 +-- .../extensions/address/ciq_address_3_0.py | 4 +- .../extensions/attack_pattern/capec_2_7.py | 4 +- .../extensions/identity/ciq_identity_3_0.py | 4 +- stix/bindings/extensions/malware/maec_4_1.py | 4 +- .../extensions/marking/simple_marking.py | 4 +- .../marking/terms_of_use_marking.py | 4 +- stix/bindings/extensions/marking/tlp.py | 4 +- .../extensions/structured_coa/generic.py | 4 +- .../extensions/test_mechanism/generic.py | 4 +- .../test_mechanism/open_ioc_2010.py | 4 +- .../extensions/test_mechanism/oval_5_10.py | 4 +- .../extensions/test_mechanism/snort.py | 4 +- .../extensions/test_mechanism/yara.py | 4 +- .../extensions/vulnerability/cvrf_1_1.py | 4 +- stix/bindings/incident.py | 6 +-- stix/bindings/indicator.py | 8 +-- stix/bindings/report.py | 2 +- stix/bindings/stix_common.py | 30 +++++------ stix/bindings/stix_core.py | 6 +-- stix/bindings/threat_actor.py | 4 +- stix/bindings/ttp.py | 4 +- stix/common/__init__.py | 3 +- stix/common/kill_chains/__init__.py | 4 +- stix/core/__init__.py | 4 +- stix/extensions/identity/ciq_identity_3_0.py | 24 +++++---- stix/extensions/malware/maec_4_1_malware.py | 4 +- .../open_ioc_2010_test_mechanism.py | 6 +-- stix/indicator/__init__.py | 2 +- stix/indicator/indicator.py | 12 ++--- stix/test/__init__.py | 20 ++++---- stix/test/common/structured_text_tests.py | 6 ++- stix/test/encoding_test.py | 5 +- .../malware/maec_4_1_malware_test.py | 2 +- .../test_mechanisms/openioc_test.py | 8 +-- stix/test/incident_test.py | 5 +- stix/test/utils/nsparser_test.py | 8 +-- stix/test/utils/parser_test.py | 2 +- stix/utils/__init__.py | 5 +- stix/utils/nsparser.py | 51 ++++++++++--------- stix/utils/walk.py | 5 +- 45 files changed, 164 insertions(+), 152 deletions(-) diff --git a/stix/__init__.py b/stix/__init__.py index 703708cc..e1816c16 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -5,6 +5,8 @@ from .base import (Entity, EntityList, TypedCollection, TypedList, # noqa BaseCoreComponent) +from mixbox.vendor.six import string_types, iteritems + #: Mapping of xsi:types to implementation/extension classes _EXTENSION_MAP = {} @@ -24,7 +26,7 @@ def _lookup_unprefixed(typename): ValueError: If no class has been registered for the input `typename`. """ - for xsi_type, klass in _EXTENSION_MAP.iteritems(): + for xsi_type, klass in iteritems(_EXTENSION_MAP): if typename in xsi_type: return klass @@ -75,7 +77,7 @@ def lookup_extension(typeinfo, default=None): return default # If the `typeinfo` was a string, consider it a full xsi:type value. - if isinstance(typeinfo, basestring): + if isinstance(typeinfo, string_types): return _lookup_extension(typeinfo) # Most extension bindings include this attribute. diff --git a/stix/bindings/campaign.py b/stix/bindings/campaign.py index a6083434..33c9e81a 100644 --- a/stix/bindings/campaign.py +++ b/stix/bindings/campaign.py @@ -710,7 +710,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -756,7 +756,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/course_of_action.py b/stix/bindings/course_of_action.py index b6ef8862..c8ee6a17 100644 --- a/stix/bindings/course_of_action.py +++ b/stix/bindings/course_of_action.py @@ -535,7 +535,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -581,7 +581,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/data_marking.py b/stix/bindings/data_marking.py index 9fbc42cc..da2f5e42 100644 --- a/stix/bindings/data_marking.py +++ b/stix/bindings/data_marking.py @@ -357,7 +357,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -403,7 +403,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/exploit_target.py b/stix/bindings/exploit_target.py index c4856181..98abf80f 100644 --- a/stix/bindings/exploit_target.py +++ b/stix/bindings/exploit_target.py @@ -216,7 +216,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): sval_ = child_.text try: ival_ = int(sval_) - except (TypeError, ValueError), exp: + except (TypeError, ValueError) as exp: raise_parse_error(child_, 'requires integer: %s' % exp) if ival_ <= 0: raise_parse_error(child_, 'requires positiveInteger') @@ -983,7 +983,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -1029,7 +1029,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/address/ciq_address_3_0.py b/stix/bindings/extensions/address/ciq_address_3_0.py index cd1e24de..3d3bad02 100644 --- a/stix/bindings/extensions/address/ciq_address_3_0.py +++ b/stix/bindings/extensions/address/ciq_address_3_0.py @@ -111,7 +111,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -157,7 +157,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/attack_pattern/capec_2_7.py b/stix/bindings/extensions/attack_pattern/capec_2_7.py index 6cc3aa0c..1678dd89 100644 --- a/stix/bindings/extensions/attack_pattern/capec_2_7.py +++ b/stix/bindings/extensions/attack_pattern/capec_2_7.py @@ -110,7 +110,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -156,7 +156,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/identity/ciq_identity_3_0.py b/stix/bindings/extensions/identity/ciq_identity_3_0.py index 3c37c4b1..f2051144 100644 --- a/stix/bindings/extensions/identity/ciq_identity_3_0.py +++ b/stix/bindings/extensions/identity/ciq_identity_3_0.py @@ -129,7 +129,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -175,7 +175,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/malware/maec_4_1.py b/stix/bindings/extensions/malware/maec_4_1.py index 552beed1..83c190b1 100644 --- a/stix/bindings/extensions/malware/maec_4_1.py +++ b/stix/bindings/extensions/malware/maec_4_1.py @@ -119,7 +119,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -165,7 +165,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/marking/simple_marking.py b/stix/bindings/extensions/marking/simple_marking.py index 839ae146..dc1cdc81 100644 --- a/stix/bindings/extensions/marking/simple_marking.py +++ b/stix/bindings/extensions/marking/simple_marking.py @@ -114,7 +114,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -160,7 +160,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/marking/terms_of_use_marking.py b/stix/bindings/extensions/marking/terms_of_use_marking.py index d9d99551..ad49b8b9 100644 --- a/stix/bindings/extensions/marking/terms_of_use_marking.py +++ b/stix/bindings/extensions/marking/terms_of_use_marking.py @@ -115,7 +115,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -161,7 +161,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/marking/tlp.py b/stix/bindings/extensions/marking/tlp.py index fecade54..340a0b39 100644 --- a/stix/bindings/extensions/marking/tlp.py +++ b/stix/bindings/extensions/marking/tlp.py @@ -111,7 +111,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -157,7 +157,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/structured_coa/generic.py b/stix/bindings/extensions/structured_coa/generic.py index 3ba383dd..82dee1ef 100644 --- a/stix/bindings/extensions/structured_coa/generic.py +++ b/stix/bindings/extensions/structured_coa/generic.py @@ -146,7 +146,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -175,7 +175,7 @@ def parse(inFileName): def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/test_mechanism/generic.py b/stix/bindings/extensions/test_mechanism/generic.py index ca06cac1..71babae8 100644 --- a/stix/bindings/extensions/test_mechanism/generic.py +++ b/stix/bindings/extensions/test_mechanism/generic.py @@ -146,7 +146,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -192,7 +192,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py index 6e1559ec..6ac133eb 100644 --- a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py +++ b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py @@ -110,7 +110,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -156,7 +156,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/test_mechanism/oval_5_10.py b/stix/bindings/extensions/test_mechanism/oval_5_10.py index 565432d2..42fafa04 100644 --- a/stix/bindings/extensions/test_mechanism/oval_5_10.py +++ b/stix/bindings/extensions/test_mechanism/oval_5_10.py @@ -120,7 +120,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -166,7 +166,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/test_mechanism/snort.py b/stix/bindings/extensions/test_mechanism/snort.py index 53908ddf..b00dd357 100644 --- a/stix/bindings/extensions/test_mechanism/snort.py +++ b/stix/bindings/extensions/test_mechanism/snort.py @@ -185,7 +185,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -231,7 +231,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/test_mechanism/yara.py b/stix/bindings/extensions/test_mechanism/yara.py index 458c9945..02d81e9c 100644 --- a/stix/bindings/extensions/test_mechanism/yara.py +++ b/stix/bindings/extensions/test_mechanism/yara.py @@ -121,7 +121,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -167,7 +167,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/extensions/vulnerability/cvrf_1_1.py b/stix/bindings/extensions/vulnerability/cvrf_1_1.py index 49bc751b..fe6c179e 100644 --- a/stix/bindings/extensions/vulnerability/cvrf_1_1.py +++ b/stix/bindings/extensions/vulnerability/cvrf_1_1.py @@ -111,7 +111,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -157,7 +157,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/incident.py b/stix/bindings/incident.py index 8e177282..9945d1b5 100644 --- a/stix/bindings/incident.py +++ b/stix/bindings/incident.py @@ -651,7 +651,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('time') try: self.time = self.gds_parse_datetime(value, node, 'time') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (time): %s' % exp) value = find_attr_value_('time_precision', node) if value is not None and 'time_precision' not in already_processed: @@ -2718,7 +2718,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -2764,7 +2764,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/indicator.py b/stix/bindings/indicator.py index d6c8b810..593559eb 100644 --- a/stix/bindings/indicator.py +++ b/stix/bindings/indicator.py @@ -389,7 +389,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('sightings_count') try: self.sightings_count = int(value) - except ValueError, exp: + except ValueError as exp: raise_parse_error(node, 'Bad integer attribute: %s' % exp) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Sighting': @@ -505,7 +505,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) value = find_attr_value_('timestamp_precision', node) if value is not None and 'timestamp_precision' not in already_processed: @@ -1221,7 +1221,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -1267,7 +1267,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/report.py b/stix/bindings/report.py index 9e3fbcc4..9faba8ec 100644 --- a/stix/bindings/report.py +++ b/stix/bindings/report.py @@ -835,7 +835,7 @@ def get_root_tag(node): def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index 257fd74e..109d37e7 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -330,7 +330,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) super(RelatedPackageRefType, self).buildAttributes(node, attrs, already_processed) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): @@ -728,7 +728,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) value = find_attr_value_('timestamp_precision', node) @@ -1092,7 +1092,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('ordinality') try: self.ordinality = int(value) - except ValueError, exp: + except ValueError as exp: raise_parse_error(node, 'Bad integer attribute: %s' % exp) value = find_attr_value_('name', node) if value is not None and 'name' not in already_processed: @@ -2098,7 +2098,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass @@ -2199,7 +2199,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass @@ -2300,7 +2300,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass @@ -2402,7 +2402,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass @@ -2503,7 +2503,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass @@ -2655,7 +2655,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Names': @@ -2824,7 +2824,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass @@ -2926,7 +2926,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass @@ -3420,7 +3420,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) value = find_attr_value_('timestamp_precision', node) if value is not None and 'timestamp_precision' not in already_processed: @@ -3813,7 +3813,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) value = find_attr_value_('idref', node) if value is not None and 'idref' not in already_processed: @@ -3904,7 +3904,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -3950,7 +3950,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/stix_core.py b/stix/bindings/stix_core.py index 0d2d779e..2f958205 100644 --- a/stix/bindings/stix_core.py +++ b/stix/bindings/stix_core.py @@ -186,7 +186,7 @@ def buildAttributes(self, node, attrs, already_processed): already_processed.add('timestamp') try: self.timestamp = self.gds_parse_datetime(value, node, 'timestamp') - except ValueError, exp: + except ValueError as exp: raise ValueError('Bad date-time attribute (timestamp): %s' % exp) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'STIX_Header': @@ -994,7 +994,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -1044,7 +1044,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/threat_actor.py b/stix/bindings/threat_actor.py index 35be13d7..0300d995 100644 --- a/stix/bindings/threat_actor.py +++ b/stix/bindings/threat_actor.py @@ -514,7 +514,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -560,7 +560,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/bindings/ttp.py b/stix/bindings/ttp.py index f67ecc0a..d50b5a1a 100644 --- a/stix/bindings/ttp.py +++ b/stix/bindings/ttp.py @@ -1552,7 +1552,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): """ def usage(): - print USAGE_TEXT + print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): @@ -1598,7 +1598,7 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from StringIO import StringIO + from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) diff --git a/stix/common/__init__.py b/stix/common/__init__.py index 5782fe1b..569db3a9 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -56,6 +56,7 @@ import stix.utils as utils import stix.bindings.stix_common as common_binding +from mixbox.vendor.six import text_type class EncodedCDATA(stix.Entity): _namespace = "http://stix.mitre.org/common-1" @@ -130,4 +131,4 @@ def __str__(self): return self.__unicode__().encode("utf-8") def __unicode__(self): - return unicode(self.value) + return text_type(self.value) diff --git a/stix/common/kill_chains/__init__.py b/stix/common/kill_chains/__init__.py index 02189dda..03ffa877 100644 --- a/stix/common/kill_chains/__init__.py +++ b/stix/common/kill_chains/__init__.py @@ -5,6 +5,8 @@ import stix import stix.bindings.stix_common as common_binding +from mixbox.vendor.six import string_types + class KillChain(stix.Entity): _binding = common_binding @@ -117,7 +119,7 @@ def phase_id(self): @phase_id.setter def phase_id(self, value): - self._set_var(basestring, try_cast=False, phase_id=value) + self._set_var(string_types, try_cast=False, phase_id=value) @property def ordinality(self): diff --git a/stix/core/__init__.py b/stix/core/__init__.py index b6519141..572e4018 100644 --- a/stix/core/__init__.py +++ b/stix/core/__init__.py @@ -120,5 +120,5 @@ def _is_valid(self, value): # Namespace flattening -from stix_package import STIXPackage # noqa -from stix_header import STIXHeader # noqa \ No newline at end of file +from .stix_package import STIXPackage # noqa +from .stix_header import STIXHeader # noqa \ No newline at end of file diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index 52178179..aecac9af 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -8,6 +8,8 @@ import stix.common as common import stix.bindings.extensions.identity.ciq_identity_3_0 as ciq_identity_binding +from mixbox.vendor.six import string_types + XML_NS_XPIL = "urn:oasis:names:tc:ciq:xpil:3" XML_NS_XNL = "urn:oasis:names:tc:ciq:xnl:3" @@ -49,8 +51,8 @@ def roles(self, valuelist): self.add_role(role) def add_role(self, role): - if not isinstance(role, basestring): - raise ValueError('role is not instance of basestring') + if not isinstance(role, string_types): + raise ValueError('role is not instance of string_types') self.roles.append(role) @@ -808,23 +810,23 @@ def __init__(self, name_lines=None, person_names=None, organisation_names=None): self.add_organisation_name(value) def add_name_line(self, value): - if isinstance(value, basestring): + if isinstance(value, string_types): self.name_lines.append(NameLine(value)) elif isinstance(value, NameLine): self.name_lines.append(value) else: - raise ValueError('value must be a basestring or NameLine instance') + raise ValueError('value must be a string_types or NameLine instance') def add_person_name(self, value): - if isinstance(value, basestring): + if isinstance(value, string_types): self.person_names.append(PersonName(name_elements=[value])) elif isinstance(value, PersonName): self.person_names.append(value) else: - raise ValueError('value must be instance of PersonName or basestring') + raise ValueError('value must be instance of PersonName or string_types') def add_organisation_name(self, value): - if isinstance(value, basestring): + if isinstance(value, string_types): self.organisation_names.append(OrganisationName(name_elements=[value])) elif isinstance(value, OrganisationName): self.organisation_names.append(value) @@ -935,8 +937,8 @@ def value(self): @value.setter def value(self, value): - if value and not isinstance(value, basestring): - raise ValueError('value must be instance of basestring') + if value and not isinstance(value, string_types): + raise ValueError('value must be instance of string_types') self._value = value @@ -1002,7 +1004,7 @@ def __init__(self, name_elements=None): self.add_name_element(name_element) def add_name_element(self, value): - if isinstance(value, basestring): + if isinstance(value, string_types): self.name_elements.append(PersonNameElement(value=value)) elif isinstance(value, PersonNameElement): self.name_elements.append(value) @@ -1087,7 +1089,7 @@ def name_elements(self, value): self.add_organisation_name_element(value) def add_organisation_name_element(self, value): - if isinstance(value, basestring): + if isinstance(value, string_types): self.name_elements.append(OrganisationNameElement(value=value)) elif isinstance(value, OrganisationNameElement): self.name_elements.append(value) diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index 4bf7b044..ecfd6c6d 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -2,12 +2,12 @@ # See LICENSE.txt for complete terms. # stdlib -from StringIO import StringIO from distutils.version import LooseVersion # external from lxml import etree import mixbox.xml +from mixbox.vendor.six import StringIO, iteritems # internal import stix @@ -149,7 +149,7 @@ def _collect_schemalocs(self, node): self.__input_schemalocations__ = {} def _collect_namespaces(self, node): - self.__input_namespaces__ = dict(node.nsmap.iteritems()) + self.__input_namespaces__ = dict(iteritems(node.nsmap)) @classmethod def from_obj(cls, obj, return_obj=None): diff --git a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py index f7ae9eff..25b918ae 100644 --- a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py +++ b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py @@ -1,12 +1,10 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# stdlib -from StringIO import StringIO - # external from lxml import etree import mixbox.xml +from mixbox.vendor.six import StringIO, iteritems # internal import stix @@ -57,7 +55,7 @@ def _collect_schemalocs(self, node): self.__input_schemalocations__ = {} def _collect_namespaces(self, node): - self.__input_namespaces__ = dict(node.nsmap.iteritems()) + self.__input_namespaces__ = dict(iteritems(node.nsmap)) def _cast_ioc(self, node): ns_ioc = "http://schemas.mandiant.com/2010/ioc" diff --git a/stix/indicator/__init__.py b/stix/indicator/__init__.py index a3116185..f6c19424 100644 --- a/stix/indicator/__init__.py +++ b/stix/indicator/__init__.py @@ -1,4 +1,4 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -from indicator import * # noqa +from .indicator import * # noqa diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index c9c0dd42..30545952 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -54,7 +54,7 @@ class SuggestedCOAs(GenericRelationshipList): >>> coa = CourseOfAction() >>> indicator = Indicator() >>> indicator.suggested_coas.append(coa) - >>> print type(indicator.suggested_coas[0]) + >>> print(type(indicator.suggested_coas[0])) Iterate over the ``suggested_coas`` property of an :class:`Indicator` @@ -62,7 +62,7 @@ class SuggestedCOAs(GenericRelationshipList): :class:`stix.coa.CourseOfAction` instance. >>> for related_coa in indicator.suggested_coas: - >>> print related_coa.item.id_ + >>> print(related_coa.item.id_) Args: suggested_coas(list): A list of :class:`stix.coa.CourseOfAction` @@ -118,7 +118,7 @@ class RelatedIndicators(GenericRelationshipList): >>> related = Indicator() >>> parent_indicator = Indicator() >>> parent_indicator.related_indicators.append(related) - >>> print type(indicator.related_indicators[0]) + >>> print(type(indicator.related_indicators[0])) Iterate over the ``related_indicators`` property of an @@ -126,7 +126,7 @@ class RelatedIndicators(GenericRelationshipList): :class:`Indicator`` instance: >>> for related in indicator.related_indicators: - >>> print related.item.id_ + >>> print(related.item.id_) Args: related_indicators (list, optional): A list of :class:`Indicator` or @@ -1133,7 +1133,7 @@ class IndicatorTypes(stix.TypedList): >>> itypes = IndicatorTypes() >>> type_ = IndicatorType(IndicatorType.TERM_IP_WATCHLIST) >>> itypes.append(type_) - >>> print len(itypes) + >>> print(len(itypes)) 1 Add a string value: @@ -1143,7 +1143,7 @@ class IndicatorTypes(stix.TypedList): >>> type(IndicatorType.TERM_IP_WATCHLIST) >>> itypes.append(IndicatorType.TERM_IP_WATCHLIST) - >>> print len(itypes) + >>> print(len(itypes)) 1 Args: diff --git a/stix/test/__init__.py b/stix/test/__init__.py index 97b43d12..8b7c08d3 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -9,6 +9,7 @@ import cybox.utils from mixbox.binding_utils import ExternalEncoding +from mixbox.vendor.six import iteritems, text_type from stix.utils import NamespaceInfo, silence_warnings @@ -68,8 +69,8 @@ def round_trip(o, output=False, list_=False): klass = o.__class__ if output: - print "Class: ", klass - print "-" * 40 + print("Class: ", klass) + print("-" * 40) # 1. cybox.Entity -> dict/list if list_: @@ -82,7 +83,7 @@ def round_trip(o, output=False, list_=False): if output: print(json_string) - print "-" * 40 + print("-" * 40) # Before parsing the JSON, make sure the cache is clear cybox.utils.cache_clear() @@ -104,18 +105,18 @@ def round_trip(o, output=False, list_=False): # 6. Bindings Object -> XML String xml_string = o2.to_xml(encoding=ExternalEncoding) - if not isinstance(xml_string, unicode): + if not isinstance(xml_string, text_type): xml_string = xml_string.decode(ExternalEncoding) except KeyError as ex: - print str(ex) + print(str(ex)) ns_info.finalize() - print ns_info.finalized_namespaces + print(ns_info.finalized_namespaces) raise ex if output: print(xml_string) - print "-" * 40 + print("-" * 40) # Before parsing the XML, make sure the cache is clear cybox.utils.cache_clear() @@ -147,8 +148,8 @@ def test_round_trip_full_dict(self): def _combine(self, d): items = itertools.chain( - self._full_dict.iteritems(), - d.iteritems() + iteritems(self._full_dict), + iteritems(d) ) return dict(items) @@ -161,6 +162,7 @@ def test_round_trip_full(self): return ent = self.klass.from_dict(self._full_dict) + ent2 = round_trip(ent, output=True) @silence_warnings diff --git a/stix/test/common/structured_text_tests.py b/stix/test/common/structured_text_tests.py index ace6f5ad..735b71ed 100644 --- a/stix/test/common/structured_text_tests.py +++ b/stix/test/common/structured_text_tests.py @@ -8,6 +8,8 @@ from stix import common +from mixbox.vendor.six.moves import range + class StructuredTextTests(unittest.TestCase, EntityTestCase): klass = common.StructuredText @@ -36,7 +38,7 @@ class StructuredTextListTests(unittest.TestCase, TypedListTestCase): def _get_text_list(cls): slist = [] - for ordinality in xrange(1, 10): + for ordinality in range(1, 10): text = common.StructuredText("Ordinality %s" % ordinality) text.ordinality = ordinality slist.append(text) @@ -68,7 +70,7 @@ def test_reset(self): # reset ordinalities slist.reset() - for o in xrange(1, len(ords) + 1): + for o in range(1, len(ords) + 1): self.assertEqual(o, slist[o].ordinality) def test_ordinalities(self): diff --git a/stix/test/encoding_test.py b/stix/test/encoding_test.py index 0ff7c7a2..ed22e2fd 100644 --- a/stix/test/encoding_test.py +++ b/stix/test/encoding_test.py @@ -5,8 +5,7 @@ """Tests for various encoding issues throughout the library""" import unittest -from StringIO import StringIO - +from mixbox.vendor.six import StringIO, text_type from mixbox import binding_utils from stix.core import STIXHeader, STIXPackage @@ -142,7 +141,7 @@ def test_to_xml_no_encoding(self): s = STIXHeader() s.title = UNICODE_STR xml = s.to_xml(encoding=None) - self.assertTrue(isinstance(xml, unicode)) + self.assertTrue(isinstance(xml, text_type)) self.assertTrue(UNICODE_STR in xml) @silence_warnings diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index 40db6948..61bc8d2a 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -1,5 +1,5 @@ import unittest -from StringIO import StringIO +from mixbox.vendor.six import StringIO from lxml import etree import mixbox.xml diff --git a/stix/test/extensions/test_mechanisms/openioc_test.py b/stix/test/extensions/test_mechanisms/openioc_test.py index 0002dbe0..ab0c2c54 100644 --- a/stix/test/extensions/test_mechanisms/openioc_test.py +++ b/stix/test/extensions/test_mechanisms/openioc_test.py @@ -2,12 +2,12 @@ # See LICENSE.txt for complete terms. import unittest -import StringIO import lxml from mixbox import idgen from mixbox.namespaces import Namespace +from mixbox.vendor.six import StringIO import mixbox.xml from stix.test import EntityTestCase @@ -130,7 +130,7 @@ def tearDown(self): def _test_xml(self, obj): xml = obj.to_xml() parser = mixbox.xml.get_xml_parser() - tree = lxml.etree.parse(StringIO.StringIO(xml), parser=parser) + tree = lxml.etree.parse(StringIO(xml), parser=parser) root = tree.getroot() xpath = "//openioc:description" @@ -142,7 +142,7 @@ def _test_xml(self, obj): def test_etree(self): parser = mixbox.xml.get_xml_parser() - tree = lxml.etree.parse(StringIO.StringIO(self.XML), parser=parser) + tree = lxml.etree.parse(StringIO(self.XML), parser=parser) ext = OpenIOCTestMechanism() ext.ioc = tree @@ -150,7 +150,7 @@ def test_etree(self): def test_etree_dict(self): parser = mixbox.xml.get_xml_parser() - tree = lxml.etree.parse(StringIO.StringIO(self.XML), parser=parser) + tree = lxml.etree.parse(StringIO(self.XML), parser=parser) ext = OpenIOCTestMechanism() ext.ioc = tree diff --git a/stix/test/incident_test.py b/stix/test/incident_test.py index 4ba9a3a8..d6eada39 100644 --- a/stix/test/incident_test.py +++ b/stix/test/incident_test.py @@ -2,7 +2,8 @@ # See LICENSE.txt for complete terms. import unittest -import StringIO + +from mixbox.vendor.six import StringIO from stix.core import STIXPackage from cybox.common import StructuredText @@ -493,7 +494,7 @@ def test_description_output(self): assets.add_Affected_Asset(asset) incident.Affected_Assets = assets - s = StringIO.StringIO() + s = StringIO() incident.export(s.write, 0, {'http://stix.mitre.org/Incident-1': 'incident'}) xml = s.getvalue() diff --git a/stix/test/utils/nsparser_test.py b/stix/test/utils/nsparser_test.py index da4cdaa9..ba7adc2f 100644 --- a/stix/test/utils/nsparser_test.py +++ b/stix/test/utils/nsparser_test.py @@ -2,11 +2,11 @@ # See LICENSE.txt for complete terms. # stdlib -import StringIO import unittest # external import lxml.etree +from mixbox.vendor.six import StringIO # internal import stix @@ -73,7 +73,7 @@ def test_namespace_collect(self): nsinfo.finalize(ns_dict=NSMAP, schemaloc_dict=SCHEMALOCS) namespaces = nsinfo.finalized_namespaces.values() - self.assertTrue(all(ns in namespaces for ns in NSMAP.iterkeys())) + self.assertTrue(all(ns in namespaces for ns in NSMAP)) @silence_warnings @@ -134,7 +134,7 @@ def test_duplicate_ns_prefix(self): timestamp="2015-04-09T14:22:25.620831+00:00"/>""" ) - sio = StringIO.StringIO(xml) + sio = StringIO(xml) p = STIXPackage.from_xml(sio) # Exporting should raise an error. @@ -168,7 +168,7 @@ def test_parsed_namespaces(self): timestamp="2015-04-09T14:22:25.620831+00:00"/>""" ) - sio = StringIO.StringIO(xml) + sio = StringIO(xml) p = STIXPackage.from_xml(sio) serialized = p.to_xml() diff --git a/stix/test/utils/parser_test.py b/stix/test/utils/parser_test.py index e54d5fb9..887960c6 100644 --- a/stix/test/utils/parser_test.py +++ b/stix/test/utils/parser_test.py @@ -1,7 +1,7 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -from StringIO import StringIO +from mixbox.vendor.six import StringIO import unittest from stix.utils import (EntityParser, UnknownVersionError, diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index 869c030b..cf5b1c80 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -9,6 +9,7 @@ from mixbox.entities import Entity, EntityList import mixbox.xml +from mixbox.vendor.six import iteritems, string_types import stix @@ -221,7 +222,7 @@ def is_sequence(item): ``tuple``). String types will return ``False``. """ - return hasattr(item, "__iter__") + return hasattr(item, "__iter__") and not isinstance(item, string_types) def check_version(expected, found): @@ -252,7 +253,7 @@ def iter_vars(obj): def check(name): return name not in ('__input_namespaces__', '__input_schemalocations__') - instance_vars = vars(obj).iteritems() + instance_vars = iteritems(vars(obj)) return ((attr_name(name), val) for name, val in instance_vars if check(name)) diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index 2804482f..84b2d20f 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -7,6 +7,7 @@ from mixbox import idgen from mixbox.entities import Entity +from mixbox.vendor.six import iteritems, itervalues import cybox import cybox.core @@ -149,7 +150,7 @@ def _check_namespaces(self, ns_dict): namespace. """ - for prefix, namespaces in ns_dict.iteritems(): + for prefix, namespaces in iteritems(ns_dict): if len(namespaces) == 1: continue @@ -201,7 +202,7 @@ def _finalize_namespaces(self, ns_dict=None): # Copy and flip the input dictionary from ns=>alias to alias=>ns user_namespaces = {} - for ns, alias in ns_dict.iteritems(): + for ns, alias in iteritems(ns_dict): user_namespaces[alias] = ns # Our return value @@ -213,7 +214,7 @@ def _finalize_namespaces(self, ns_dict=None): ns_dict[id_alias].add(id_ns) # Build namespace dictionaries from the collected Entity objects. - collected_prefixed = dict(self._collected_namespaces.iteritems()) + collected_prefixed = dict(iteritems(self._collected_namespaces)) # Pop the unprefixed entries. no_prefix = collected_prefixed.pop(None, set()) @@ -227,11 +228,11 @@ def _finalize_namespaces(self, ns_dict=None): # All the namespaces dictionaries we need to merge and export. namespace_dicts = itertools.chain( - self._BASELINE_NAMESPACES.iteritems(), - self._input_namespaces.iteritems(), - collected_prefixed.iteritems(), - collected_unprefixed.iteritems(), - user_namespaces.iteritems() + iteritems(self._BASELINE_NAMESPACES), + iteritems(self._input_namespaces), + iteritems(collected_prefixed), + iteritems(collected_unprefixed), + iteritems(user_namespaces) ) # Build our merged namespace dictionary. It will be inspected for @@ -245,7 +246,7 @@ def _finalize_namespaces(self, ns_dict=None): # Flatten the dictionary by popping the namespace from the namespace # set values in ns_dict. flattened = {} - for alias, ns_set in ns_dict.iteritems(): + for alias, ns_set in iteritems(ns_dict): flattened[alias] = ns_set.pop() # Return the flattened dictionary @@ -255,7 +256,7 @@ def _finalize_schemalocs(self, schemaloc_dict=None): # If schemaloc_dict was passed in, make a copy so we don't mistakenly # modify the original. if schemaloc_dict: - schemaloc_dict = dict(schemaloc_dict.iteritems()) + schemaloc_dict = dict(iteritems(schemaloc_dict)) else: schemaloc_dict = {} @@ -270,7 +271,7 @@ def _finalize_schemalocs(self, schemaloc_dict=None): # # If there is a schemalocation found in both the parsed schemalocs and # the schema_loc dict, use the schemaloc_dict value. - for ns, loc in self._input_schemalocs.iteritems(): + for ns, loc in iteritems(self._input_schemalocs): if ns in schemaloc_dict: continue schemaloc_dict[ns] = loc @@ -278,7 +279,7 @@ def _finalize_schemalocs(self, schemaloc_dict=None): # Iterate over the finalized namespaces for a document and attempt # to map them to schemalocations. Warn if the namespace should have a # schemalocation and we can't find it anywhere. - nsset = set(self.finalized_namespaces.itervalues()) + nsset = set(itervalues(self.finalized_namespaces)) for ns in nsset: if ns in DEFAULT_STIX_SCHEMALOCATIONS: schemaloc_dict[ns] = DEFAULT_STIX_SCHEMALOCATIONS[ns] @@ -306,7 +307,7 @@ def _finalize_binding_namespaces(self): return {} # TODO: Should this return the DEFAULT_STIX_NAMESPACES? binding_namespaces = {} - for alias, ns in self.finalized_namespaces.iteritems(): + for alias, ns in iteritems(self.finalized_namespaces): binding_namespaces[ns] = alias # Always use the default STIX prefixes for STIX namespaces. @@ -360,7 +361,7 @@ def get_namespace_schemalocation_dict(self, entity, ns_dict=None, schemaloc_dict return ns_info.finalized_schemalocs def get_xmlns_str(self, ns_dict): - pairs = sorted(ns_dict.iteritems()) + pairs = sorted(iteritems(ns_dict)) return "\n\t".join( 'xmlns:%s="%s"' % (alias, ns) for alias, ns in pairs ) @@ -372,7 +373,7 @@ def get_schemaloc_str(self, schemaloc_dict): schemaloc_str_start = 'xsi:schemaLocation="\n\t' schemaloc_str_end = '"' - pairs = sorted(schemaloc_dict.iteritems()) + pairs = sorted(iteritems(schemaloc_dict)) schemaloc_str_content = "\n\t".join( "%s %s" % (ns, loc) for ns, loc in pairs ) @@ -496,16 +497,16 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): #: Mapping of all STIX/STIX Extension/CybOX/XML namespaces DEFAULT_STIX_NAMESPACES = dict( itertools.chain( - DEFAULT_CYBOX_NAMESPACES.iteritems(), - XML_NAMESPACES.iteritems(), - DEFAULT_STIX_NS_TO_PREFIX.iteritems(), - DEFAULT_EXT_TO_PREFIX.iteritems() + iteritems(DEFAULT_CYBOX_NAMESPACES), + iteritems(XML_NAMESPACES), + iteritems(DEFAULT_STIX_NS_TO_PREFIX), + iteritems(DEFAULT_EXT_TO_PREFIX) ) ) #: Prefix-to-namespace mapping of the `DEFAULT_STIX_NAMESPACES` mapping DEFAULT_STIX_PREFIX_TO_NAMESPACE = dict( - (alias, ns) for ns, alias in DEFAULT_STIX_NAMESPACES.iteritems() + (alias, ns) for ns, alias in iteritems(DEFAULT_STIX_NAMESPACES) ) #: Tuple of all keys found in `DEFAULT_STIX_NAMESPACES` mapping. @@ -514,9 +515,9 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): #: Mapping of STIX/CybOX/STIX Extension namespaces to canonical schema locations DEFAULT_STIX_SCHEMALOCATIONS = dict( itertools.chain( - STIX_NS_TO_SCHEMALOCATION.iteritems(), - EXT_NS_TO_SCHEMALOCATION.iteritems(), - CYBOX_NS_TO_SCHEMALOCATION.iteritems(), + iteritems(STIX_NS_TO_SCHEMALOCATION), + iteritems(EXT_NS_TO_SCHEMALOCATION), + iteritems(CYBOX_NS_TO_SCHEMALOCATION), ) ) @@ -531,7 +532,7 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): del ns_to_prefix['http://maec.mitre.org/default_vocabularies-1'] prefix_to_ns = dict( - (prefix, ns) for (ns, prefix) in ns_to_prefix.iteritems() + (prefix, ns) for (ns, prefix) in iteritems(ns_to_prefix) ) ns_to_schemalocation = dict( @@ -540,5 +541,5 @@ def get_namespace_def_str(self, namespaces, schemaloc_dict): DEFAULT_STIX_NAMESPACES.update(ns_to_prefix) DEFAULT_STIX_PREFIX_TO_NAMESPACE.update(prefix_to_ns) - DEFAULT_STIX_NAMESPACES_TUPLE = tuple(DEFAULT_STIX_NAMESPACES.iterkeys()) + DEFAULT_STIX_NAMESPACES_TUPLE = tuple(DEFAULT_STIX_NAMESPACES) DEFAULT_STIX_SCHEMALOCATIONS.update(ns_to_schemalocation) diff --git a/stix/utils/walk.py b/stix/utils/walk.py index fe1261ea..be1f9e8c 100644 --- a/stix/utils/walk.py +++ b/stix/utils/walk.py @@ -6,6 +6,7 @@ # external from cybox.common import ObjectProperties +from mixbox.vendor.six import iteritems # internal from . import is_entity, is_entitylist, attr_name, is_sequence @@ -28,10 +29,10 @@ def _iter_vars(obj): attrs = [] if hasattr(obj, "__dict__"): - attrs.append(vars(obj).iteritems()) + attrs.append(iteritems(vars(obj))) if hasattr(obj, "_fields"): - attrs.append(obj._fields.iteritems()) + attrs.append(iteritems(obj._fields)) return itertools.chain.from_iterable(attrs) From fe159b065b181a67d10935f93d3fc89d936d9f14 Mon Sep 17 00:00:00 2001 From: clenk Date: Wed, 13 Jul 2016 12:08:08 -0400 Subject: [PATCH 318/438] Fix Python 3 support --- .travis.yml | 8 ++++++- stix/base.py | 23 ++++++++++--------- .../extensions/address/ciq_address_3_0.py | 2 +- .../extensions/attack_pattern/capec_2_7.py | 2 +- .../extensions/identity/ciq_identity_3_0.py | 2 +- stix/bindings/extensions/malware/maec_4_1.py | 2 +- .../test_mechanism/open_ioc_2010.py | 2 +- .../extensions/test_mechanism/oval_5_10.py | 4 ++-- .../extensions/vulnerability/cvrf_1_1.py | 2 +- stix/bindings/incident.py | 4 ++-- stix/common/__init__.py | 6 ++++- stix/common/structured_text.py | 9 ++++++-- stix/extensions/malware/maec_4_1_malware.py | 4 ++-- .../open_ioc_2010_test_mechanism.py | 4 ++-- stix/test/core/stix_package_test.py | 5 ++-- stix/test/encoding_test.py | 8 +++---- .../malware/maec_4_1_malware_test.py | 4 ++-- .../test_mechanisms/openioc_test.py | 15 ++++++------ tox.ini | 2 +- 19 files changed, 62 insertions(+), 46 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3a162b37..e3f9b674 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,17 @@ language: python +python: + - 3.5 + env: - TOXENV=py26 - TOXENV=py27 + - TOXENV=py33 + - TOXENV=py34 + - TOXENV=py35 - TOXENV=lxml23 install: - - pip install tox + - pip install -U tox script: - tox diff --git a/stix/base.py b/stix/base.py index f9ef7ebc..5bdf1d22 100644 --- a/stix/base.py +++ b/stix/base.py @@ -5,16 +5,16 @@ import json import collections import itertools -import StringIO +from sys import version_info from mixbox import idgen from mixbox.binding_utils import save_encoding from mixbox.cache import Cached +from mixbox.vendor.six import StringIO, iteritems, itervalues, text_type, binary_type # internal from . import utils - def _override(*args, **kwargs): raise NotImplementedError() @@ -51,7 +51,7 @@ def _set_var(self, klass, try_cast=True, arg=None, **kwargs): and the field value is the value. """ - name, item = kwargs.iteritems().next() + name, item = next(iteritems(kwargs)) attr = utils.private_name(name) # 'title' => '_title' if item is None: @@ -86,7 +86,7 @@ def _set_vocab(self, klass=None, **kwargs): from stix.common import VocabString klass = klass or VocabString - item = kwargs.itervalues().next() + item = next(itervalues(kwargs)) if isinstance(item, VocabString): self._set_var(VocabString, **kwargs) @@ -114,8 +114,8 @@ def to_xml(self, include_namespaces=True, include_schemalocs=False, """Serializes a :class:`Entity` instance to an XML string. The default character encoding is ``utf-8`` and can be set via the - `encoding` parameter. If `encoding` is ``None``, a unicode string - is returned. + `encoding` parameter. If `encoding` is ``None``, a string (unicode in + Python 2, str in Python 3) is returned. Args: auto_namespace: Automatically discover and export XML namespaces @@ -136,7 +136,8 @@ def to_xml(self, include_namespaces=True, include_schemalocs=False, only be included if `auto_namespace` is ``False``. pretty: Pretty-print the XML. encoding: The output character encoding. Default is ``utf-8``. If - `encoding` is set to ``None``, a unicode string is returned. + `encoding` is set to ``None``, a string (unicode in Python 2, + str in Python 3) is returned. Returns: An XML string for this @@ -169,8 +170,8 @@ def to_xml(self, include_namespaces=True, include_schemalocs=False, ns_info.finalized_schemalocs = schemaloc_dict or {} obj_ns_dict = dict( itertools.chain( - ns_dict.iteritems(), - nsparser.DEFAULT_STIX_NAMESPACES.iteritems() + iteritems(ns_dict), + iteritems(nsparser.DEFAULT_STIX_NAMESPACES) ) ) @@ -187,7 +188,7 @@ def to_xml(self, include_namespaces=True, include_schemalocs=False, namespace_def = namespace_def.replace('\n\t', ' ') with save_encoding(encoding): - sio = StringIO.StringIO() + sio = StringIO() obj.export( sio.write, # output buffer 0, # output level @@ -197,7 +198,7 @@ def to_xml(self, include_namespaces=True, include_schemalocs=False, ) # Ensure that the StringIO buffer is unicode - s = unicode(sio.getvalue()) + s = text_type(sio.getvalue()) if encoding: return s.encode(encoding) diff --git a/stix/bindings/extensions/address/ciq_address_3_0.py b/stix/bindings/extensions/address/ciq_address_3_0.py index 3d3bad02..9a4902d9 100644 --- a/stix/bindings/extensions/address/ciq_address_3_0.py +++ b/stix/bindings/extensions/address/ciq_address_3_0.py @@ -88,7 +88,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CIQAddr eol_ = '' if self.Location is not None: showIndent(lwrite, level, pretty_print) - lwrite(etree_.tostring(self.Location, pretty_print=pretty_print)) + lwrite(etree_.tostring(self.Location, pretty_print=pretty_print).decode()) #self.Location.export(lwrite, level, nsmap, namespace_, name_='Location', pretty_print=pretty_print) def build(self, node): already_processed = set() diff --git a/stix/bindings/extensions/attack_pattern/capec_2_7.py b/stix/bindings/extensions/attack_pattern/capec_2_7.py index 1678dd89..160fb182 100644 --- a/stix/bindings/extensions/attack_pattern/capec_2_7.py +++ b/stix/bindings/extensions/attack_pattern/capec_2_7.py @@ -87,7 +87,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CAPEC2. eol_ = '' if self.CAPEC is not None: showIndent(lwrite, level, pretty_print) - lwrite(etree_.tostring(self.CAPEC, pretty_print=pretty_print)) + lwrite(etree_.tostring(self.CAPEC, pretty_print=pretty_print).decode()) #self.CAPEC.export(lwrite, level, nsmap, namespace_, name_='CAPEC', pretty_print=pretty_print) def build(self, node): already_processed = set() diff --git a/stix/bindings/extensions/identity/ciq_identity_3_0.py b/stix/bindings/extensions/identity/ciq_identity_3_0.py index f2051144..a92b39aa 100644 --- a/stix/bindings/extensions/identity/ciq_identity_3_0.py +++ b/stix/bindings/extensions/identity/ciq_identity_3_0.py @@ -99,7 +99,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CIQIden eol_ = '' if self.Specification is not None: showIndent(lwrite, level, pretty_print) - lwrite(etree_.tostring(self.Specification, pretty_print=pretty_print)) + lwrite(etree_.tostring(self.Specification, pretty_print=pretty_print).decode()) #self.Specification.export(lwrite, level, nsmap, namespace_, name_='Specification', pretty_print=pretty_print) for Role_ in self.Role: showIndent(lwrite, level, pretty_print) diff --git a/stix/bindings/extensions/malware/maec_4_1.py b/stix/bindings/extensions/malware/maec_4_1.py index 83c190b1..622dd90d 100644 --- a/stix/bindings/extensions/malware/maec_4_1.py +++ b/stix/bindings/extensions/malware/maec_4_1.py @@ -92,7 +92,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='MAEC4.1 self.MAEC.export(lwrite, level, namespace_='stix-maec:', name_='MAEC', pretty_print=pretty_print) else: showIndent(lwrite, level, pretty_print) - lwrite(etree_.tostring(self.MAEC, pretty_print=pretty_print)) + lwrite(etree_.tostring(self.MAEC, pretty_print=pretty_print).decode()) def build(self, node): already_processed = set() self.buildAttributes(node, node.attrib, already_processed) diff --git a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py index 6ac133eb..f882f0b4 100644 --- a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py +++ b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py @@ -87,7 +87,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='OpenIOC eol_ = '' if self.ioc is not None: showIndent(lwrite, level, pretty_print) - lwrite(etree_.tostring(self.ioc, pretty_print=pretty_print)) + lwrite(etree_.tostring(self.ioc, pretty_print=pretty_print).decode()) #self.ioc.export(lwrite, level, nsmap, namespace_, name_='ioc', pretty_print=pretty_print) def build(self, node): already_processed = set() diff --git a/stix/bindings/extensions/test_mechanism/oval_5_10.py b/stix/bindings/extensions/test_mechanism/oval_5_10.py index 42fafa04..9093cfe9 100644 --- a/stix/bindings/extensions/test_mechanism/oval_5_10.py +++ b/stix/bindings/extensions/test_mechanism/oval_5_10.py @@ -91,11 +91,11 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='OVAL5.1 eol_ = '' if self.oval_definitions is not None: showIndent(lwrite, level, pretty_print) - lwrite(etree_.tostring(self.oval_definitions, pretty_print=pretty_print)) + lwrite(etree_.tostring(self.oval_definitions, pretty_print=pretty_print).decode()) #self.oval_definitions.export(lwrite, level, nsmap, namespace_, name_='oval_definitions', pretty_print=pretty_print) if self.oval_variables is not None: showIndent(lwrite, level, pretty_print) - lwrite(etree_.tostring(self.oval_variables, pretty_print=pretty_print)) + lwrite(etree_.tostring(self.oval_variables, pretty_print=pretty_print).decode()) #self.oval_variables.export(lwrite, level, nsmap, namespace_, name_='oval_variables', pretty_print=pretty_print) def build(self, node): already_processed = set() diff --git a/stix/bindings/extensions/vulnerability/cvrf_1_1.py b/stix/bindings/extensions/vulnerability/cvrf_1_1.py index fe6c179e..c67a9065 100644 --- a/stix/bindings/extensions/vulnerability/cvrf_1_1.py +++ b/stix/bindings/extensions/vulnerability/cvrf_1_1.py @@ -88,7 +88,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='CVRF1.1 eol_ = '' if self.cvrfdoc is not None: showIndent(lwrite, level, pretty_print) - lwrite(etree_.tostring(self.cvrfdoc, pretty_print=pretty_print)) + lwrite(etree_.tostring(self.cvrfdoc, pretty_print=pretty_print).decode()) #self.cvrfdoc.export(lwrite, level, nsmap, namespace_, name_='cvrfdoc', pretty_print=pretty_print) def build(self, node): already_processed = set() diff --git a/stix/bindings/incident.py b/stix/bindings/incident.py index 9945d1b5..56dd2f6c 100644 --- a/stix/bindings/incident.py +++ b/stix/bindings/incident.py @@ -2764,8 +2764,8 @@ def parseEtree(inFileName): return rootObj, rootElement def parseString(inString): - from mixbox.vendor.six import StringIO - doc = parsexml_(StringIO(inString)) + from mixbox.vendor.six import BytesIO + doc = parsexml_(BytesIO(inString.encode('utf-8'))) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) if rootClass is None: diff --git a/stix/common/__init__.py b/stix/common/__init__.py index 569db3a9..1cc3844c 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -2,6 +2,7 @@ # See LICENSE.txt for complete terms. from __future__ import absolute_import +from sys import version_info from .structured_text import StructuredText, StructuredTextList # noqa from .vocabs import VocabString # noqa @@ -128,7 +129,10 @@ def to_dict(self): return d def __str__(self): - return self.__unicode__().encode("utf-8") + if version_info < (3,): + return self.__unicode__().encode("utf-8") + else: + return self.__unicode__() def __unicode__(self): return text_type(self.value) diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index c1257751..c4ba299e 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -4,10 +4,12 @@ import itertools import contextlib import collections +from sys import version_info import stix import stix.utils as utils import stix.bindings.stix_common as stix_common_binding +from mixbox.vendor.six import text_type #: Default ordinality value for StructuredText. DEFAULT_ORDINALITY = 1 @@ -150,13 +152,16 @@ def __str__(self): """Returns a UTF-8 encoded string representation of the ``value``. """ - return self.__unicode__().encode("utf-8") + if version_info < (3,): + return self.__unicode__().encode("utf-8") + else: + return self.__unicode__() def __unicode__(self): """Returns a ``unicode`` string representation of the ``value``. """ - return unicode(self.value) + return text_type(self.value) @contextlib.contextmanager diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index ecfd6c6d..61100724 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -7,7 +7,7 @@ # external from lxml import etree import mixbox.xml -from mixbox.vendor.six import StringIO, iteritems +from mixbox.vendor.six import BytesIO, iteritems # internal import stix @@ -206,7 +206,7 @@ def from_dict(cls, d, return_obj=None): return_obj.maec = cls._maec_from_dict(maec) else: parser = mixbox.xml.get_xml_parser() - return_obj.maec = etree.parse(StringIO(maec), parser=parser) + return_obj.maec = etree.parse(BytesIO(maec), parser=parser) return return_obj diff --git a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py index 25b918ae..03e05d57 100644 --- a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py +++ b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py @@ -4,7 +4,7 @@ # external from lxml import etree import mixbox.xml -from mixbox.vendor.six import StringIO, iteritems +from mixbox.vendor.six import BytesIO, iteritems # internal import stix @@ -98,7 +98,7 @@ def from_dict(cls, d, return_obj=None): super(OpenIOCTestMechanism, cls).from_dict(d, return_obj) if 'ioc' in d: parser = mixbox.xml.get_xml_parser() - return_obj.ioc = etree.parse(StringIO(d['ioc']), parser=parser) + return_obj.ioc = etree.parse(BytesIO(d['ioc']), parser=parser) return return_obj diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index 02d1d1a1..e932a146 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -2,9 +2,10 @@ # See LICENSE.txt for complete terms. import copy -import StringIO import unittest +from mixbox.vendor.six import BytesIO + from stix.test import EntityTestCase, assert_warnings from stix.test import report_test from stix.test.common import kill_chains_test, related_test @@ -126,7 +127,7 @@ def test_deepcopy(self): """ package = core.STIXPackage.from_xml( - StringIO.StringIO( + BytesIO( core.STIXPackage().to_xml() ) ) diff --git a/stix/test/encoding_test.py b/stix/test/encoding_test.py index ed22e2fd..859f8d71 100644 --- a/stix/test/encoding_test.py +++ b/stix/test/encoding_test.py @@ -5,7 +5,7 @@ """Tests for various encoding issues throughout the library""" import unittest -from mixbox.vendor.six import StringIO, text_type +from mixbox.vendor.six import BytesIO, text_type from mixbox import binding_utils from stix.core import STIXHeader, STIXPackage @@ -147,7 +147,7 @@ def test_to_xml_no_encoding(self): @silence_warnings def test_from_xml_utf16_encoded(self): utf16_xml = XML.encode('utf-16') - sio = StringIO(utf16_xml) + sio = BytesIO(utf16_xml) sp = STIXPackage.from_xml(sio, encoding='utf-16') header = sp.stix_header self.assertEqual(header.title, UNICODE_STR) @@ -155,7 +155,7 @@ def test_from_xml_utf16_encoded(self): @silence_warnings def test_from_xml_default_encoded(self): utf8_xml = XML.encode('utf-8') - sio = StringIO(utf8_xml) + sio = BytesIO(utf8_xml) sp = STIXPackage.from_xml(sio) header = sp.stix_header self.assertEqual(header.title, UNICODE_STR) @@ -171,7 +171,7 @@ def test_utf16_roundtrip(self): xml16 = sp.to_xml(encoding='utf-16') # deserialize as utf-16 - sp2 = STIXPackage.from_xml(StringIO(xml16), encoding='utf-16') + sp2 = STIXPackage.from_xml(BytesIO(xml16), encoding='utf-16') sh2 = sp2.stix_header # check that the titles align diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index 61bc8d2a..aee084ae 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -1,5 +1,5 @@ import unittest -from mixbox.vendor.six import StringIO +from mixbox.vendor.six import StringIO, BytesIO from lxml import etree import mixbox.xml @@ -73,7 +73,7 @@ class PythonMAECEtreeTests(unittest.TestCase): def _test_xml(self, obj): xml = obj.to_xml() parser = mixbox.xml.get_xml_parser() - tree = etree.parse(StringIO(xml), parser=parser) + tree = etree.parse(BytesIO(xml), parser=parser) root = tree.getroot() xpath = "//cyboxCommon:Type" diff --git a/stix/test/extensions/test_mechanisms/openioc_test.py b/stix/test/extensions/test_mechanisms/openioc_test.py index ab0c2c54..01b4da4b 100644 --- a/stix/test/extensions/test_mechanisms/openioc_test.py +++ b/stix/test/extensions/test_mechanisms/openioc_test.py @@ -7,7 +7,7 @@ from mixbox import idgen from mixbox.namespaces import Namespace -from mixbox.vendor.six import StringIO +from mixbox.vendor.six import StringIO, BytesIO import mixbox.xml from stix.test import EntityTestCase @@ -41,12 +41,11 @@ class OpenIOCTestMechanismTests(EntityTestCase, unittest.TestCase): class OpenIOCEtreeTests(unittest.TestCase): DESCRIPTION = "Finds Zeus variants, twexts, sdra64, ntos" XML = ( - """ + r""" Zeus @@ -120,8 +119,8 @@ class OpenIOCEtreeTests(unittest.TestCase): ) def setUp(self): - ioc_ns = Namespace("http://schemas.mandiant.com/2010/ioc", - "mandiant-openioc", '') + ioc_ns = Namespace("http://stix.mitre.org/extensions/TestMechanism#OpenIOC2010-1", + "stix-openioc", '') idgen.set_id_namespace(ioc_ns) def tearDown(self): @@ -130,11 +129,11 @@ def tearDown(self): def _test_xml(self, obj): xml = obj.to_xml() parser = mixbox.xml.get_xml_parser() - tree = lxml.etree.parse(StringIO(xml), parser=parser) + tree = lxml.etree.parse(BytesIO(xml), parser=parser) root = tree.getroot() - xpath = "//openioc:description" - nodes = root.xpath(xpath, namespaces={'openioc': 'http://schemas.mandiant.com/2010/ioc'}) + xpath = "//stix-openioc:ioc//description" + nodes = root.xpath(xpath, namespaces={'stix-openioc': 'http://stix.mitre.org/extensions/TestMechanism#OpenIOC2010-1'}) self.assertTrue(nodes is not None) self.assertEqual(len(nodes), 1) diff --git a/tox.ini b/tox.ini index 250fe85d..444b6902 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py26, py27, lxml23 +envlist = py26, py27, py33, py34, py35, lxml23 [testenv] commands = From 8f5a604e10d1a0573f01bab7a9c03c7ef920fa3d Mon Sep 17 00:00:00 2001 From: clenk Date: Fri, 15 Jul 2016 11:35:44 -0400 Subject: [PATCH 319/438] Update examples in docs to avoid deprecation warnings --- docs/examples/index.rst | 34 +++++++++++++++++++++++++--------- docs/getting_started.rst | 15 +++++++++------ 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/docs/examples/index.rst b/docs/examples/index.rst index 1ff8e757..d050bfe9 100755 --- a/docs/examples/index.rst +++ b/docs/examples/index.rst @@ -21,26 +21,42 @@ Creating a STIX Package .. code-block:: python - from stix.core import STIXPackage, STIXHeader + from stix.core import STIXPackage + from stix.report import Report + from stix.report.header import Header from stix.utils import IDGenerator, set_id_method set_id_method(IDGenerator.METHOD_INT) # For testing and demonstration only! stix_package = STIXPackage() - stix_header = STIXHeader() - stix_header.description = "Getting Started!" - stix_package.stix_header = stix_header + stix_report = Report() + stix_report.header = Header() + stix_report.header.description = "Getting Started!" + stix_package.add(stix_report) - print stix_package.to_xml() + print(stix_package.to_xml()) Which outputs: .. code-block:: xml - - - Getting Started! - + + + + + Getting Started! + + + diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 833cff93..10e291ba 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -29,14 +29,17 @@ Creating a STIX Package .. code-block:: python - from stix.core import STIXPackage, STIXHeader # Import the STIX Package and STIX Header APIs + from stix.core import STIXPackage # Import the STIX Package API + from stix.report import Report # Import the STIX Report API + from stix.report.header import Header # Import the STIX Report Header API - stix_package = STIXPackage() # Create an instance of STIXPackage - stix_header = STIXHeader() # Create an instance of STIXHeader - stix_header.description = "Getting Started!" # Set the description - stix_package.stix_header = stix_header # Link the STIX Head to our STIX Package + stix_package = STIXPackage() # Create an instance of STIXPackage + stix_report = Report() # Create a Report instance + stix_report.header = Header() # Create a header for the report + stix_report.header.description = "Getting Started!" # Set the description + stix_package.add(stix_report) # Add the report to our STIX Package - print(stix_package.to_xml()) # print the XML for this STIX Package + print(stix_package.to_xml()) # Print the XML for this STIX Package Parsing STIX XML **************** From cf27c268e0c51e0f76af87d4b82a380ddf177f53 Mon Sep 17 00:00:00 2001 From: clenk Date: Fri, 15 Jul 2016 11:47:01 -0400 Subject: [PATCH 320/438] Update sample file for deprecated fields, bringing back header info --- examples/sample.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/sample.xml b/examples/sample.xml index add37949..b48053fd 100755 --- a/examples/sample.xml +++ b/examples/sample.xml @@ -15,7 +15,6 @@ xmlns:stixVocabs="http://stix.mitre.org/default_vocabularies-1" xmlns:example="http://example.com/" id="example:STIXPackage-33fe3b22-0201-47cf-85d0-97c02164528d" - timestamp="2014-05-08T09:00:00.000000Z" version="1.2"> @@ -31,5 +30,11 @@ + + + Example watchlist that contains IP information. + Indicators - Watchlist + + From 8bca09820803f35f95b9327056651f53e2db4f48 Mon Sep 17 00:00:00 2001 From: clenk Date: Mon, 18 Jul 2016 13:56:57 -0400 Subject: [PATCH 321/438] Fix sample XML report element --- examples/sample.xml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/sample.xml b/examples/sample.xml index b48053fd..2e2cb25e 100755 --- a/examples/sample.xml +++ b/examples/sample.xml @@ -13,6 +13,7 @@ xmlns:AddressObject="http://cybox.mitre.org/objects#AddressObject-2" xmlns:cyboxVocabs="http://cybox.mitre.org/default_vocabularies-2" xmlns:stixVocabs="http://stix.mitre.org/default_vocabularies-1" + xmlns:report="http://stix.mitre.org/Report-1" xmlns:example="http://example.com/" id="example:STIXPackage-33fe3b22-0201-47cf-85d0-97c02164528d" version="1.2"> @@ -30,11 +31,13 @@ - - - Example watchlist that contains IP information. - Indicators - Watchlist - + + + + Example watchlist that contains IP information. + Indicators - Watchlist + + From 20d540a0055b0810f1fd227fc61bee0f5e6208c9 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Thu, 21 Jul 2016 19:18:18 -0400 Subject: [PATCH 322/438] Fixed bugs in CIQIdentity extension code. Nosetests now pass again. - Super.to_obj() calls now don't pass a return_obj - Added a missing super.to_obj() call - Fixed a from_obj() function which was populating its entity incorrectly --- stix/extensions/identity/ciq_identity_3_0.py | 47 +++++++++++--------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index 03497dbd..29e42b58 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -66,7 +66,7 @@ def specification(self, value): self._specification = value def to_obj(self, ns_info=None): - obj = super(CIQIdentity3_0Instance, self).to_obj() + obj = super(CIQIdentity3_0Instance, self).to_obj(ns_info=ns_info) obj.xsi_type = self._XSI_TYPE if self.roles: @@ -82,8 +82,8 @@ def to_obj(self, ns_info=None): def from_obj(cls, cls_obj): obj = super(CIQIdentity3_0Instance, cls).from_obj(cls_obj) - roles = obj.Role - specification = obj.Specification + roles = cls_obj.Role + specification = cls_obj.Specification if roles: for role in roles: @@ -332,7 +332,13 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_obj(self, return_obj=None, ns_info=None): - super(STIXCIQIdentity3_0, self).to_obj(return_obj=return_obj, ns_info=ns_info) + # Throw away return value; this class has no _binding_class, so + # it will return None anyway. This to_obj() is anomalous in that it + # returns an etree Element instead of a generateDS object. Bindings + # have all been hacked up to make this work. The super call does, + # however, do namespace collection (if ns_info is given), so it's + # still important. + super(STIXCIQIdentity3_0, self).to_obj(ns_info=ns_info) if not return_obj: root_tag = STIXCIQIdentity3_0.XML_TAG @@ -456,7 +462,7 @@ def free_text_address(self, value): self._set_var(FreeTextAddress, free_text_address=value) def to_obj(self, return_obj=None, ns_info=None): - super(Address, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(Address, self).to_obj(ns_info=ns_info) if not return_obj: return_obj = et.Element(self.XML_TAG) @@ -559,7 +565,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_obj(self, return_obj=None, ns_info=None): - super(AdministrativeArea, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(AdministrativeArea, self).to_obj(ns_info=ns_info) if not return_obj: return_obj = et.Element(self.XML_TAG) @@ -631,7 +637,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_obj(self, return_obj=None, ns_info=None): - super(Country, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(Country, self).to_obj(ns_info=ns_info) if not return_obj: return_obj = et.Element(self.XML_TAG) @@ -666,7 +672,7 @@ def __init__(self, value=None): self.value = value def to_obj(self, return_obj=None, ns_info=None): - super(NameElement, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(NameElement, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) return_obj.text = self.value @@ -739,7 +745,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_obj(self, return_obj=None, ns_info=None): - super(FreeTextAddress, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(FreeTextAddress, self).to_obj(ns_info=ns_info) if not return_obj: return_obj = et.Element(self.XML_TAG) @@ -815,7 +821,7 @@ def add_organisation_name(self, value): raise ValueError('value must be instance of OrganisationName') def to_obj(self, return_obj=None, ns_info=None): - super(PartyName, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(PartyName, self).to_obj(ns_info=ns_info) if not return_obj: root_tag = PartyName.XML_TAG @@ -924,7 +930,7 @@ def value(self, value): self._value = value def to_obj(self, return_obj=None, ns_info=None): - super(NameLine, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(NameLine, self).to_obj(ns_info=ns_info) if not return_obj: root_tag = NameLine.XML_TAG @@ -993,7 +999,7 @@ def add_name_element(self, value): raise ValueError('value must be instance of PersonNameElement') def to_obj(self, return_obj=None, ns_info=None): - super(PersonName, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(PersonName, self).to_obj(ns_info=ns_info) if not return_obj: root_tag = PersonName.XML_TAG @@ -1099,7 +1105,7 @@ def add_subdivision_name(self, value): self.subdivision_names.append(value) def to_obj(self, return_obj=None, ns_info=None): - super(OrganisationName, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(OrganisationName, self).to_obj(ns_info=ns_info) if not return_obj: root_tag = OrganisationName.XML_TAG @@ -1198,7 +1204,7 @@ def from_obj(cls, obj, return_obj=None): return return_obj def to_obj(self, return_obj=None, ns_info=None): - super(_BaseNameElement, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(_BaseNameElement, self).to_obj(ns_info=ns_info) return_obj.text = self.value return return_obj @@ -1403,7 +1409,7 @@ def type(self, value): self._type = value def to_obj(self, return_obj=None, ns_info=None): - super(SubDivisionName, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(SubDivisionName, self).to_obj(ns_info=ns_info) if not return_obj: root_tag = SubDivisionName.XML_TAG @@ -1457,7 +1463,7 @@ def __init__(self, value=None): self.value = value def to_obj(self, return_obj=None, ns_info=None): - super(Language, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(Language, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) return_obj.text = self.value @@ -1497,7 +1503,7 @@ def __init__(self, value=None, type_=None): self.value = value def to_obj(self, return_obj=None, ns_info=None): - super(ElectronicAddressIdentifier, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(ElectronicAddressIdentifier, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) return_obj.text = self.value @@ -1548,7 +1554,7 @@ def __init__(self, industry_type=None): self.industry_type = industry_type def to_obj(self, return_obj=None, ns_info=None): - super(OrganisationInfo, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(OrganisationInfo, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) if self.industry_type: @@ -1594,7 +1600,7 @@ def __init__(self, value=None, type_=None): self.type_ = type_ def to_obj(self, return_obj=None, ns_info=None): - super(FreeTextLine, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(FreeTextLine, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) if self.type_: @@ -1693,6 +1699,7 @@ def communication_media_type(self, value): self._communication_media_type = value def to_obj(self, return_obj=None, ns_info=None): + super(ContactNumber, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) if self.communication_media_type: return_obj.attrib['{%s}CommunicationMediaType' % self._namespace] = self.communication_media_type @@ -1778,7 +1785,7 @@ def type_(self, value): self._type = value def to_obj(self, return_obj=None, ns_info=None): - super(ContactNumberElement, self).to_obj(return_obj=return_obj, ns_info=ns_info) + super(ContactNumberElement, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) if self.type_: From 3797a080d0a39e9c6846a0f594b786c400e230a5 Mon Sep 17 00:00:00 2001 From: clenk Date: Mon, 1 Aug 2016 14:28:25 -0400 Subject: [PATCH 323/438] Fix Python 3 errors --- stix/extensions/malware/maec_4_1_malware.py | 4 ++-- stix/indicator/indicator.py | 2 -- stix/test/encoding_test.py | 2 +- stix/utils/nsparser.py | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index 1de6c08b..f91f8906 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -7,7 +7,7 @@ # external from lxml import etree import mixbox.xml -from mixbox.vendor.six import BytesIO, iteritems +from mixbox.vendor.six import BytesIO, iteritems, binary_type # internal import stix @@ -204,7 +204,7 @@ def from_dict(cls, d, return_obj=None): pass elif isinstance(maec, dict): d['maec'] = cls._maec_from_dict(maec) - elif isinstance(maec, basestring): + elif isinstance(maec, binary_type): d['maec'] = mixbox.xml.get_etree_root(BytesIO(maec)) else: raise TypeError("Unknown type for 'maec' entry.") diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index d76e95f0..2131d855 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -27,8 +27,6 @@ from .sightings import Sightings from .valid_time import ValidTime -from operator import isSequenceType - class SuggestedCOAs(GenericRelationshipList): """The ``SuggestedCOAs`` class provides functionality for adding :class:`stix.common.related.RelatedCOA` instances to an :class:`Indicator` diff --git a/stix/test/encoding_test.py b/stix/test/encoding_test.py index 03832cc2..c099b392 100644 --- a/stix/test/encoding_test.py +++ b/stix/test/encoding_test.py @@ -127,7 +127,7 @@ def test_to_xml_utf16_encoded(self): s = STIXHeader() s.title = UNICODE_STR xml = s.to_xml(encoding=encoding) - print xml + print(xml) self.assertTrue(UNICODE_STR in xml.decode(encoding)) @silence_warnings diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index 4d9fefbc..e46cb356 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -44,7 +44,7 @@ STIX_NAMESPACES = mixbox.namespaces.NamespaceSet() # Magic to automatically register all Namespaces defined in this module. -for k, v in globals().items(): +for k, v in list(globals().items()): if k.startswith('NS_'): mixbox.namespaces.register_namespace(v) STIX_NAMESPACES.add_namespace(v) From b6ef77d413a5eaa9080f4e9ff7793a743e09a65a Mon Sep 17 00:00:00 2001 From: clenk Date: Mon, 1 Aug 2016 15:38:10 -0400 Subject: [PATCH 324/438] Fix Indicator.negate tests --- stix/indicator/indicator.py | 16 ++++++++++++++++ stix/test/indicator_test.py | 3 +++ 2 files changed, 19 insertions(+) diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 2131d855..1ffc5242 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -722,6 +722,22 @@ def add_object(self, object_): observable = Observable(object_) self.add_observable(observable) + def _finalize_obj(self, entity_obj): + """Omits the `negate` field if it is not equal to True. + """ + if self.negate: + entity_obj.negate = True + elif hasattr(entity_obj, 'negate'): + entity_obj.negate = None + + def _finalize_dict(self, entity_dict): + """Omits the `negate` field if it is not equal to True. + """ + if self.negate: + entity_dict['negate'] = True + elif 'negate' in entity_dict: + del entity_dict['negate'] + def check_operator(composite_indicator_exp, value): allowed = CompositeIndicatorExpression.OPERATORS diff --git a/stix/test/indicator_test.py b/stix/test/indicator_test.py index f2020a3f..6cdc1ca9 100644 --- a/stix/test/indicator_test.py +++ b/stix/test/indicator_test.py @@ -37,6 +37,9 @@ def test_negate(self): d2 = self.klass.from_dict(d).to_dict() self.assertTrue('negate' not in d2) + o2 = self.klass.from_dict(d).to_obj() + self.assertTrue(o2.negate is None) + def test_indicator_types(self): d = { From ae4776bbd79955a748c10821f949ab68ede789e2 Mon Sep 17 00:00:00 2001 From: clenk Date: Tue, 2 Aug 2016 17:15:22 -0400 Subject: [PATCH 325/438] Require latest versions of dependencies --- setup.py | 6 +++--- tox.ini | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index c5ea9ad3..682c31f3 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ def get_version(): 'test': [ 'nose==1.3.0', 'tox==1.6.1', - 'maec>=4.1.0.13.dev1,<4.1.1.0', + 'maec>=4.1.0.13.dev4,<4.1.1.0', ], } @@ -39,8 +39,8 @@ def get_version(): install_requires = [ 'lxml>=2.3', 'python-dateutil', - 'cybox>=2.1.0.13.dev0,<2.1.1.0', - 'mixbox>=0.0.10', + 'cybox>=2.1.0.13.dev1,<2.1.1.0', + 'mixbox>=0.0.13', ] diff --git a/tox.ini b/tox.ini index 444b6902..6748f214 100644 --- a/tox.ini +++ b/tox.ini @@ -19,7 +19,7 @@ commands = deps = lxml==2.3 python-dateutil==1.4.1 - mixbox>=0.0.10 - cybox>=2.1.0.12.dev1 - maec>=4.1.0.13.dev1 + mixbox>=0.0.13 + cybox>=2.1.0.13.dev1 + maec>=4.1.0.13.dev4 nose From 67f1893b25991173265ea79d391c00ae77328102 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Thu, 4 Aug 2016 16:09:33 -0400 Subject: [PATCH 326/438] Add Windows installation notes Also put pip installation first in the order, as it is the preferred installation method. --- README.rst | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index 947cb436..7e4fadfa 100644 --- a/README.rst +++ b/README.rst @@ -24,17 +24,21 @@ A python library for parsing, manipulating, and generating STIX v1.2 content. Installation ------------ -The python-stix library can be installed via the distutils setup.py script -included at the root directory: - - $ python setup.py install +The python-stix library is hosted on `PyPI +`_ and the most recent stable version can be +installed with `pip `_: -The python-stix library is also hosted on `PyPI -`_ and can be installed with `pip -`_: +:: $ pip install stix +The python-stix library can also be installed via the distutils setup.py script +included at the root directory: + +:: + + $ python setup.py install + Dependencies ------------ @@ -53,6 +57,18 @@ Installation on Ubuntu 14.04 (and older) $ sudo apt-get install python-dev python-pip libxml2-dev libxslt-dev zlib1g-dev $ sudo pip install stix +Installation on Windows +~~~~~~~~~~~~~~~~~~~~~~~ + +Download the Lxml wheel for your version of Python from +http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml, then install it via "pip install +.whl". For example, to install it on 64-bit Windows running Python 2.7: + +:: + + > pip install lxml-3.6.1-cp27-cp27m-win_amd64.whl + > pip install stix + Versioning ---------- From 2e10988e6cd9c23ff677b7e509f000ca43574380 Mon Sep 17 00:00:00 2001 From: clenk Date: Mon, 8 Aug 2016 09:53:14 -0400 Subject: [PATCH 327/438] Remove caching from STIX Entity classes At least until mixbox caching has been reworked. --- stix/base.py | 3 +-- stix/coa/structured_coa.py | 3 +-- stix/common/identity.py | 3 +-- stix/core/stix_package.py | 3 +-- stix/data_marking.py | 5 ++--- stix/indicator/test_mechanism.py | 3 +-- stix/report/__init__.py | 3 +-- stix/ttp/attack_pattern.py | 5 +---- stix/ttp/exploit.py | 5 +---- stix/ttp/infrastructure.py | 3 +-- stix/ttp/malware_instance.py | 5 +---- 11 files changed, 12 insertions(+), 29 deletions(-) diff --git a/stix/base.py b/stix/base.py index e65ea1db..aab5f5ba 100644 --- a/stix/base.py +++ b/stix/base.py @@ -12,7 +12,6 @@ from mixbox import entities from mixbox import fields from mixbox import binding_utils -from mixbox.cache import Cached from mixbox import namespaces from mixbox.vendor.six import StringIO, iteritems, itervalues, text_type, binary_type @@ -354,7 +353,7 @@ def _validate_version(instance, value): utils.check_version(instance._ALL_VERSIONS, value) -class BaseCoreComponent(Cached, Entity): +class BaseCoreComponent(Entity): _ALL_VERSIONS = () _ID_PREFIX = None diff --git a/stix/coa/structured_coa.py b/stix/coa/structured_coa.py index f69561ae..c0aebf57 100644 --- a/stix/coa/structured_coa.py +++ b/stix/coa/structured_coa.py @@ -2,7 +2,6 @@ # See LICENSE.txt for complete terms. # external -from mixbox.cache import Cached from mixbox import entities from mixbox import fields @@ -18,7 +17,7 @@ def entity_class(cls, key): return stix.lookup_extension(key) -class _BaseStructuredCOA(Cached, stix.Entity): +class _BaseStructuredCOA(stix.Entity): _namespace = "http://stix.mitre.org/CourseOfAction-1" _binding = coa_binding _binding_class = coa_binding.StructuredCOAType diff --git a/stix/common/identity.py b/stix/common/identity.py index 07278446..b2a9f28c 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -4,7 +4,6 @@ # external from mixbox import fields from mixbox import entities -from mixbox.cache import Cached # internal import stix @@ -19,7 +18,7 @@ def entity_class(cls, key): return stix.lookup_extension(key, default=Identity) -class Identity(Cached, stix.Entity): +class Identity(stix.Entity): _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' _binding_class = IdentityType diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 983143a6..f25810f1 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -4,7 +4,6 @@ # mixbox from mixbox import idgen from mixbox import fields -from mixbox.cache import Cached # cybox from cybox.core import Observable, Observables @@ -40,7 +39,7 @@ import stix.bindings.stix_core as stix_core_binding import mixbox.entities -class STIXPackage(Cached, stix.Entity): +class STIXPackage(stix.Entity): """A STIX Package object. Args: diff --git a/stix/data_marking.py b/stix/data_marking.py index c88f0370..57c61eab 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -4,7 +4,6 @@ # external from mixbox import fields from mixbox import entities -from mixbox.cache import Cached # internal import stix @@ -23,7 +22,7 @@ def entity_class(cls, key): return stix.lookup_extension(key, default=MarkingStructure) -class MarkingStructure(Cached, stix.Entity): +class MarkingStructure(stix.Entity): _binding = stix_data_marking_binding _binding_class = stix_data_marking_binding.MarkingStructureType _namespace = 'http://data-marking.mitre.org/Marking-1' @@ -55,7 +54,7 @@ def lookup_class(xsi_type): return stix.lookup_extension(xsi_type, default=MarkingStructure) -class MarkingSpecification(Cached, stix.Entity): +class MarkingSpecification(stix.Entity): _binding = stix_data_marking_binding _binding_class = stix_data_marking_binding.MarkingSpecificationType _namespace = 'http://data-marking.mitre.org/Marking-1' diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index ce69d20d..db8300ef 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -3,7 +3,6 @@ # external from mixbox import fields, entities -from mixbox.cache import Cached # internal import stix @@ -13,7 +12,7 @@ import stix.bindings.indicator as indicator_binding -class _BaseTestMechanism(Cached, stix.Entity): +class _BaseTestMechanism(stix.Entity): _namespace = "http://stix.mitre.org/Indicator-2" _binding = indicator_binding _binding_class = indicator_binding.TestMechanismType() diff --git a/stix/report/__init__.py b/stix/report/__init__.py index d58d4d52..34ebd6e9 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -3,7 +3,6 @@ from mixbox import idgen from mixbox import fields -from mixbox.cache import Cached from cybox.core import Observable, Observables @@ -31,7 +30,7 @@ import stix.bindings.report as report_binding -class Report(Cached, stix.Entity): +class Report(stix.Entity): """A STIX Report Object. Args: diff --git a/stix/ttp/attack_pattern.py b/stix/ttp/attack_pattern.py index 52471374..db341706 100644 --- a/stix/ttp/attack_pattern.py +++ b/stix/ttp/attack_pattern.py @@ -1,9 +1,6 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# external -from mixbox.cache import Cached - # internal import stix from stix.common import StructuredTextList @@ -13,7 +10,7 @@ from mixbox import fields, entities -class AttackPattern(Cached, stix.Entity): +class AttackPattern(stix.Entity): _binding = ttp_binding _binding_class = _binding.AttackPatternType _namespace = "http://stix.mitre.org/TTP-1" diff --git a/stix/ttp/exploit.py b/stix/ttp/exploit.py index 72bb87d1..241d430e 100644 --- a/stix/ttp/exploit.py +++ b/stix/ttp/exploit.py @@ -1,9 +1,6 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# external -from mixbox.cache import Cached - # internal import stix from stix.common import StructuredTextList @@ -13,7 +10,7 @@ from mixbox import fields -class Exploit(Cached, stix.Entity): +class Exploit(stix.Entity): _binding = ttp_binding _binding_class = _binding.ExploitType _namespace = "http://stix.mitre.org/TTP-1" diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index f35e9ec0..33b7d51c 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -3,7 +3,6 @@ # mixbox from mixbox import fields -from mixbox.cache import Cached # cybox from cybox.core import Observables @@ -15,7 +14,7 @@ import stix.bindings.ttp as ttp_binding from mixbox import fields, entities -class Infrastructure(Cached, stix.Entity): +class Infrastructure(stix.Entity): _binding = ttp_binding _binding_class = _binding.InfrastructureType _namespace = "http://stix.mitre.org/TTP-1" diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index bf976aff..588372cc 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -1,9 +1,6 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# external -from mixbox.cache import Cached - # internal import stix import stix.utils as utils @@ -16,7 +13,7 @@ from mixbox import fields, entities -class MalwareInstance(Cached, stix.Entity): +class MalwareInstance(stix.Entity): _binding = ttp_binding _binding_class = _binding.MalwareInstanceType _namespace = "http://stix.mitre.org/TTP-1" From 9530bca4efbf4d3e076d53bb3aef66e5e9b0ddde Mon Sep 17 00:00:00 2001 From: clenk Date: Mon, 8 Aug 2016 10:18:47 -0400 Subject: [PATCH 328/438] Update nsparser API documentation --- docs/api/utils/nsparser.rst | 77 +++++++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 12 deletions(-) diff --git a/docs/api/utils/nsparser.rst b/docs/api/utils/nsparser.rst index a39c808f..49c1964f 100644 --- a/docs/api/utils/nsparser.rst +++ b/docs/api/utils/nsparser.rst @@ -3,22 +3,75 @@ .. module:: stix.utils.nsparser -Classes -------- - -.. autoclass:: NamespaceParser - :show-inheritance: - :members: - Constants --------- -.. autodata:: XML_NAMESPACES +.. autodata:: NS_CAMPAIGN_OBJECT + +.. autodata:: NS_CAPEC_OBJECT + +.. autodata:: NS_CIQIDENTITY_OBJECT + +.. autodata:: NS_COA_OBJECT + +.. autodata:: NS_CVRF_OBJECT + +.. autodata:: NS_ET_OBJECT + +.. autodata:: NS_GENERICSTRUCTUREDCOA_OBJECT + +.. autodata:: NS_GENERICTM_OBJECT + +.. autodata:: NS_INCIDENT_OBJECT + +.. autodata:: NS_INDICATOR_OBJECT + +.. autodata:: NS_IOC_OBJECT + +.. autodata:: NS_IOCTR_OBJECT + +.. autodata:: NS_MARKING_OBJECT + +.. autodata:: NS_OVALDEF_OBJECT + +.. autodata:: NS_OVALVAR_OBJECT + +.. autodata:: NS_REPORT_OBJECT + +.. autodata:: NS_SIMPLEMARKING_OBJECT + +.. autodata:: NS_SNORTTM_OBJECT + +.. autodata:: NS_STIX_OBJECT + +.. autodata:: NS_STIXCAPEC_OBJECT + +.. autodata:: NS_STIXCIQADDRESS_OBJECT + +.. autodata:: NS_STIXCVRF_OBJECT + +.. autodata:: NS_STIXMAEC_OBJECT + +.. autodata:: NS_STIXOPENIOC_OBJECT + +.. autodata:: NS_STIXOVAL_OBJECT + +.. autodata:: NS_STIXCOMMON_OBJECT + +.. autodata:: NS_STIXVOCABS_OBJECT + +.. autodata:: NS_TA_OBJECT + +.. autodata:: NS_TLPMARKING_OBJECT + +.. autodata:: NS_TOUMARKING_OBJECT + +.. autodata:: NS_TTP_OBJECT -.. autodata:: STIX_NS_TO_SCHEMALOCATION +.. autodata:: NS_XAL_OBJECT -.. autodata:: EXT_NS_TO_SCHEMALOCATION +.. autodata:: NS_XNL_OBJECT -.. autodata:: DEFAULT_STIX_NS_TO_PREFIX +.. autodata:: NS_XPIL_OBJECT -.. autodata:: DEFAULT_EXT_TO_PREFIX +.. autodata:: NS_YARATM_OBJECT From bf78d39d92c3f89f5450b04dc2e9ca6d264bfc54 Mon Sep 17 00:00:00 2001 From: clenk Date: Mon, 8 Aug 2016 10:56:27 -0400 Subject: [PATCH 329/438] Correct version number --- stix/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/version.py b/stix/version.py index 8b906dce..9bc15709 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.2" +__version__ = "1.2.0.1" From 4a7e601d0be30b2a858a788d6430b77237bb71de Mon Sep 17 00:00:00 2001 From: Greg Back Date: Thu, 11 Aug 2016 08:55:03 -0500 Subject: [PATCH 330/438] Update changelog for v1.2.0.1 --- CHANGES.txt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index ed71ee28..a166980d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,13 @@ +Version 1.2.0.1 +2016-08-08 +- Add support for Python 3.3+ +- Use 'mixbox' library for features shared with python-cybox and python-maec. +- #292 Support organisation_info in STIXCIQIdentity. +- #276 Fix published_datetime on Vulnerability. +- #274 Correctly add TTPs to STIXPackage. +- #269, #271 Make STIXPackage version readonly. +- #266 Handle custom VocabString values even if they aren't registered. + Version 1.2.0.0 2015-05-15 - Support for parsing and creating STIX 1.2 content. @@ -5,10 +15,10 @@ Version 1.2.0.0 vocabularies. - Refactored internal class resolution for xsi:types. - #262 Added support for STIX Report content -- #261 Added deprecation warnings when setting fields that have been +- #261 Added deprecation warnings when setting fields that have been deprecated in STIX 1.2. - #260 Added Versioning controlled vocabulary. -- #253 Added support for Kill Chain Phases and Related Pacakges on TTP +- #253 Added support for Kill Chain Phases and Related Pacakges on TTP Version 1.1.1.5 2015-04-29 @@ -236,4 +246,4 @@ Version 1.0.0a2 Version 1.0.0a1 2013-04-22 - First (alpha) release on PyPI -- Compatible with STIX 1.0 Draft 2 \ No newline at end of file +- Compatible with STIX 1.0 Draft 2 From 0f6f5d10d05159e8fbcc6ce932e2cba58dfa3a86 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 16 Aug 2016 11:33:17 -0500 Subject: [PATCH 331/438] Update badges to .svg --- README.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 7e4fadfa..fc01fbe7 100644 --- a/README.rst +++ b/README.rst @@ -9,15 +9,15 @@ A python library for parsing, manipulating, and generating STIX v1.2 content. |travis badge| |landscape.io badge| |version badge| |downloads badge| -.. |travis badge| image:: https://api.travis-ci.org/STIXProject/python-stix.png?branch=master +.. |travis badge| image:: https://api.travis-ci.org/STIXProject/python-stix.svg?branch=master :target: https://travis-ci.org/STIXProject/python-stix :alt: Build Status -.. |landscape.io badge| image:: https://landscape.io/github/STIXProject/python-stix/master/landscape.png +.. |landscape.io badge| image:: https://landscape.io/github/STIXProject/python-stix/master/landscape.svg :target: https://landscape.io/github/STIXProject/python-stix/master :alt: Code Health -.. |version badge| image:: https://img.shields.io/pypi/v/stix.png?maxAge=2592000 +.. |version badge| image:: https://img.shields.io/pypi/v/stix.svg?maxAge=3600 :target: https://pypi.python.org/pypi/stix/ -.. |downloads badge| image:: https://img.shields.io/pypi/dm/stix.png?maxAge=2592000 +.. |downloads badge| image:: https://img.shields.io/pypi/dm/stix.svg?maxAge=3600 :target: https://pypi.python.org/pypi/stix/ From 8cd48dd7f934fd8a76803cd2ba2c7df370d3d50a Mon Sep 17 00:00:00 2001 From: clenk Date: Tue, 30 Aug 2016 14:23:41 -0400 Subject: [PATCH 332/438] Update doc examples to latest version Closes #301. --- docs/overview/controlled_vocabularies.rst | 10 ++++++---- docs/overview/id_namespaces.rst | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/overview/controlled_vocabularies.rst b/docs/overview/controlled_vocabularies.rst index e0f18733..a1642022 100644 --- a/docs/overview/controlled_vocabularies.rst +++ b/docs/overview/controlled_vocabularies.rst @@ -59,7 +59,7 @@ values. header = STIXHeader() header.package_intents.append(PackageIntent.TERM_INDICATORS) - print header.to_xml() + print(header.to_xml()) Which outputs: @@ -92,7 +92,7 @@ requirements. non_default_term = VocabString("NON-DEFAULT VOCABULARY TERM") header.package_intents.append(non_default_term) - print header.to_xml() + print(header.to_xml()) Which outputs: @@ -248,6 +248,7 @@ XML Schema definition, but in Python! # python-stix modules from stix.core import STIXPackage from stix.common.vocabs import VocabString, register_vocab + from mixbox.namespaces import register_namespace, Namespace XML = \ """ @@ -274,6 +275,7 @@ XML Schema definition, but in Python! _XSI_TYPE = 'customVocabs:CustomVocab-1.0' TERM_FOO = 'FOO' TERM_BAR = 'BAR' + register_namespace(Namespace(CustomVocab._namespace, "customVocabNS")) # Parse the input document sio = StringIO(XML) @@ -283,12 +285,12 @@ XML Schema definition, but in Python! package_intent = package.stix_header.package_intents[0] # Print information about the input Package_Intent - print type(package_intent), package_intent.xsi_type, package_intent + print('%s %s %s' % (type(package_intent), package_intent.xsi_type, package_intent)) # Add another Package Intent bar = CustomVocab('BAR') package.stix_header.add_package_intent(bar) # This will include the 'BAR' CustomVocab entry - print package.to_xml() + print(package.to_xml()) diff --git a/docs/overview/id_namespaces.rst b/docs/overview/id_namespaces.rst index ec7329a5..62de6ad2 100644 --- a/docs/overview/id_namespaces.rst +++ b/docs/overview/id_namespaces.rst @@ -12,9 +12,10 @@ a dictionary as a parameter. .. code-block:: python from stix.core import STIXPackage - from stix.utils import set_id_namespace + from mixbox.idgen import set_id_namespace + from mixbox.namespaces import Namespace - NAMESPACE = {"http://MY-NAMESPACE.com" : "myNS"} + NAMESPACE = Namespace("http://MY-NAMESPACE.com", "myNS") set_id_namespace(NAMESPACE) # new ids will be prefixed by "myNS" stix_package = STIXPackage() # id will be created automatically @@ -25,11 +26,12 @@ Which outputs: .. code-block:: xml Success! The ``xmlns:myNS="http://MY-NAMESPACE.com"`` matches our ``NAMESPACE`` From c50ecc901aee5199fee97bad9b2a9ea436571cde Mon Sep 17 00:00:00 2001 From: clenk Date: Thu, 29 Sep 2016 16:54:14 -0400 Subject: [PATCH 333/438] Make MAECInstance.to_obj() retain all information Add a test to show the bug this fixes. Fixes #303 --- stix/extensions/malware/maec_4_1_malware.py | 2 +- stix/test/extensions/malware/maec_4_1_malware_test.py | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index f91f8906..6ce0b467 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -166,7 +166,7 @@ def to_obj(self, return_obj=None, ns_info=None): if not return_obj: return_obj = self._binding_class() - super(MAECInstance, self).to_obj(ns_info=ns_info) + return_obj = super(MAECInstance, self).to_obj(ns_info=ns_info) if mixbox.xml.is_element(self.maec) or mixbox.xml.is_etree(self.maec): tree = mixbox.xml.get_etree(self.maec) diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index aee084ae..1cc339e0 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -1,5 +1,5 @@ import unittest -from mixbox.vendor.six import StringIO, BytesIO +from mixbox.vendor.six import StringIO, BytesIO, text_type from lxml import etree import mixbox.xml @@ -33,6 +33,15 @@ class PythonMAECTests(EntityTestCase, unittest.TestCase): } } + def test_add_name_type(self): + maec_malware_instance = MAECInstance() + maec_malware_instance.add_name("Poison Ivy Variant v4392-acc") + maec_malware_instance.add_type("Remote Access Trojan") + maec_xml = text_type(maec_malware_instance.to_xml()) + self.assertTrue("Poison Ivy Variant v4392-acc" in maec_xml) + self.assertTrue("Remote Access Trojan" in maec_xml) + + class PythonMAECEtreeTests(unittest.TestCase): XML = ( """ From fe8fef5b12d1e18a9f170aa3147e19a86f3ef310 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Mon, 3 Oct 2016 08:52:34 -0500 Subject: [PATCH 334/438] Clean up outdated code --- stix/extensions/malware/maec_4_1_malware.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index 6ce0b467..6516497f 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -152,20 +152,17 @@ def from_obj(cls, obj): return None return_obj = cls() - + if _MAEC_INSTALLED: obj.MAEC = maecPackage.from_obj(obj.MAEC) else: obj.MAEC = obj.MAEC - + super(MAECInstance, cls).from_obj(obj) return return_obj - - def to_obj(self, return_obj=None, ns_info=None): - if not return_obj: - return_obj = self._binding_class() - + + def to_obj(self, ns_info=None): return_obj = super(MAECInstance, self).to_obj(ns_info=ns_info) if mixbox.xml.is_element(self.maec) or mixbox.xml.is_etree(self.maec): From 1dbcb9adb61c4113419af22c242eb7fbca4a9daf Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 4 Oct 2016 14:49:57 -0500 Subject: [PATCH 335/438] Add failing test for issue #302 --- .../identity/ciq_identity_3_0_test.py | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/stix/test/extensions/identity/ciq_identity_3_0_test.py b/stix/test/extensions/identity/ciq_identity_3_0_test.py index 882e496c..d32a5fc4 100644 --- a/stix/test/extensions/identity/ciq_identity_3_0_test.py +++ b/stix/test/extensions/identity/ciq_identity_3_0_test.py @@ -2,8 +2,10 @@ # See LICENSE.txt for complete terms. import unittest -from stix.test import EntityTestCase + +from stix.threat_actor import ThreatActor import stix.extensions.identity.ciq_identity_3_0 as ciq +from stix.test import EntityTestCase class CIQIdentity3_0InstanceTests(EntityTestCase, unittest.TestCase): @@ -108,5 +110,48 @@ class CIQIdentity3_0InstanceTests(EntityTestCase, unittest.TestCase): } +class IdentityInThreatActorTests(EntityTestCase, unittest.TestCase): + klass = ThreatActor + _full_dict = { + "id": "example:threatactor-c96266cf-ccb3-43f3-b44e-26dbd66273e5", + "identity": { + "specification": { + "addresses": [ + { + "administrative_area": { + "name_elements": [{"value": "California"} + ] + }, + "country": { + "name_elements": [{"value": "United States"}] + } + } + ], + "electronic_address_identifiers": [ + {"value": "disco-team@stealthemail.com"}, + {"value": "facebook.com/thediscoteam"}, + {"value": "twitter.com/realdiscoteam"} + ], + "languages": [{"value": "Spanish"}], + "party_name": { + "organisation_names": [ + { + "name_elements": [{"value": "Disco Tean"}], + "type": "CommonUse" + }, + { + "name_elements": [{"value": "Equipo del Discoteca"}], + "type": "UnofficialName" + } + ] + } + }, + "xsi:type": "ciqIdentity:CIQIdentity3.0InstanceType" + }, + "timestamp": "2016-10-04T19:43:57.382126+00:00", + "title": "Disco Team Threat Actor Group" + } + + if __name__ == "__main__": unittest.main() From 3cbdc5efb5e5754c8ab2b3a38f61306e2382f654 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 4 Oct 2016 15:14:01 -0500 Subject: [PATCH 336/438] Use IdentityFactory for identity TypedFields. Fix #302 --- stix/test/ttp_test.py | 28 ++++++++++++++++++++++++++++ stix/threat_actor/__init__.py | 5 +++-- stix/ttp/resource.py | 5 +++-- stix/ttp/victim_targeting.py | 8 +++++--- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/stix/test/ttp_test.py b/stix/test/ttp_test.py index 04f11903..a7a81aa7 100644 --- a/stix/test/ttp_test.py +++ b/stix/test/ttp_test.py @@ -6,6 +6,7 @@ from stix.test import EntityTestCase, assert_warnings from stix.test import data_marking_test from stix.test.common import related_test, identity_test, kill_chains_test +from stix.test.extensions.identity import ciq_identity_3_0_test from stix.core import STIXPackage import stix.ttp as ttp @@ -34,6 +35,14 @@ class PersonasTests(EntityTestCase, unittest.TestCase): ] +class PersonasWithCIQTests(EntityTestCase, unittest.TestCase): + klass = resource.Personas + + _full_dict = [ + ciq_identity_3_0_test.CIQIdentity3_0InstanceTests._full_dict + ] + + class InfrastructureTests(EntityTestCase, unittest.TestCase): klass = infrastructure.Infrastructure @@ -194,5 +203,24 @@ def test_deprecated_related_packages(self): self.assertEqual(len(t.related_packages), 1) +class TTPIdentityTests(EntityTestCase, unittest.TestCase): + klass = ttp.TTP + _full_dict = { + "id": "example:ttp-775591f7-7e01-4546-9522-d4211df4aac7", + "timestamp": "2016-10-04T19:57:44.446575+00:00", + "title": "Victim Targeting: Electricity Sector and Industrial Control System Sector", + "victim_targeting": { + "identity": { + "specification": { + "organisation_info": { + "industry_type": "Electricity, Industrial Control Systems" + } + }, + "xsi:type": "ciqIdentity:CIQIdentity3.0InstanceType" + } + } + } + + if __name__ == "__main__": unittest.main() diff --git a/stix/threat_actor/__init__.py b/stix/threat_actor/__init__.py index 01e63d9b..e045b7fc 100644 --- a/stix/threat_actor/__init__.py +++ b/stix/threat_actor/__init__.py @@ -7,7 +7,8 @@ # internal import stix import stix.bindings.threat_actor as threat_actor_binding -from stix.common import vocabs, Confidence, Identity, Statement +from stix.common import vocabs, Confidence, Statement +from stix.common.identity import Identity, IdentityFactory from stix.common.related import ( GenericRelationshipList, RelatedCampaign, RelatedPackageRefs, RelatedTTP, RelatedThreatActor @@ -65,7 +66,7 @@ class ThreatActor(stix.BaseCoreComponent): _ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2") _ID_PREFIX = 'threatactor' - identity = fields.TypedField("Identity", Identity) + identity = fields.TypedField("Identity", Identity, factory=IdentityFactory) types = StatementField("Type", Statement, vocab_type=vocabs.ThreatActorType, multiple=True, key_name="types") motivations = StatementField("Motivation", Statement, vocab_type=vocabs.Motivation, multiple=True, key_name="motivations") sophistications = StatementField("Sophistication", Statement, vocab_type=vocabs.ThreatActorSophistication, multiple=True, key_name="sophistications") diff --git a/stix/ttp/resource.py b/stix/ttp/resource.py index 2b8240e2..4600ebc2 100644 --- a/stix/ttp/resource.py +++ b/stix/ttp/resource.py @@ -7,7 +7,8 @@ # internal import stix -from stix.common import ToolInformation, Identity +from stix.common import ToolInformation +from stix.common.identity import Identity, IdentityFactory import stix.bindings.ttp as ttp_binding # relative @@ -28,7 +29,7 @@ class Personas(stix.EntityList): _binding = ttp_binding _binding_class = _binding.PersonasType - persona = fields.TypedField("Persona", Identity, multiple=True, listfunc=_IdentityList) + persona = fields.TypedField("Persona", Identity, multiple=True, factory=IdentityFactory, listfunc=_IdentityList) class Tools(stix.EntityList): diff --git a/stix/ttp/victim_targeting.py b/stix/ttp/victim_targeting.py index eeb4bef6..4928bbcc 100644 --- a/stix/ttp/victim_targeting.py +++ b/stix/ttp/victim_targeting.py @@ -6,17 +6,19 @@ # internal import stix -from stix.common import vocabs, VocabString, Identity import stix.bindings.ttp as ttp_binding +from stix.common import vocabs, VocabString +from stix.common.identity import Identity, IdentityFactory from mixbox import fields + class VictimTargeting(stix.Entity): _binding = ttp_binding _binding_class = _binding.VictimTargetingType _namespace = "http://stix.mitre.org/TTP-1" - identity = fields.TypedField("Identity", Identity) - + identity = fields.TypedField("Identity", Identity, factory=IdentityFactory) + targeted_systems = vocabs.VocabField("Targeted_Systems", vocabs.SystemType, multiple=True) targeted_information = vocabs.VocabField("Targeted_Information", vocabs.InformationType, multiple=True) From d3b64f160232b7f6b8470307438c8f5a6b762541 Mon Sep 17 00:00:00 2001 From: clenk Date: Wed, 5 Oct 2016 10:12:25 -0400 Subject: [PATCH 337/438] Add test for datetime format Related to #306 --- stix/test/indicator_test.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/stix/test/indicator_test.py b/stix/test/indicator_test.py index 6cdc1ca9..4912f753 100644 --- a/stix/test/indicator_test.py +++ b/stix/test/indicator_test.py @@ -4,10 +4,11 @@ import unittest from stix.core import STIXPackage -from stix.indicator import Indicator, RelatedCampaignRefs +from stix.indicator import Indicator, RelatedCampaignRefs, ValidTime from stix.test import EntityTestCase, assert_warnings from stix.test.common import related_test +from datetime import datetime class IndicatorTest(EntityTestCase, unittest.TestCase): @@ -446,6 +447,15 @@ def test_deprecated_related_packages(self): i.related_packages.append(STIXPackage()) self.assertEqual(len(i.related_packages), 1) + def test_datetime_format(self): + indicator = Indicator(title="title") + valid_time = ValidTime(start_time=datetime.strptime("2010-03-05", + "%Y-%m-%d")) + indicator.add_valid_time_position(valid_time) + + ixml = indicator.to_xml() + self.assertTrue("2010-03-05T" in ixml) + class RelatedCampaignReferencesTests(unittest.TestCase, EntityTestCase): klass = RelatedCampaignRefs From 71145677f51a16e7d20b97e0715fd31e178e92bd Mon Sep 17 00:00:00 2001 From: clenk Date: Wed, 5 Oct 2016 13:25:37 -0400 Subject: [PATCH 338/438] Add failing test showing STIXPackage.to_xml() not preserving CIQIdentity --- stix/test/extensions/identity/ciq_identity_3_0_test.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/stix/test/extensions/identity/ciq_identity_3_0_test.py b/stix/test/extensions/identity/ciq_identity_3_0_test.py index d32a5fc4..b2b7089a 100644 --- a/stix/test/extensions/identity/ciq_identity_3_0_test.py +++ b/stix/test/extensions/identity/ciq_identity_3_0_test.py @@ -2,10 +2,12 @@ # See LICENSE.txt for complete terms. import unittest +from six import StringIO from stix.threat_actor import ThreatActor import stix.extensions.identity.ciq_identity_3_0 as ciq from stix.test import EntityTestCase +from stix.core import STIXPackage class CIQIdentity3_0InstanceTests(EntityTestCase, unittest.TestCase): @@ -152,6 +154,14 @@ class IdentityInThreatActorTests(EntityTestCase, unittest.TestCase): "title": "Disco Team Threat Actor Group" } + def test_identity_from_xml(self): + obj = self.klass.from_dict(self._full_dict) + sp = STIXPackage() + sp.add(obj) + s = StringIO(sp.to_xml()) + pkg = STIXPackage.from_xml(s) + self.assertTrue("CIQIdentity3.0InstanceType" in pkg.to_xml()) + if __name__ == "__main__": unittest.main() From 82eb10cd3ae67b9421157844d54219fdfc85a412 Mon Sep 17 00:00:00 2001 From: clenk Date: Thu, 6 Oct 2016 09:32:20 -0400 Subject: [PATCH 339/438] Fix DateTimeField test for Python3 --- stix/test/indicator_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stix/test/indicator_test.py b/stix/test/indicator_test.py index 4912f753..d95cfcd3 100644 --- a/stix/test/indicator_test.py +++ b/stix/test/indicator_test.py @@ -2,13 +2,14 @@ # See LICENSE.txt for complete terms. import unittest +from datetime import datetime +from mixbox.vendor.six import text_type from stix.core import STIXPackage from stix.indicator import Indicator, RelatedCampaignRefs, ValidTime from stix.test import EntityTestCase, assert_warnings from stix.test.common import related_test -from datetime import datetime class IndicatorTest(EntityTestCase, unittest.TestCase): @@ -454,7 +455,7 @@ def test_datetime_format(self): indicator.add_valid_time_position(valid_time) ixml = indicator.to_xml() - self.assertTrue("2010-03-05T" in ixml) + self.assertTrue("2010-03-05T" in text_type(ixml)) class RelatedCampaignReferencesTests(unittest.TestCase, EntityTestCase): From c5cd14f4f60de0c5c058d3194eb1e3c86263bd64 Mon Sep 17 00:00:00 2001 From: clenk Date: Thu, 6 Oct 2016 10:01:02 -0400 Subject: [PATCH 340/438] Fix CIQ Identity test for Python3 --- stix/test/extensions/identity/ciq_identity_3_0_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stix/test/extensions/identity/ciq_identity_3_0_test.py b/stix/test/extensions/identity/ciq_identity_3_0_test.py index b2b7089a..4784ca6f 100644 --- a/stix/test/extensions/identity/ciq_identity_3_0_test.py +++ b/stix/test/extensions/identity/ciq_identity_3_0_test.py @@ -2,7 +2,7 @@ # See LICENSE.txt for complete terms. import unittest -from six import StringIO +from mixbox.vendor.six import StringIO, text_type from stix.threat_actor import ThreatActor import stix.extensions.identity.ciq_identity_3_0 as ciq @@ -160,7 +160,7 @@ def test_identity_from_xml(self): sp.add(obj) s = StringIO(sp.to_xml()) pkg = STIXPackage.from_xml(s) - self.assertTrue("CIQIdentity3.0InstanceType" in pkg.to_xml()) + self.assertTrue("CIQIdentity3.0InstanceType" in text_type(pkg.to_xml())) if __name__ == "__main__": From ef84b23f4fd5a5138021bc83cb906dc179a1bd1c Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Thu, 6 Oct 2016 11:19:33 -0400 Subject: [PATCH 341/438] Changes to bindings, xsi_type is now properly collected and resolved. --- .../extensions/identity/ciq_identity_3_0.py | 1 - stix/bindings/stix_common.py | 1 - stix/common/identity.py | 13 ++++++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/stix/bindings/extensions/identity/ciq_identity_3_0.py b/stix/bindings/extensions/identity/ciq_identity_3_0.py index 63f30772..a4ea469c 100644 --- a/stix/bindings/extensions/identity/ciq_identity_3_0.py +++ b/stix/bindings/extensions/identity/ciq_identity_3_0.py @@ -37,7 +37,6 @@ class CIQIdentity3_0InstanceType(stix_common_binding.IdentityType): def __init__(self, idref=None, id=None, Name=None, Related_Identities=None, Specification=None, Role=None): super(CIQIdentity3_0InstanceType, self).__init__(idref=idref, id=id, Name=Name, Related_Identities=Related_Identities) - self.xsi_type = None self.Specification = Specification if Role is None: self.Role = [] diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index 16cb84a9..c5c9c0b3 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -1283,7 +1283,6 @@ def __init__(self, idref=None, id=None, Name=None, Related_Identities=None): self.id = _cast(None, id) self.Name = Name self.Related_Identities = Related_Identities - self.xsi_type = None def factory(*args_, **kwargs_): if IdentityType.subclass: return IdentityType.subclass(*args_, **kwargs_) diff --git a/stix/common/identity.py b/stix/common/identity.py index b2a9f28c..35fea9db 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -20,8 +20,8 @@ def entity_class(cls, key): class Identity(stix.Entity): _binding = common_binding - _namespace = 'http://stix.mitre.org/common-1' _binding_class = IdentityType + _namespace = 'http://stix.mitre.org/common-1' id_ = fields.IdField("id") idref = fields.IdrefField("idref") @@ -36,6 +36,17 @@ def __init__(self, id_=None, idref=None, name=None, related_identities=None): self.name = name self.related_identities = related_identities + def to_dict(self): + d = super(Identity, self).to_dict() + + if self._XSI_TYPE: + d['xsi:type'] = self._XSI_TYPE + + return d + + @staticmethod + def lookup_class(xsi_type): + return stix.lookup_extension(xsi_type, default=Identity) # We can't import RelatedIdentity until we have defined the Identity class. from stix.common.related import RelatedIdentity From 21a1b1ef950c340e9a96a3815e116e0ad1887f1e Mon Sep 17 00:00:00 2001 From: clenk Date: Thu, 6 Oct 2016 12:10:37 -0400 Subject: [PATCH 342/438] Fix CIQ Identity from XML test for Python 3 --- stix/test/extensions/identity/ciq_identity_3_0_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stix/test/extensions/identity/ciq_identity_3_0_test.py b/stix/test/extensions/identity/ciq_identity_3_0_test.py index 4784ca6f..fbd50ac5 100644 --- a/stix/test/extensions/identity/ciq_identity_3_0_test.py +++ b/stix/test/extensions/identity/ciq_identity_3_0_test.py @@ -2,7 +2,7 @@ # See LICENSE.txt for complete terms. import unittest -from mixbox.vendor.six import StringIO, text_type +from mixbox.vendor.six import BytesIO, text_type from stix.threat_actor import ThreatActor import stix.extensions.identity.ciq_identity_3_0 as ciq @@ -158,7 +158,7 @@ def test_identity_from_xml(self): obj = self.klass.from_dict(self._full_dict) sp = STIXPackage() sp.add(obj) - s = StringIO(sp.to_xml()) + s = BytesIO(sp.to_xml()) pkg = STIXPackage.from_xml(s) self.assertTrue("CIQIdentity3.0InstanceType" in text_type(pkg.to_xml())) From bc5558154696eb6a5c58922fe2e7b760fb9fcf04 Mon Sep 17 00:00:00 2001 From: clenk Date: Fri, 7 Oct 2016 08:11:56 -0400 Subject: [PATCH 343/438] Add test for parsing the MAEC extension from XML --- .../malware/maec_4_1_malware_test.py | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index 1cc339e0..7915f413 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -1,4 +1,5 @@ import unittest +from stix.core import STIXPackage from mixbox.vendor.six import StringIO, BytesIO, text_type from lxml import etree @@ -113,5 +114,103 @@ def test_etree_dict(self): self._test_xml(ext2) +class PythonMAECInPackageTests(unittest.TestCase): + XML = BytesIO( + """ + + + + Poison Ivy Variant v4392-acc + + + + Remote Access Trojan + Poison Ivy Variant v4392-acc + + + + + + + """ + ) + XML_MAEC = BytesIO( + """ + + + + Poison Ivy Variant v4392-acc + + + + Remote Access Trojan + Poison Ivy Variant v4392-acc + + + + + + + + + + + + + + + + """ + ) + + def test_parse_malware(self): + """Test parsing a normal MalwareInstance from XML + """ + stix_pkg = STIXPackage.from_xml(self.XML) + mw = stix_pkg.ttps[0].behavior.malware_instances[0].to_dict() + self.assertTrue('names' in mw) + + def test_parse_malware_maec(self): + """Test parsing a MaecInstance from XML + """ + stix_pkg = STIXPackage.from_xml(self.XML_MAEC) + mw = stix_pkg.ttps[0].behavior.malware_instances[0].to_dict() + self.assertTrue('names' in mw) + + if __name__ == "__main__": unittest.main() From cd696c8682ec46d180fde2368132db22741c8afc Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 11 Oct 2016 11:09:56 -0500 Subject: [PATCH 344/438] Build universal wheels --- setup.cfg | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..2be68365 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal = True From 4e2f4f470992611c17bdf696c4027c76b326c997 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Fri, 14 Oct 2016 09:14:30 -0500 Subject: [PATCH 345/438] Update documentation for new releases. --- CHANGES.txt | 5 +++++ docs/index.rst | 12 ++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index a166980d..71ac5c17 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,8 @@ +Version 1.1.1.6 +2016-10-14 +- Add support for AIS Markings in STIX 1.1.1 +- Support additional fields in CIQ Identity + Version 1.2.0.1 2016-08-08 - Add support for Python 3.3+ diff --git a/docs/index.rst b/docs/index.rst index 7befc8d0..3513be0f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,17 +22,17 @@ version of STIX. ============ =================== STIX Version python-stix Version ============ =================== -1.2 1.2.0.0 (`PyPI`__) (`GitHub`__) -1.1.1 1.1.1.5 (`PyPI`__) (`GitHub`__) +1.2 1.2.0.1 (`PyPI`__) (`GitHub`__) +1.1.1 1.1.1.6 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) ============ =================== -__ https://pypi.python.org/pypi/stix/1.2.0.0 -__ https://github.com/STIXProject/python-stix/tree/v1.2.0.0 -__ https://pypi.python.org/pypi/stix/1.1.1.5 -__ https://github.com/STIXProject/python-stix/tree/v1.1.1.5 +__ https://pypi.python.org/pypi/stix/1.2.0.1 +__ https://github.com/STIXProject/python-stix/tree/v1.2.0.1 +__ https://pypi.python.org/pypi/stix/1.1.1.6 +__ https://github.com/STIXProject/python-stix/tree/v1.1.1.6 __ https://pypi.python.org/pypi/stix/1.1.0.6 __ https://github.com/STIXProject/python-stix/tree/v1.1.0.6 __ https://pypi.python.org/pypi/stix/1.0.1.1 From 689cbae2bed174413eefe3db978860483c461d45 Mon Sep 17 00:00:00 2001 From: clenk Date: Thu, 20 Oct 2016 16:34:33 -0400 Subject: [PATCH 346/438] Retain content when going from a MAEC4_1 binding object to a MAECInstance entity object --- stix/extensions/malware/maec_4_1_malware.py | 18 +++++++++--------- stix/test/__init__.py | 7 +++---- .../malware/maec_4_1_malware_test.py | 5 ++--- stix/ttp/malware_instance.py | 2 +- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index 6516497f..e45dbebf 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -158,7 +158,7 @@ def from_obj(cls, obj): else: obj.MAEC = obj.MAEC - super(MAECInstance, cls).from_obj(obj) + return_obj = super(MAECInstance, cls).from_obj(obj) return return_obj @@ -192,11 +192,11 @@ def _maec_from_dict(cls, d): def from_dict(cls, d, return_obj=None): if not d: return None - + d = d.copy() - + maec = d.get('maec') - + if maec is None: pass elif isinstance(maec, dict): @@ -205,9 +205,9 @@ def from_dict(cls, d, return_obj=None): d['maec'] = mixbox.xml.get_etree_root(BytesIO(maec)) else: raise TypeError("Unknown type for 'maec' entry.") - + return_obj = super(MAECInstance, cls).from_dict(d) - + return return_obj def to_dict(self): @@ -219,13 +219,13 @@ def to_dict(self): root = mixbox.xml.get_etree_root(tree) self._parse_etree(root) self.maec = root - + if _MAEC_INSTALLED and isinstance(self.maec, maecPackage): d['maec'] = self.maec.to_dict() else: d['maec'] = etree.tostring(self.maec) - + if self._XSI_TYPE: d['xsi:type'] = self._XSI_TYPE - + return d diff --git a/stix/test/__init__.py b/stix/test/__init__.py index 940576f6..aabac57d 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -54,6 +54,7 @@ def round_trip_dict(cls, dict_): dict2 = cls.to_dict(api_obj) return dict2 + def round_trip(o, output=False, list_=False): """ Performs all eight conversions to verify import/export functionality. @@ -124,7 +125,7 @@ def round_trip(o, output=False, list_=False): # Before parsing the XML, make sure the cache is clear cybox.utils.cache_clear() - #7. XML String -> Bindings Object + # 7. XML String -> Bindings Object xobj2 = klass._binding.parseString(xml_string) # 8. Bindings object -> cybox.Entity @@ -132,6 +133,7 @@ def round_trip(o, output=False, list_=False): return o3 + class EntityTestCase(object): """A base class for testing STIX Entities""" @@ -157,7 +159,6 @@ def _combine(self, d): return dict(items) - @silence_warnings def test_round_trip_full(self): # Don't run this test on the base class @@ -165,7 +166,6 @@ def test_round_trip_full(self): return ent = self.klass.from_dict(self._full_dict) - ent2 = round_trip(ent, output=True) @silence_warnings @@ -190,4 +190,3 @@ def test_round_trip_rt(self): obj = self.klass.from_dict(self._full_dict) dict2 = obj.to_dict() self.assertEqual(self._full_dict, dict2) - diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index 7915f413..5cd92523 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -115,7 +115,7 @@ def test_etree_dict(self): class PythonMAECInPackageTests(unittest.TestCase): - XML = BytesIO( + XML = StringIO( """ """ ) - XML_MAEC = BytesIO( + XML_MAEC = StringIO( """ Remote Access Trojan Poison Ivy Variant v4392-acc - diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index 588372cc..053bdc61 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -91,7 +91,7 @@ def add_short_description(self, description): This is the same as calling "foo.short_descriptions.add(bar)". """ self.short_descriptions.add(description) - + def add_name(self, name): self.names.append(name) From 7f05e1a9f0631046fd6bfb015a8d21b7bdcba709 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Fri, 21 Oct 2016 11:08:50 -0500 Subject: [PATCH 347/438] Bump required version of mixbox --- setup.py | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 682c31f3..7dbf4f30 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ def get_version(): 'lxml>=2.3', 'python-dateutil', 'cybox>=2.1.0.13.dev1,<2.1.1.0', - 'mixbox>=0.0.13', + 'mixbox>=1.0.1', ] diff --git a/tox.ini b/tox.ini index 6748f214..5ef36035 100644 --- a/tox.ini +++ b/tox.ini @@ -19,7 +19,7 @@ commands = deps = lxml==2.3 python-dateutil==1.4.1 - mixbox>=0.0.13 + mixbox>=1.0.1 cybox>=2.1.0.13.dev1 maec>=4.1.0.13.dev4 nose From 007b19099d0e7da1e84681cfe45d677f47d73b18 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Fri, 21 Oct 2016 16:25:42 -0500 Subject: [PATCH 348/438] Build branches other than master --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index e3f9b674..f5de8635 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,10 +16,6 @@ install: script: - tox -branches: - only: - - master - notifications: email: - stix-commits-list@lists.mitre.org From 5b0f411e13c4fc967233cbb9542c227eb963b0a2 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Thu, 27 Oct 2016 17:17:43 -0500 Subject: [PATCH 349/438] Add failing test for #309 --- stix/test/indicator_test.py | 39 +++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/stix/test/indicator_test.py b/stix/test/indicator_test.py index d95cfcd3..98aad335 100644 --- a/stix/test/indicator_test.py +++ b/stix/test/indicator_test.py @@ -1,8 +1,11 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -import unittest from datetime import datetime +import unittest + +from cybox.core import Observable, ObservableComposition +from cybox.objects.file_object import File from mixbox.vendor.six import text_type from stix.core import STIXPackage @@ -41,7 +44,6 @@ def test_negate(self): o2 = self.klass.from_dict(d).to_obj() self.assertTrue(o2.negate is None) - def test_indicator_types(self): d = { @@ -457,6 +459,39 @@ def test_datetime_format(self): ixml = indicator.to_xml() self.assertTrue("2010-03-05T" in text_type(ixml)) + def test_observables_property_empty(self): + ind = Indicator() + ind2 = Indicator.from_dict(ind.to_dict()) + + self.assertEqual([], ind2.observables) + + def test_observables_property_composition(self): + f1 = File() + f1.file_name = "README.txt" + f2 = File() + f2.file_name = "README2.txt" + obs1 = Observable(f1) + obs2 = Observable(f2) + + comp = Observable(ObservableComposition('AND', [obs1, obs2])) + + ind = Indicator() + ind.observable = comp + ind2 = Indicator.from_dict(ind.to_dict()) + self.assertEqual([obs1.to_dict(), obs2.to_dict()], + [x.to_dict() for x in ind2.observables]) + + def test_observables_property_standard(self): + f = File() + f.file_name = "README.txt" + obs = Observable(f) + ind = Indicator() + ind.observable = obs + + ind2 = Indicator.from_dict(ind.to_dict()) + + self.assertEqual([obs], ind2.observables) + class RelatedCampaignReferencesTests(unittest.TestCase, EntityTestCase): klass = RelatedCampaignRefs From f7f90a88a4370225e9adf35d54800199e41dfb33 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Thu, 27 Oct 2016 17:19:53 -0500 Subject: [PATCH 350/438] Return single observable correctly. Fix #309 --- stix/indicator/indicator.py | 3 ++- stix/test/indicator_test.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 1ffc5242..8b67078c 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -248,7 +248,8 @@ def observables(self): elif self.observable.observable_composition: return self.observable.observable_composition.observables - return [] + # self.observable is defined and not a composition. + return [self.observable] @observables.setter def observables(self, value): diff --git a/stix/test/indicator_test.py b/stix/test/indicator_test.py index 98aad335..05a4b3f3 100644 --- a/stix/test/indicator_test.py +++ b/stix/test/indicator_test.py @@ -490,7 +490,8 @@ def test_observables_property_standard(self): ind2 = Indicator.from_dict(ind.to_dict()) - self.assertEqual([obs], ind2.observables) + self.assertEqual([obs.to_dict()], + [x.to_dict() for x in ind2.observables]) class RelatedCampaignReferencesTests(unittest.TestCase, EntityTestCase): From d95d6e83157b73131e80d161876e12cd187496a1 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Thu, 27 Oct 2016 19:29:18 -0500 Subject: [PATCH 351/438] Remove deprecated timestamp field from test data --- stix/test/extensions/malware/maec_4_1_malware_test.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index 5cd92523..d8e9084b 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -131,7 +131,6 @@ class PythonMAECInPackageTests(unittest.TestCase): http://stix.mitre.org/stix-1 http://stix.mitre.org/XMLSchema/core/1.2/stix_core.xsd" id="example:Package-2b8fb66f-b6b3-4d40-865a-33e4a5ee1246" version="1.2" - timestamp="2014-05-08T09:00:00.000000Z" > @@ -169,7 +168,6 @@ class PythonMAECInPackageTests(unittest.TestCase): http://maec.mitre.org/XMLSchema/maec-package-2 http://maec.mitre.org/language/version4.1/maec_package_schema.xsd" id="example:Package-2b8fb66f-b6b3-4d40-865a-33e4a5ee1246" version="1.2" - timestamp="2014-05-08T09:00:00.000000Z" > From 3f724e1b2d54b7b5615d6119dfa676121aed0546 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Fri, 28 Oct 2016 11:06:09 -0500 Subject: [PATCH 352/438] Bump version to 1.2.0.2.dev0 --- stix/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/version.py b/stix/version.py index 9bc15709..063454e2 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.1" +__version__ = "1.2.0.2.dev0" From 297a9ca337e988eed8d04c8e15274937e8cec47f Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 11 Oct 2016 10:56:17 -0500 Subject: [PATCH 353/438] Use stix-ciqidentity as default namespace prefix. --- stix/extensions/identity/ciq_identity_3_0.py | 12 ++++++------ .../extensions/identity/ciq_identity_3_0_test.py | 2 +- stix/test/indicator_test.py | 2 +- stix/utils/nsparser.py | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index 78fb58f8..b424cb5d 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -24,12 +24,12 @@ @stix.register_extension class CIQIdentity3_0Instance(common.Identity): - _binding = ciq_identity_binding - _binding_class = _binding.CIQIdentity3_0InstanceType - _namespace = "http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1" - _XML_NS_PREFIX = "ciqIdentity" - _XML_TYPE = "CIQIdentity3.0InstanceType" - _XSI_TYPE = "ciqIdentity:CIQIdentity3.0InstanceType" + _binding = ciq_identity_binding + _binding_class = _binding.CIQIdentity3_0InstanceType + _namespace = "http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1" + _XML_NS_PREFIX = "stix-ciqidentity" + _XML_TYPE = "CIQIdentity3.0InstanceType" + _XSI_TYPE = "stix-ciqidentity:CIQIdentity3.0InstanceType" def __init__(self, roles=None, specification=None): super(CIQIdentity3_0Instance, self).__init__() diff --git a/stix/test/extensions/identity/ciq_identity_3_0_test.py b/stix/test/extensions/identity/ciq_identity_3_0_test.py index fbd50ac5..086f5f56 100644 --- a/stix/test/extensions/identity/ciq_identity_3_0_test.py +++ b/stix/test/extensions/identity/ciq_identity_3_0_test.py @@ -108,7 +108,7 @@ class CIQIdentity3_0InstanceTests(EntityTestCase, unittest.TestCase): } ] }, - 'xsi:type': 'ciqIdentity:CIQIdentity3.0InstanceType' + 'xsi:type': 'stix-ciqidentity:CIQIdentity3.0InstanceType' } diff --git a/stix/test/indicator_test.py b/stix/test/indicator_test.py index 05a4b3f3..da5314e7 100644 --- a/stix/test/indicator_test.py +++ b/stix/test/indicator_test.py @@ -190,7 +190,7 @@ def test_producer(self): ] } }, - 'xsi:type': 'ciqIdentity:CIQIdentity3.0InstanceType' + 'xsi:type': 'stix-ciqidentity:CIQIdentity3.0InstanceType' }, 'time': {'produced_time': '2014-02-21T10:16:14.947201'} } diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index e46cb356..94ca64c6 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -7,7 +7,7 @@ NS_CAMPAIGN_OBJECT = Namespace("http://stix.mitre.org/Campaign-1", "campaign", "http://stix.mitre.org/XMLSchema/campaign/1.2/campaign.xsd") NS_CAPEC_OBJECT = Namespace("http://capec.mitre.org/capec-2", "capec", "") -NS_CIQIDENTITY_OBJECT = Namespace("http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1", "ciqIdentity", "http://stix.mitre.org/XMLSchema/extensions/identity/ciq_3.0/1.2/ciq_3.0_identity.xsd") +NS_CIQIDENTITY_OBJECT = Namespace("http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1", "stix-ciqidentity", "http://stix.mitre.org/XMLSchema/extensions/identity/ciq_3.0/1.2/ciq_3.0_identity.xsd") NS_COA_OBJECT = Namespace("http://stix.mitre.org/CourseOfAction-1", "coa", "http://stix.mitre.org/XMLSchema/course_of_action/1.2/course_of_action.xsd") NS_CVRF_OBJECT = Namespace("http://www.icasi.org/CVRF/schema/cvrf/1.1", "cvrf", "") NS_ET_OBJECT = Namespace("http://stix.mitre.org/ExploitTarget-1", "et", "http://stix.mitre.org/XMLSchema/exploit_target/1.2/exploit_target.xsd") From 6101b0e88bd784b3cb670596b9014e70c94905e6 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Tue, 11 Oct 2016 10:46:58 -0400 Subject: [PATCH 354/438] Update OrganisationInfo and test accordingly. --- stix/extensions/identity/ciq_identity_3_0.py | 22 ++++++++++++++++--- .../identity/ciq_identity_3_0_test.py | 5 ++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index b424cb5d..681ef1d9 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -290,7 +290,20 @@ def add_nationality(self, value): elif isinstance(value, Country): self.nationalities.append(value) else: - self.nationalities.append(Country(value)) + self.nationalities.append(Country(value)) + + @property + def organisation_info(self): + return self._organisation_info + + @organisation_info.setter + def organisation_info(self, value): + if not value: + self._organisation_info = None + elif isinstance(value, OrganisationInfo): + self._organisation_info = value + else: + raise ValueError('organisation_info must be instance of OrganisationInfo') @classmethod def from_obj(cls, obj, return_obj=None): @@ -318,7 +331,7 @@ def from_obj(cls, obj, return_obj=None): organisation_info = obj.findall(OrganisationInfo.XML_TAG) if organisation_info is not None and len(organisation_info) > 0: return_obj.organisation_info = OrganisationInfo.from_obj(organisation_info[0]) - + electronic_address_identifiers = obj.findall("{%s}ElectronicAddressIdentifiers" % XML_NS_XPIL) if electronic_address_identifiers is not None and len(electronic_address_identifiers) > 0: return_obj.electronic_address_identifiers = [ElectronicAddressIdentifier.from_obj(x) for x in electronic_address_identifiers[0]] @@ -375,7 +388,7 @@ def to_obj(self, return_obj=None, ns_info=None): if self.organisation_info: return_obj.append(self.organisation_info.to_obj(ns_info=ns_info)) - + if self.languages: languages_root = et.Element("{%s}Languages" % XML_NS_XPIL) return_obj.append(languages_root) @@ -407,6 +420,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.free_text_lines = [FreeTextLine.from_dict(x) for x in dict_repr.get('free_text_lines', [])] return_obj.contact_numbers = [ContactNumber.from_dict(x) for x in dict_repr.get('contact_numbers', [])] return_obj.nationalities = [Country.from_dict(x) for x in dict_repr.get('nationalities', [])] + return_obj.organisation_info = OrganisationInfo.from_dict(dict_repr.get('organisation_info')) return return_obj @@ -429,6 +443,8 @@ def to_dict(self): d['contact_numbers'] = [x.to_dict() for x in self.contact_numbers] if self.nationalities: d['nationalities'] = [x.to_dict() for x in self.nationalities] + if self.organisation_info: + d['organisation_info'] = self.organisation_info.to_dict() return d diff --git a/stix/test/extensions/identity/ciq_identity_3_0_test.py b/stix/test/extensions/identity/ciq_identity_3_0_test.py index 086f5f56..69367724 100644 --- a/stix/test/extensions/identity/ciq_identity_3_0_test.py +++ b/stix/test/extensions/identity/ciq_identity_3_0_test.py @@ -106,7 +106,10 @@ class CIQIdentity3_0InstanceTests(EntityTestCase, unittest.TestCase): {'value': 'name 2'} ] } - ] + ], + 'organisation_info': { + 'industry_type': 'SECTOR 1 | SECTOR 2', + } }, 'xsi:type': 'stix-ciqidentity:CIQIdentity3.0InstanceType' } From 3b3c44abf02d19ab27ddbf8ce7394aab5f8f0ac5 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 1 Nov 2016 15:59:45 -0500 Subject: [PATCH 355/438] Update to new CIQ namespace --- stix/bindings/extensions/identity/ciq_identity_3_0.py | 2 +- stix/test/extensions/identity/ciq_identity_3_0_test.py | 2 +- stix/test/ttp_test.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stix/bindings/extensions/identity/ciq_identity_3_0.py b/stix/bindings/extensions/identity/ciq_identity_3_0.py index a4ea469c..5fa3610c 100644 --- a/stix/bindings/extensions/identity/ciq_identity_3_0.py +++ b/stix/bindings/extensions/identity/ciq_identity_3_0.py @@ -31,7 +31,7 @@ class CIQIdentity3_0InstanceType(stix_common_binding.IdentityType): superclass = stix_common_binding.IdentityType xmlns = XML_NS - xmlns_prefix = "ciqIdentity" + xmlns_prefix = "stix-ciqidentity" xml_type = "CIQIdentity3.0InstanceType" xsi_type = "%s:%s" % (xmlns_prefix, xml_type) diff --git a/stix/test/extensions/identity/ciq_identity_3_0_test.py b/stix/test/extensions/identity/ciq_identity_3_0_test.py index 69367724..332db1c9 100644 --- a/stix/test/extensions/identity/ciq_identity_3_0_test.py +++ b/stix/test/extensions/identity/ciq_identity_3_0_test.py @@ -151,7 +151,7 @@ class IdentityInThreatActorTests(EntityTestCase, unittest.TestCase): ] } }, - "xsi:type": "ciqIdentity:CIQIdentity3.0InstanceType" + "xsi:type": "stix-ciqidentity:CIQIdentity3.0InstanceType" }, "timestamp": "2016-10-04T19:43:57.382126+00:00", "title": "Disco Team Threat Actor Group" diff --git a/stix/test/ttp_test.py b/stix/test/ttp_test.py index a7a81aa7..1f19a357 100644 --- a/stix/test/ttp_test.py +++ b/stix/test/ttp_test.py @@ -216,7 +216,7 @@ class TTPIdentityTests(EntityTestCase, unittest.TestCase): "industry_type": "Electricity, Industrial Control Systems" } }, - "xsi:type": "ciqIdentity:CIQIdentity3.0InstanceType" + "xsi:type": "stix-ciqidentity:CIQIdentity3.0InstanceType" } } } From 1eb6497980da3b6c15b2b80f570a7c2589620b0a Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 2 Nov 2016 08:41:58 -0400 Subject: [PATCH 356/438] Update CIQ: namespace, properties for NameElement, general formatting and tests. --- stix/extensions/identity/ciq_identity_3_0.py | 288 ++++++++++-------- .../identity/ciq_identity_3_0_test.py | 26 +- 2 files changed, 174 insertions(+), 140 deletions(-) diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index 681ef1d9..a2d89f08 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2016, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import lxml.etree as et @@ -19,7 +19,7 @@ et.register_namespace('xpil', XML_NS_XPIL) et.register_namespace('xnl', XML_NS_XNL) et.register_namespace('xal', XML_NS_XAL) -et.register_namespace('ExtSch', XML_NS_STIX_EXT) +et.register_namespace('stix-ciqidentity', XML_NS_STIX_EXT) @stix.register_extension @@ -99,7 +99,7 @@ def from_obj(cls, cls_obj): def to_dict(self): d = super(CIQIdentity3_0Instance, self).to_dict() d['xsi:type'] = self._XSI_TYPE - + if self.roles: d['roles'] = [str(x) for x in self.roles] if self.specification: @@ -126,12 +126,13 @@ def from_dict(cls, cls_dict): class STIXCIQIdentity3_0(stix.Entity): - _namespace = "http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1" + _namespace = "http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1" XML_TAG = "{%s}Specification" % _namespace - def __init__(self, party_name=None, languages=None, addresses=None, + def __init__(self, party_name=None, languages=None, addresses=None, organisation_info=None, electronic_address_identifiers=None, - free_text_lines=None, contact_numbers=None, nationalities=None): + free_text_lines=None, contact_numbers=None, + nationalities=None): self.party_name = party_name self.languages = languages self.addresses = addresses @@ -140,11 +141,11 @@ def __init__(self, party_name=None, languages=None, addresses=None, self.free_text_lines = free_text_lines self.contact_numbers = contact_numbers self.nationalities = nationalities - + @property def addresses(self): - return self._addresses - + return self._addresses + @addresses.setter def addresses(self, value): self._addresses = [] @@ -155,7 +156,7 @@ def addresses(self, value): self.add_address(v) else: self.add_address(value) - + def add_address(self, value): if not value: return @@ -163,11 +164,11 @@ def add_address(self, value): self.addresses.append(value) else: raise ValueError('value must be instance of Address') - + @property def languages(self): return self._languages - + @languages.setter def languages(self, value): self._languages = [] @@ -178,7 +179,7 @@ def languages(self, value): self.add_language(v) else: self.add_language(value) - + def add_language(self, value): if not value: return @@ -186,7 +187,7 @@ def add_language(self, value): self.languages.append(value) else: self.languages.append(Language(value)) - + @property def party_name(self): return self._party_name @@ -202,8 +203,8 @@ def party_name(self, value): @property def electronic_address_identifiers(self): - return self._electronic_address_identifiers - + return self._electronic_address_identifiers + @electronic_address_identifiers.setter def electronic_address_identifiers(self, value): self._electronic_address_identifiers = [] @@ -214,7 +215,7 @@ def electronic_address_identifiers(self, value): self.add_electronic_address_identifier(v) else: self.add_electronic_address_identifier(value) - + def add_electronic_address_identifier(self, value): if not value: return @@ -237,7 +238,7 @@ def free_text_lines(self, value): self.add_free_text_line(v) else: self.add_free_text_line(value) - + def add_free_text_line(self, value): if not value: return @@ -260,7 +261,7 @@ def contact_numbers(self, value): self.add_contact_number(v) else: self.add_contact_number(value) - + def add_contact_number(self, value): if not value: return @@ -319,7 +320,7 @@ def from_obj(cls, obj, return_obj=None): languages = obj.findall("{%s}Languages" % XML_NS_XPIL) if languages is not None and len(languages) > 0: return_obj.languages = [Language.from_obj(x) for x in languages[0]] - + addresses = obj.findall("{%s}Addresses" % XML_NS_XPIL) if addresses is not None and len(addresses) > 0: return_obj.addresses = [Address.from_obj(x) for x in addresses[0]] @@ -327,7 +328,7 @@ def from_obj(cls, obj, return_obj=None): nationalities = obj.findall("{%s}Nationalities" % XML_NS_XPIL) if nationalities is not None and len(nationalities) > 0: return_obj.nationalities = [Country.from_obj(x) for x in nationalities[0]] - + organisation_info = obj.findall(OrganisationInfo.XML_TAG) if organisation_info is not None and len(organisation_info) > 0: return_obj.organisation_info = OrganisationInfo.from_obj(organisation_info[0]) @@ -335,15 +336,15 @@ def from_obj(cls, obj, return_obj=None): electronic_address_identifiers = obj.findall("{%s}ElectronicAddressIdentifiers" % XML_NS_XPIL) if electronic_address_identifiers is not None and len(electronic_address_identifiers) > 0: return_obj.electronic_address_identifiers = [ElectronicAddressIdentifier.from_obj(x) for x in electronic_address_identifiers[0]] - + free_text_lines = obj.findall("{%s}FreeTextLines" % XML_NS_XPIL) if free_text_lines is not None and len(free_text_lines) > 0: return_obj.free_text_lines = [FreeTextLine.from_obj(x) for x in free_text_lines[0]] - + contact_numbers = obj.findall("{%s}ContactNumbers" % XML_NS_XPIL) if contact_numbers is not None and len(contact_numbers) > 0: return_obj.contact_numbers = [ContactNumber.from_obj(x) for x in contact_numbers[0]] - + return return_obj def to_obj(self, return_obj=None, ns_info=None): @@ -364,7 +365,7 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.append(ftl_root) for ftl in self.free_text_lines: ftl_root.append(ftl.to_obj(ns_info=ns_info)) - + if self.party_name: return_obj.append(self.party_name.to_obj(ns_info=ns_info)) @@ -373,19 +374,19 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.append(addresses_root) for address in self.addresses: addresses_root.append(address.to_obj(ns_info=ns_info)) - + if self.contact_numbers: contact_numbers_root = et.Element("{%s}ContactNumbers" % XML_NS_XPIL) return_obj.append(contact_numbers_root) for contact_number in self.contact_numbers: contact_numbers_root.append(contact_number.to_obj(ns_info=ns_info)) - + if self.electronic_address_identifiers: eai_root = et.Element("{%s}ElectronicAddressIdentifiers" % XML_NS_XPIL) return_obj.append(eai_root) for eai in self.electronic_address_identifiers: eai_root.append(eai.to_obj(ns_info=ns_info)) - + if self.organisation_info: return_obj.append(self.organisation_info.to_obj(ns_info=ns_info)) @@ -402,7 +403,7 @@ def to_obj(self, return_obj=None, ns_info=None): country_obj = country.to_obj(ns_info=ns_info) country_obj.tag = "{%s}Country" % XML_NS_XPIL nationalities_root.append(country_obj) - + return return_obj @classmethod @@ -413,7 +414,6 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj = cls() return_obj.party_name = PartyName.from_dict(dict_repr.get('party_name')) - return_obj.organisation_info = OrganisationInfo.from_dict(dict_repr.get('organisation_info')) return_obj.languages = [Language.from_dict(x) for x in dict_repr.get('languages', [])] return_obj.addresses = [Address.from_dict(x) for x in dict_repr.get('addresses', [])] return_obj.electronic_address_identifiers = [ElectronicAddressIdentifier.from_dict(x) for x in dict_repr.get('electronic_address_identifiers', [])] @@ -429,8 +429,6 @@ def to_dict(self): if self.party_name: d['party_name'] = self.party_name.to_dict() - if self.organisation_info: - d['organisation_info'] = self.organisation_info.to_dict() if self.languages: d['languages'] = [x.to_dict() for x in self.languages] if self.addresses: @@ -452,8 +450,9 @@ def to_dict(self): class Address(stix.Entity): _namespace = XML_NS_XPIL XML_TAG = "{%s}Address" % _namespace - - def __init__(self, free_text_address=None, country=None, administrative_area=None): + + def __init__(self, free_text_address=None, country=None, + administrative_area=None): self.free_text_address = free_text_address self.country = country self.administrative_area = administrative_area @@ -513,34 +512,34 @@ def from_obj(cls, obj, return_obj=None): return None if not return_obj: return_obj = cls() - + free_text_address = obj.findall("{%s}FreeTextAddress" % XML_NS_XAL) if len(free_text_address) > 0: return_obj.free_text_address = FreeTextAddress.from_obj(free_text_address[0]) - + country = obj.findall("{%s}Country" % XML_NS_XAL) if len(country) > 0: return_obj.country = Country.from_obj(country[0]) - + administrative_area = obj.findall("{%s}AdministrativeArea" % XML_NS_XAL) if len(administrative_area) > 0: return_obj.administrative_area = AdministrativeArea.from_obj(administrative_area[0]) - + return return_obj - + @classmethod def from_dict(cls, d, return_obj=None): if not d: return None if not return_obj: return_obj = cls() - + return_obj.free_text_address = FreeTextAddress.from_dict(d.get('free_text_address')) return_obj.country = Country.from_dict(d.get('country')) return_obj.administrative_area = AdministrativeArea.from_dict(d.get('administrative_area')) return return_obj - + class AdministrativeArea(stix.Entity): _namespace = XML_NS_XAL XML_TAG = "{%s}AdministrativeArea" % _namespace @@ -551,7 +550,7 @@ def __init__(self, name_elements=None): @property def name_elements(self): return self._name_elements - + @name_elements.setter def name_elements(self, value): self._name_elements = [] @@ -577,42 +576,42 @@ def from_obj(cls, obj, return_obj=None): return None if not return_obj: return_obj = cls() - + name_elements = obj.findall(NameElement.XML_TAG) if name_elements: for name_element in name_elements: return_obj.name_elements.append(NameElement.from_obj(name_element)) - + return return_obj - + def to_obj(self, return_obj=None, ns_info=None): super(AdministrativeArea, self).to_obj(ns_info=ns_info) if not return_obj: return_obj = et.Element(self.XML_TAG) - + for name_element in self.name_elements: return_obj.append(name_element.to_obj(ns_info=ns_info)) - + return return_obj - + def to_dict(self): d = {} if self.name_elements: d['name_elements'] = [x.to_dict() for x in self.name_elements] return d - + @classmethod def from_dict(cls, d, return_obj=None): if not d: return None if not return_obj: return_obj = cls() - + return_obj.name_elements = [NameElement.from_dict(x) for x in d.get('name_elements', [])] return return_obj - + class Country(stix.Entity): _namespace = XML_NS_XAL XML_TAG = "{%s}Country" % _namespace @@ -623,7 +622,7 @@ def __init__(self, name_elements=None): @property def name_elements(self): return self._name_elements - + @name_elements.setter def name_elements(self, value): self._name_elements = [] @@ -649,25 +648,25 @@ def from_obj(cls, obj, return_obj=None): return None if not return_obj: return_obj = cls() - + name_elements = obj.findall("{%s}NameElement" % XML_NS_XAL) if name_elements: for name_element in name_elements: return_obj.name_elements.append(NameElement.from_obj(name_element)) - + return return_obj - + def to_obj(self, return_obj=None, ns_info=None): super(Country, self).to_obj(ns_info=ns_info) if not return_obj: return_obj = et.Element(self.XML_TAG) - + for name_element in self.name_elements: return_obj.append(name_element.to_obj(ns_info=ns_info)) - + return return_obj - + def to_dict(self): d = {} if self.name_elements: @@ -680,7 +679,7 @@ def from_dict(cls, d, return_obj=None): return None if not return_obj: return_obj = cls() - + return_obj.name_elements = [NameElement.from_dict(x) for x in d.get('name_elements', [])] return return_obj @@ -688,17 +687,29 @@ def from_dict(cls, d, return_obj=None): class NameElement(stix.Entity): _namespace = XML_NS_XAL XML_TAG = "{%s}NameElement" % XML_NS_XAL - - def __init__(self, value=None): + + def __init__(self, value=None, name_type=None, name_code=None, + name_code_type=None): self.value = value - + self.name_type = name_type + self.name_code = name_code + self.name_code_type = name_code_type + def to_obj(self, return_obj=None, ns_info=None): super(NameElement, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) return_obj.text = self.value + + if self.name_type: + return_obj.set('{%s}NameType' % self._namespace, self.name_type) + if self.name_code: + return_obj.set('{%s}NameCode' % self._namespace, self.name_code) + if self.name_code_type: + return_obj.set('{%s}NameCodeType' % self._namespace, self.name_code_type) + return return_obj - + @classmethod def from_obj(cls, obj, return_obj=None): if obj is None: @@ -708,14 +719,24 @@ def from_obj(cls, obj, return_obj=None): return_obj = cls() return_obj.value = obj.text + return_obj.name_type = obj.get('{%s}NameType' % cls._namespace) + return_obj.name_code = obj.get('{%s}NameCode' % cls._namespace) + return_obj.name_code_type = obj.get('{%s}NameCodeType' % cls._namespace) + return return_obj - + def to_dict(self): d = {} if self.value: d['value'] = self.value + if self.name_type: + d['name_type'] = self.name_type + if self.name_code: + d['name_code'] = self.name_code + if self.name_code_type: + d['name_code_type'] = self.name_code_type return d - + @classmethod def from_dict(cls, d, return_obj=None): if not d: @@ -725,20 +746,23 @@ def from_dict(cls, d, return_obj=None): return_obj = cls() return_obj.value = d.get('value') + return_obj.name_type = d.get('name_type') + return_obj.name_code = d.get('name_code') + return_obj.name_code_type = d.get('name_code_type') return return_obj class FreeTextAddress(stix.Entity): _namespace = XML_NS_XAL XML_TAG = "{%s}FreeTextAddress" % XML_NS_XAL - + def __init__(self, address_lines=None): self.address_lines = address_lines @property def address_lines(self): return self._address_lines - + @address_lines.setter def address_lines(self, value): self._address_lines = [] @@ -756,13 +780,13 @@ def from_obj(cls, obj, return_obj=None): return None if not return_obj: return_obj = cls() - + address_line_tag = "{%s}AddressLine" % XML_NS_XAL address_lines = obj.findall(address_line_tag) if address_lines: for address_line in address_lines: return_obj.address_lines.append(address_line.text) - + return return_obj def to_obj(self, return_obj=None, ns_info=None): @@ -775,9 +799,9 @@ def to_obj(self, return_obj=None, ns_info=None): address_line = et.Element("{%s}AddressLine" % XML_NS_XAL) address_line.text = address return_obj.append(address_line) - + return return_obj - + @classmethod def from_dict(cls, d, return_obj=None): if not d: @@ -785,10 +809,10 @@ def from_dict(cls, d, return_obj=None): if not return_obj: return_obj = cls() - + return_obj.address_lines = d.get('address_lines', []) return return_obj - + def to_dict(self): d = {} if self.address_lines: @@ -838,7 +862,7 @@ def add_organisation_name(self, value): self.organisation_names.append(OrganisationName(name_elements=[value])) elif isinstance(value, OrganisationName): self.organisation_names.append(value) - else: + else: raise ValueError('value must be instance of OrganisationName') def to_obj(self, return_obj=None, ns_info=None): @@ -926,7 +950,7 @@ def from_dict(cls, dict_repr, return_obj=None): for pn in pn_dicts: person_name = PersonName.from_dict(pn) - return_obj.add_person_name(person_name) + return_obj.add_person_name(person_name) return return_obj @@ -941,7 +965,7 @@ def __init__(self, value=None, type_=None): @property def value(self): - return self._value + return self._value @value.setter def value(self, value): @@ -960,7 +984,7 @@ def to_obj(self, return_obj=None, ns_info=None): if self.type: return_obj.attrib['Type'] = self.type - if self.value: + if self.value: return_obj.text = self.value return return_obj @@ -1107,7 +1131,7 @@ def add_organisation_name_element(self, value): @property def subdivision_names(self): return self._subdivision_names - + @subdivision_names.setter def subdivision_names(self, value): self._subdivision_names = [] @@ -1149,7 +1173,7 @@ def from_obj(cls, obj, return_obj=None): return_obj = cls() return_obj.type_ = obj.attrib.get('{%s}Type' % XML_NS_XNL) - + name_elements = obj.findall(OrganisationNameElement.XML_TAG) if name_elements: for name_element_obj in name_elements: @@ -1166,7 +1190,7 @@ def from_obj(cls, obj, return_obj=None): def to_dict(self): d = {} - + if self.type_: d['type'] = self.type_ if self.name_elements: @@ -1195,7 +1219,7 @@ def from_dict(cls, dict_repr, return_obj=None): return_obj.add_subdivision_name(SubDivisionName.from_dict(sn_dict)) return return_obj - + class _BaseNameElement(stix.Entity): """Do not instantiate directly: use PersonNameElement or @@ -1275,7 +1299,7 @@ def element_type(self, value): if value and value not in self.TYPES: raise ValueError('value must be one of %s: ' % (self.TYPES,)) - self._element_type = value + self._element_type = value def to_obj(self, return_obj=None, ns_info=None): if not return_obj: @@ -1297,7 +1321,7 @@ def from_obj(cls, obj, return_obj=None): if not return_obj: return_obj = cls() - return_obj.element_type = obj.get('ElementType') + return_obj.element_type = obj.get('ElementType') return_obj.value = obj.text return return_obj @@ -1479,61 +1503,61 @@ def from_dict(cls, dict_repr, return_obj=None): class Language(stix.Entity): _namespace = XML_NS_XPIL XML_TAG = "{%s}Language" % _namespace - + def __init__(self, value=None): self.value = value - + def to_obj(self, return_obj=None, ns_info=None): super(Language, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) return_obj.text = self.value return return_obj - + @classmethod def from_obj(cls, obj): if obj is None: return None - + return_obj = cls() return_obj.value = obj.text return return_obj - + def to_dict(self): d = {} if self.value: d['value'] = self.value return d - + @classmethod def from_dict(cls, d): if not d: return None - + return_obj = cls() return_obj.value = d.get('value') return return_obj - + class ElectronicAddressIdentifier(stix.Entity): _namespace = XML_NS_XPIL XML_TAG = "{%s}ElectronicAddressIdentifier" % _namespace - + def __init__(self, value=None, type_=None): self.type_ = type_ self.value = value - + def to_obj(self, return_obj=None, ns_info=None): super(ElectronicAddressIdentifier, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) return_obj.text = self.value - + if self.type_: return_obj.attrib['{%s}Type' % XML_NS_XPIL] = self.type_ - + return return_obj - + @classmethod def from_obj(cls, obj, return_obj=None): if obj is None: @@ -1545,7 +1569,7 @@ def from_obj(cls, obj, return_obj=None): return_obj.type_ = obj.attrib.get('{%s}Type' % XML_NS_XPIL) return_obj.value = obj.text return return_obj - + def to_dict(self): d = {} if self.value: @@ -1553,7 +1577,7 @@ def to_dict(self): if self.type_: d['type'] = self.type_ return d - + @classmethod def from_dict(cls, d, return_obj=None): if not d: @@ -1573,16 +1597,16 @@ class OrganisationInfo(stix.Entity): def __init__(self, industry_type=None): self.industry_type = industry_type - + def to_obj(self, return_obj=None, ns_info=None): super(OrganisationInfo, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) if self.industry_type: return_obj.attrib['{%s}IndustryType' % self._namespace] = self.industry_type - + return return_obj - + @classmethod def from_obj(cls, obj, return_obj=None): if obj is None: @@ -1599,7 +1623,7 @@ def to_dict(self): if self.industry_type: d['industry_type'] = self.industry_type return d - + @classmethod def from_dict(cls, d, return_obj=None): if not d: @@ -1615,11 +1639,11 @@ def from_dict(cls, d, return_obj=None): class FreeTextLine(stix.Entity): _namespace = XML_NS_XPIL XML_TAG = "{%s}FreeTextLine" % _namespace - + def __init__(self, value=None, type_=None): self.value = value self.type_ = type_ - + def to_obj(self, return_obj=None, ns_info=None): super(FreeTextLine, self).to_obj(ns_info=ns_info) @@ -1628,9 +1652,9 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.attrib['{%s}Type' % self._namespace] = self.type_ if self.value: return_obj.text = self.value - + return return_obj - + @classmethod def from_obj(cls, obj, return_obj=None): if obj is None: @@ -1650,7 +1674,7 @@ def to_dict(self): if self.value: d['value'] = self.value return d - + @classmethod def from_dict(cls, d, return_obj=None): if not d: @@ -1667,26 +1691,26 @@ def from_dict(cls, d, return_obj=None): class ContactNumber(stix.Entity): _namespace = XML_NS_XPIL XML_TAG = "{%s}ContactNumber" % _namespace - + COM_MEDIA_TYPE_CELLPHONE = "Cellphone" COM_MEDIA_TYPE_FAX = "Fax" COM_MEDIA_TYPE_PAGER = "Pager" COM_MEDIA_TYPE_TELEPHONE = "Telephone" COM_MEDIA_TYPE_VOIP = "VOIP" - + ALLOWED_COM_MEDIA_TYPES = ( COM_MEDIA_TYPE_CELLPHONE, COM_MEDIA_TYPE_FAX, COM_MEDIA_TYPE_PAGER, COM_MEDIA_TYPE_TELEPHONE, COM_MEDIA_TYPE_VOIP ) - + def __init__(self, contact_number_elements=None, communication_media_type=None): self.communication_media_type = communication_media_type self.contact_number_elements = contact_number_elements - + @property def contact_number_elements(self): return self._contact_number_elements - + @contact_number_elements.setter def contact_number_elements(self, value): self._contact_number_elements = [] @@ -1697,7 +1721,7 @@ def contact_number_elements(self, value): self.add_contact_number_element(v) else: self.add_contact_number_element(value) - + def add_contact_number_element(self, value): if not value: return @@ -1705,11 +1729,11 @@ def add_contact_number_element(self, value): self.contact_number_elements.append(value) else: self.contact_number_elements.append(ContactNumberElement(value)) - + @property def communication_media_type(self): return self._communication_media_type - + @communication_media_type.setter def communication_media_type(self, value): if not value: @@ -1718,7 +1742,7 @@ def communication_media_type(self, value): raise ValueError('value must be one of %s' % (self.ALLOWED_COM_MEDIA_TYPES,)) else: self._communication_media_type = value - + def to_obj(self, return_obj=None, ns_info=None): super(ContactNumber, self).to_obj(ns_info=ns_info) return_obj = et.Element(self.XML_TAG) @@ -1727,9 +1751,9 @@ def to_obj(self, return_obj=None, ns_info=None): if self.contact_number_elements: for contact_number_element in self.contact_number_elements: return_obj.append(contact_number_element.to_obj(ns_info=ns_info)) - + return return_obj - + @classmethod def from_obj(cls, obj, return_obj=None): if obj is None: @@ -1739,11 +1763,11 @@ def from_obj(cls, obj, return_obj=None): return_obj = cls() return_obj.communication_media_type = obj.get('{%s}CommunicationMediaType' % cls._namespace) - + contact_number_elements = obj.findall("{%s}ContactNumberElement" % XML_NS_XPIL) if contact_number_elements is not None and len(contact_number_elements) > 0: return_obj.contact_number_elements = [ContactNumberElement.from_obj(x) for x in contact_number_elements] - + return return_obj def to_dict(self): @@ -1752,9 +1776,9 @@ def to_dict(self): d['communication_media_type'] = self.communication_media_type if self.contact_number_elements: d['contact_number_elements'] = [x.to_dict() for x in self.contact_number_elements] - + return d - + @classmethod def from_dict(cls, d, return_obj=None): if not d: @@ -1765,14 +1789,14 @@ def from_dict(cls, d, return_obj=None): return_obj.communication_media_type = d.get('communication_media_type') return_obj.contact_number_elements = [ContactNumberElement.from_dict(x) for x in d.get('contact_number_elements', [])] - + return return_obj class ContactNumberElement(stix.Entity): _namespace = XML_NS_XPIL XML_TAG = "{%s}ContactNumberElement" % _namespace - + TYPE_COUNTRY_CODE = "CountryCode" TYPE_AREA_CODE = "AreaCode" TYPE_LOCAL_NUMBER = "LocalNumber" @@ -1781,21 +1805,21 @@ class ContactNumberElement(stix.Entity): TYPE_SEPARATOR = "Separator" TYPE_NATIONAL_NUMBER = "NationalNumber" TYPE_INTERNATIONAL_NUMBER = "InternationalNumber" - + ALLOWED_TYPES = ( TYPE_AREA_CODE, TYPE_COUNTRY_CODE, TYPE_EXTENSION, TYPE_INTERNATIONAL_NUMBER, TYPE_LOCAL_NUMBER, TYPE_NATIONAL_NUMBER, TYPE_SEPARATOR, TYPE_PIN ) - + def __init__(self, value=None, type_=None): self.value = value self.type_ = type_ - + @property def type_(self): return self._type - + @type_.setter def type_(self, value): if not value: @@ -1804,7 +1828,7 @@ def type_(self, value): raise ValueError('value must be one of %s' % (self.ALLOWED_TYPES,)) else: self._type = value - + def to_obj(self, return_obj=None, ns_info=None): super(ContactNumberElement, self).to_obj(ns_info=ns_info) @@ -1813,9 +1837,9 @@ def to_obj(self, return_obj=None, ns_info=None): return_obj.attrib['{%s}Type' % self._namespace] = self.type_ if self.value: return_obj.text = self.value - + return return_obj - + @classmethod def from_obj(cls, obj, return_obj=None): if obj is None: @@ -1835,7 +1859,7 @@ def to_dict(self): if self.value: d['value'] = self.value return d - + @classmethod def from_dict(cls, d, return_obj=None): if not d: diff --git a/stix/test/extensions/identity/ciq_identity_3_0_test.py b/stix/test/extensions/identity/ciq_identity_3_0_test.py index 332db1c9..677707f0 100644 --- a/stix/test/extensions/identity/ciq_identity_3_0_test.py +++ b/stix/test/extensions/identity/ciq_identity_3_0_test.py @@ -51,9 +51,6 @@ class CIQIdentity3_0InstanceTests(EntityTestCase, unittest.TestCase): } ] }, - 'organisation_info': { - 'industry_type': 'test industry' - }, 'languages': [ {'value': 'test language'} ], @@ -64,8 +61,17 @@ class CIQIdentity3_0InstanceTests(EntityTestCase, unittest.TestCase): }, 'country': { 'name_elements': [ - {'value': 'name 1'}, - {'value': 'name 2'} + { + 'value': 'name 1', + 'name_code': 'US', + 'name_code_type': 'ISO 3166-1 alpha-2' + }, + { + 'value': 'name 2', + 'name_code': 'BZ', + 'name_code_type': 'ISO 3166-1 alpha-2', + 'name_type': 'ISO' + } ] }, 'administrative_area': { @@ -124,11 +130,15 @@ class IdentityInThreatActorTests(EntityTestCase, unittest.TestCase): "addresses": [ { "administrative_area": { - "name_elements": [{"value": "California"} - ] + "name_elements": [{"value": "California"}] }, "country": { - "name_elements": [{"value": "United States"}] + "name_elements": [ + { + "name_code": "US", + "name_code_type": "ISO 3166-1 alpha-2" + } + ] } } ], From b1a1ce0b94d62843dd5aa930af9be4ac58d62599 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Wed, 2 Nov 2016 15:33:02 -0500 Subject: [PATCH 357/438] Add CHANGES from 1.1.1.7 --- CHANGES.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 71ac5c17..4e681fe8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,7 @@ +Version 1.1.1.7 +2016-10-21 +- Improved handling of Industry Sectors in CIQ Identity for AIS Markings + Version 1.1.1.6 2016-10-14 - Add support for AIS Markings in STIX 1.1.1 From b9d1c2072176bf6680d0c43933e0c4224eed699c Mon Sep 17 00:00:00 2001 From: Greg Back Date: Wed, 2 Nov 2016 15:39:41 -0500 Subject: [PATCH 358/438] Update CHANGES.txt for Version 1.2.0.2 --- CHANGES.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 4e681fe8..b19f549e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,11 @@ +Version 1.2.0.2 +2016-11-02 +- #309 Correctly return a single observable from Indicator.observables. +- #306 Incorporate mixbox 1.0.1, which handles dates correctly. +- #303 Property serialize MAEC content to XML. +- #302 Correctly handle CIQ Identity objects. +- Add additional fields to CIQ Identity object. + Version 1.1.1.7 2016-10-21 - Improved handling of Industry Sectors in CIQ Identity for AIS Markings From e75235da625e0125f3e3c3e1c813baf069dfda9f Mon Sep 17 00:00:00 2001 From: Greg Back Date: Wed, 2 Nov 2016 15:42:55 -0500 Subject: [PATCH 359/438] Bump version to 1.2.0.2 --- docs/index.rst | 12 ++++++------ stix/version.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 3513be0f..59107315 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,17 +22,17 @@ version of STIX. ============ =================== STIX Version python-stix Version ============ =================== -1.2 1.2.0.1 (`PyPI`__) (`GitHub`__) -1.1.1 1.1.1.6 (`PyPI`__) (`GitHub`__) +1.2 1.2.0.2 (`PyPI`__) (`GitHub`__) +1.1.1 1.1.1.7 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) ============ =================== -__ https://pypi.python.org/pypi/stix/1.2.0.1 -__ https://github.com/STIXProject/python-stix/tree/v1.2.0.1 -__ https://pypi.python.org/pypi/stix/1.1.1.6 -__ https://github.com/STIXProject/python-stix/tree/v1.1.1.6 +__ https://pypi.python.org/pypi/stix/1.2.0.2 +__ https://github.com/STIXProject/python-stix/tree/v1.2.0.2 +__ https://pypi.python.org/pypi/stix/1.1.1.7 +__ https://github.com/STIXProject/python-stix/tree/v1.1.1.7 __ https://pypi.python.org/pypi/stix/1.1.0.6 __ https://github.com/STIXProject/python-stix/tree/v1.1.0.6 __ https://pypi.python.org/pypi/stix/1.0.1.1 diff --git a/stix/version.py b/stix/version.py index 063454e2..8b906dce 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.2.dev0" +__version__ = "1.2.0.2" From 44eddb599cd5fa83f3806edcb2c2429968918d16 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Wed, 2 Nov 2016 15:48:12 -0500 Subject: [PATCH 360/438] Bump version to 1.2.0.3.dev0 --- stix/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/version.py b/stix/version.py index 8b906dce..ab6a0ba2 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2015, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.2" +__version__ = "1.2.0.3.dev0" From 267dbf390abc0897c691e256396cd1888f423494 Mon Sep 17 00:00:00 2001 From: clenk Date: Wed, 30 Nov 2016 10:13:54 -0500 Subject: [PATCH 361/438] Update doc to match example code --- docs/overview/id_namespaces.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/overview/id_namespaces.rst b/docs/overview/id_namespaces.rst index 62de6ad2..a0cffa26 100644 --- a/docs/overview/id_namespaces.rst +++ b/docs/overview/id_namespaces.rst @@ -6,7 +6,7 @@ By default, **python-stix** sets the default ID namespace to id declarations that look like ``id="example:Package-2813128d-f45e-41f7-b10a-20a5656e3785"``. -To change this, use the :meth:`stix.utils.idgen.set_id_namespace` method which takes +To change this, use the :meth:`mixbox.idgen.set_id_namespace` method which takes a dictionary as a parameter. .. code-block:: python From 26b62ff2d88c2ca32a5d1e227116f608ba950e3b Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 7 Mar 2017 14:38:32 -0600 Subject: [PATCH 362/438] Update Travis notification addresses. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f5de8635..f6fa5be0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,4 +18,5 @@ script: notifications: email: + - gback@mitre.org - stix-commits-list@lists.mitre.org From 7c9c0428485dce0c6892c1d2fb5edc2bf11ac0af Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 13 Mar 2017 13:46:08 -0400 Subject: [PATCH 363/438] AIS support for 1.2. Fix #310 --- stix/bindings/extensions/marking/ais.py | 570 ++++++++++++++++++++++++ stix/extensions/marking/ais.py | 297 ++++++++++++ stix/test/extensions/marking/ais.py | 92 ++++ 3 files changed, 959 insertions(+) create mode 100644 stix/bindings/extensions/marking/ais.py create mode 100644 stix/extensions/marking/ais.py create mode 100644 stix/test/extensions/marking/ais.py diff --git a/stix/bindings/extensions/marking/ais.py b/stix/bindings/extensions/marking/ais.py new file mode 100644 index 00000000..a095c3e8 --- /dev/null +++ b/stix/bindings/extensions/marking/ais.py @@ -0,0 +1,570 @@ +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +import sys + +from mixbox.binding_utils import * +import stix.bindings.data_marking as data_marking_binding +from stix.bindings import register_extension + +XML_NS = "http://www.us-cert.gov/STIXMarkingStructure#AISConsentMarking-2" + + +# +# Data representation classes. +# + +@register_extension +class AISMarkingStructure(data_marking_binding.MarkingStructureType): + """ + The AISMarkingStructure is an implementation of the data marking schema + that allows determining consent to share information source attribution. + """ + subclass = None + superclass = data_marking_binding.MarkingStructureType + + xmlns = XML_NS + xmlns_prefix = "AIS" + xml_type = "AISMarkingStructure" + xsi_type = "%s:%s" % (xmlns_prefix, xml_type) + + def __init__(self, idref=None, marking_model_ref=None, marking_model_name=None, id=None, Is_Proprietary=None, Not_Proprietary=None): + super(AISMarkingStructure, self).__init__(idref=idref, marking_model_ref=marking_model_ref, marking_model_name=marking_model_name, id=id) + self.Is_Proprietary = Is_Proprietary + self.Not_Proprietary = Not_Proprietary + + def factory(*args_, **kwargs_): + if AISMarkingStructure.subclass: + return AISMarkingStructure.subclass(*args_, **kwargs_) + else: + return AISMarkingStructure(*args_, **kwargs_) + factory = staticmethod(factory) + + def get_Is_Proprietary(self): + return self.Is_Proprietary + + def set_Is_Proprietary(self, Is_Proprietary): + self.Is_Proprietary = Is_Proprietary + + def get_Not_Proprietary(self): + return self.Not_Proprietary + + def set_Not_Proprietary(self, Not_Proprietary): + self.Not_Proprietary = Not_Proprietary + + def hasContent_(self): + if ( + self.Is_Proprietary is not None or + self.Not_Proprietary is not None or + super(AISMarkingStructure, self).hasContent_() + ): + return True + else: + return False + + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='AISMarkingStructure', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='AISMarkingStructure') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + + def exportAttributes(self, lwrite, level, already_processed, namespace_=XML_NS, name_='AISMarkingStructure'): + super(AISMarkingStructure, self).exportAttributes(lwrite, level, already_processed, namespace_, name_='AISMarkingStructure') + if 'xsi:type' not in already_processed: + already_processed.add('xsi:type') + lwrite(" xsi:type=%s" % (self.gds_format_string(quote_attrib(self.xsi_type).encode(ExternalEncoding), input_name='xsi:type'))) + + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='AISMarkingStructure', fromsubclass_=False, pretty_print=True): + super(AISMarkingStructure, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.Is_Proprietary is not None: + self.Is_Proprietary.export(lwrite, level, nsmap, namespace_, name_='Is_Proprietary', pretty_print=pretty_print) + if self.Not_Proprietary is not None: + self.Not_Proprietary.export(lwrite, level, nsmap, namespace_, name_='Not_Proprietary', pretty_print=pretty_print) + + def build(self, node): + self.__sourcenode__ = node + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + + def buildAttributes(self, node, attrs, already_processed): + super(AISMarkingStructure, self).buildAttributes(node, attrs, already_processed) + + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'Is_Proprietary': + obj_ = IsProprietary.factory() + obj_.build(child_) + self.set_Is_Proprietary(obj_) + if nodeName_ == 'Not_Proprietary': + obj_ = NotProprietary.factory() + obj_.build(child_) + self.set_Not_Proprietary(obj_) + super(AISMarkingStructure, self).buildChildren(child_, node, nodeName_, True) +# end class AISMarkingStructure + + +class IsProprietary(GeneratedsSuper): + subclass = None + superclass = None + + def __init__(self, CISA_Proprietary=None, AISConsent=None, TLPMarking=None): + self.CISA_Proprietary = _cast(bool, CISA_Proprietary) + self.AISConsent = AISConsent + self.TLPMarking = TLPMarking + + def factory(*args_, **kwargs_): + if IsProprietary.subclass: + return IsProprietary.subclass(*args_, **kwargs_) + else: + return IsProprietary(*args_, **kwargs_) + factory = staticmethod(factory) + + def get_AISConsent(self): + return self.AISConsent + + def set_AISConsent(self, AISConsent): + self.AISConsent = AISConsent + + def get_TLPMarking(self): + return self.TLPMarking + + def set_TLPMarking(self, TLPMarking): + self.TLPMarking = TLPMarking + + def get_CISA_Proprietary(self): + return self.CISA_Proprietary + + def set_CISA_Proprietary(self, CISA_Proprietary): + self.CISA_Proprietary = CISA_Proprietary + + def hasContent_(self): + if ( + self.AISConsent is not None or + self.TLPMarking is not None + ): + return True + else: + return False + + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='IsProprietary', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='IsProprietary') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + + def exportAttributes(self, lwrite, level, already_processed, namespace_=XML_NS, name_='IsProprietary'): + if self.CISA_Proprietary is not None and 'CISA_Proprietary' not in already_processed: + already_processed.add('CISA_Proprietary') + lwrite(' CISA_Proprietary="%s"' % self.gds_format_boolean(self.CISA_Proprietary, input_name='CISA_Proprietary')) + + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='IsProprietary', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.AISConsent is not None: + self.AISConsent.export(lwrite, level, nsmap, namespace_, name_='AISConsent', pretty_print=pretty_print) + if self.TLPMarking is not None: + self.TLPMarking.export(lwrite, level, nsmap, namespace_, name_='TLPMarking', pretty_print=pretty_print) + + def build(self, node): + self.__sourcenode__ = node + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + + def buildAttributes(self, node, attrs, already_processed): + value = find_attr_value_('CISA_Proprietary', node) + if value is not None and 'CISA_Proprietary' not in already_processed: + already_processed.add('CISA_Proprietary') + if value in ('true', '1'): + self.CISA_Proprietary = True + elif value in ('false', '0'): + self.CISA_Proprietary = False + else: + raise_parse_error(node, 'Bad boolean attribute') + + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'AISConsent': + obj_ = AISConsentType.factory() + obj_.build(child_) + self.set_AISConsent(obj_) + elif nodeName_ == 'TLPMarking': + obj_ = TLPMarkingType.factory() + obj_.build(child_) + self.set_TLPMarking(obj_) +# end class IsProprietary + + +class NotProprietary(GeneratedsSuper): + subclass = None + superclass = None + + def __init__(self, CISA_Proprietary=None, AISConsent=None, TLPMarking=None): + self.CISA_Proprietary = _cast(bool, CISA_Proprietary) + self.AISConsent = AISConsent + self.TLPMarking = TLPMarking + + def factory(*args_, **kwargs_): + if NotProprietary.subclass: + return NotProprietary.subclass(*args_, **kwargs_) + else: + return NotProprietary(*args_, **kwargs_) + factory = staticmethod(factory) + + def get_AISConsent(self): + return self.AISConsent + + def set_AISConsent(self, AISConsent): + self.AISConsent = AISConsent + + def get_TLPMarking(self): + return self.TLPMarking + + def set_TLPMarking(self, TLPMarking): + self.TLPMarking = TLPMarking + + def get_CISA_Proprietary(self): + return self.CISA_Proprietary + + def set_CISA_Proprietary(self, CISA_Proprietary): + self.CISA_Proprietary = CISA_Proprietary + + def hasContent_(self): + if ( + self.AISConsent is not None or + self.TLPMarking is not None + ): + return True + else: + return False + + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='NotProprietary', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='NotProprietary') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + showIndent(lwrite, level, pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + + def exportAttributes(self, lwrite, level, already_processed, namespace_=XML_NS, name_='NotProprietary'): + if self.CISA_Proprietary is not None and 'CISA_Proprietary' not in already_processed: + already_processed.add('CISA_Proprietary') + lwrite(' CISA_Proprietary="%s"' % self.gds_format_boolean(self.CISA_Proprietary, input_name='CISA_Proprietary')) + + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='NotProprietary', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.AISConsent is not None: + self.AISConsent.export(lwrite, level, nsmap, namespace_, name_='AISConsent', pretty_print=pretty_print) + if self.TLPMarking is not None: + self.TLPMarking.export(lwrite, level, nsmap, namespace_, name_='TLPMarking', pretty_print=pretty_print) + + def build(self, node): + self.__sourcenode__ = node + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + + def buildAttributes(self, node, attrs, already_processed): + value = find_attr_value_('CISA_Proprietary', node) + if value is not None and 'CISA_Proprietary' not in already_processed: + already_processed.add('CISA_Proprietary') + if value in ('true', '1'): + self.CISA_Proprietary = True + elif value in ('false', '0'): + self.CISA_Proprietary = False + else: + raise_parse_error(node, 'Bad boolean attribute') + + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'AISConsent': + obj_ = AISConsentType.factory() + obj_.build(child_) + self.set_AISConsent(obj_) + elif nodeName_ == 'TLPMarking': + obj_ = TLPMarkingType.factory() + obj_.build(child_) + self.set_TLPMarking(obj_) +# end class NotProprietary + + +class AISConsentType(GeneratedsSuper): + subclass = None + superclass = None + + def __init__(self, consent=None): + self.consent = _cast(None, consent) + pass + + def factory(*args_, **kwargs_): + if AISConsentType.subclass: + return AISConsentType.subclass(*args_, **kwargs_) + else: + return AISConsentType(*args_, **kwargs_) + factory = staticmethod(factory) + + def get_consent(self): + return self.consent + + def set_consent(self, consent): + self.consent = consent + + def hasContent_(self): + if ( + + ): + return True + else: + return False + + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='AISConsentType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='AISConsentType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + + def exportAttributes(self, lwrite, level, already_processed, namespace_=XML_NS, name_='AISConsentType'): + if self.consent is not None and 'consent' not in already_processed: + already_processed.add('consent') + lwrite(' consent=%s' % (quote_attrib(self.consent), )) + + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='AISConsentType', fromsubclass_=False, pretty_print=True): + pass + + def build(self, node): + self.__sourcenode__ = node + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + + def buildAttributes(self, node, attrs, already_processed): + value = find_attr_value_('consent', node) + if value is not None and 'consent' not in already_processed: + already_processed.add('consent') + self.consent = value + + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + pass +# end class AISConsentType + + +class TLPMarkingType(GeneratedsSuper): + subclass = None + superclass = None + + def __init__(self, color=None): + self.color = _cast(None, color) + pass + + def factory(*args_, **kwargs_): + if TLPMarkingType.subclass: + return TLPMarkingType.subclass(*args_, **kwargs_) + else: + return TLPMarkingType(*args_, **kwargs_) + factory = staticmethod(factory) + + def get_color(self): + return self.color + + def set_color(self, color): + self.color = color + + def hasContent_(self): + if ( + + ): + return True + else: + return False + + def export(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TLPMarkingType', namespacedef_='', pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + showIndent(lwrite, level, pretty_print) + lwrite('<%s:%s%s' % (nsmap[namespace_], name_, namespacedef_ and ' ' + namespacedef_ or '', )) + already_processed = set() + self.exportAttributes(lwrite, level, already_processed, namespace_, name_='TLPMarkingType') + if self.hasContent_(): + lwrite('>%s' % (eol_, )) + self.exportChildren(lwrite, level + 1, nsmap, XML_NS, name_, pretty_print=pretty_print) + lwrite('%s' % (nsmap[namespace_], name_, eol_)) + else: + lwrite('/>%s' % (eol_, )) + + def exportAttributes(self, lwrite, level, already_processed, namespace_=XML_NS, name_='TLPMarkingType'): + if self.color is not None and 'color' not in already_processed: + already_processed.add('color') + lwrite(' color=%s' % (quote_attrib(self.color), )) + + def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='TLPMarkingType', fromsubclass_=False, pretty_print=True): + pass + + def build(self, node): + self.__sourcenode__ = node + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + + def buildAttributes(self, node, attrs, already_processed): + value = find_attr_value_('color', node) + if value is not None and 'color' not in already_processed: + already_processed.add('color') + self.color = value + + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + pass +# end class TLPMarkingType + +GDSClassesMapping = {} + +USAGE_TEXT = """ +Usage: python .py [ -s ] +""" + + +def usage(): + print(USAGE_TEXT) + sys.exit(1) + + +def get_root_tag(node): + tag = Tag_pattern_.match(node.tag).groups()[-1] + rootClass = GDSClassesMapping.get(tag) + if rootClass is None: + rootClass = globals().get(tag) + return tag, rootClass + + +def parse(inFileName): + doc = parsexml_(inFileName) + rootNode = doc.getroot() + rootTag, rootClass = get_root_tag(rootNode) + if rootClass is None: + rootTag = 'AISMarkingStructure' + rootClass = AISMarkingStructure + rootObj = rootClass.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + # sys.stdout.write('\n') + # rootObj.export(sys.stdout, 0, name_=rootTag, + # namespacedef_='', + # pretty_print=True) + return rootObj + + +def parseEtree(inFileName): + doc = parsexml_(inFileName) + rootNode = doc.getroot() + rootTag, rootClass = get_root_tag(rootNode) + if rootClass is None: + rootTag = 'AISMarkingStructure' + rootClass = AISMarkingStructure + rootObj = rootClass.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + rootElement = rootObj.to_etree(None, name_=rootTag) + content = etree_.tostring(rootElement, pretty_print=True, + xml_declaration=True, encoding="utf-8") + sys.stdout.write(content) + sys.stdout.write('\n') + return rootObj, rootElement + + +def parseString(inString): + from mixbox.vendor.six import StringIO + doc = parsexml_(StringIO(inString)) + rootNode = doc.getroot() + rootTag, rootClass = get_root_tag(rootNode) + if rootClass is None: + rootTag = 'AISMarkingStructure' + rootClass = AISMarkingStructure + rootObj = rootClass.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + # sys.stdout.write('\n') + # rootObj.export(sys.stdout, 0, name_="AISHandling", + # namespacedef_='') + return rootObj + + +def main(): + args = sys.argv[1:] + if len(args) == 1: + parse(args[0]) + else: + usage() + +if __name__ == '__main__': + #import pdb; pdb.set_trace() + main() + +__all__ = [ + "NotProprietary", + "IsProprietary" + "AISConsentType", + "AISMarkingStructure" + "TLPMarkingType" + ] diff --git a/stix/extensions/marking/ais.py b/stix/extensions/marking/ais.py new file mode 100644 index 00000000..bd2b76cf --- /dev/null +++ b/stix/extensions/marking/ais.py @@ -0,0 +1,297 @@ +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +from mixbox import fields +from mixbox.namespaces import Namespace + +import stix.bindings.extensions.marking.ais as ais_binding +import stix.data_marking +from stix.data_marking import MarkingStructure + + +def validate_value(instance, value): + allowed = instance._ALLOWED_VALUES + if not value: + return + elif not allowed: + return + elif value in allowed: + return + else: + error = "Value must be one of {allowed}. Received '{value}'" + error = error.format(**locals()) + raise ValueError(error) + + +class AISConsentType(stix.Entity): + _binding = ais_binding + _binding_class = _binding.AISConsentType + _namespace = 'http://www.us-cert.gov/STIXMarkingStructure#AISConsentMarking-2' + _ALLOWED_VALUES = ('EVERYONE', 'USG', 'NONE') + + consent = fields.TypedField("consent", preset_hook=validate_value) + + def __init__(self, consent=None): + super(AISConsentType, self).__init__() + self.consent = consent + + +class TLPMarkingType(stix.Entity): + _binding = ais_binding + _binding_class = _binding.TLPMarkingType + _namespace = 'http://www.us-cert.gov/STIXMarkingStructure#AISConsentMarking-2' + _ALLOWED_VALUES = ('WHITE', 'GREEN', 'AMBER') + + color = fields.TypedField("color", preset_hook=validate_value) + + def __init__(self, color=None): + super(TLPMarkingType, self).__init__() + self.color = color + + +class NotProprietary(stix.Entity): + _binding = ais_binding + _binding_class = _binding.NotProprietary + _namespace = 'http://www.us-cert.gov/STIXMarkingStructure#AISConsentMarking-2' + + cisa_proprietary = fields.TypedField("CISA_Proprietary") + ais_consent = fields.TypedField("AISConsent", AISConsentType, key_name="ais_consent") + tlp_marking = fields.TypedField("TLPMarking", TLPMarkingType, key_name="tlp_marking") + + def __init__(self, cisa_proprietary='false', ais_consent=None, + tlp_marking=None): + super(NotProprietary, self).__init__() + + self.cisa_proprietary = cisa_proprietary + self.ais_consent = ais_consent + self.tlp_marking = tlp_marking + + +class IsProprietary(stix.Entity): + _binding = ais_binding + _binding_class = _binding.IsProprietary + _namespace = 'http://www.us-cert.gov/STIXMarkingStructure#AISConsentMarking-2' + + cisa_proprietary = fields.TypedField("CISA_Proprietary") + ais_consent = fields.TypedField("AISConsent", AISConsentType, key_name="ais_consent") + tlp_marking = fields.TypedField("TLPMarking", TLPMarkingType, key_name="tlp_marking") + + def __init__(self, cisa_proprietary='true', ais_consent=None, + tlp_marking=None): + super(IsProprietary, self).__init__() + + self.cisa_proprietary = cisa_proprietary + self.ais_consent = ais_consent + self.tlp_marking = tlp_marking + + +@stix.register_extension +class AISMarkingStructure(MarkingStructure): + _binding = ais_binding + _binding_class = _binding.AISMarkingStructure + _namespace = 'http://www.us-cert.gov/STIXMarkingStructure#AISConsentMarking-2' + _XSI_TYPE = "AIS:AISMarkingStructure" + + is_proprietary = fields.TypedField("Is_Proprietary", IsProprietary) + not_proprietary = fields.TypedField("Not_Proprietary", NotProprietary) + + def __init__(self, is_proprietary=None, not_proprietary=None): + super(AISMarkingStructure, self).__init__() + + self.is_proprietary = is_proprietary + self.not_proprietary = not_proprietary + + +NAMESPACES = [ + Namespace('http://www.us-cert.gov/STIXMarkingStructure#AISConsentMarking-2', 'AIS', 'http://www.us-cert.gov/sites/default/files/STIX_Namespace/AIS_Bundle_Marking_1.1.1_v1.0.xsd') +] + + +def _update_namespaces(): + # Update the python-stix namespace dictionary + from stix.utils import nsparser + import mixbox.namespaces + + nsparser.STIX_NAMESPACES.add_namespace(NAMESPACES[0]) + mixbox.namespaces.register_namespace(NAMESPACES[0]) + + +_update_namespaces() + + +# IndustryType allowed sectors +CHEMICAL_SECTOR = 'Chemical Sector' +COMMERCIAL_FACILITIES_SECTOR = 'Commercial Facilities Sector' +COMMUNICATIONS_SECTOR = 'Communications Sector' +CRITICAL_MANUFACTURING_SECTOR = 'Critical Manufacturing Sector' +DAMS_SECTOR = 'Dams Sector' +DEFENSE_INDUSTRIAL_BASE_SECTOR = 'Defense Industrial Base Sector' +EMERGENCY_SERVICES_SECTOR = 'Emergency Services Sector' +ENERGY_SECTOR = 'Energy Sector' +FINANCIAL_SERVICES_SECTOR = 'Financial Services Sector' +FOOD_AND_AGRICULTURE_SECTOR = 'Food and Agriculture Sector' +GOVERNMENT_FACILITIES_SECTOR = 'Government Facilities Sector' +HEALTH_CARE_AND_PUBLIC_HEALTH_SECTOR = 'Healthcare and Public Health Sector' +INFORMATION_TECHNOLOGY_SECTOR = 'Information Technology Sector' +NUCLEAR_REACTORS_MATERIALS_AND_WASTE_SECTOR = 'Nuclear Reactors, Materials, and Waste Sector' +OTHER = 'Other' +TRANSPORTATION_SYSTEMS_SECTOR = 'Transportation Systems Sector' +WATER_AND_WASTEWATER_SYSTEMS_SECTOR = 'Water and Wastewater Systems Sector' + + +def _validate_and_create_industry_type(industry_type): + INDUSTRY_SECTORS = (CHEMICAL_SECTOR, COMMERCIAL_FACILITIES_SECTOR, + COMMUNICATIONS_SECTOR, CRITICAL_MANUFACTURING_SECTOR, + DAMS_SECTOR, DEFENSE_INDUSTRIAL_BASE_SECTOR, + EMERGENCY_SERVICES_SECTOR, ENERGY_SECTOR, + FINANCIAL_SERVICES_SECTOR, FOOD_AND_AGRICULTURE_SECTOR, + GOVERNMENT_FACILITIES_SECTOR, + HEALTH_CARE_AND_PUBLIC_HEALTH_SECTOR, + INFORMATION_TECHNOLOGY_SECTOR, + NUCLEAR_REACTORS_MATERIALS_AND_WASTE_SECTOR, + TRANSPORTATION_SYSTEMS_SECTOR, OTHER, + WATER_AND_WASTEWATER_SYSTEMS_SECTOR) + + lower_case_sectors = tuple(x.lower() for x in INDUSTRY_SECTORS) + result = "" + error = False + val = [] + + if isinstance(industry_type, str): + # Pipe-delimited or single string supplied. + val = [x.lower().strip() for x in industry_type.split("|")] + + elif isinstance(industry_type, (list, tuple)): + # Create pipe-delimited string when list of strings is provided. + val = [x.lower().strip() for x in industry_type] + + else: + error = True + + for item in val: + for idx, sector in enumerate(lower_case_sectors): + if item == sector: + if not result: + result = INDUSTRY_SECTORS[idx] + else: + result = "{0}|{1}".format(result, INDUSTRY_SECTORS[idx]) + break + else: + # The sectors collection was exhausted. No match found. + error = True + break + + if not error and val: + return result + + msg = 'IndustryType must be one of the following: {0}. Received \'{1}\'.' + raise ValueError(msg.format(INDUSTRY_SECTORS, industry_type)) + + +def add_ais_marking(stix_package, proprietary, consent, color, **kwargs): + """ + This utility functions aids in the creation of an AIS marking and appends + it to the provided STIX package. + Args: + stix_package: A stix.core.STIXPackage object. + proprietary: True if marking uses IsProprietary, False for + NotProprietary. + consent: A string with one of the following values: "EVERYONE", "NONE" + or "USG". + color: A string that corresponds to TLP values: "WHITE", "GREEN" or + "AMBER". + **kwargs: Six required keyword arguments that are used to create a CIQ + identity object. These are: country_name_code, + country_name_code_type, admin_area_name_code, + admin_area_name_code_type, organisation_name, industry_type. + Raises: + ValueError: When keyword arguments are missing. User did not supply + correct values for: proprietary, color and consent. + Note: + The following line is required to register the AIS extension: + >>> import stix.extensions.marking.ais + Any Markings under STIX Header will be removed. Please follow the + guidelines for `AIS`_. + The industry_type keyword argument accepts: a list of string based on + defined sectors, a pipe-delimited string of sectors, or a single + sector. + .. _AIS: + https://www.us-cert.gov/ais + """ + from stix.common import InformationSource + from stix.extensions.identity.ciq_identity_3_0 import ( + CIQIdentity3_0Instance, STIXCIQIdentity3_0, PartyName, Address, + Country, NameElement, OrganisationInfo, AdministrativeArea) + from stix.core.stix_header import STIXHeader + from stix.data_marking import MarkingSpecification, Marking + + args = ('country_name_code', 'country_name_code_type', 'industry_type', + 'admin_area_name_code', 'admin_area_name_code_type', + 'organisation_name') + + diff = set(args) - set(kwargs.keys()) + + if diff: + msg = 'All keyword arguments must be provided. Missing: {0}' + raise ValueError(msg.format(tuple(diff))) + + party_name = PartyName() + party_name.add_organisation_name(kwargs['organisation_name']) + + country = Country() + country_name = NameElement() + country_name.name_code = kwargs['country_name_code'] + country_name.name_code_type = kwargs['country_name_code_type'] + country.add_name_element(country_name) + + admin_area = AdministrativeArea() + admin_area_name = NameElement() + admin_area_name.name_code = kwargs['admin_area_name_code'] + admin_area_name.name_code_type = kwargs['admin_area_name_code_type'] + admin_area.add_name_element(admin_area_name) + + address = Address() + address.country = country + address.administrative_area = admin_area + + org_info = OrganisationInfo() + org_info.industry_type = _validate_and_create_industry_type(kwargs['industry_type']) + + id_spec = STIXCIQIdentity3_0() + id_spec.party_name = party_name + id_spec.add_address(address) + id_spec.organisation_info = org_info + + identity = CIQIdentity3_0Instance() + identity.specification = id_spec + + if proprietary is True: + proprietary_obj = IsProprietary() + consent = 'EVERYONE' + elif proprietary is False: + proprietary_obj = NotProprietary() + else: + raise ValueError('proprietary expected True or False.') + + proprietary_obj.ais_consent = AISConsentType(consent=consent) + proprietary_obj.tlp_marking = TLPMarkingType(color=color) + + ais_marking = AISMarkingStructure() + + if isinstance(proprietary_obj, IsProprietary): + ais_marking.is_proprietary = proprietary_obj + else: + ais_marking.not_proprietary = proprietary_obj + + marking_spec = MarkingSpecification() + marking_spec.controlled_structure = '//node() | //@*' + marking_spec.marking_structures.append(ais_marking) + marking_spec.information_source = InformationSource() + marking_spec.information_source.identity = identity + + if not stix_package.stix_header: + stix_package.stix_header = STIXHeader() + + # Removes any other Markings if present. + stix_package.stix_header.handling = Marking() + stix_package.stix_header.handling.add_marking(marking_spec) diff --git a/stix/test/extensions/marking/ais.py b/stix/test/extensions/marking/ais.py new file mode 100644 index 00000000..7f7a8327 --- /dev/null +++ b/stix/test/extensions/marking/ais.py @@ -0,0 +1,92 @@ +# Copyright (c) 2016, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +import unittest + +from stix.test import EntityTestCase + +from stix.core import STIXPackage +from stix.extensions.marking import ais + + +class AISMarkingStructureNotProprietaryTests(EntityTestCase, unittest.TestCase): + klass = ais.AISMarkingStructure + _full_dict = { + 'not_proprietary': + { + 'cisa_proprietary': 'false', + 'ais_consent': {'consent': 'NONE'}, + 'tlp_marking': {'color': 'GREEN'} + }, + 'xsi:type': 'AIS:AISMarkingStructure' + } + + +class AISMarkingStructureIsProprietaryTests(EntityTestCase, unittest.TestCase): + klass = ais.AISMarkingStructure + _full_dict = { + 'is_proprietary': + { + 'cisa_proprietary': 'true', + 'ais_consent': {'consent': 'EVERYONE'}, + 'tlp_marking': {'color': 'AMBER'} + }, + 'xsi:type': 'AIS:AISMarkingStructure' + } + + +class AISMarkingGeneralTests(unittest.TestCase): + """General tests for ais module helpers.""" + + @classmethod + def setUpClass(cls): + cls.INDUSTRY_SECTORS = (ais.CHEMICAL_SECTOR, ais.COMMERCIAL_FACILITIES_SECTOR, + ais.COMMUNICATIONS_SECTOR, + ais.CRITICAL_MANUFACTURING_SECTOR, + ais.DAMS_SECTOR, ais.DEFENSE_INDUSTRIAL_BASE_SECTOR, + ais.EMERGENCY_SERVICES_SECTOR, ais.ENERGY_SECTOR, + ais.FINANCIAL_SERVICES_SECTOR, + ais.FOOD_AND_AGRICULTURE_SECTOR, + ais.GOVERNMENT_FACILITIES_SECTOR, + ais.HEALTH_CARE_AND_PUBLIC_HEALTH_SECTOR, + ais.INFORMATION_TECHNOLOGY_SECTOR, + ais.NUCLEAR_REACTORS_MATERIALS_AND_WASTE_SECTOR, + ais.TRANSPORTATION_SYSTEMS_SECTOR, ais.OTHER, + ais.WATER_AND_WASTEWATER_SYSTEMS_SECTOR) + + def test_validate_and_create_industry_type(self): + self.assertRaises(ValueError, ais._validate_and_create_industry_type, []) + self.assertRaises(ValueError, ais._validate_and_create_industry_type, "") + self.assertRaises(ValueError, ais._validate_and_create_industry_type, [""]) + self.assertRaises(ValueError, ais._validate_and_create_industry_type, ["Energy Sector", "Others", "Dams Sector"]) + self.assertRaises(ValueError, ais._validate_and_create_industry_type, "Energy Sector| Others|Dams Sector") + self.assertRaises(ValueError, ais._validate_and_create_industry_type, 3) + self.assertRaises(ValueError, ais._validate_and_create_industry_type, "|") + self.assertRaises(ValueError, ais._validate_and_create_industry_type, ["Energy Sector|Dams Sector"]) + + self.assertEqual(ais._validate_and_create_industry_type("eNergY sectOr"), ais.ENERGY_SECTOR) + self.assertEqual(ais._validate_and_create_industry_type("eNergY sectOr |Dams sector"), "Energy Sector|Dams Sector") + self.assertEqual(ais._validate_and_create_industry_type(["eNergY sectOr ", " Dams sectOr "]), "Energy Sector|Dams Sector") + self.assertEqual(ais._validate_and_create_industry_type([ais.ENERGY_SECTOR, ais.DAMS_SECTOR]), "Energy Sector|Dams Sector") + self.assertEqual(ais._validate_and_create_industry_type("Energy Sector|Dams Sector"), "Energy Sector|Dams Sector") + + for idx, x in enumerate(self.INDUSTRY_SECTORS): + self.assertEqual(ais._validate_and_create_industry_type(x), self.INDUSTRY_SECTORS[idx]) + + def test_add_ais_marking(self): + PACKAGE = STIXPackage() + + # Missing kwarg. + self.assertRaises(ValueError, ais.add_ais_marking, PACKAGE, True, 'NONE', 'GREEN', + country_name_code='US', + country_name_code_type='ISO 3166-1 alpha-2', + admin_area_name_code='US-DC', + admin_area_name_code_type='ISO 3166-2', + organisation_name='NCCIC') + + def test_bad_values_raises_error(self): + self.assertRaises(ValueError, ais.TLPMarkingType, "ORANGE") + self.assertRaises(ValueError, ais.AISConsentType, "WHAT?") + +if __name__ == "__main__": + unittest.main() From 9331004fe2101507d27970d500de6c1a0b6c8d52 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Mon, 20 Mar 2017 21:54:28 -0400 Subject: [PATCH 364/438] Update copyright date to 2017. --- LICENSE.txt | 2 +- docs/conf.py | 2 +- examples/campaign-reference.py | 2 +- examples/ciq_identity.py | 2 +- examples/creation_tool_metadata.py | 2 +- examples/custom_vocabstring.py | 2 +- examples/indicator-hash.py | 2 +- examples/indicator-simplehash.py | 2 +- examples/sample.xml | 2 +- examples/vocabstrings.py | 2 +- examples/vuln_affected_software.py | 2 +- examples/xml2object.py | 2 +- setup.py | 4 ++-- stix/__init__.py | 2 +- stix/base.py | 2 +- stix/bindings/__init__.py | 2 +- stix/bindings/campaign.py | 2 +- stix/bindings/course_of_action.py | 2 +- stix/bindings/data_marking.py | 2 +- stix/bindings/exploit_target.py | 2 +- stix/bindings/extensions/__init__.py | 2 +- stix/bindings/extensions/address/__init__.py | 2 +- stix/bindings/extensions/address/ciq_address_3_0.py | 2 +- stix/bindings/extensions/attack_pattern/__init__.py | 2 +- stix/bindings/extensions/attack_pattern/capec_2_7.py | 2 +- stix/bindings/extensions/identity/__init__.py | 2 +- stix/bindings/extensions/identity/ciq_identity_3_0.py | 2 +- stix/bindings/extensions/malware/__init__.py | 2 +- stix/bindings/extensions/malware/maec_4_1.py | 2 +- stix/bindings/extensions/marking/__init__.py | 2 +- stix/bindings/extensions/marking/simple_marking.py | 2 +- stix/bindings/extensions/marking/terms_of_use_marking.py | 2 +- stix/bindings/extensions/marking/tlp.py | 2 +- stix/bindings/extensions/structured_coa/__init__.py | 2 +- stix/bindings/extensions/structured_coa/generic.py | 2 +- stix/bindings/extensions/test_mechanism/__init__.py | 2 +- stix/bindings/extensions/test_mechanism/generic.py | 2 +- stix/bindings/extensions/test_mechanism/open_ioc_2010.py | 2 +- stix/bindings/extensions/test_mechanism/oval_5_10.py | 2 +- stix/bindings/extensions/test_mechanism/snort.py | 2 +- stix/bindings/extensions/test_mechanism/yara.py | 2 +- stix/bindings/extensions/vulnerability/__init__.py | 2 +- stix/bindings/extensions/vulnerability/cvrf_1_1.py | 2 +- stix/bindings/incident.py | 2 +- stix/bindings/indicator.py | 2 +- stix/bindings/report.py | 2 +- stix/bindings/stix_common.py | 2 +- stix/bindings/stix_core.py | 2 +- stix/bindings/threat_actor.py | 2 +- stix/bindings/ttp.py | 2 +- stix/campaign/__init__.py | 2 +- stix/coa/__init__.py | 2 +- stix/coa/objective.py | 2 +- stix/coa/structured_coa.py | 2 +- stix/common/__init__.py | 2 +- stix/common/activity.py | 2 +- stix/common/campaign_reference.py | 2 +- stix/common/confidence.py | 2 +- stix/common/datetimewithprecision.py | 2 +- stix/common/identity.py | 2 +- stix/common/information_source.py | 2 +- stix/common/kill_chains/__init__.py | 2 +- stix/common/kill_chains/lmco.py | 2 +- stix/common/names.py | 2 +- stix/common/profiles.py | 2 +- stix/common/references.py | 2 +- stix/common/related.py | 2 +- stix/common/statement.py | 2 +- stix/common/structured_text.py | 2 +- stix/common/tools.py | 2 +- stix/common/vocabs.py | 2 +- stix/core/__init__.py | 2 +- stix/core/stix_header.py | 2 +- stix/core/stix_package.py | 2 +- stix/core/ttps.py | 2 +- stix/data_marking.py | 2 +- stix/exploit_target/__init__.py | 2 +- stix/exploit_target/configuration.py | 2 +- stix/exploit_target/vulnerability.py | 2 +- stix/exploit_target/weakness.py | 2 +- stix/extensions/__init__.py | 2 +- stix/extensions/identity/__init__.py | 2 +- stix/extensions/malware/__init__.py | 2 +- stix/extensions/malware/maec_4_1_malware.py | 2 +- stix/extensions/marking/__init__.py | 2 +- stix/extensions/marking/simple_marking.py | 2 +- stix/extensions/marking/terms_of_use_marking.py | 2 +- stix/extensions/marking/tlp.py | 2 +- stix/extensions/structured_coa/__init__.py | 2 +- stix/extensions/structured_coa/generic_structured_coa.py | 2 +- stix/extensions/test_mechanism/__init__.py | 2 +- stix/extensions/test_mechanism/generic_test_mechanism.py | 2 +- .../extensions/test_mechanism/open_ioc_2010_test_mechanism.py | 2 +- stix/extensions/test_mechanism/snort_test_mechanism.py | 2 +- stix/extensions/test_mechanism/yara_test_mechanism.py | 2 +- stix/incident/__init__.py | 2 +- stix/incident/affected_asset.py | 2 +- stix/incident/coa.py | 2 +- stix/incident/contributors.py | 2 +- stix/incident/direct_impact_summary.py | 2 +- stix/incident/external_id.py | 2 +- stix/incident/history.py | 2 +- stix/incident/impact_assessment.py | 2 +- stix/incident/indirect_impact_summary.py | 2 +- stix/incident/loss_estimation.py | 2 +- stix/incident/property_affected.py | 2 +- stix/incident/time.py | 2 +- stix/incident/total_loss_estimation.py | 2 +- stix/indicator/__init__.py | 2 +- stix/indicator/indicator.py | 2 +- stix/indicator/sightings.py | 2 +- stix/indicator/test_mechanism.py | 2 +- stix/indicator/valid_time.py | 2 +- stix/report/__init__.py | 2 +- stix/report/header.py | 2 +- stix/test/__init__.py | 2 +- stix/test/campaign_test.py | 2 +- stix/test/coa_test.py | 2 +- stix/test/common/__init__.py | 2 +- stix/test/common/activity_test.py | 2 +- stix/test/common/campaign_reference_test.py | 2 +- stix/test/common/cdata_test.py | 2 +- stix/test/common/confidence_test.py | 2 +- stix/test/common/datetimewithprecision_test.py | 2 +- stix/test/common/identity_test.py | 2 +- stix/test/common/information_source_test.py | 2 +- stix/test/common/kill_chains_test.py | 2 +- stix/test/common/names_test.py | 2 +- stix/test/common/related_test.py | 2 +- stix/test/common/statement_test.py | 2 +- stix/test/common/structured_text_tests.py | 2 +- stix/test/common/tools_tests.py | 2 +- stix/test/core/__init__.py | 2 +- stix/test/core/stix_header_test.py | 2 +- stix/test/core/stix_package_test.py | 2 +- stix/test/data_marking_test.py | 2 +- stix/test/encoding_test.py | 2 +- stix/test/exploit_target_test.py | 2 +- stix/test/extensions/identity/__init__.py | 2 +- stix/test/extensions/identity/ciq_identity_3_0_test.py | 2 +- stix/test/extensions/marking/terms_of_use_marking_test.py | 2 +- stix/test/extensions/structured_coa/__init__.py | 2 +- stix/test/extensions/structured_coa/generic_test.py | 2 +- stix/test/extensions/test_mechanisms/__init__.py | 2 +- stix/test/extensions/test_mechanisms/generic_test.py | 2 +- stix/test/extensions/test_mechanisms/openioc_test.py | 2 +- stix/test/extensions/test_mechanisms/snort_test.py | 2 +- stix/test/extensions/test_mechanisms/yara_test.py | 2 +- stix/test/incident_test.py | 2 +- stix/test/indicator_test.py | 2 +- stix/test/report_test.py | 2 +- stix/test/threat_actor_test.py | 2 +- stix/test/ttp_test.py | 2 +- stix/test/utils/__init__.py | 2 +- stix/test/utils/nsparser_test.py | 2 +- stix/test/utils/parser_test.py | 2 +- stix/test/utils/utils_test.py | 2 +- stix/threat_actor/__init__.py | 2 +- stix/ttp/__init__.py | 2 +- stix/ttp/attack_pattern.py | 2 +- stix/ttp/behavior.py | 2 +- stix/ttp/exploit.py | 2 +- stix/ttp/exploit_targets.py | 2 +- stix/ttp/infrastructure.py | 2 +- stix/ttp/malware_instance.py | 2 +- stix/ttp/related_ttps.py | 2 +- stix/ttp/resource.py | 2 +- stix/ttp/victim_targeting.py | 2 +- stix/utils/__init__.py | 2 +- stix/utils/dates.py | 2 +- stix/utils/deprecated.py | 2 +- stix/utils/nsparser.py | 2 +- stix/utils/parser.py | 2 +- stix/utils/walk.py | 2 +- stix/version.py | 2 +- stix/xmlconst.py | 2 +- 176 files changed, 177 insertions(+), 177 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index fdf626e1..d98dd6be 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2015, The MITRE Corporation +Copyright (c) 2017, The MITRE Corporation All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/docs/conf.py b/docs/conf.py index c4c7dc0b..97422a1f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -3,7 +3,7 @@ import stix project = u'python-stix' -copyright = u'2015, The MITRE Corporation' +copyright = u'2017, The MITRE Corporation' version = stix.__version__ release = version diff --git a/examples/campaign-reference.py b/examples/campaign-reference.py index 08403495..3fa3f4d6 100644 --- a/examples/campaign-reference.py +++ b/examples/campaign-reference.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. """ diff --git a/examples/ciq_identity.py b/examples/ciq_identity.py index 28659ce4..ae0166d5 100644 --- a/examples/ciq_identity.py +++ b/examples/ciq_identity.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. """ diff --git a/examples/creation_tool_metadata.py b/examples/creation_tool_metadata.py index f79e4610..d03510d3 100644 --- a/examples/creation_tool_metadata.py +++ b/examples/creation_tool_metadata.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. """ Description: Build a STIX Document with Tool Information diff --git a/examples/custom_vocabstring.py b/examples/custom_vocabstring.py index a0b06260..14ad4d90 100644 --- a/examples/custom_vocabstring.py +++ b/examples/custom_vocabstring.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. """ Description: Demonstrate the use and parsing of custom VocabString controlled diff --git a/examples/indicator-hash.py b/examples/indicator-hash.py index 75bfeb26..7503df79 100644 --- a/examples/indicator-hash.py +++ b/examples/indicator-hash.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. """ diff --git a/examples/indicator-simplehash.py b/examples/indicator-simplehash.py index 54f95bd7..bcc27e50 100644 --- a/examples/indicator-simplehash.py +++ b/examples/indicator-simplehash.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. """ Description: Build a STIX File Hash Observables document. Note that this diff --git a/examples/sample.xml b/examples/sample.xml index 2e2cb25e..109d3813 100644 --- a/examples/sample.xml +++ b/examples/sample.xml @@ -1,7 +1,7 @@ diff --git a/examples/vocabstrings.py b/examples/vocabstrings.py index e9f73051..6fd5f7f6 100644 --- a/examples/vocabstrings.py +++ b/examples/vocabstrings.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. """ diff --git a/examples/vuln_affected_software.py b/examples/vuln_affected_software.py index 0fb90ad6..3f1d5532 100644 --- a/examples/vuln_affected_software.py +++ b/examples/vuln_affected_software.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. """ diff --git a/examples/xml2object.py b/examples/xml2object.py index 6f0ddabe..80989a03 100644 --- a/examples/xml2object.py +++ b/examples/xml2object.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. """ diff --git a/setup.py b/setup.py index 7dbf4f30..fe95d5c2 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -# Copyright (c) 2015 - The MITRE Corporation -# For license information, see the LICENSE.txt file +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. from os.path import abspath, dirname, join diff --git a/stix/__init__.py b/stix/__init__.py index 786f95e4..4bcc0568 100644 --- a/stix/__init__.py +++ b/stix/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # Make sure base gets imported before common. diff --git a/stix/base.py b/stix/base.py index aab5f5ba..14f50a6d 100644 --- a/stix/base.py +++ b/stix/base.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # stdlib diff --git a/stix/bindings/__init__.py b/stix/bindings/__init__.py index 3376c9b5..cb123e71 100644 --- a/stix/bindings/__init__.py +++ b/stix/bindings/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import collections diff --git a/stix/bindings/campaign.py b/stix/bindings/campaign.py index c10cadd3..0a29313c 100644 --- a/stix/bindings/campaign.py +++ b/stix/bindings/campaign.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/course_of_action.py b/stix/bindings/course_of_action.py index 9c3ab8d6..52ee6019 100644 --- a/stix/bindings/course_of_action.py +++ b/stix/bindings/course_of_action.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/data_marking.py b/stix/bindings/data_marking.py index 94ddd6d7..9bafcba3 100644 --- a/stix/bindings/data_marking.py +++ b/stix/bindings/data_marking.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/exploit_target.py b/stix/bindings/exploit_target.py index 78735ac2..3d9fd981 100644 --- a/stix/bindings/exploit_target.py +++ b/stix/bindings/exploit_target.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/__init__.py b/stix/bindings/extensions/__init__.py index 2e7a26b0..9b8f6780 100644 --- a/stix/bindings/extensions/__init__.py +++ b/stix/bindings/extensions/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/bindings/extensions/address/__init__.py b/stix/bindings/extensions/address/__init__.py index 2e7a26b0..9b8f6780 100644 --- a/stix/bindings/extensions/address/__init__.py +++ b/stix/bindings/extensions/address/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/bindings/extensions/address/ciq_address_3_0.py b/stix/bindings/extensions/address/ciq_address_3_0.py index 2684cf1f..b55cc7fd 100644 --- a/stix/bindings/extensions/address/ciq_address_3_0.py +++ b/stix/bindings/extensions/address/ciq_address_3_0.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/attack_pattern/__init__.py b/stix/bindings/extensions/attack_pattern/__init__.py index 2e7a26b0..9b8f6780 100644 --- a/stix/bindings/extensions/attack_pattern/__init__.py +++ b/stix/bindings/extensions/attack_pattern/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/bindings/extensions/attack_pattern/capec_2_7.py b/stix/bindings/extensions/attack_pattern/capec_2_7.py index 762bd3df..5b1f5e5f 100644 --- a/stix/bindings/extensions/attack_pattern/capec_2_7.py +++ b/stix/bindings/extensions/attack_pattern/capec_2_7.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/identity/__init__.py b/stix/bindings/extensions/identity/__init__.py index 2e7a26b0..9b8f6780 100644 --- a/stix/bindings/extensions/identity/__init__.py +++ b/stix/bindings/extensions/identity/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/bindings/extensions/identity/ciq_identity_3_0.py b/stix/bindings/extensions/identity/ciq_identity_3_0.py index 5fa3610c..4aa03f74 100644 --- a/stix/bindings/extensions/identity/ciq_identity_3_0.py +++ b/stix/bindings/extensions/identity/ciq_identity_3_0.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/malware/__init__.py b/stix/bindings/extensions/malware/__init__.py index 2e7a26b0..9b8f6780 100644 --- a/stix/bindings/extensions/malware/__init__.py +++ b/stix/bindings/extensions/malware/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/bindings/extensions/malware/maec_4_1.py b/stix/bindings/extensions/malware/maec_4_1.py index 696738ff..e32a0ad1 100644 --- a/stix/bindings/extensions/malware/maec_4_1.py +++ b/stix/bindings/extensions/malware/maec_4_1.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/marking/__init__.py b/stix/bindings/extensions/marking/__init__.py index 2e7a26b0..9b8f6780 100644 --- a/stix/bindings/extensions/marking/__init__.py +++ b/stix/bindings/extensions/marking/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/bindings/extensions/marking/simple_marking.py b/stix/bindings/extensions/marking/simple_marking.py index 95a01e8e..58a1eb64 100644 --- a/stix/bindings/extensions/marking/simple_marking.py +++ b/stix/bindings/extensions/marking/simple_marking.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/marking/terms_of_use_marking.py b/stix/bindings/extensions/marking/terms_of_use_marking.py index b564bf53..5cb2dd2d 100644 --- a/stix/bindings/extensions/marking/terms_of_use_marking.py +++ b/stix/bindings/extensions/marking/terms_of_use_marking.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/marking/tlp.py b/stix/bindings/extensions/marking/tlp.py index 0b537183..8f23145d 100644 --- a/stix/bindings/extensions/marking/tlp.py +++ b/stix/bindings/extensions/marking/tlp.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/structured_coa/__init__.py b/stix/bindings/extensions/structured_coa/__init__.py index 2e7a26b0..9b8f6780 100644 --- a/stix/bindings/extensions/structured_coa/__init__.py +++ b/stix/bindings/extensions/structured_coa/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/bindings/extensions/structured_coa/generic.py b/stix/bindings/extensions/structured_coa/generic.py index e3776580..b70c21ca 100644 --- a/stix/bindings/extensions/structured_coa/generic.py +++ b/stix/bindings/extensions/structured_coa/generic.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/test_mechanism/__init__.py b/stix/bindings/extensions/test_mechanism/__init__.py index 2e7a26b0..9b8f6780 100644 --- a/stix/bindings/extensions/test_mechanism/__init__.py +++ b/stix/bindings/extensions/test_mechanism/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/bindings/extensions/test_mechanism/generic.py b/stix/bindings/extensions/test_mechanism/generic.py index 8ae609bc..58ca10b6 100644 --- a/stix/bindings/extensions/test_mechanism/generic.py +++ b/stix/bindings/extensions/test_mechanism/generic.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py index 338fc94a..e542a8e1 100644 --- a/stix/bindings/extensions/test_mechanism/open_ioc_2010.py +++ b/stix/bindings/extensions/test_mechanism/open_ioc_2010.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/test_mechanism/oval_5_10.py b/stix/bindings/extensions/test_mechanism/oval_5_10.py index f4868424..c217323d 100644 --- a/stix/bindings/extensions/test_mechanism/oval_5_10.py +++ b/stix/bindings/extensions/test_mechanism/oval_5_10.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/test_mechanism/snort.py b/stix/bindings/extensions/test_mechanism/snort.py index c1143aa0..9a432c05 100644 --- a/stix/bindings/extensions/test_mechanism/snort.py +++ b/stix/bindings/extensions/test_mechanism/snort.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/test_mechanism/yara.py b/stix/bindings/extensions/test_mechanism/yara.py index ed3efea0..fe099f18 100644 --- a/stix/bindings/extensions/test_mechanism/yara.py +++ b/stix/bindings/extensions/test_mechanism/yara.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/extensions/vulnerability/__init__.py b/stix/bindings/extensions/vulnerability/__init__.py index 2e7a26b0..9b8f6780 100644 --- a/stix/bindings/extensions/vulnerability/__init__.py +++ b/stix/bindings/extensions/vulnerability/__init__.py @@ -1,3 +1,3 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/bindings/extensions/vulnerability/cvrf_1_1.py b/stix/bindings/extensions/vulnerability/cvrf_1_1.py index 7423a00a..52aee50d 100644 --- a/stix/bindings/extensions/vulnerability/cvrf_1_1.py +++ b/stix/bindings/extensions/vulnerability/cvrf_1_1.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/incident.py b/stix/bindings/incident.py index 4ba796f4..75487e4b 100644 --- a/stix/bindings/incident.py +++ b/stix/bindings/incident.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/indicator.py b/stix/bindings/indicator.py index 701ad239..918e6023 100644 --- a/stix/bindings/indicator.py +++ b/stix/bindings/indicator.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/report.py b/stix/bindings/report.py index 7faa0bae..5ebbfef6 100644 --- a/stix/bindings/report.py +++ b/stix/bindings/report.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index c5c9c0b3..64cfac7c 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/stix_core.py b/stix/bindings/stix_core.py index f1ebcaae..9354add5 100644 --- a/stix/bindings/stix_core.py +++ b/stix/bindings/stix_core.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/threat_actor.py b/stix/bindings/threat_actor.py index 352e4eae..2ee9fc5e 100644 --- a/stix/bindings/threat_actor.py +++ b/stix/bindings/threat_actor.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. #!/usr/bin/env python diff --git a/stix/bindings/ttp.py b/stix/bindings/ttp.py index cb454b31..5279063c 100644 --- a/stix/bindings/ttp.py +++ b/stix/bindings/ttp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # diff --git a/stix/campaign/__init__.py b/stix/campaign/__init__.py index 5ef089e9..37fdc397 100644 --- a/stix/campaign/__init__.py +++ b/stix/campaign/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from functools import partial diff --git a/stix/coa/__init__.py b/stix/coa/__init__.py index 9a70f896..f5adaf24 100644 --- a/stix/coa/__init__.py +++ b/stix/coa/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/coa/objective.py b/stix/coa/objective.py index 09c708a6..3725df6a 100644 --- a/stix/coa/objective.py +++ b/stix/coa/objective.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/coa/structured_coa.py b/stix/coa/structured_coa.py index c0aebf57..a929f37e 100644 --- a/stix/coa/structured_coa.py +++ b/stix/coa/structured_coa.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/common/__init__.py b/stix/common/__init__.py index 2854ef2e..d345b961 100644 --- a/stix/common/__init__.py +++ b/stix/common/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from __future__ import absolute_import diff --git a/stix/common/activity.py b/stix/common/activity.py index 7d82741d..bfb4953b 100644 --- a/stix/common/activity.py +++ b/stix/common/activity.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/common/campaign_reference.py b/stix/common/campaign_reference.py index 3a9e7a38..fb56a79f 100644 --- a/stix/common/campaign_reference.py +++ b/stix/common/campaign_reference.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/common/confidence.py b/stix/common/confidence.py index d5c1d946..437033d6 100644 --- a/stix/common/confidence.py +++ b/stix/common/confidence.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from __future__ import absolute_import diff --git a/stix/common/datetimewithprecision.py b/stix/common/datetimewithprecision.py index 5775a099..98fceb34 100644 --- a/stix/common/datetimewithprecision.py +++ b/stix/common/datetimewithprecision.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/common/identity.py b/stix/common/identity.py index 35fea9db..620b7b92 100644 --- a/stix/common/identity.py +++ b/stix/common/identity.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/common/information_source.py b/stix/common/information_source.py index 006ca08b..f7042f27 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/common/kill_chains/__init__.py b/stix/common/kill_chains/__init__.py index 5bfd8c83..681c1c73 100644 --- a/stix/common/kill_chains/__init__.py +++ b/stix/common/kill_chains/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/common/kill_chains/lmco.py b/stix/common/kill_chains/lmco.py index 76430d4f..77625d1a 100644 --- a/stix/common/kill_chains/lmco.py +++ b/stix/common/kill_chains/lmco.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from . import KillChain, KillChainPhase diff --git a/stix/common/names.py b/stix/common/names.py index 47296864..b346fc5b 100644 --- a/stix/common/names.py +++ b/stix/common/names.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/common/profiles.py b/stix/common/profiles.py index 1a4311e2..a4499d01 100644 --- a/stix/common/profiles.py +++ b/stix/common/profiles.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import collections diff --git a/stix/common/references.py b/stix/common/references.py index 2bb4d5be..45bfbb27 100644 --- a/stix/common/references.py +++ b/stix/common/references.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import collections diff --git a/stix/common/related.py b/stix/common/related.py index bb8f1ffe..8c0ab6f6 100644 --- a/stix/common/related.py +++ b/stix/common/related.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # stdlib diff --git a/stix/common/statement.py b/stix/common/statement.py index 241d7b66..688d34dd 100644 --- a/stix/common/statement.py +++ b/stix/common/statement.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from __future__ import absolute_import diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 02ef1491..b90c0396 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import itertools import contextlib diff --git a/stix/common/tools.py b/stix/common/tools.py index 2865098c..6d32d266 100644 --- a/stix/common/tools.py +++ b/stix/common/tools.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index d0ed3bff..2512e947 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # stdlib diff --git a/stix/core/__init__.py b/stix/core/__init__.py index e6d4b9dc..71b28105 100644 --- a/stix/core/__init__.py +++ b/stix/core/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # stdlib diff --git a/stix/core/stix_header.py b/stix/core/stix_header.py index fb4c2917..65b44e8e 100644 --- a/stix/core/stix_header.py +++ b/stix/core/stix_header.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index f25810f1..14e9fbb1 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # mixbox diff --git a/stix/core/ttps.py b/stix/core/ttps.py index 82832e40..d5620509 100644 --- a/stix/core/ttps.py +++ b/stix/core/ttps.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # stdlib diff --git a/stix/data_marking.py b/stix/data_marking.py index 57c61eab..8ea6fcd0 100644 --- a/stix/data_marking.py +++ b/stix/data_marking.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/exploit_target/__init__.py b/stix/exploit_target/__init__.py index 9d27d0b6..394a22ef 100644 --- a/stix/exploit_target/__init__.py +++ b/stix/exploit_target/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # mixbox diff --git a/stix/exploit_target/configuration.py b/stix/exploit_target/configuration.py index 44c0e867..5cd1b459 100644 --- a/stix/exploit_target/configuration.py +++ b/stix/exploit_target/configuration.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import stix diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index 7691716d..78e0974a 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/exploit_target/weakness.py b/stix/exploit_target/weakness.py index db9f4ecc..73ac82d3 100644 --- a/stix/exploit_target/weakness.py +++ b/stix/exploit_target/weakness.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import stix diff --git a/stix/extensions/__init__.py b/stix/extensions/__init__.py index 9a9569c5..8468f459 100644 --- a/stix/extensions/__init__.py +++ b/stix/extensions/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/extensions/identity/__init__.py b/stix/extensions/identity/__init__.py index 9a9569c5..8468f459 100644 --- a/stix/extensions/identity/__init__.py +++ b/stix/extensions/identity/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/extensions/malware/__init__.py b/stix/extensions/malware/__init__.py index 9a9569c5..8468f459 100644 --- a/stix/extensions/malware/__init__.py +++ b/stix/extensions/malware/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index e45dbebf..b1f873c8 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # stdlib diff --git a/stix/extensions/marking/__init__.py b/stix/extensions/marking/__init__.py index 9a9569c5..8468f459 100644 --- a/stix/extensions/marking/__init__.py +++ b/stix/extensions/marking/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/extensions/marking/simple_marking.py b/stix/extensions/marking/simple_marking.py index bcf41193..8c1b83b0 100644 --- a/stix/extensions/marking/simple_marking.py +++ b/stix/extensions/marking/simple_marking.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/extensions/marking/terms_of_use_marking.py b/stix/extensions/marking/terms_of_use_marking.py index 2df6ea1d..222a2a53 100644 --- a/stix/extensions/marking/terms_of_use_marking.py +++ b/stix/extensions/marking/terms_of_use_marking.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/extensions/marking/tlp.py b/stix/extensions/marking/tlp.py index 5b8b732c..7ffd64bc 100644 --- a/stix/extensions/marking/tlp.py +++ b/stix/extensions/marking/tlp.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/extensions/structured_coa/__init__.py b/stix/extensions/structured_coa/__init__.py index 9a9569c5..8468f459 100644 --- a/stix/extensions/structured_coa/__init__.py +++ b/stix/extensions/structured_coa/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/extensions/structured_coa/generic_structured_coa.py b/stix/extensions/structured_coa/generic_structured_coa.py index 83c2b8a1..0f52043b 100644 --- a/stix/extensions/structured_coa/generic_structured_coa.py +++ b/stix/extensions/structured_coa/generic_structured_coa.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/extensions/test_mechanism/__init__.py b/stix/extensions/test_mechanism/__init__.py index 9a9569c5..8468f459 100644 --- a/stix/extensions/test_mechanism/__init__.py +++ b/stix/extensions/test_mechanism/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/extensions/test_mechanism/generic_test_mechanism.py b/stix/extensions/test_mechanism/generic_test_mechanism.py index dd3a816b..aa7dfe56 100644 --- a/stix/extensions/test_mechanism/generic_test_mechanism.py +++ b/stix/extensions/test_mechanism/generic_test_mechanism.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py index 52a2e93c..160b7b97 100644 --- a/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py +++ b/stix/extensions/test_mechanism/open_ioc_2010_test_mechanism.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/extensions/test_mechanism/snort_test_mechanism.py b/stix/extensions/test_mechanism/snort_test_mechanism.py index 8dc58daa..a66e1d91 100644 --- a/stix/extensions/test_mechanism/snort_test_mechanism.py +++ b/stix/extensions/test_mechanism/snort_test_mechanism.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import stix diff --git a/stix/extensions/test_mechanism/yara_test_mechanism.py b/stix/extensions/test_mechanism/yara_test_mechanism.py index 6682b67b..c9000477 100644 --- a/stix/extensions/test_mechanism/yara_test_mechanism.py +++ b/stix/extensions/test_mechanism/yara_test_mechanism.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/incident/__init__.py b/stix/incident/__init__.py index 49df7e51..3cba38e1 100644 --- a/stix/incident/__init__.py +++ b/stix/incident/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/incident/affected_asset.py b/stix/incident/affected_asset.py index 36b882c4..3076f958 100644 --- a/stix/incident/affected_asset.py +++ b/stix/incident/affected_asset.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/incident/coa.py b/stix/incident/coa.py index 93a6313a..420fd4f5 100644 --- a/stix/incident/coa.py +++ b/stix/incident/coa.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # internal diff --git a/stix/incident/contributors.py b/stix/incident/contributors.py index f31dd3a1..c6fdccc7 100644 --- a/stix/incident/contributors.py +++ b/stix/incident/contributors.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/incident/direct_impact_summary.py b/stix/incident/direct_impact_summary.py index e7a18471..4d4c2e7d 100644 --- a/stix/incident/direct_impact_summary.py +++ b/stix/incident/direct_impact_summary.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import stix diff --git a/stix/incident/external_id.py b/stix/incident/external_id.py index b9391240..868cb3b5 100644 --- a/stix/incident/external_id.py +++ b/stix/incident/external_id.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import stix diff --git a/stix/incident/history.py b/stix/incident/history.py index 1baf87cf..5b44aa1a 100644 --- a/stix/incident/history.py +++ b/stix/incident/history.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # internal diff --git a/stix/incident/impact_assessment.py b/stix/incident/impact_assessment.py index c6f0f78a..ab46df17 100644 --- a/stix/incident/impact_assessment.py +++ b/stix/incident/impact_assessment.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # internal diff --git a/stix/incident/indirect_impact_summary.py b/stix/incident/indirect_impact_summary.py index 0e2b0903..aaa40ccd 100644 --- a/stix/incident/indirect_impact_summary.py +++ b/stix/incident/indirect_impact_summary.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import stix diff --git a/stix/incident/loss_estimation.py b/stix/incident/loss_estimation.py index 294c027a..89644a94 100644 --- a/stix/incident/loss_estimation.py +++ b/stix/incident/loss_estimation.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import stix diff --git a/stix/incident/property_affected.py b/stix/incident/property_affected.py index 50ec2453..409a01b0 100644 --- a/stix/incident/property_affected.py +++ b/stix/incident/property_affected.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/incident/time.py b/stix/incident/time.py index f566b897..3b1975c4 100644 --- a/stix/incident/time.py +++ b/stix/incident/time.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import stix diff --git a/stix/incident/total_loss_estimation.py b/stix/incident/total_loss_estimation.py index d7b73dfe..24750864 100644 --- a/stix/incident/total_loss_estimation.py +++ b/stix/incident/total_loss_estimation.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # internal diff --git a/stix/indicator/__init__.py b/stix/indicator/__init__.py index f6c19424..0ebd23b7 100644 --- a/stix/indicator/__init__.py +++ b/stix/indicator/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from .indicator import * # noqa diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 8b67078c..a9549717 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # mixbox diff --git a/stix/indicator/sightings.py b/stix/indicator/sightings.py index 704e9c25..85f3b063 100644 --- a/stix/indicator/sightings.py +++ b/stix/indicator/sightings.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/indicator/test_mechanism.py b/stix/indicator/test_mechanism.py index db8300ef..62e90ebd 100644 --- a/stix/indicator/test_mechanism.py +++ b/stix/indicator/test_mechanism.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/indicator/valid_time.py b/stix/indicator/valid_time.py index 83c67c22..bdbbdde1 100644 --- a/stix/indicator/valid_time.py +++ b/stix/indicator/valid_time.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/report/__init__.py b/stix/report/__init__.py index 34ebd6e9..bf994581 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import idgen diff --git a/stix/report/header.py b/stix/report/header.py index 2506af22..2b123312 100644 --- a/stix/report/header.py +++ b/stix/report/header.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/test/__init__.py b/stix/test/__init__.py index aabac57d..33381e1f 100644 --- a/stix/test/__init__.py +++ b/stix/test/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import contextlib diff --git a/stix/test/campaign_test.py b/stix/test/campaign_test.py index e7d9ab74..1cdb8f86 100644 --- a/stix/test/campaign_test.py +++ b/stix/test/campaign_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/coa_test.py b/stix/test/coa_test.py index 58a72ba3..9a3c0e17 100644 --- a/stix/test/coa_test.py +++ b/stix/test/coa_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/common/__init__.py b/stix/test/common/__init__.py index 9a9569c5..8468f459 100644 --- a/stix/test/common/__init__.py +++ b/stix/test/common/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/test/common/activity_test.py b/stix/test/common/activity_test.py index 00b7027c..03f7f6af 100644 --- a/stix/test/common/activity_test.py +++ b/stix/test/common/activity_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/common/campaign_reference_test.py b/stix/test/common/campaign_reference_test.py index 39893b37..eb407308 100644 --- a/stix/test/common/campaign_reference_test.py +++ b/stix/test/common/campaign_reference_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/common/cdata_test.py b/stix/test/common/cdata_test.py index fabc5338..0db082d6 100644 --- a/stix/test/common/cdata_test.py +++ b/stix/test/common/cdata_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/common/confidence_test.py b/stix/test/common/confidence_test.py index 9e69fd05..6d3a44da 100644 --- a/stix/test/common/confidence_test.py +++ b/stix/test/common/confidence_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/common/datetimewithprecision_test.py b/stix/test/common/datetimewithprecision_test.py index 2f8e5057..a027e344 100644 --- a/stix/test/common/datetimewithprecision_test.py +++ b/stix/test/common/datetimewithprecision_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/common/identity_test.py b/stix/test/common/identity_test.py index 46887359..8c85bc9d 100644 --- a/stix/test/common/identity_test.py +++ b/stix/test/common/identity_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/common/information_source_test.py b/stix/test/common/information_source_test.py index 97e56f2c..6e2db398 100644 --- a/stix/test/common/information_source_test.py +++ b/stix/test/common/information_source_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/common/kill_chains_test.py b/stix/test/common/kill_chains_test.py index e26a85ff..b0e922b3 100644 --- a/stix/test/common/kill_chains_test.py +++ b/stix/test/common/kill_chains_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/common/names_test.py b/stix/test/common/names_test.py index 2c7b9d2b..74dc1a6b 100644 --- a/stix/test/common/names_test.py +++ b/stix/test/common/names_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/common/related_test.py b/stix/test/common/related_test.py index d34beb64..bc56bb90 100644 --- a/stix/test/common/related_test.py +++ b/stix/test/common/related_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/common/statement_test.py b/stix/test/common/statement_test.py index a266a866..99752430 100644 --- a/stix/test/common/statement_test.py +++ b/stix/test/common/statement_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/common/structured_text_tests.py b/stix/test/common/structured_text_tests.py index 735b71ed..270e828f 100644 --- a/stix/test/common/structured_text_tests.py +++ b/stix/test/common/structured_text_tests.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/common/tools_tests.py b/stix/test/common/tools_tests.py index 9348f6d8..3e88713e 100644 --- a/stix/test/common/tools_tests.py +++ b/stix/test/common/tools_tests.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/core/__init__.py b/stix/test/core/__init__.py index 9a9569c5..8468f459 100644 --- a/stix/test/core/__init__.py +++ b/stix/test/core/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/test/core/stix_header_test.py b/stix/test/core/stix_header_test.py index 3cd580bd..9b470987 100644 --- a/stix/test/core/stix_header_test.py +++ b/stix/test/core/stix_header_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index e932a146..bfde2d15 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import copy diff --git a/stix/test/data_marking_test.py b/stix/test/data_marking_test.py index 4db86680..6eb4c14c 100644 --- a/stix/test/data_marking_test.py +++ b/stix/test/data_marking_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/encoding_test.py b/stix/test/encoding_test.py index c099b392..259c7907 100644 --- a/stix/test/encoding_test.py +++ b/stix/test/encoding_test.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. """Tests for various encoding issues throughout the library""" diff --git a/stix/test/exploit_target_test.py b/stix/test/exploit_target_test.py index 89fe3b8a..0c6bf9a9 100644 --- a/stix/test/exploit_target_test.py +++ b/stix/test/exploit_target_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/extensions/identity/__init__.py b/stix/test/extensions/identity/__init__.py index 462a1719..8006b221 100644 --- a/stix/test/extensions/identity/__init__.py +++ b/stix/test/extensions/identity/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. \ No newline at end of file diff --git a/stix/test/extensions/identity/ciq_identity_3_0_test.py b/stix/test/extensions/identity/ciq_identity_3_0_test.py index 677707f0..20d7d101 100644 --- a/stix/test/extensions/identity/ciq_identity_3_0_test.py +++ b/stix/test/extensions/identity/ciq_identity_3_0_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/extensions/marking/terms_of_use_marking_test.py b/stix/test/extensions/marking/terms_of_use_marking_test.py index 55b9cc45..12022e9d 100644 --- a/stix/test/extensions/marking/terms_of_use_marking_test.py +++ b/stix/test/extensions/marking/terms_of_use_marking_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/extensions/structured_coa/__init__.py b/stix/test/extensions/structured_coa/__init__.py index 462a1719..8006b221 100644 --- a/stix/test/extensions/structured_coa/__init__.py +++ b/stix/test/extensions/structured_coa/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. \ No newline at end of file diff --git a/stix/test/extensions/structured_coa/generic_test.py b/stix/test/extensions/structured_coa/generic_test.py index 155409b2..e96e07fc 100644 --- a/stix/test/extensions/structured_coa/generic_test.py +++ b/stix/test/extensions/structured_coa/generic_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/extensions/test_mechanisms/__init__.py b/stix/test/extensions/test_mechanisms/__init__.py index 462a1719..8006b221 100644 --- a/stix/test/extensions/test_mechanisms/__init__.py +++ b/stix/test/extensions/test_mechanisms/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. \ No newline at end of file diff --git a/stix/test/extensions/test_mechanisms/generic_test.py b/stix/test/extensions/test_mechanisms/generic_test.py index 41d4aeb2..cec56495 100644 --- a/stix/test/extensions/test_mechanisms/generic_test.py +++ b/stix/test/extensions/test_mechanisms/generic_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/extensions/test_mechanisms/openioc_test.py b/stix/test/extensions/test_mechanisms/openioc_test.py index 01b4da4b..8ddfbd0e 100644 --- a/stix/test/extensions/test_mechanisms/openioc_test.py +++ b/stix/test/extensions/test_mechanisms/openioc_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/extensions/test_mechanisms/snort_test.py b/stix/test/extensions/test_mechanisms/snort_test.py index 954f37c6..1d6aa96d 100644 --- a/stix/test/extensions/test_mechanisms/snort_test.py +++ b/stix/test/extensions/test_mechanisms/snort_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/extensions/test_mechanisms/yara_test.py b/stix/test/extensions/test_mechanisms/yara_test.py index b5928934..e47f9cc3 100644 --- a/stix/test/extensions/test_mechanisms/yara_test.py +++ b/stix/test/extensions/test_mechanisms/yara_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/incident_test.py b/stix/test/incident_test.py index 62727b12..9beb3f7b 100644 --- a/stix/test/incident_test.py +++ b/stix/test/incident_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/indicator_test.py b/stix/test/indicator_test.py index da5314e7..a8f06c68 100644 --- a/stix/test/indicator_test.py +++ b/stix/test/indicator_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from datetime import datetime diff --git a/stix/test/report_test.py b/stix/test/report_test.py index 5ba9cf77..db49e673 100644 --- a/stix/test/report_test.py +++ b/stix/test/report_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/threat_actor_test.py b/stix/test/threat_actor_test.py index 36b8dda8..f393ba13 100644 --- a/stix/test/threat_actor_test.py +++ b/stix/test/threat_actor_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/ttp_test.py b/stix/test/ttp_test.py index 1f19a357..8e6b537a 100644 --- a/stix/test/ttp_test.py +++ b/stix/test/ttp_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import unittest diff --git a/stix/test/utils/__init__.py b/stix/test/utils/__init__.py index 9a9569c5..8468f459 100644 --- a/stix/test/utils/__init__.py +++ b/stix/test/utils/__init__.py @@ -1,2 +1,2 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. diff --git a/stix/test/utils/nsparser_test.py b/stix/test/utils/nsparser_test.py index 12c61f64..98217ef3 100644 --- a/stix/test/utils/nsparser_test.py +++ b/stix/test/utils/nsparser_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # stdlib diff --git a/stix/test/utils/parser_test.py b/stix/test/utils/parser_test.py index 887960c6..68a20eaf 100644 --- a/stix/test/utils/parser_test.py +++ b/stix/test/utils/parser_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox.vendor.six import StringIO diff --git a/stix/test/utils/utils_test.py b/stix/test/utils/utils_test.py index a42e21c1..ef6325af 100644 --- a/stix/test/utils/utils_test.py +++ b/stix/test/utils/utils_test.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # stdlib diff --git a/stix/threat_actor/__init__.py b/stix/threat_actor/__init__.py index e045b7fc..879d8c28 100644 --- a/stix/threat_actor/__init__.py +++ b/stix/threat_actor/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # mixbox diff --git a/stix/ttp/__init__.py b/stix/ttp/__init__.py index 83f6e679..d788c9f7 100644 --- a/stix/ttp/__init__.py +++ b/stix/ttp/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/ttp/attack_pattern.py b/stix/ttp/attack_pattern.py index db341706..250f02dd 100644 --- a/stix/ttp/attack_pattern.py +++ b/stix/ttp/attack_pattern.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # internal diff --git a/stix/ttp/behavior.py b/stix/ttp/behavior.py index 5d53e643..98ec2412 100644 --- a/stix/ttp/behavior.py +++ b/stix/ttp/behavior.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # mixbox diff --git a/stix/ttp/exploit.py b/stix/ttp/exploit.py index 241d430e..ebdbb5a7 100644 --- a/stix/ttp/exploit.py +++ b/stix/ttp/exploit.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # internal diff --git a/stix/ttp/exploit_targets.py b/stix/ttp/exploit_targets.py index ed7b9fca..781e8f7d 100644 --- a/stix/ttp/exploit_targets.py +++ b/stix/ttp/exploit_targets.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/ttp/infrastructure.py b/stix/ttp/infrastructure.py index 33b7d51c..01355b46 100644 --- a/stix/ttp/infrastructure.py +++ b/stix/ttp/infrastructure.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # mixbox diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index 053bdc61..0d3b6ca7 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # internal diff --git a/stix/ttp/related_ttps.py b/stix/ttp/related_ttps.py index c590ae4f..95c8a66c 100644 --- a/stix/ttp/related_ttps.py +++ b/stix/ttp/related_ttps.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. from mixbox import fields diff --git a/stix/ttp/resource.py b/stix/ttp/resource.py index 4600ebc2..e6b99d9b 100644 --- a/stix/ttp/resource.py +++ b/stix/ttp/resource.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # mixbox diff --git a/stix/ttp/victim_targeting.py b/stix/ttp/victim_targeting.py index 4928bbcc..8649c1b9 100644 --- a/stix/ttp/victim_targeting.py +++ b/stix/ttp/victim_targeting.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # external diff --git a/stix/utils/__init__.py b/stix/utils/__init__.py index 525c1892..1315bbc7 100644 --- a/stix/utils/__init__.py +++ b/stix/utils/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import contextlib diff --git a/stix/utils/dates.py b/stix/utils/dates.py index 19802e8f..1e91daa6 100644 --- a/stix/utils/dates.py +++ b/stix/utils/dates.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # stdlib diff --git a/stix/utils/deprecated.py b/stix/utils/deprecated.py index 66025ace..d313ccad 100644 --- a/stix/utils/deprecated.py +++ b/stix/utils/deprecated.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import warnings diff --git a/stix/utils/nsparser.py b/stix/utils/nsparser.py index 94ca64c6..c5e1293f 100644 --- a/stix/utils/nsparser.py +++ b/stix/utils/nsparser.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import mixbox.namespaces diff --git a/stix/utils/parser.py b/stix/utils/parser.py index 9001b676..1eb9026d 100644 --- a/stix/utils/parser.py +++ b/stix/utils/parser.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. import stix diff --git a/stix/utils/walk.py b/stix/utils/walk.py index be1f9e8c..0faec6a4 100644 --- a/stix/utils/walk.py +++ b/stix/utils/walk.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # stdlib diff --git a/stix/version.py b/stix/version.py index ab6a0ba2..fa7f4fdc 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. __version__ = "1.2.0.3.dev0" diff --git a/stix/xmlconst.py b/stix/xmlconst.py index 4acf3d25..aa498b3e 100644 --- a/stix/xmlconst.py +++ b/stix/xmlconst.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The MITRE Corporation. All rights reserved. +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. # STIX TAGS From eff19b194ab4ca1d868a16a57cf6ae1a73db25f6 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Mon, 20 Mar 2017 21:58:03 -0400 Subject: [PATCH 365/438] Bump version to 1.2.0.3 --- CHANGES.txt | 17 +++++++++++++---- docs/index.rst | 13 ++++++------- stix/version.py | 2 +- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index b19f549e..d9e71629 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,12 @@ +Version 1.2.0.3 +2017-03-20 +- #310 Support AIS Markings + +Version 1.1.1.8 +2017-01-18 +- Update to support Python 3. +- Convert to use mixbox. + Version 1.2.0.2 2016-11-02 - #309 Correctly return a single observable from Indicator.observables. @@ -139,7 +148,7 @@ Version 1.1.0.4 2014-02-31 - Added COAs, Exploit Targets, Campaigns, and Related Packages to STIXPackage class - Updated behavior of id, idref, and timestamp on core STIX constructs to align with best practices -- Added MAEC malware extension +- Added MAEC malware extension - Improved Identity extension mechanism - Added Sightings to Indicator - Updates to OpenIOC test mechanism extension @@ -149,7 +158,7 @@ Version 1.1.0.4 - Added Handling support to Indicator - Added several fields to COA and Exploit Target - Bug fixes - + Version 1.1.0.3 2014-02-24 - Added TTP structure (stix.ttp.TTP) @@ -179,7 +188,7 @@ Version 1.1.0.1 - Fixed several CIQ Identity extension bugs - Improved namespace parser performance - Updated Incident test -- Added initial code for better support of non-standard id namespaces in input documents +- Added initial code for better support of non-standard id namespaces in input documents Version 1.1.0.0 2014-02-20 @@ -239,7 +248,7 @@ Version 1.0.0a5 2013-06-27 - Improved README documentation - Fixed interface issues between python-stix and python-cybox classes -- Added support for additional namespaces to be added to STIXPackage.to_xml() +- Added support for additional namespaces to be added to STIXPackage.to_xml() - Fixed installation issues with pip and setup.py Version 1.0.0a4 diff --git a/docs/index.rst b/docs/index.rst index 59107315..a5b564a3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,17 +22,17 @@ version of STIX. ============ =================== STIX Version python-stix Version ============ =================== -1.2 1.2.0.2 (`PyPI`__) (`GitHub`__) -1.1.1 1.1.1.7 (`PyPI`__) (`GitHub`__) +1.2 1.2.0.3 (`PyPI`__) (`GitHub`__) +1.1.1 1.1.1.8 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) ============ =================== -__ https://pypi.python.org/pypi/stix/1.2.0.2 -__ https://github.com/STIXProject/python-stix/tree/v1.2.0.2 -__ https://pypi.python.org/pypi/stix/1.1.1.7 -__ https://github.com/STIXProject/python-stix/tree/v1.1.1.7 +__ https://pypi.python.org/pypi/stix/1.2.0.3 +__ https://github.com/STIXProject/python-stix/tree/v1.2.0.3 +__ https://pypi.python.org/pypi/stix/1.1.1.8 +__ https://github.com/STIXProject/python-stix/tree/v1.1.1.8 __ https://pypi.python.org/pypi/stix/1.1.0.6 __ https://github.com/STIXProject/python-stix/tree/v1.1.0.6 __ https://pypi.python.org/pypi/stix/1.0.1.1 @@ -84,4 +84,3 @@ Indices and tables * :ref:`genindex` * :ref:`modindex` * :ref:`search` - diff --git a/stix/version.py b/stix/version.py index fa7f4fdc..d1f9539c 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.3.dev0" +__version__ = "1.2.0.3" From f03e92104927d9595758ae1137963cc01432a966 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Mon, 20 Mar 2017 22:56:49 -0400 Subject: [PATCH 366/438] Bump version to 1.2.0.4.dev0 --- stix/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/version.py b/stix/version.py index d1f9539c..138182a4 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.3" +__version__ = "1.2.0.4.dev0" From b76e7b33c0b8762a1e5af3745b67c1bb47b5ecd3 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 26 Apr 2017 09:02:21 -0400 Subject: [PATCH 367/438] Replace __hash__ definition for __hash__ as class variable. --- stix/common/kill_chains/__init__.py | 11 +++++------ stix/common/vocabs.py | 3 +++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/stix/common/kill_chains/__init__.py b/stix/common/kill_chains/__init__.py index 681c1c73..22775aac 100644 --- a/stix/common/kill_chains/__init__.py +++ b/stix/common/kill_chains/__init__.py @@ -3,15 +3,16 @@ from mixbox import fields from mixbox import typedlist +from mixbox import entities # internal import stix import stix.bindings.stix_common as common_binding -from mixbox.vendor.six import string_types - class KillChain(stix.Entity): + __hash__ = entities.Entity.__hash__ + _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' _binding_class = _binding.KillChainType @@ -61,6 +62,8 @@ def _dict_as_list(cls): class KillChainPhase(stix.Entity): + __hash__ = entities.Entity.__hash__ + _binding = common_binding _namespace = 'http://stix.mitre.org/common-1' _binding_class = _binding.KillChainPhaseType @@ -88,10 +91,6 @@ def __eq__(self, other): def __ne__(self, other): return not self.__eq__(other) - def __hash__(self): - # TODO (bworrell): Is all the tuple(sorted(...))) needed? - return hash(tuple(sorted(self.to_dict().items()))) - class KillChainPhaseReference(KillChainPhase): _binding = common_binding diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index 2512e947..98b74a58 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -28,6 +28,7 @@ def validate_value(instance, value): error = error.format(**locals()) raise ValueError(error) + class VocabList(typedlist.TypedList): """VocabString fields can be any type of VocabString, though there is often a preferred/default VocabString type. @@ -80,6 +81,8 @@ def entity_class(cls, key): class VocabString(stix.Entity): + __hash__ = entities.Entity.__hash__ + _binding = stix_common_binding _binding_class = stix_common_binding.ControlledVocabularyStringType _namespace = 'http://stix.mitre.org/common-1' From 2792b7861013560f0dfac97bc8f68c3b7af0820e Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 2 May 2017 10:15:31 -0500 Subject: [PATCH 368/438] Ensure all tests get run --- .gitignore | 2 +- stix/test/common/activity_test.py | 4 ++-- stix/test/common/confidence_test.py | 4 ++-- stix/test/common/information_source_test.py | 4 ++-- stix/test/common/statement_test.py | 4 ++-- .../{structured_text_tests.py => structured_text_test.py} | 0 stix/test/common/{tools_tests.py => tools_test.py} | 4 ++-- stix/test/core/stix_header_test.py | 6 +++--- .../test/extensions/marking/{ais.py => ais_marking_test.py} | 0 .../extensions/marking/{tlp_test.py => tlp_marking_test.py} | 0 stix/test/report_test.py | 6 +++--- 11 files changed, 17 insertions(+), 17 deletions(-) rename stix/test/common/{structured_text_tests.py => structured_text_test.py} (100%) rename stix/test/common/{tools_tests.py => tools_test.py} (83%) rename stix/test/extensions/marking/{ais.py => ais_marking_test.py} (100%) rename stix/test/extensions/marking/{tlp_test.py => tlp_marking_test.py} (100%) diff --git a/.gitignore b/.gitignore index 267b66db..9a9c7d31 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,4 @@ dist/ .tox docs/_build - +.cache diff --git a/stix/test/common/activity_test.py b/stix/test/common/activity_test.py index 03f7f6af..ad80754a 100644 --- a/stix/test/common/activity_test.py +++ b/stix/test/common/activity_test.py @@ -4,7 +4,7 @@ import unittest from stix.test import EntityTestCase -from stix.test.common import structured_text_tests +from stix.test.common import structured_text_test from stix.common import Activity @@ -21,7 +21,7 @@ class ActivityMultiDescTests(EntityTestCase, unittest.TestCase): klass = Activity _full_dict = { 'date_time': "2014-01-31T06:14:46", - 'description': structured_text_tests.StructuredTextListTests._full_dict + 'description': structured_text_test.StructuredTextListTests._full_dict } diff --git a/stix/test/common/confidence_test.py b/stix/test/common/confidence_test.py index 6d3a44da..3a72c493 100644 --- a/stix/test/common/confidence_test.py +++ b/stix/test/common/confidence_test.py @@ -4,7 +4,7 @@ import unittest from stix.test import EntityTestCase -from stix.test.common import structured_text_tests +from stix.test.common import structured_text_test from stix.common import Confidence @@ -25,7 +25,7 @@ class ConfidenceTests(EntityTestCase, unittest.TestCase): class ConfidenceMultiDescTests(EntityTestCase, unittest.TestCase): klass = Confidence _full_dict = { - 'description': structured_text_tests.StructuredTextListTests._full_dict + 'description': structured_text_test.StructuredTextListTests._full_dict } diff --git a/stix/test/common/information_source_test.py b/stix/test/common/information_source_test.py index 6e2db398..7be1a586 100644 --- a/stix/test/common/information_source_test.py +++ b/stix/test/common/information_source_test.py @@ -4,7 +4,7 @@ import unittest from stix.test import EntityTestCase -from stix.test.common import structured_text_tests +from stix.test.common import structured_text_test from stix.common import InformationSource @@ -67,7 +67,7 @@ class InformationSourceTests(EntityTestCase, unittest.TestCase): class InformationSourceMultiDescTests(EntityTestCase, unittest.TestCase): klass = InformationSource _full_dict = { - 'description': structured_text_tests.StructuredTextListTests._full_dict + 'description': structured_text_test.StructuredTextListTests._full_dict } diff --git a/stix/test/common/statement_test.py b/stix/test/common/statement_test.py index 99752430..6b9d155d 100644 --- a/stix/test/common/statement_test.py +++ b/stix/test/common/statement_test.py @@ -4,7 +4,7 @@ import unittest from stix.test import EntityTestCase -from stix.test.common import structured_text_tests +from stix.test.common import structured_text_test from stix.common import Statement @@ -28,7 +28,7 @@ class StatementTests(EntityTestCase, unittest.TestCase): class StatementMultiDescTests(EntityTestCase, unittest.TestCase): klass = Statement _full_dict = { - 'description': structured_text_tests.StructuredTextListTests._full_dict + 'description': structured_text_test.StructuredTextListTests._full_dict } diff --git a/stix/test/common/structured_text_tests.py b/stix/test/common/structured_text_test.py similarity index 100% rename from stix/test/common/structured_text_tests.py rename to stix/test/common/structured_text_test.py diff --git a/stix/test/common/tools_tests.py b/stix/test/common/tools_test.py similarity index 83% rename from stix/test/common/tools_tests.py rename to stix/test/common/tools_test.py index 3e88713e..1c84e3ed 100644 --- a/stix/test/common/tools_tests.py +++ b/stix/test/common/tools_test.py @@ -4,7 +4,7 @@ import unittest from stix.test import EntityTestCase -from stix.test.common import structured_text_tests +from stix.test.common import structured_text_test from stix import common @@ -24,7 +24,7 @@ class ToolInformationMultiDescTests(EntityTestCase, unittest.TestCase): klass = common.ToolInformation _full_dict = { - 'short_description': structured_text_tests.StructuredTextListTests._full_dict + 'short_description': structured_text_test.StructuredTextListTests._full_dict } if __name__ == "__main__": diff --git a/stix/test/core/stix_header_test.py b/stix/test/core/stix_header_test.py index 9b470987..514bdaca 100644 --- a/stix/test/core/stix_header_test.py +++ b/stix/test/core/stix_header_test.py @@ -5,7 +5,7 @@ from stix.test import assert_warnings from stix.test import EntityTestCase, data_marking_test -from stix.test.common import information_source_test, structured_text_tests +from stix.test.common import information_source_test, structured_text_test from stix import core from stix.utils import silence_warnings @@ -60,8 +60,8 @@ def test_deprecated_package_intents(self): class STIXHeaderMultiDescTests(EntityTestCase, unittest.TestCase): klass = core.STIXHeader _full_dict = { - 'description': structured_text_tests.StructuredTextListTests._full_dict, - 'short_description': structured_text_tests.StructuredTextListTests._full_dict + 'description': structured_text_test.StructuredTextListTests._full_dict, + 'short_description': structured_text_test.StructuredTextListTests._full_dict } diff --git a/stix/test/extensions/marking/ais.py b/stix/test/extensions/marking/ais_marking_test.py similarity index 100% rename from stix/test/extensions/marking/ais.py rename to stix/test/extensions/marking/ais_marking_test.py diff --git a/stix/test/extensions/marking/tlp_test.py b/stix/test/extensions/marking/tlp_marking_test.py similarity index 100% rename from stix/test/extensions/marking/tlp_test.py rename to stix/test/extensions/marking/tlp_marking_test.py diff --git a/stix/test/report_test.py b/stix/test/report_test.py index db49e673..264276db 100644 --- a/stix/test/report_test.py +++ b/stix/test/report_test.py @@ -7,7 +7,7 @@ from stix.test import EntityTestCase, data_marking_test from stix.test.common import (kill_chains_test, information_source_test, - structured_text_tests, related_test) + structured_text_test, related_test) class HeaderTests(EntityTestCase, unittest.TestCase): @@ -30,8 +30,8 @@ def test_duplicate_package_intent(self): class HeaderMultiDescTests(EntityTestCase, unittest.TestCase): klass = report.Header _full_dict = { - 'description': structured_text_tests.StructuredTextListTests._full_dict, - 'short_description': structured_text_tests.StructuredTextListTests._full_dict + 'description': structured_text_test.StructuredTextListTests._full_dict, + 'short_description': structured_text_test.StructuredTextListTests._full_dict } From 7aaa2ae34bb4300dc5ec2f6d6e419fc5f9f6c6a9 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 2 May 2017 10:19:18 -0500 Subject: [PATCH 369/438] Emit proper xsi:type for AISMarkingStructure. Fix #319 --- stix/bindings/extensions/marking/ais.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stix/bindings/extensions/marking/ais.py b/stix/bindings/extensions/marking/ais.py index a095c3e8..d3cd9dc1 100644 --- a/stix/bindings/extensions/marking/ais.py +++ b/stix/bindings/extensions/marking/ais.py @@ -83,7 +83,8 @@ def exportAttributes(self, lwrite, level, already_processed, namespace_=XML_NS, super(AISMarkingStructure, self).exportAttributes(lwrite, level, already_processed, namespace_, name_='AISMarkingStructure') if 'xsi:type' not in already_processed: already_processed.add('xsi:type') - lwrite(" xsi:type=%s" % (self.gds_format_string(quote_attrib(self.xsi_type).encode(ExternalEncoding), input_name='xsi:type'))) + xsi_type = " xsi:type='%s:%s'" % (self.xmlns_prefix, self.xml_type) + lwrite(xsi_type) def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='AISMarkingStructure', fromsubclass_=False, pretty_print=True): super(AISMarkingStructure, self).exportChildren(lwrite, level, nsmap, namespace_, name_, True, pretty_print=pretty_print) From fb5d7b2ee23513524f9ecf44db00c2d9c24f6068 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 2 May 2017 10:38:47 -0500 Subject: [PATCH 370/438] Update tox/travis; add Python 3.6 support. --- .travis.yml | 20 +++++++------------- requirements.txt | 8 +++++++- setup.py | 30 ++++++++++++------------------ tox.ini | 17 ++++++++++++----- 4 files changed, 38 insertions(+), 37 deletions(-) diff --git a/.travis.yml b/.travis.yml index f6fa5be0..e3485ff6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,15 @@ language: python python: - - 3.5 - -env: - - TOXENV=py26 - - TOXENV=py27 - - TOXENV=py33 - - TOXENV=py34 - - TOXENV=py35 - - TOXENV=lxml23 - + - "2.6" + - "2.7" + - "3.3" + - "3.4" + - "3.5" + - "3.6" install: - - pip install -U tox - + - pip install tox-travis script: - tox - notifications: email: - gback@mitre.org diff --git a/requirements.txt b/requirements.txt index 54d46380..c27803bd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,7 @@ --e .[docs,test] +maec>=4.1.0.13.dev4,<4.1.1.0 # For tests that include MAEC +nose==1.3.7 +sphinx==1.3.6 +sphinx_rtd_theme==0.2.4 +tox==2.7.0 + +-e . diff --git a/setup.py b/setup.py index fe95d5c2..249c63c0 100644 --- a/setup.py +++ b/setup.py @@ -23,18 +23,6 @@ def get_version(): with open('README.rst') as f: readme = f.read() -extras_require = { - 'docs': [ - 'Sphinx==1.3.1', - 'sphinx_rtd_theme==0.1.8', - ], - 'test': [ - 'nose==1.3.0', - 'tox==1.6.1', - 'maec>=4.1.0.13.dev4,<4.1.1.0', - ], -} - install_requires = [ 'lxml>=2.3', @@ -54,12 +42,18 @@ def get_version(): url="http://stix.mitre.org", packages=find_packages(), install_requires=install_requires, - extras_require=extras_require, classifiers=[ - "Programming Language :: Python", - "Development Status :: 4 - Beta", - "Intended Audience :: Developers", - "License :: OSI Approved :: BSD License", - "Operating System :: OS Independent", + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', ] ) diff --git a/tox.ini b/tox.ini index 5ef36035..450e4418 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py26, py27, py33, py34, py35, lxml23 +envlist = py26, py27, py33, py34, py35, py36, lxml23 [testenv] commands = @@ -17,9 +17,16 @@ basepython=python2.6 commands = nosetests stix deps = + # Pin specific versions of LXML and python-dateutil lxml==2.3 python-dateutil==1.4.1 - mixbox>=1.0.1 - cybox>=2.1.0.13.dev1 - maec>=4.1.0.13.dev4 - nose + -rrequirements.txt + +[travis] +python = + 2.6: py26, lxml23 + 2.7: py27, docs + 3.3: py33 + 3.4: py34 + 3.5: py35 + 3.6: py36 From a1e080fe5db90e705d9b213662d7a269320b5086 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 2 May 2017 10:40:17 -0500 Subject: [PATCH 371/438] Bump required version of mixbox. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 249c63c0..74f729dd 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ def get_version(): 'lxml>=2.3', 'python-dateutil', 'cybox>=2.1.0.13.dev1,<2.1.1.0', - 'mixbox>=1.0.1', + 'mixbox>=1.0.2', ] From 554bab71178a6a12e134644b6310818dd7b23630 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 2 May 2017 10:53:59 -0500 Subject: [PATCH 372/438] Update CHANGES.txt for 1.2.0.4 --- CHANGES.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index d9e71629..db34abe5 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,10 @@ +Version 1.2.0.4 +2017-05-02 +- Add support for Python 3.6. +- Update to latest mixbox. +- #319 Emit proper xsi:type for AISMarkingStructure. +- #317 Implement __hash__ for required objects + Version 1.2.0.3 2017-03-20 - #310 Support AIS Markings From b06cab97bdf9e920d01ff5319226bba1ca3d9b99 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 2 May 2017 10:54:34 -0500 Subject: [PATCH 373/438] Bump version to 1.2.0.4 --- docs/index.rst | 6 +++--- stix/version.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index a5b564a3..b26e81c1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,15 +22,15 @@ version of STIX. ============ =================== STIX Version python-stix Version ============ =================== -1.2 1.2.0.3 (`PyPI`__) (`GitHub`__) +1.2 1.2.0.4 (`PyPI`__) (`GitHub`__) 1.1.1 1.1.1.8 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) ============ =================== -__ https://pypi.python.org/pypi/stix/1.2.0.3 -__ https://github.com/STIXProject/python-stix/tree/v1.2.0.3 +__ https://pypi.python.org/pypi/stix/1.2.0.4 +__ https://github.com/STIXProject/python-stix/tree/v1.2.0.4 __ https://pypi.python.org/pypi/stix/1.1.1.8 __ https://github.com/STIXProject/python-stix/tree/v1.1.1.8 __ https://pypi.python.org/pypi/stix/1.1.0.6 diff --git a/stix/version.py b/stix/version.py index 138182a4..6439fff9 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.4.dev0" +__version__ = "1.2.0.4" From 4b1422d25fe81d8e1910e6826706555c72dfec22 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 2 May 2017 11:28:39 -0500 Subject: [PATCH 374/438] Bump version to 1.2.0.5.dev0 --- stix/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/version.py b/stix/version.py index 6439fff9..956c4394 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.4" +__version__ = "1.2.0.5.dev0" From 1fce8ae85a04081a87d7f85227c8360cb99b6305 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Wed, 20 Sep 2017 14:35:55 +0000 Subject: [PATCH 375/438] Add documentation on using AIS Markings. Fix #326 --- docs/api/extensions/marking/ais.rst | 41 ++++++++++++++++++++++++ stix/extensions/marking/ais.py | 48 +++++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 docs/api/extensions/marking/ais.rst diff --git a/docs/api/extensions/marking/ais.rst b/docs/api/extensions/marking/ais.rst new file mode 100644 index 00000000..397b56cb --- /dev/null +++ b/docs/api/extensions/marking/ais.rst @@ -0,0 +1,41 @@ +:mod:`stix.extensions.marking.ais` Module +==================================================== + +.. automodule:: stix.extensions.marking.ais + +Classes +------- + +.. autoclass:: AISMarkingStructure + :show-inheritance: + :members: + +Functions +--------- + +.. autofunction:: add_ais_marking + + +Constants +--------- + +The following constants can be used for the ``industry_type`` argument to +``add_ais_marking``: + +.. autodata:: CHEMICAL_SECTOR +.. autodata:: COMMERCIAL_FACILITIES_SECTOR +.. autodata:: COMMUNICATIONS_SECTOR +.. autodata:: CRITICAL_MANUFACTURING_SECTOR +.. autodata:: DAMS_SECTOR +.. autodata:: DEFENSE_INDUSTRIAL_BASE_SECTOR +.. autodata:: EMERGENCY_SERVICES_SECTOR +.. autodata:: ENERGY_SECTOR +.. autodata:: FINANCIAL_SERVICES_SECTOR +.. autodata:: FOOD_AND_AGRICULTURE_SECTOR +.. autodata:: GOVERNMENT_FACILITIES_SECTOR +.. autodata:: HEALTH_CARE_AND_PUBLIC_HEALTH_SECTOR +.. autodata:: INFORMATION_TECHNOLOGY_SECTOR +.. autodata:: NUCLEAR_REACTORS_MATERIALS_AND_WASTE_SECTOR +.. autodata:: OTHER +.. autodata:: TRANSPORTATION_SYSTEMS_SECTOR +.. autodata:: WATER_AND_WASTEWATER_SYSTEMS_SECTOR diff --git a/stix/extensions/marking/ais.py b/stix/extensions/marking/ais.py index bd2b76cf..5686ca30 100644 --- a/stix/extensions/marking/ais.py +++ b/stix/extensions/marking/ais.py @@ -1,6 +1,23 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +""" +STIX Extension for AIS Data Markings + +Unlike the other marking extensions, the AIS marking extension is not loaded +automatically, since AIS markings are not a part of the published STIX 1.x +specifications. They are included in python-stix because they're common enough +that it is not worth creating a separate package. + +If you are writing code that needs to parse AIS markings, make sure that your +program imports this module before beginning to parse any STIX documents: + +.. code-block:: python + + import stix.extensions.marking.ais + +""" + from mixbox import fields from mixbox.namespaces import Namespace @@ -120,22 +137,39 @@ def _update_namespaces(): # IndustryType allowed sectors +#: Chemical Sector CHEMICAL_SECTOR = 'Chemical Sector' +#: Chemical Sector COMMERCIAL_FACILITIES_SECTOR = 'Commercial Facilities Sector' +#: Commercial Facilities Sector COMMUNICATIONS_SECTOR = 'Communications Sector' +#: Critical Manufacturing Sector CRITICAL_MANUFACTURING_SECTOR = 'Critical Manufacturing Sector' +#: Dams Sector DAMS_SECTOR = 'Dams Sector' +#: Defense Industrial Base Sector DEFENSE_INDUSTRIAL_BASE_SECTOR = 'Defense Industrial Base Sector' +#: Emergency Services Sector EMERGENCY_SERVICES_SECTOR = 'Emergency Services Sector' +#: Energy Sector ENERGY_SECTOR = 'Energy Sector' +#: Financial Services Sector FINANCIAL_SERVICES_SECTOR = 'Financial Services Sector' +#: Food and Agriculture Sector FOOD_AND_AGRICULTURE_SECTOR = 'Food and Agriculture Sector' +#: Government Facilities Sector GOVERNMENT_FACILITIES_SECTOR = 'Government Facilities Sector' +#: Healthcare and Public Health Sector HEALTH_CARE_AND_PUBLIC_HEALTH_SECTOR = 'Healthcare and Public Health Sector' +#: Information Technology Sector INFORMATION_TECHNOLOGY_SECTOR = 'Information Technology Sector' +#: Nuclear Reactors, Materials, and Waste Sector NUCLEAR_REACTORS_MATERIALS_AND_WASTE_SECTOR = 'Nuclear Reactors, Materials, and Waste Sector' +#: Other OTHER = 'Other' +#: Transportation Systems Sector TRANSPORTATION_SYSTEMS_SECTOR = 'Transportation Systems Sector' +#: Water and Wastewater Systems Sector WATER_AND_WASTEWATER_SYSTEMS_SECTOR = 'Water and Wastewater Systems Sector' @@ -192,10 +226,11 @@ def add_ais_marking(stix_package, proprietary, consent, color, **kwargs): """ This utility functions aids in the creation of an AIS marking and appends it to the provided STIX package. + Args: stix_package: A stix.core.STIXPackage object. proprietary: True if marking uses IsProprietary, False for - NotProprietary. + NotProprietary. consent: A string with one of the following values: "EVERYONE", "NONE" or "USG". color: A string that corresponds to TLP values: "WHITE", "GREEN" or @@ -204,19 +239,26 @@ def add_ais_marking(stix_package, proprietary, consent, color, **kwargs): identity object. These are: country_name_code, country_name_code_type, admin_area_name_code, admin_area_name_code_type, organisation_name, industry_type. + Raises: ValueError: When keyword arguments are missing. User did not supply correct values for: proprietary, color and consent. + Note: - The following line is required to register the AIS extension: - >>> import stix.extensions.marking.ais + The following line is required to register the AIS extension:: + + >>> import stix.extensions.marking.ais + Any Markings under STIX Header will be removed. Please follow the guidelines for `AIS`_. + The industry_type keyword argument accepts: a list of string based on defined sectors, a pipe-delimited string of sectors, or a single sector. + .. _AIS: https://www.us-cert.gov/ais + """ from stix.common import InformationSource from stix.extensions.identity.ciq_identity_3_0 import ( From 1d0857c7d02cf4b9b71611caae660e21e448ef83 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Thu, 21 Sep 2017 10:13:36 -0400 Subject: [PATCH 376/438] Add ais example usage. closes #326 --- docs/api/extensions/marking/ais.rst | 143 +++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/docs/api/extensions/marking/ais.rst b/docs/api/extensions/marking/ais.rst index 397b56cb..4405abeb 100644 --- a/docs/api/extensions/marking/ais.rst +++ b/docs/api/extensions/marking/ais.rst @@ -16,10 +16,151 @@ Functions .. autofunction:: add_ais_marking +Examples +-------- + +Applying AIS Markings +--------------------- + +The STIX specification allows data markings to be applied to any combination of +attributes and elements that can be described by XPath. That being said, the +Automated Indicator Sharing (AIS) capability requires those markings controlled +structure to select all nodes and attributes ``//node() | //@*``. All required +fields to create a valid AIS Markings are provided through the ``add_ais_marking`` +function. + +.. code:: python + + # python-stix imports + import stix + from stix.core import STIXPackage + from stix.extensions.marking.ais import (add_ais_marking, + COMMUNICATIONS_SECTOR, + INFORMATION_TECHNOLOGY_SECTOR) + from stix.indicator import Indicator + + # Create new STIX Package + stix_package = STIXPackage() + + # Create new Indicator + indicator = Indicator(title='My Indicator Example', + description='Example using AIS') + + # Add indicator to our STIX Package + stix_package.add_indicator(indicator) + + # Create AIS Marking with CIQ Identity and attach it to STIX Header. + add_ais_marking(stix_package, False, 'EVERYONE', 'GREEN', + country_name_code='US', + country_name_code_type='ISO 3166-1 alpha-2', + admin_area_name_code='US-DC', + admin_area_name_code_type='ISO 3166-2', + organisation_name='NCCIC', + industry_type=[INFORMATION_TECHNOLOGY_SECTOR, COMMUNICATIONS_SECTOR] + ) + + # Print the XML. + print stix_package.to_xml() + +This corresponds to the XML result: + +.. code-block:: xml + + + + + + //node() | //@* + + + + + + + + + \ + + + NCCIC + + + + + + + + + + + + + + + + + + + + + + My Indicator Example + Example using AIS + + + + +Parsing AIS Markings +-------------------- + +Using the same example used for Applying AIS Markings. This would be how a +consumer of AIS would parse the data. + +.. code:: python + + # python-stix imports + import stix + from stix.core import STIXPackage + import stix.extensions.marking.ais # Register the AIS markings + + # Parse STIX Package + stix_package = STIXPackage.from_xml("stix_input.xml") + + # Print all indicators + for indicator in stix_package.indicators: + print(indicator) + + # Extract markings from STIX Header + markings = stix_package.stix_header.handling + + # Print all markings contained in the STIX Header + for marking in markings: + print(marking) + print(marking.marking_structures) + + >>> + >>> + >>> [, ...] + Constants --------- -The following constants can be used for the ``industry_type`` argument to +The following constants can be used for the ``industry_type`` keyword argument to ``add_ais_marking``: .. autodata:: CHEMICAL_SECTOR From 15dabf1c22d69fb98c3f56147b4f959695925c78 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Thu, 21 Sep 2017 16:23:26 +0000 Subject: [PATCH 377/438] Add syntax highlighting to AIS examples. --- docs/api/extensions/marking/ais.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/extensions/marking/ais.rst b/docs/api/extensions/marking/ais.rst index 4405abeb..630a11c7 100644 --- a/docs/api/extensions/marking/ais.rst +++ b/docs/api/extensions/marking/ais.rst @@ -29,7 +29,7 @@ structure to select all nodes and attributes ``//node() | //@*``. All required fields to create a valid AIS Markings are provided through the ``add_ais_marking`` function. -.. code:: python +.. code-block:: python # python-stix imports import stix @@ -131,7 +131,7 @@ Parsing AIS Markings Using the same example used for Applying AIS Markings. This would be how a consumer of AIS would parse the data. -.. code:: python +.. code-block:: python # python-stix imports import stix From 9f9b7e2ca18413ac96c4188b74a165a506e6cd4e Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Thu, 28 Sep 2017 17:30:23 -0400 Subject: [PATCH 378/438] Update AIS example. closes #326 --- docs/api/extensions/marking/ais.rst | 40 ++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/docs/api/extensions/marking/ais.rst b/docs/api/extensions/marking/ais.rst index 630a11c7..676b969b 100644 --- a/docs/api/extensions/marking/ais.rst +++ b/docs/api/extensions/marking/ais.rst @@ -53,9 +53,9 @@ function. add_ais_marking(stix_package, False, 'EVERYONE', 'GREEN', country_name_code='US', country_name_code_type='ISO 3166-1 alpha-2', - admin_area_name_code='US-DC', + admin_area_name_code='US-VA', admin_area_name_code_type='ISO 3166-2', - organisation_name='NCCIC', + organisation_name='Example Corporation', industry_type=[INFORMATION_TECHNOLOGY_SECTOR, COMMUNICATIONS_SECTOR] ) @@ -97,7 +97,7 @@ This corresponds to the XML result: \ - NCCIC + Example Corporation @@ -106,7 +106,7 @@ This corresponds to the XML result: - + @@ -152,10 +152,42 @@ consumer of AIS would parse the data. for marking in markings: print(marking) print(marking.marking_structures) + print("----------MARKING CONTENT----------") + ais_struct = marking.marking_structures[0] + print("OBJ: %s" % ais_struct) + print("NotProprietary OBJ: %s" % ais_struct.not_proprietary) + print("CISA_Proprietary: %s" % ais_struct.not_proprietary.cisa_proprietary) + print("Consent: %s" % ais_struct.not_proprietary.ais_consent.consent) + print("TLP color: %s" % ais_struct.not_proprietary.tlp_marking.color) + + print("----------INFORMATION SOURCE----------") + identity = marking.information_source.identity.specification + print("OBJ: %s" % identity) + print("Organization Name: %s" % identity.party_name.organisation_names[0].name_elements[0].value) + print("Country: %s" % identity.addresses[0].country.name_elements[0].name_code) + print("Country code type: %s" % identity.addresses[0].country.name_elements[0].name_code_type) + print("Administrative area: %s" % identity.addresses[0].administrative_area.name_elements[0].name_code) + print("Administrative area code type: %s" % identity.addresses[0].administrative_area.name_elements[0].name_code_type) + print("Industry Type: %s" % identity.organisation_info.industry_type) + >>> >>> >>> [, ...] + >>> ----------MARKING CONTENT---------- + >>> OBJ: + >>> NotProprietary OBJ: + >>> CISA_Proprietary: False + >>> Consent: EVERYONE + >>> TLP color: GREEN + >>> ----------INFORMATION SOURCE---------- + >>> OBJ: + >>> Organization Name: Example Corporation + >>> Country: US + >>> Country code type: ISO 3166-1 alpha-2 + >>> Administrative area: US-VA + >>> Administrative area code type: ISO 3166-2 + >>> Industry Type: Information Technology Sector|Communications Sector Constants --------- From a1d8fca80c6c850721424b59c6e038b36e5c5213 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 2 Oct 2017 10:49:36 -0400 Subject: [PATCH 379/438] Add equivalent JSON output for example --- docs/api/extensions/marking/ais.rst | 83 +++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/docs/api/extensions/marking/ais.rst b/docs/api/extensions/marking/ais.rst index 676b969b..79bd6973 100644 --- a/docs/api/extensions/marking/ais.rst +++ b/docs/api/extensions/marking/ais.rst @@ -62,6 +62,9 @@ function. # Print the XML. print stix_package.to_xml() + # Print the JSON. + print stix_package.to_json() + This corresponds to the XML result: .. code-block:: xml @@ -125,6 +128,85 @@ This corresponds to the XML result: +The following corresponds to the JSON result: + +.. code-block:: json + + { + "stix_header": { + "handling": [ + { + "controlled_structure": "//node() | //@*", + "information_source": { + "identity": { + "xsi:type": "stix-ciqidentity:CIQIdentity3.0InstanceType", + "specification": { + "organisation_info": { + "industry_type": "Information Technology Sector|Communications Sector" + }, + "party_name": { + "organisation_names": [ + { + "name_elements": [ + { + "value": "Example Corporation" + } + ] + } + ] + }, + "addresses": [ + { + "country": { + "name_elements": [ + { + "name_code_type": "ISO 3166-1 alpha-2", + "name_code": "US" + } + ] + }, + "administrative_area": { + "name_elements": [ + { + "name_code_type": "ISO 3166-2", + "name_code": "US-VA" + } + ] + } + } + ] + } + } + }, + "marking_structures": [ + { + "xsi:type": "AIS:AISMarkingStructure", + "not_proprietary": { + "tlp_marking": { + "color": "GREEN" + }, + "ais_consent": { + "consent": "EVERYONE" + }, + "cisa_proprietary": "false" + } + } + ] + } + ] + }, + "version": "1.2", + "indicators": [ + { + "description": "Example using AIS", + "title": "My Indicator Example", + "timestamp": "2017-10-02T14:26:57.510000+00:00", + "id": "example:indicator-81466b8d-4efb-460f-ba13-b072420b9540" + } + ], + "id": "example:Package-a8c8135d-18d8-4384-903f-71285a02346e" + } + Parsing AIS Markings -------------------- @@ -140,6 +222,7 @@ consumer of AIS would parse the data. # Parse STIX Package stix_package = STIXPackage.from_xml("stix_input.xml") + # stix_package = STIXPackage.from_json("stix_input.json") # Print all indicators for indicator in stix_package.indicators: From c732a2a05b90a1098d5256d2c9a17081b51d4cf5 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Thu, 22 Feb 2018 11:02:16 -0500 Subject: [PATCH 380/438] Passing list with single observable gets set. closes #325 --- stix/indicator/indicator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index a9549717..5842209f 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -281,7 +281,7 @@ def observables(self, value): elif utils.is_sequence(value): if len(value) == 1: - self.observable = value + self.add_observable(value[0]) return observable_comp = ObservableComposition() From b9c6fe471ce02183bef76e447aaf29b330ad542f Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Thu, 22 Feb 2018 12:10:53 -0500 Subject: [PATCH 381/438] Add missing stix.report.TTPs closes #336 --- stix/report/__init__.py | 12 +++++++++--- stix/test/report_test.py | 16 ++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/stix/report/__init__.py b/stix/report/__init__.py index bf994581..c2d18b3b 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -69,7 +69,7 @@ class Report(stix.Entity): indicators = fields.TypedField("Indicators", type_="stix.report.Indicators") incidents = fields.TypedField("Incidents", type_="stix.report.Incidents") threat_actors = fields.TypedField("Threat_Actors", type_="stix.report.ThreatActors") - ttps = fields.TypedField("TTPs", type_="stix.core.ttps.TTPs") + ttps = fields.TypedField("TTPs", type_="stix.report.TTPs") related_reports = fields.TypedField("Related_Reports", type_="stix.report.RelatedReports") def __init__(self, id_=None, idref=None, timestamp=None, header=None, @@ -207,6 +207,7 @@ def add(self, entity): error = error.format(type(entity)) raise TypeError(error) + class Campaigns(stix.EntityList): _binding = report_binding _namespace = 'http://stix.mitre.org/Report-1' @@ -243,7 +244,6 @@ class Indicators(stix.EntityList): _binding = report_binding _namespace = 'http://stix.mitre.org/Report-1' _binding_class = _binding.IndicatorsType - _contained_type = Indicator indicator = fields.TypedField("Indicator", Indicator, multiple=True, key_name="indicators") @@ -255,4 +255,10 @@ class ThreatActors(stix.EntityList): threat_actor = fields.TypedField("Threat_Actor", ThreatActor, multiple=True, key_name="threat_actors") -from stix.core.ttps import TTPs + +class TTPs(stix.EntityList): + _binding = report_binding + _namespace = 'http://stix.mitre.org/Report-1' + _binding_class = _binding.TTPsType + + ttp = fields.TypedField("TTP", TTP, multiple=True, key_name="ttps") diff --git a/stix/test/report_test.py b/stix/test/report_test.py index 264276db..334ef519 100644 --- a/stix/test/report_test.py +++ b/stix/test/report_test.py @@ -6,8 +6,8 @@ from stix import report from stix.test import EntityTestCase, data_marking_test -from stix.test.common import (kill_chains_test, information_source_test, - structured_text_test, related_test) +from stix.test.common import (information_source_test, structured_text_test, + related_test) class HeaderTests(EntityTestCase, unittest.TestCase): @@ -50,6 +50,7 @@ class COAsTests(EntityTestCase, unittest.TestCase): {'idref': 'example:test-1'} ] + class ExploitTargetsTests(EntityTestCase, unittest.TestCase): klass = report.ExploitTargets @@ -57,6 +58,7 @@ class ExploitTargetsTests(EntityTestCase, unittest.TestCase): {'idref': 'example:test-1'} ] + class IncidentsTests(EntityTestCase, unittest.TestCase): klass = report.Incidents @@ -64,6 +66,7 @@ class IncidentsTests(EntityTestCase, unittest.TestCase): {'idref': 'example:test-1'} ] + class IndicatorsTests(EntityTestCase, unittest.TestCase): klass = report.Indicators @@ -83,12 +86,9 @@ class ThreatActorsTests(EntityTestCase, unittest.TestCase): class TTPsTests(EntityTestCase, unittest.TestCase): klass = report.TTPs - _full_dict = { - 'kill_chains': kill_chains_test.KillChainsTests._full_dict, - 'ttps': [ - {'idref': 'example:test-1'} - ] - } + _full_dict = [ + {'idref': 'example:test-1'} + ] class ReportTests(EntityTestCase, unittest.TestCase): From 86c9fe3ba6c7aee88f691593c4b021d226ae1064 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Thu, 22 Feb 2018 12:23:58 -0500 Subject: [PATCH 382/438] Make MAECInstance extension fully compatible with TypedFields. closes #339 --- stix/bindings/extensions/malware/maec_4_1.py | 26 +- stix/extensions/malware/maec_4_1_malware.py | 226 ++---------------- .../malware/maec_4_1_malware_test.py | 139 +++++------ stix/ttp/malware_instance.py | 12 +- 4 files changed, 104 insertions(+), 299 deletions(-) diff --git a/stix/bindings/extensions/malware/maec_4_1.py b/stix/bindings/extensions/malware/maec_4_1.py index e32a0ad1..0e0d5a5d 100644 --- a/stix/bindings/extensions/malware/maec_4_1.py +++ b/stix/bindings/extensions/malware/maec_4_1.py @@ -15,12 +15,6 @@ from stix.bindings import register_extension import stix.bindings.ttp as ttp_binding -try: - from maec.bindings.maec_package import PackageType - maec_installed = True -except ImportError: - PackageType = None - maec_installed = False XML_NS = "http://stix.mitre.org/extensions/Malware#MAEC4.1-1" @@ -28,10 +22,11 @@ # Data representation classes. # + @register_extension class MAEC4_1InstanceType(ttp_binding.MalwareInstanceType): """The MAEC4.1InstanceType provides an extension to ttp_binding.MalwareInstanceType - which imports and leverages the MAEC 4.0.1 schema for structured + which imports and leverages the MAEC 4.1 schema for structured characterization of Malware.""" subclass = None superclass = ttp_binding.MalwareInstanceType @@ -89,11 +84,7 @@ def exportChildren(self, lwrite, level, nsmap, namespace_=XML_NS, name_='MAEC4.1 else: eol_ = '' if self.MAEC is not None: - if maec_installed and isinstance(self.MAEC, PackageType): - self.MAEC.export(lwrite, level, namespace_='stix-maec:', name_='MAEC', pretty_print=pretty_print) - else: - showIndent(lwrite, level, pretty_print) - lwrite(etree_.tostring(self.MAEC, pretty_print=pretty_print).decode()) + self.MAEC.export(lwrite, level, namespace_='stix-maec:', name_='MAEC', pretty_print=pretty_print) def build(self, node): self.__sourcenode__ = node already_processed = set() @@ -105,12 +96,11 @@ def buildAttributes(self, node, attrs, already_processed): super(MAEC4_1InstanceType, self).buildAttributes(node, attrs, already_processed) def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'MAEC': - if maec_installed: - obj_ = PackageType.factory() - obj_.build(child_) - self.set_MAEC(obj_) - else: - self.set_MAEC(child_) + # Fails hard if maec library is not installed in your Python environment. + from maec.bindings.maec_package import PackageType + obj_ = PackageType.factory() + obj_.build(child_) + self.set_MAEC(obj_) super(MAEC4_1InstanceType, self).buildChildren(child_, node, nodeName_, True) # end class MAEC4_1InstanceType diff --git a/stix/extensions/malware/maec_4_1_malware.py b/stix/extensions/malware/maec_4_1_malware.py index b1f873c8..57e0751a 100644 --- a/stix/extensions/malware/maec_4_1_malware.py +++ b/stix/extensions/malware/maec_4_1_malware.py @@ -1,231 +1,37 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -# stdlib -from distutils.version import LooseVersion - # external -from lxml import etree -import mixbox.xml -from mixbox.vendor.six import BytesIO, iteritems, binary_type +from mixbox import fields + # internal import stix -import stix.utils as utils -import stix.ttp.malware_instance +from stix.bindings.extensions.malware import maec_4_1 as maec_instance_binding from stix.ttp.malware_instance import MalwareInstance -import stix.bindings.extensions.malware.maec_4_1 as ext_binding -from mixbox import fields -from stix.bindings.extensions.malware.maec_4_1 import maec_installed -from lxml.etree import _ElementTree - -_MIN_PYTHON_MAEC_VERSION = '4.1.0.12' - - -class UnsupportedVersion(Exception): - def __init__(self, message, expected, found): - super(UnsupportedVersion, self).__init__(message) - self.expected = expected - self.found = found -def _check_maec_version(): - """Checks that the installed python-maec has a version greater than or - equal to the minimum supported version. - - Note: - We do this rather than having a python-maec dependency requirement - listed in setup.py because MAEC is used as an extension to STIX and - not a core component to STIX (like CybOX). - - Raises: - ImportError: If python-maec is not installed. - UnsupportedVersion: If the python-maec installation does not satisfy - the version requirements. - +@stix.register_extension +class MAECInstance(MalwareInstance): """ - import maec - - found = maec.__version__ - expected = _MIN_PYTHON_MAEC_VERSION - - if LooseVersion(found) >= LooseVersion(expected): - return + The MAECInstance object provides an extension to the MalwareInstanceType + which imports and leverages the MAEC 4.1 schema for structured + characterization of Malware. - fmt = ("Unsupported python-maec version installed: '%s'. Minimum version " - "is '%s'.") - error = fmt % (found, expected) - raise UnsupportedVersion(error, expected=expected, found=found) - - -try: - # Check that the correct version of python-maec is installed. - _check_maec_version() - - # Import maecPackage into global space - from maec.package.package import Package as maecPackage - - _MAEC_INSTALLED = True -except ImportError: - maecPackage, Package = None, None - _MAEC_INSTALLED = False - - -def is_maec(obj): - """Checks if the input object is python-maec object. - - Returns: - True if python-maec is ins + This class extension is automatically registered by the + MalwareInstanceFactory. + Warnings: + Interacting with the ``maec`` field will fail if the maec library is + not installed in your Python environment. """ - if not _MAEC_INSTALLED: - return False - - return isinstance(obj, maecPackage) - -def validate_maec_input(instance, value): - if value is None: - return - elif _MAEC_INSTALLED and is_maec(value): - return - elif mixbox.xml.is_element(value) or mixbox.xml.is_etree(value): - return - else: - error = ( - "Cannot set maec to '{0}'. Expected 'lxml.etree._Element' or " - "'maec.package.package.Package'." - ) - error = error.format(type(value)) - raise ValueError(error) - -@stix.register_extension -class MAECInstance(MalwareInstance): - _binding = ext_binding + _binding = maec_instance_binding _binding_class = _binding.MAEC4_1InstanceType - _namespace = 'http://stix.mitre.org/extensions/Malware#MAEC4.1-1' - _xml_ns_prefix = "stix-maec" + _namespace = "http://stix.mitre.org/extensions/Malware#MAEC4.1-1" _XSI_TYPE = "stix-maec:MAEC4.1InstanceType" - _TAG_MAEC = "{%s}MAEC" % _namespace - maec = fields.TypedField("MAEC", preset_hook=validate_maec_input) + maec = fields.TypedField("MAEC", type_="maec.package.package.Package") def __init__(self, maec=None): super(MAECInstance, self).__init__() - self.__input_namespaces__ = {} - self.__input_schemalocations__ = {} self.maec = maec - - def _parse_etree(self, root): - node_tag = root.tag - - if node_tag != self._TAG_MAEC: - self._cast_maec(root) - - self._collect_namespaces(root) - self._collect_schemalocs(root) - - def _cast_maec(self, node): - ns_maec = "http://maec.mitre.org/XMLSchema/maec-package-2" - node_ns = etree.QName(node).namespace - - if node_ns == ns_maec: - etree.register_namespace(self._xml_ns_prefix, self._namespace) - node.tag = self._TAG_MAEC - else: - error = "Cannot set maec. Expected tag '{0}' found '{1}'." - error = error.format(self._TAG_MAEC, node.tag) - raise ValueError(error) - - def _collect_schemalocs(self, node): - try: - schemaloc = mixbox.xml.get_schemaloc_pairs(node) - self.__input_schemalocations__ = dict(schemaloc) - except KeyError: - self.__input_schemalocations__ = {} - - def _collect_namespaces(self, node): - self.__input_namespaces__ = dict(iteritems(node.nsmap)) - - @classmethod - def from_obj(cls, obj): - if not obj: - return None - - return_obj = cls() - - if _MAEC_INSTALLED: - obj.MAEC = maecPackage.from_obj(obj.MAEC) - else: - obj.MAEC = obj.MAEC - - return_obj = super(MAECInstance, cls).from_obj(obj) - - return return_obj - - def to_obj(self, ns_info=None): - return_obj = super(MAECInstance, self).to_obj(ns_info=ns_info) - - if mixbox.xml.is_element(self.maec) or mixbox.xml.is_etree(self.maec): - tree = mixbox.xml.get_etree(self.maec) - root = mixbox.xml.get_etree_root(tree) - self._parse_etree(root) - self.maec = root - - if _MAEC_INSTALLED and isinstance(self.maec, maecPackage): - return_obj.MAEC = self.maec.to_obj(ns_info=ns_info) - else: - return_obj.MAEC = self.maec - - return return_obj - - @classmethod - def _maec_from_dict(cls, d): - if _MAEC_INSTALLED: - return maecPackage.from_dict(d) - - raise ValueError( - "Unable to parse 'maec' value in dictionary. Please " - "install python-maec to parse dictionary value." - ) - - @classmethod - def from_dict(cls, d, return_obj=None): - if not d: - return None - - d = d.copy() - - maec = d.get('maec') - - if maec is None: - pass - elif isinstance(maec, dict): - d['maec'] = cls._maec_from_dict(maec) - elif isinstance(maec, binary_type): - d['maec'] = mixbox.xml.get_etree_root(BytesIO(maec)) - else: - raise TypeError("Unknown type for 'maec' entry.") - - return_obj = super(MAECInstance, cls).from_dict(d) - - return return_obj - - def to_dict(self): - d = super(MAECInstance, self).to_dict() - - if self.maec is not None: - if mixbox.xml.is_element(self.maec) or mixbox.xml.is_etree(self.maec): - tree = mixbox.xml.get_etree(self.maec) - root = mixbox.xml.get_etree_root(tree) - self._parse_etree(root) - self.maec = root - - if _MAEC_INSTALLED and isinstance(self.maec, maecPackage): - d['maec'] = self.maec.to_dict() - else: - d['maec'] = etree.tostring(self.maec) - - if self._XSI_TYPE: - d['xsi:type'] = self._XSI_TYPE - - return d diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index d8e9084b..8d74d4c0 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -43,75 +43,76 @@ def test_add_name_type(self): self.assertTrue("Remote Access Trojan" in maec_xml) -class PythonMAECEtreeTests(unittest.TestCase): - XML = ( - """ - - - - - - - - MD5 - 9d7006e30fdf15e9c8e03e62534b3a3e - - - - - - - - """ - ) - - def _test_xml(self, obj): - xml = obj.to_xml() - parser = mixbox.xml.get_xml_parser() - tree = etree.parse(BytesIO(xml), parser=parser) - root = tree.getroot() - - xpath = "//cyboxCommon:Type" - nodes = root.xpath(xpath, namespaces={'cyboxCommon': 'http://cybox.mitre.org/common-2'}) - - self.assertTrue(nodes is not None) - self.assertEqual(len(nodes), 1) - self.assertEqual(nodes[0].text, "MD5") - - - def test_etree(self): - parser = mixbox.xml.get_xml_parser() - tree = etree.parse(StringIO(self.XML), parser=parser) - - ext = MAECInstance() - ext.maec = tree - self._test_xml(ext) - - - def test_etree_dict(self): - parser = mixbox.xml.get_xml_parser() - tree = etree.parse(StringIO(self.XML), parser=parser) - ext = MAECInstance() - ext.maec = tree - - d = ext.to_dict() - ext2 = MAECInstance.from_dict(d) - self._test_xml(ext2) +# This test no longer reflects the proper usage of the MAECInstance object +# class PythonMAECEtreeTests(unittest.TestCase): +# XML = ( +# """ +# +# +# +# +# +# +# +# MD5 +# 9d7006e30fdf15e9c8e03e62534b3a3e +# +# +# +# +# +# +# +# """ +# ) +# +# def _test_xml(self, obj): +# xml = obj.to_xml() +# parser = mixbox.xml.get_xml_parser() +# tree = etree.parse(BytesIO(xml), parser=parser) +# root = tree.getroot() +# +# xpath = "//cyboxCommon:Type" +# nodes = root.xpath(xpath, namespaces={'cyboxCommon': 'http://cybox.mitre.org/common-2'}) +# +# self.assertTrue(nodes is not None) +# self.assertEqual(len(nodes), 1) +# self.assertEqual(nodes[0].text, "MD5") +# +# +# def test_etree(self): +# parser = mixbox.xml.get_xml_parser() +# tree = etree.parse(StringIO(self.XML), parser=parser) +# +# ext = MAECInstance() +# ext.maec = tree +# self._test_xml(ext) +# +# +# def test_etree_dict(self): +# parser = mixbox.xml.get_xml_parser() +# tree = etree.parse(StringIO(self.XML), parser=parser) +# ext = MAECInstance() +# ext.maec = tree +# +# d = ext.to_dict() +# ext2 = MAECInstance.from_dict(d) +# self._test_xml(ext2) class PythonMAECInPackageTests(unittest.TestCase): diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index 0d3b6ca7..109ad1cf 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -3,7 +3,6 @@ # internal import stix -import stix.utils as utils from stix.common import vocabs from stix.common import StructuredTextList, VocabString @@ -17,7 +16,7 @@ class MalwareInstance(stix.Entity): _binding = ttp_binding _binding_class = _binding.MalwareInstanceType _namespace = "http://stix.mitre.org/TTP-1" - _XSI_TYPE = None # defined by subclasses + _XSI_TYPE = None # defined by subclasses id_ = fields.IdField("id") idref = fields.IdrefField("idref") @@ -105,10 +104,19 @@ def lookup_class(xsi_type): return stix.lookup_extension(xsi_type) + def to_dict(self): + d = super(MalwareInstance, self).to_dict() + + if self._XSI_TYPE: + d["xsi:type"] = self._XSI_TYPE + + return d + class MalwareInstanceFactory(entities.EntityFactory): @classmethod def entity_class(cls, key): + from stix.extensions.malware.maec_4_1_malware import MAECInstance #noqa return stix.lookup_extension(key, default=MalwareInstance) # Backwards compatibility From f7261abfc92eadca15da0d77a5a138b8cfee5afc Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Thu, 22 Feb 2018 12:32:55 -0500 Subject: [PATCH 383/438] Update README and requirements --- README.rst | 11 +++++------ requirements.txt | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index fc01fbe7..6df07068 100644 --- a/README.rst +++ b/README.rst @@ -7,18 +7,17 @@ A python library for parsing, manipulating, and generating STIX v1.2 content. :Documentation: http://stix.readthedocs.org :Information: https://stixproject.github.io/ -|travis badge| |landscape.io badge| |version badge| |downloads badge| +|travis_badge| |landscape_io_badge| |version_badge| -.. |travis badge| image:: https://api.travis-ci.org/STIXProject/python-stix.svg?branch=master +.. |travis_badge| image:: https://api.travis-ci.org/STIXProject/python-stix.svg?branch=master :target: https://travis-ci.org/STIXProject/python-stix :alt: Build Status -.. |landscape.io badge| image:: https://landscape.io/github/STIXProject/python-stix/master/landscape.svg +.. |landscape_io_badge| image:: https://landscape.io/github/STIXProject/python-stix/master/landscape.svg :target: https://landscape.io/github/STIXProject/python-stix/master :alt: Code Health -.. |version badge| image:: https://img.shields.io/pypi/v/stix.svg?maxAge=3600 - :target: https://pypi.python.org/pypi/stix/ -.. |downloads badge| image:: https://img.shields.io/pypi/dm/stix.svg?maxAge=3600 +.. |version_badge| image:: https://img.shields.io/pypi/v/stix.svg?maxAge=3600 :target: https://pypi.python.org/pypi/stix/ + :alt: Version Installation diff --git a/requirements.txt b/requirements.txt index c27803bd..5262a086 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -maec>=4.1.0.13.dev4,<4.1.1.0 # For tests that include MAEC +maec>=4.1.0.13<4.1.1.0 # For tests that include MAEC nose==1.3.7 sphinx==1.3.6 sphinx_rtd_theme==0.2.4 From 67170b8b979b153c9c357c15fa0214f8453bc124 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Thu, 22 Feb 2018 12:40:14 -0500 Subject: [PATCH 384/438] Update requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5262a086..14df8061 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -maec>=4.1.0.13<4.1.1.0 # For tests that include MAEC +maec>=4.1.0.13,<4.1.1.0 # For tests that include MAEC nose==1.3.7 sphinx==1.3.6 sphinx_rtd_theme==0.2.4 From 9422892a4107963ad9c9a78e4a04a2a23a9f805e Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 23 Feb 2018 08:09:11 -0500 Subject: [PATCH 385/438] Format changes and Report TTPs test --- stix/test/report_test.py | 9 +++++++++ stix/ttp/malware_instance.py | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/stix/test/report_test.py b/stix/test/report_test.py index 334ef519..35f63d54 100644 --- a/stix/test/report_test.py +++ b/stix/test/report_test.py @@ -6,6 +6,7 @@ from stix import report from stix.test import EntityTestCase, data_marking_test +from stix.test.core import stix_package_test from stix.test.common import (information_source_test, structured_text_test, related_test) @@ -116,6 +117,14 @@ class ReportTests(EntityTestCase, unittest.TestCase): 'version': "1.0" } + def test_report_with_stix_core_ttps_fails(self): + r = self.klass() + + with self.assertRaises(TypeError) as exc_info: + r.ttps = stix_package_test.TTPsTests.klass() + + assert str(exc_info.exception) == 'TTPs must be a , not a ' + if __name__ == "__main__": unittest.main() diff --git a/stix/ttp/malware_instance.py b/stix/ttp/malware_instance.py index 109ad1cf..d80359bd 100644 --- a/stix/ttp/malware_instance.py +++ b/stix/ttp/malware_instance.py @@ -116,8 +116,9 @@ def to_dict(self): class MalwareInstanceFactory(entities.EntityFactory): @classmethod def entity_class(cls, key): - from stix.extensions.malware.maec_4_1_malware import MAECInstance #noqa + from stix.extensions.malware.maec_4_1_malware import MAECInstance # noqa return stix.lookup_extension(key, default=MalwareInstance) + # Backwards compatibility add_extension = stix.add_extension From 6942fb8f592a249ed3739cc6df29ba49a58aa658 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 23 Feb 2018 09:01:25 -0500 Subject: [PATCH 386/438] Fix tests for report and stix_package --- stix/test/core/stix_package_test.py | 14 +++++++++++++- stix/test/report_test.py | 4 ++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index bfde2d15..c0258534 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -12,7 +12,7 @@ from . import stix_header_test -from stix import core +from stix import core, report from stix.core import stix_package from stix.campaign import Campaign from stix.coa import CourseOfAction @@ -39,6 +39,7 @@ class COAsTests(EntityTestCase, unittest.TestCase): {'idref': 'example:test-1'} ] + class ExploitTargetsTests(EntityTestCase, unittest.TestCase): klass = stix_package.ExploitTargets @@ -46,6 +47,7 @@ class ExploitTargetsTests(EntityTestCase, unittest.TestCase): {'idref': 'example:test-1'} ] + class IncidentsTests(EntityTestCase, unittest.TestCase): klass = stix_package.Incidents @@ -53,6 +55,7 @@ class IncidentsTests(EntityTestCase, unittest.TestCase): {'idref': 'example:test-1'} ] + class IndicatorsTests(EntityTestCase, unittest.TestCase): klass = stix_package.Indicators @@ -68,6 +71,7 @@ class ThreatActorsTests(EntityTestCase, unittest.TestCase): {'idref': 'example:test-1'} ] + class TTPsTests(EntityTestCase, unittest.TestCase): klass = stix_package.TTPs @@ -188,6 +192,14 @@ def test_related_package_idref_deprecation(self): package = core.STIXPackage() package.add_related_package(core.STIXPackage(idref='foo')) + def test_setting_report_ttps_fails_on_stix_package(self): + package = core.STIXPackage() + + with self.assertRaises(TypeError) as exc_info: + package.ttps = report.TTPs() + + assert str(exc_info.exception) == 'TTPs must be a , not a ' + if __name__ == "__main__": unittest.main() diff --git a/stix/test/report_test.py b/stix/test/report_test.py index 35f63d54..be09b1a0 100644 --- a/stix/test/report_test.py +++ b/stix/test/report_test.py @@ -4,9 +4,9 @@ import unittest from stix import report +from stix.core.ttps import TTPs from stix.test import EntityTestCase, data_marking_test -from stix.test.core import stix_package_test from stix.test.common import (information_source_test, structured_text_test, related_test) @@ -121,7 +121,7 @@ def test_report_with_stix_core_ttps_fails(self): r = self.klass() with self.assertRaises(TypeError) as exc_info: - r.ttps = stix_package_test.TTPsTests.klass() + r.ttps = TTPs() assert str(exc_info.exception) == 'TTPs must be a , not a ' From e0c487e182fe9a6c7398db6bd599277f643641af Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 23 Feb 2018 09:14:34 -0500 Subject: [PATCH 387/438] Fix tests for backwards Python compatibility --- stix/test/core/stix_package_test.py | 7 +------ stix/test/report_test.py | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index c0258534..47e31db4 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -193,12 +193,7 @@ def test_related_package_idref_deprecation(self): package.add_related_package(core.STIXPackage(idref='foo')) def test_setting_report_ttps_fails_on_stix_package(self): - package = core.STIXPackage() - - with self.assertRaises(TypeError) as exc_info: - package.ttps = report.TTPs() - - assert str(exc_info.exception) == 'TTPs must be a , not a ' + self.assertRaises(TypeError, core.STIXPackage(), report.TTPs(), 'TTPs must be a , not a ') if __name__ == "__main__": diff --git a/stix/test/report_test.py b/stix/test/report_test.py index be09b1a0..f99ecb7f 100644 --- a/stix/test/report_test.py +++ b/stix/test/report_test.py @@ -118,12 +118,7 @@ class ReportTests(EntityTestCase, unittest.TestCase): } def test_report_with_stix_core_ttps_fails(self): - r = self.klass() - - with self.assertRaises(TypeError) as exc_info: - r.ttps = TTPs() - - assert str(exc_info.exception) == 'TTPs must be a , not a ' + self.assertRaises(TypeError, self.klass().ttps, TTPs(), 'TTPs must be a , not a ') if __name__ == "__main__": From f37e71128ee8ae5b14c77f46fa9e84507475f02a Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 27 Feb 2018 10:58:13 -0600 Subject: [PATCH 388/438] GH-325: Add tests to verify desired behavior. --- stix/test/indicator_test.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/stix/test/indicator_test.py b/stix/test/indicator_test.py index a8f06c68..953a076c 100644 --- a/stix/test/indicator_test.py +++ b/stix/test/indicator_test.py @@ -6,6 +6,7 @@ from cybox.core import Observable, ObservableComposition from cybox.objects.file_object import File +import mixbox.typedlist from mixbox.vendor.six import text_type from stix.core import STIXPackage @@ -493,6 +494,36 @@ def test_observables_property_standard(self): self.assertEqual([obs.to_dict()], [x.to_dict() for x in ind2.observables]) + def test_set_indicator_observables_to_single_observable(self): + # https://github.com/STIXProject/python-stix/issues/325 + i = Indicator() + o1 = Observable() + o2 = Observable() + + i.observables = o1 + self.assertEqual(type([]), type(i.observables)) + self.assertEqual(1, len(i.observables)) + + def test_set_indicator_observables_to_list_of_two_observables(self): + # https://github.com/STIXProject/python-stix/issues/325 + i = Indicator() + o1 = Observable() + o2 = Observable() + + i.observables = [o1, o2] + self.assertEqual(mixbox.typedlist.TypedList, type(i.observables)) + self.assertEqual(2, len(i.observables)) + + def test_set_indicator_observables_to_list_of_one_observable(self): + # https://github.com/STIXProject/python-stix/issues/325 + i = Indicator() + o1 = Observable() + o2 = Observable() + + i.observables = [o1] + self.assertEqual(type([]), type(i.observables)) + self.assertEqual(1, len(i.observables)) + class RelatedCampaignReferencesTests(unittest.TestCase, EntityTestCase): klass = RelatedCampaignRefs From 97a105bc4243577ceea81264ef62c41b6b6a5803 Mon Sep 17 00:00:00 2001 From: Greg Back Date: Tue, 27 Feb 2018 16:39:25 -0600 Subject: [PATCH 389/438] Remove commented test. --- .../malware/maec_4_1_malware_test.py | 80 +------------------ 1 file changed, 4 insertions(+), 76 deletions(-) diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index 8d74d4c0..7edb13d8 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -43,82 +43,10 @@ def test_add_name_type(self): self.assertTrue("Remote Access Trojan" in maec_xml) -# This test no longer reflects the proper usage of the MAECInstance object -# class PythonMAECEtreeTests(unittest.TestCase): -# XML = ( -# """ -# -# -# -# -# -# -# -# MD5 -# 9d7006e30fdf15e9c8e03e62534b3a3e -# -# -# -# -# -# -# -# """ -# ) -# -# def _test_xml(self, obj): -# xml = obj.to_xml() -# parser = mixbox.xml.get_xml_parser() -# tree = etree.parse(BytesIO(xml), parser=parser) -# root = tree.getroot() -# -# xpath = "//cyboxCommon:Type" -# nodes = root.xpath(xpath, namespaces={'cyboxCommon': 'http://cybox.mitre.org/common-2'}) -# -# self.assertTrue(nodes is not None) -# self.assertEqual(len(nodes), 1) -# self.assertEqual(nodes[0].text, "MD5") -# -# -# def test_etree(self): -# parser = mixbox.xml.get_xml_parser() -# tree = etree.parse(StringIO(self.XML), parser=parser) -# -# ext = MAECInstance() -# ext.maec = tree -# self._test_xml(ext) -# -# -# def test_etree_dict(self): -# parser = mixbox.xml.get_xml_parser() -# tree = etree.parse(StringIO(self.XML), parser=parser) -# ext = MAECInstance() -# ext.maec = tree -# -# d = ext.to_dict() -# ext2 = MAECInstance.from_dict(d) -# self._test_xml(ext2) - - class PythonMAECInPackageTests(unittest.TestCase): XML = StringIO( """ - @@ -151,7 +79,7 @@ class PythonMAECInPackageTests(unittest.TestCase): ) XML_MAEC = StringIO( """ - From 6336210969215c97524c9aa16396c970dc4c16d7 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 28 Feb 2018 10:47:08 -0500 Subject: [PATCH 390/438] Register AttackerToolType for cybox. Provide more information in error message --- stix/common/vocabs.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/stix/common/vocabs.py b/stix/common/vocabs.py index 98b74a58..462d757b 100644 --- a/stix/common/vocabs.py +++ b/stix/common/vocabs.py @@ -5,9 +5,10 @@ from functools import partial # mixbox -from mixbox import fields -from mixbox import entities -from mixbox import typedlist +from mixbox import entities, fields, typedlist + +# cybox +from cybox.common import vocabs # stix import stix @@ -24,7 +25,7 @@ def validate_value(instance, value): elif value in allowed: return else: - error = "Value must be one of {allowed}. Received '{value}'" + error = "Value for vocab {instance.__class__} must be one of {allowed}. Received '{value}'" error = error.format(**locals()) raise ValueError(error) @@ -124,7 +125,6 @@ def to_dict(self): return self.value return super(VocabString, self).to_dict() - @classmethod def from_dict(cls, cls_dict): if not cls_dict: @@ -306,8 +306,9 @@ class DiscoveryMethod_2_0(VocabString): TERM_USER = "User" +@vocabs.register_vocab @register_vocab -class AttackerToolType_1_0(VocabString): +class AttackerToolType_1_0(vocabs.VocabString): _namespace = 'http://stix.mitre.org/default_vocabularies-1' _XSI_TYPE = 'stixVocabs:AttackerToolTypeVocab-1.0' _VOCAB_VERSION = '1.0' From 933875a40db6d82abe0964df191cc00f30c0faec Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 28 Feb 2018 10:48:00 -0500 Subject: [PATCH 391/438] Modify test to assert vocab works as intended --- stix/test/ttp_test.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/stix/test/ttp_test.py b/stix/test/ttp_test.py index 8e6b537a..da9c4b88 100644 --- a/stix/test/ttp_test.py +++ b/stix/test/ttp_test.py @@ -71,7 +71,13 @@ class ResourcesTests(EntityTestCase, unittest.TestCase): 'personas': PersonasTests._full_dict, 'tools': [ { - 'title': "Tool" + 'title': "Tool", + 'type': [ + { + 'value': 'Malware', + 'xsi:type': 'stixVocabs:AttackerToolTypeVocab-1.0' + } + ] } ], 'infrastructure': InfrastructureTests._full_dict @@ -81,7 +87,7 @@ class ResourcesTests(EntityTestCase, unittest.TestCase): class MalwareInstanceTests(EntityTestCase, unittest.TestCase): klass = malware_instance.MalwareInstance - _full_dict = _full_dict = { + _full_dict = { 'id': 'example:test-1', 'title': 'Title', 'description': 'Description', @@ -156,6 +162,7 @@ class BehaviorTests(EntityTestCase, unittest.TestCase): 'attack_patterns': AttackPatternsTests._full_dict } + class TTPTests(EntityTestCase, unittest.TestCase): klass = ttp.TTP _full_dict = { From bb44e559963e74b55ce02fcdbd04075c798be2c6 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 28 Feb 2018 13:15:13 -0500 Subject: [PATCH 392/438] Fix imports in resource.py --- stix/ttp/resource.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/stix/ttp/resource.py b/stix/ttp/resource.py index e6b99d9b..cabdef4a 100644 --- a/stix/ttp/resource.py +++ b/stix/ttp/resource.py @@ -2,19 +2,15 @@ # See LICENSE.txt for complete terms. # mixbox -from mixbox import fields -from mixbox import typedlist +from mixbox import fields, typedlist # internal import stix +import stix.bindings.ttp as ttp_binding from stix.common import ToolInformation from stix.common.identity import Identity, IdentityFactory -import stix.bindings.ttp as ttp_binding - -# relative -from .infrastructure import Infrastructure +from stix.ttp.infrastructure import Infrastructure -from mixbox import entities, fields class _IdentityList(typedlist.TypedList): def __init__(self, *args): From b936be2d708f9cea4031262e656a36f82ee778cc Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 28 Feb 2018 13:16:05 -0500 Subject: [PATCH 393/438] stix ToolInformation overrides type_ to AttackerToolType vocab --- stix/common/tools.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stix/common/tools.py b/stix/common/tools.py index 6d32d266..5cc0f155 100644 --- a/stix/common/tools.py +++ b/stix/common/tools.py @@ -3,7 +3,9 @@ # external from mixbox import fields + import cybox.common +from cybox.common.vocabs import VocabField # internal import stix @@ -11,6 +13,7 @@ # relative from .structured_text import StructuredTextList +from .vocabs import AttackerToolType class ToolInformation(stix.Entity, cybox.common.ToolInformation): @@ -20,6 +23,7 @@ class ToolInformation(stix.Entity, cybox.common.ToolInformation): title = fields.TypedField("Title") short_descriptions = fields.TypedField("Short_Description", StructuredTextList) + type_ = VocabField("Type", AttackerToolType, multiple=True) def __init__(self, title=None, short_description=None, tool_name=None, tool_vendor=None): super(ToolInformation, self).__init__(tool_name=tool_name, tool_vendor=tool_vendor) From 13a33a5a13b15bd6029209e7c635ee10f3e1631f Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 28 Feb 2018 14:05:22 -0500 Subject: [PATCH 394/438] Refactor MAEC tests to include behavior when library is not installed. closes #343 --- .../malware/maec_4_1_malware_test.py | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index 7edb13d8..59d23f5a 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -1,14 +1,18 @@ import unittest from stix.core import STIXPackage -from mixbox.vendor.six import StringIO, BytesIO, text_type - -from lxml import etree -import mixbox.xml +from mixbox.vendor.six import StringIO, text_type from stix.test import EntityTestCase from stix.extensions.malware.maec_4_1_malware import MAECInstance +try: + import maec + maec_present = True +except ImportError: + maec_present = False + +@unittest.skipIf(condition=maec_present, reason="These tests require the 'maec' library.") class PythonMAECTests(EntityTestCase, unittest.TestCase): klass = MAECInstance @@ -43,6 +47,7 @@ def test_add_name_type(self): self.assertTrue("Remote Access Trojan" in maec_xml) +@unittest.skipIf(condition=maec_present, reason="These tests require the 'maec' library.") class PythonMAECInPackageTests(unittest.TestCase): XML = StringIO( """ @@ -138,5 +143,28 @@ def test_parse_malware_maec(self): self.assertTrue('names' in mw) +@unittest.skipIf(condition=not maec_present, reason="These tests require the 'maec' library.") +class PythonMAECNotInstalledTest(unittest.TestCase): + + def test_parsing_maec_fails(self): + try: + STIXPackage.from_xml(PythonMAECInPackageTests.XML_MAEC) + except ImportError as e: + self.assertEqual(str(e), "No module named 'maec'") + + def test_handling_maec_object_fails(self): + try: + MAECInstance().from_dict(PythonMAECTests._full_dict) + except ImportError as e: + self.assertEqual(str(e), "No module named 'maec'") + + def test_setting_maec_property_fails(self): + try: + m = MAECInstance() + m.maec = "foo" + except ImportError as e: + self.assertEqual(str(e), "No module named 'maec'") + + if __name__ == "__main__": unittest.main() From 5b80722a19b74f284f79d70a35139afb80df94f8 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 28 Feb 2018 14:06:25 -0500 Subject: [PATCH 395/438] Add no-maec test environment to simulate behavior when 'maec' is not present. --- tox.ini | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/tox.ini b/tox.ini index 450e4418..f9bf3cb9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py26, py27, py33, py34, py35, py36, lxml23 +envlist = py26, py27, py33, py34, py35, py36, lxml23, no-maec [testenv] commands = @@ -22,11 +22,19 @@ deps = python-dateutil==1.4.1 -rrequirements.txt +# Test the behavior when MAEC is not installed in the environment. +[testenv:no-maec] +commands = + nosetests stix +deps = + nose==1.3.7 + tox==2.7.0 + [travis] python = - 2.6: py26, lxml23 - 2.7: py27, docs - 3.3: py33 - 3.4: py34 - 3.5: py35 - 3.6: py36 + 2.6: py26, lxml23, no-maec + 2.7: py27, docs, no-maec + 3.3: py33, no-maec + 3.4: py34, no-maec + 3.5: py35, no-maec + 3.6: py36, no-maec From 1ef1ba1dd52b6ada2b3747b1ce0085fefe7b12c9 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 28 Feb 2018 14:22:43 -0500 Subject: [PATCH 396/438] Some changes to MAEC tests --- .../malware/maec_4_1_malware_test.py | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index 59d23f5a..51cabdf8 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -12,7 +12,7 @@ maec_present = False -@unittest.skipIf(condition=maec_present, reason="These tests require the 'maec' library.") +@unittest.skipIf(condition=maec_present is True, reason="These tests require the 'maec' library.") class PythonMAECTests(EntityTestCase, unittest.TestCase): klass = MAECInstance @@ -21,18 +21,20 @@ class PythonMAECTests(EntityTestCase, unittest.TestCase): 'maec': { 'malware_subjects': [ - {'malware_instance_object_attributes': - {'id': 'maec-tst-obj-1', - 'properties': { - 'hashes': - [ - { - 'simple_hash_value': '9d7006e30fdf15e9c8e03e62534b3a3e', - 'type': 'MD5' - } - ], - 'xsi:type': 'FileObjectType'} - } + { + 'malware_instance_object_attributes': { + 'id': 'maec-tst-obj-1', + 'properties': { + 'hashes': + [ + { + 'simple_hash_value': '9d7006e30fdf15e9c8e03e62534b3a3e', + 'type': 'MD5' + } + ], + 'xsi:type': 'FileObjectType' + } + } } ] } @@ -47,7 +49,7 @@ def test_add_name_type(self): self.assertTrue("Remote Access Trojan" in maec_xml) -@unittest.skipIf(condition=maec_present, reason="These tests require the 'maec' library.") +@unittest.skipIf(condition=maec_present is True, reason="These tests require the 'maec' library.") class PythonMAECInPackageTests(unittest.TestCase): XML = StringIO( """ @@ -143,7 +145,7 @@ def test_parse_malware_maec(self): self.assertTrue('names' in mw) -@unittest.skipIf(condition=not maec_present, reason="These tests require the 'maec' library.") +@unittest.skipIf(condition=maec_present is False, reason="These tests require the 'maec' library to be missing.") class PythonMAECNotInstalledTest(unittest.TestCase): def test_parsing_maec_fails(self): From 691285d9c91c51e53673f0119854439aec7f34d3 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 28 Feb 2018 14:44:02 -0500 Subject: [PATCH 397/438] Yet again... fix maec_malware_test.py --- stix/test/extensions/malware/maec_4_1_malware_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index 51cabdf8..45e898e1 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -12,7 +12,7 @@ maec_present = False -@unittest.skipIf(condition=maec_present is True, reason="These tests require the 'maec' library.") +@unittest.skipIf(condition=maec_present is False, reason="These tests require the 'maec' library.") class PythonMAECTests(EntityTestCase, unittest.TestCase): klass = MAECInstance @@ -49,7 +49,7 @@ def test_add_name_type(self): self.assertTrue("Remote Access Trojan" in maec_xml) -@unittest.skipIf(condition=maec_present is True, reason="These tests require the 'maec' library.") +@unittest.skipIf(condition=maec_present is False, reason="These tests require the 'maec' library.") class PythonMAECInPackageTests(unittest.TestCase): XML = StringIO( """ @@ -145,7 +145,7 @@ def test_parse_malware_maec(self): self.assertTrue('names' in mw) -@unittest.skipIf(condition=maec_present is False, reason="These tests require the 'maec' library to be missing.") +@unittest.skipIf(condition=maec_present is True, reason="These tests require the 'maec' library to be missing.") class PythonMAECNotInstalledTest(unittest.TestCase): def test_parsing_maec_fails(self): From de4a3a9244d434ba964664ade1943fba0443d913 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 28 Feb 2018 16:20:41 -0500 Subject: [PATCH 398/438] Fix timestamp in Report to DateTimeField. closes #342 --- stix/report/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stix/report/__init__.py b/stix/report/__init__.py index c2d18b3b..b83070e7 100644 --- a/stix/report/__init__.py +++ b/stix/report/__init__.py @@ -43,7 +43,7 @@ class Report(stix.Entity): ``datetime.datetime`` or ``str``. header: A Report :class:`.Header` object. campaigns: A collection of :class:`.Campaign` objects. - course_of_action: A collection of :class:`.CourseOfAction` objects. + courses_of_action: A collection of :class:`.CourseOfAction` objects. exploit_targets: A collection of :class:`.ExploitTarget` objects. incidents: A collection of :class:`.Incident` objects. indicators: A collection of :class:`.Indicator` objects. @@ -59,7 +59,7 @@ class Report(stix.Entity): id_ = fields.IdField("id") idref = fields.IdrefField("idref") - timestamp = fields.TypedField("timestamp") + timestamp = fields.DateTimeField("timestamp") version = fields.TypedField("version") header = fields.TypedField("Header", Header) campaigns = fields.TypedField("Campaigns", type_="stix.report.Campaigns") From 803c3701676382cd999b3e7ec23a036eaf5231f8 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 28 Feb 2018 16:28:22 -0500 Subject: [PATCH 399/438] Fix time in JournalEntry to DateTimeField --- stix/incident/history.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/stix/incident/history.py b/stix/incident/history.py index 5b44aa1a..175d2ed0 100644 --- a/stix/incident/history.py +++ b/stix/incident/history.py @@ -1,16 +1,16 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from mixbox import fields + # internal import stix -import stix.utils as utils import stix.bindings.incident as incident_binding from stix.common.datetimewithprecision import DATETIME_PRECISION_VALUES # relative from .coa import COATaken -from mixbox import fields, entities def validate_precision(instance, value): if value and (value not in DATETIME_PRECISION_VALUES): @@ -18,6 +18,7 @@ def validate_precision(instance, value): error = error.format(DATETIME_PRECISION_VALUES, value) raise ValueError(error) + class JournalEntry(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding @@ -25,7 +26,7 @@ class JournalEntry(stix.Entity): value = fields.TypedField("valueOf_", key_name="value") author = fields.TypedField("author") - time = fields.TypedField("time") #TDOO: utils.dates.parse_value(value) + time = fields.DateTimeField("time") time_precision = fields.TypedField("time_precision", preset_hook=validate_precision) def __init__(self, value=None): @@ -38,10 +39,10 @@ class HistoryItem(stix.Entity): _namespace = "http://stix.mitre.org/Incident-1" _binding = incident_binding _binding_class = incident_binding.HistoryItemType - + action_entry = fields.TypedField("Action_Entry", COATaken) journal_entry = fields.TypedField("Journal_Entry", JournalEntry) - + def __init__(self): super(HistoryItem, self).__init__() @@ -52,8 +53,7 @@ class History(stix.EntityList): _binding_class = incident_binding.HistoryType history_items = fields.TypedField("History_Item", HistoryItem, multiple=True, key_name="history_items") - + @classmethod def _dict_as_list(cls): return False - \ No newline at end of file From 25f376ba56aa3b75ca39fd779ef72288e44568eb Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 2 Mar 2018 13:18:50 -0500 Subject: [PATCH 400/438] Fix maec tests --- stix/test/extensions/malware/maec_4_1_malware_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index 45e898e1..1829246c 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -152,20 +152,20 @@ def test_parsing_maec_fails(self): try: STIXPackage.from_xml(PythonMAECInPackageTests.XML_MAEC) except ImportError as e: - self.assertEqual(str(e), "No module named 'maec'") + self.assertTrue(all(x in str(e) for x in ("No module named", "maec"))) def test_handling_maec_object_fails(self): try: MAECInstance().from_dict(PythonMAECTests._full_dict) except ImportError as e: - self.assertEqual(str(e), "No module named 'maec'") + self.assertTrue(all(x in str(e) for x in ("No module named", "maec"))) def test_setting_maec_property_fails(self): try: m = MAECInstance() m.maec = "foo" except ImportError as e: - self.assertEqual(str(e), "No module named 'maec'") + self.assertTrue(all(x in str(e) for x in ("No module named", "maec"))) if __name__ == "__main__": From 4916e5abb785c968ed0b2ab83b4626360c7b026a Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 2 Mar 2018 14:34:08 -0500 Subject: [PATCH 401/438] Fix install_requires and setup classifiers --- setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 74f729dd..fb657a39 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ def get_version(): install_requires = [ 'lxml>=2.3', 'python-dateutil', - 'cybox>=2.1.0.13.dev1,<2.1.1.0', + 'cybox>=2.1.0.13,<2.1.1.0', 'mixbox>=1.0.2', ] @@ -48,7 +48,6 @@ def get_version(): 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', From 8ee624a9805a4f64ee9cbfa31e57195c1d2ad53a Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 2 Mar 2018 14:39:54 -0500 Subject: [PATCH 402/438] Remove py26 from our CI tests --- .travis.yml | 1 - docs/getting_started.rst | 2 +- tox.ini | 7 +++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index e3485ff6..d38a6fa1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: python python: - - "2.6" - "2.7" - "3.3" - "3.4" diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 10e291ba..5a48b125 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -10,7 +10,7 @@ This page gives an introduction to **python-stix** and how to use it. Prerequisites ------------- -The python-stix library provides an API for creating or processing STIX content. As such, it is a developer tool that can be leveraged by those who know Python 2.6/2.7 and are familiar with object-oriented programming practices, Python package layouts, and are comfortable with the installation of Python libraries. To contribute code to the python-stix repository, users must be familiar with `git`_ and `GitHub pull request`_ methodologies. Understanding XML, XML Schema, and the STIX language is also incredibly helpful when using python-stix in an application. +The python-stix library provides an API for creating or processing STIX content. As such, it is a developer tool that can be leveraged by those who know Python 2.7/3.3+ and are familiar with object-oriented programming practices, Python package layouts, and are comfortable with the installation of Python libraries. To contribute code to the python-stix repository, users must be familiar with `git`_ and `GitHub pull request`_ methodologies. Understanding XML, XML Schema, and the STIX language is also incredibly helpful when using python-stix in an application. .. _git: http://git-scm.com/documentation .. _GitHub pull request: https://help.github.com/articles/using-pull-requests diff --git a/tox.ini b/tox.ini index f9bf3cb9..c62be2ae 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py26, py27, py33, py34, py35, py36, lxml23, no-maec +envlist = py27, py33, py34, py35, py36, lxml23, no-maec [testenv] commands = @@ -13,7 +13,7 @@ deps = # We call this "lxml23" instead of "rhel6", since RHEL6 ships with LXML 2.2.3. # python-stix requires at least 2.3. [testenv:lxml23] -basepython=python2.6 +basepython=python2.7 commands = nosetests stix deps = @@ -32,8 +32,7 @@ deps = [travis] python = - 2.6: py26, lxml23, no-maec - 2.7: py27, docs, no-maec + 2.7: py27, docs, lxml23, no-maec 3.3: py33, no-maec 3.4: py34, no-maec 3.5: py35, no-maec From 095b715317ebdfffdf2ed86e09b77c0d9cda6949 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Tue, 6 Mar 2018 12:52:14 -0500 Subject: [PATCH 403/438] Update CHANGES.txt --- CHANGES.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index db34abe5..a6e42e97 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,13 @@ +Version 1.2.0.5 +2018-03-06 +- #343 Create separate test environments for when maec is or is not installed +- #342 to_json fails on parsing datetime +- #339 [Python3 not supported - v1.1/1.2] to_json vaguely broken on some files +- #336 Report field ttp has the wrong type information +- #325 Bug in Indicator class setter for observables property +- Change stix.ToolInformation to use AttackerToolType vocab +- Removed Python 2.6 environment from CI tests + Version 1.2.0.4 2017-05-02 - Add support for Python 3.6. From 1b34956f6b347c10a42f21d394c4ee69fd60eb41 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Tue, 6 Mar 2018 12:56:12 -0500 Subject: [PATCH 404/438] =?UTF-8?q?Bump=20version:=201.2.0.4=20=E2=86=92?= =?UTF-8?q?=201.2.0.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/index.rst | 6 +++--- stix/version.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index b26e81c1..5ac464a6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,15 +22,15 @@ version of STIX. ============ =================== STIX Version python-stix Version ============ =================== -1.2 1.2.0.4 (`PyPI`__) (`GitHub`__) +1.2 1.2.0.5 (`PyPI`__) (`GitHub`__) 1.1.1 1.1.1.8 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) ============ =================== -__ https://pypi.python.org/pypi/stix/1.2.0.4 -__ https://github.com/STIXProject/python-stix/tree/v1.2.0.4 +__ https://pypi.python.org/pypi/stix/1.2.0.5 +__ https://github.com/STIXProject/python-stix/tree/v1.2.0.5 __ https://pypi.python.org/pypi/stix/1.1.1.8 __ https://github.com/STIXProject/python-stix/tree/v1.1.1.8 __ https://pypi.python.org/pypi/stix/1.1.0.6 diff --git a/stix/version.py b/stix/version.py index 956c4394..63c24dd6 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.5.dev0" +__version__ = "1.2.0.5" From f6154cceaeb9d9be718df8f21153b09052bd597c Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 23 Apr 2018 08:07:54 -0400 Subject: [PATCH 405/438] Add 'targeted_technical_details' TypedField to VictimTargeting --- stix/ttp/victim_targeting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stix/ttp/victim_targeting.py b/stix/ttp/victim_targeting.py index 8649c1b9..f6364193 100644 --- a/stix/ttp/victim_targeting.py +++ b/stix/ttp/victim_targeting.py @@ -7,7 +7,7 @@ # internal import stix import stix.bindings.ttp as ttp_binding -from stix.common import vocabs, VocabString +from stix.common import vocabs from stix.common.identity import Identity, IdentityFactory from mixbox import fields @@ -21,6 +21,7 @@ class VictimTargeting(stix.Entity): targeted_systems = vocabs.VocabField("Targeted_Systems", vocabs.SystemType, multiple=True) targeted_information = vocabs.VocabField("Targeted_Information", vocabs.InformationType, multiple=True) + targeted_technical_details = fields.TypedField("Targeted_Technical_Details", Observables) def __init__(self): super(VictimTargeting, self).__init__() From adc9161dc1b0c88f670b7279b08b569a80605915 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 23 Apr 2018 08:09:14 -0400 Subject: [PATCH 406/438] Add test for VictimTargeting objects. closes #347 --- stix/test/ttp_test.py | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/stix/test/ttp_test.py b/stix/test/ttp_test.py index da9c4b88..ef43689f 100644 --- a/stix/test/ttp_test.py +++ b/stix/test/ttp_test.py @@ -12,7 +12,7 @@ import stix.ttp as ttp from stix.ttp import ( resource, infrastructure, exploit_targets, malware_instance, exploit, - attack_pattern, behavior + attack_pattern, behavior, victim_targeting ) @@ -163,6 +163,43 @@ class BehaviorTests(EntityTestCase, unittest.TestCase): } +class VictimTargetingTests(EntityTestCase, unittest.TestCase): + klass = victim_targeting.VictimTargeting + + _full_dict = { + 'identity': { + 'specification': { + 'organisation_info': { + 'industry_type': 'Electricity, Industrial Control Systems' + } + }, + 'xsi:type': 'stix-ciqidentity:CIQIdentity3.0InstanceType' + }, + 'targeted_systems': [ + { + 'value': 'Industrial Control Systems', + 'xsi:type': 'stixVocabs:SystemTypeVocab-1.0' + } + ], + 'targeted_information': [ + { + 'value': 'Information Assets - Intellectual Property', + 'xsi:type': 'stixVocabs:InformationTypeVocab-1.0' + } + ], + 'targeted_technical_details': { + 'major_version': 2, + 'minor_version': 1, + 'update_version': 0, + 'observables': [ + { + 'idref': "example:Observable-2" + } + ] + } + } + + class TTPTests(EntityTestCase, unittest.TestCase): klass = ttp.TTP _full_dict = { @@ -176,7 +213,8 @@ class TTPTests(EntityTestCase, unittest.TestCase): 'exploit_targets': ExploitTargetsTests._full_dict, 'behavior': BehaviorTests._full_dict, 'related_packages': related_test.RelatedPackageRefsTests._full_dict, - 'kill_chain_phases': kill_chains_test.KillChainPhasesReferenceTests._full_dict + 'kill_chain_phases': kill_chains_test.KillChainPhasesReferenceTests._full_dict, + 'victim_targeting': VictimTargetingTests._full_dict } def test_add_description(self): From 8ff2c1d4f04d9b7e439643283b4993d66fcc49c1 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 25 Apr 2018 12:34:08 -0400 Subject: [PATCH 407/438] Update STIX 1.1.1.X index links --- docs/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 5ac464a6..97a01d4b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -23,7 +23,7 @@ version of STIX. STIX Version python-stix Version ============ =================== 1.2 1.2.0.5 (`PyPI`__) (`GitHub`__) -1.1.1 1.1.1.8 (`PyPI`__) (`GitHub`__) +1.1.1 1.1.1.12 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) @@ -31,8 +31,8 @@ STIX Version python-stix Version __ https://pypi.python.org/pypi/stix/1.2.0.5 __ https://github.com/STIXProject/python-stix/tree/v1.2.0.5 -__ https://pypi.python.org/pypi/stix/1.1.1.8 -__ https://github.com/STIXProject/python-stix/tree/v1.1.1.8 +__ https://pypi.python.org/pypi/stix/1.1.1.12 +__ https://github.com/STIXProject/python-stix/tree/v1.1.1.12 __ https://pypi.python.org/pypi/stix/1.1.0.6 __ https://github.com/STIXProject/python-stix/tree/v1.1.0.6 __ https://pypi.python.org/pypi/stix/1.0.1.1 From 45a65dd886dbe608cdc1f1baac48cd3b3a112c22 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 25 Apr 2018 12:40:19 -0400 Subject: [PATCH 408/438] Update CHANGES.txt for Version 1.2.0.6 --- CHANGES.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index a6e42e97..4ff6a402 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,7 @@ +Version 1.2.0.6 +2018-04-25 +- #347 Property targeted_technical_details missing in VictimTargeting class + Version 1.2.0.5 2018-03-06 - #343 Create separate test environments for when maec is or is not installed From 596d157b5384ce7c66471e9c21690a297972760b Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 25 Apr 2018 12:42:52 -0400 Subject: [PATCH 409/438] =?UTF-8?q?Bump=20version:=201.2.0.5=20=E2=86=92?= =?UTF-8?q?=201.2.0.6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/index.rst | 12 ++++++------ stix/version.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 97a01d4b..30c11946 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,15 +22,15 @@ version of STIX. ============ =================== STIX Version python-stix Version ============ =================== -1.2 1.2.0.5 (`PyPI`__) (`GitHub`__) +1.2 1.2.0.6 (`PyPI`__) (`GitHub`__) 1.1.1 1.1.1.12 (`PyPI`__) (`GitHub`__) -1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) -1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) -1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) +1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) +1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) +1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) ============ =================== -__ https://pypi.python.org/pypi/stix/1.2.0.5 -__ https://github.com/STIXProject/python-stix/tree/v1.2.0.5 +__ https://pypi.python.org/pypi/stix/1.2.0.6 +__ https://github.com/STIXProject/python-stix/tree/v1.2.0.6 __ https://pypi.python.org/pypi/stix/1.1.1.12 __ https://github.com/STIXProject/python-stix/tree/v1.1.1.12 __ https://pypi.python.org/pypi/stix/1.1.0.6 diff --git a/stix/version.py b/stix/version.py index 63c24dd6..e146c343 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.5" +__version__ = "1.2.0.6" From 4ed04fed1b9179bbe2acc73b92f68d5dbbaee1e7 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 13 Jun 2018 14:52:21 -0400 Subject: [PATCH 410/438] Add FAQ section to python-stix. closes #352 --- docs/index.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/index.rst b/docs/index.rst index 30c11946..9d61b71d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -71,6 +71,18 @@ API Reference api/index api/coverage +FAQ +=== + +- My RAM consumption rises when processing a large amount of files. + This problem is caused by a python-cybox_ caching mechanism that is enabled + by default. To prevent this issue from happening use the + ``cybox.utils.caches.cache_clear()`` method in your code/script to release + the cached resources as appropriate. Refer to the ``cybox`` documentation + for more details. + +.. _python-cybox: http://cybox.readthedocs.io/ + Contributing ============ If a bug is found, a feature is missing, or something just isn't behaving the way you'd expect it to, please submit an issue to our `tracker`_. If you'd like to contribute code to our repository, you can do so by issuing a `pull request`_ and we will work with you to try and integrate that code into our repository. From 288bbd11c0a1baae38b1e742e0cb604ba3d9b1c2 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 13 Jun 2018 15:06:19 -0400 Subject: [PATCH 411/438] Add .pytest_cache/ to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9a9c7d31..a5ba1ac5 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ # pycharm .idea/ .idea +.pytest_cache/ # python setuptools build/ From aa0178099f45c606e20e2a35aa196422fa644dca Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 13 Jun 2018 15:34:10 -0400 Subject: [PATCH 412/438] Update Tox and Travis CI configuration --- .travis.yml | 1 - tox.ini | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d38a6fa1..05fdf8f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: python python: - "2.7" - - "3.3" - "3.4" - "3.5" - "3.6" diff --git a/tox.ini b/tox.ini index c62be2ae..8067c9d6 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27, py33, py34, py35, py36, lxml23, no-maec +envlist = py27, py34, py35, py36, lxml23, no-maec [testenv] commands = @@ -33,7 +33,6 @@ deps = [travis] python = 2.7: py27, docs, lxml23, no-maec - 3.3: py33, no-maec 3.4: py34, no-maec 3.5: py35, no-maec 3.6: py36, no-maec From cf0ea6861d9fd4dec6003d948b6901cada954c4d Mon Sep 17 00:00:00 2001 From: Greg Back <1045796+gtback@users.noreply.github.com> Date: Wed, 1 Aug 2018 12:16:11 -0400 Subject: [PATCH 413/438] Update notification email [skip ci] --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 05fdf8f5..f55fcac7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,5 +10,4 @@ script: - tox notifications: email: - - gback@mitre.org - - stix-commits-list@lists.mitre.org + - stix-commits-list@groups.mitre.org From a9b0406d5cff8d73e054fbcdcea56273fc259c8c Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 6 Sep 2019 12:21:16 -0400 Subject: [PATCH 414/438] update project requirements, test harness and small rst fix --- .travis.yml | 4 ++++ docs/api/indicator/indicator.rst | 2 +- setup.py | 16 +++++++++------- tox.ini | 7 +++++-- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index f55fcac7..06f45c26 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,14 @@ language: python +sudo: false # Since this is an older project, this is not the default. +cache: pip +dist: xenial python: - "2.7" - "3.4" - "3.5" - "3.6" install: + - pip install -U pip setuptools - pip install tox-travis script: - tox diff --git a/docs/api/indicator/indicator.rst b/docs/api/indicator/indicator.rst index 0b299213..ccc78ff9 100644 --- a/docs/api/indicator/indicator.rst +++ b/docs/api/indicator/indicator.rst @@ -29,7 +29,7 @@ Classes add_short_description, add_test_mechanism, add_valid_time_position, alternative_id, confidence, description, descriptions, find, get_produced_time, get_received_time, handling, id_, idref, - indicated_ttps, indicator_types, information_source, kill_chain_phases, + indicated_ttps, indicator_types, kill_chain_phases, likely_impact, negate, observable, observable_composition_operator, observables, producer, related_campaigns, related_indicators, related_packages, set_produced_time, set_producer_identity, diff --git a/setup.py b/setup.py index fb657a39..c1d83491 100644 --- a/setup.py +++ b/setup.py @@ -11,6 +11,7 @@ BASE_DIR = dirname(abspath(__file__)) VERSION_FILE = join(BASE_DIR, 'stix', 'version.py') + def get_version(): with open(VERSION_FILE) as f: for line in f.readlines(): @@ -20,15 +21,17 @@ def get_version(): raise AttributeError("Package does not have a __version__") -with open('README.rst') as f: - readme = f.read() +def get_long_description(): + with open('README.rst') as f: + return f.read() install_requires = [ - 'lxml>=2.3', - 'python-dateutil', - 'cybox>=2.1.0.13,<2.1.1.0', + 'lxml>=2.2.3 ; python_version == "2.7" or python_version >= "3.5"', + 'lxml>=2.2.3,<4.4.0 ; python_version > "2.7" and python_version < "3.5"', 'mixbox>=1.0.2', + 'cybox>=2.1.0.13,<2.1.1.0', + 'python-dateutil', ] @@ -38,7 +41,7 @@ def get_version(): author="STIX Project, MITRE Corporation", author_email="stix@mitre.org", description="An API for parsing and generating STIX content.", - long_description=readme, + long_description=get_long_description(), url="http://stix.mitre.org", packages=find_packages(), install_requires=install_requires, @@ -50,7 +53,6 @@ def get_version(): 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', diff --git a/tox.ini b/tox.ini index 8067c9d6..5df72797 100644 --- a/tox.ini +++ b/tox.ini @@ -1,12 +1,11 @@ [tox] -envlist = py27, py34, py35, py36, lxml23, no-maec +envlist = py27, py34, py35, py36, lxml23, docs, no-maec [testenv] commands = nosetests stix # NOTE: python-stix does not have any doctests # sphinx-build -b doctest docs docs/_build/doctest - sphinx-build -b html docs docs/_build/html deps = -rrequirements.txt @@ -30,6 +29,10 @@ deps = nose==1.3.7 tox==2.7.0 +[testenv:docs] +commands = + sphinx-build -W -b html -d {envtmpdir}/doctrees docs {envtmpdir}/html + [travis] python = 2.7: py27, docs, lxml23, no-maec From 7ec27cbc988be17dd8222299d75f51b5dd4c76be Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 6 Sep 2019 15:05:32 -0400 Subject: [PATCH 415/438] add Python 3.7 to Travis CI test harness --- .travis.yml | 1 + tox.ini | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 06f45c26..1f090c23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ python: - "3.4" - "3.5" - "3.6" + - "3.7" install: - pip install -U pip setuptools - pip install tox-travis diff --git a/tox.ini b/tox.ini index 5df72797..6f076952 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27, py34, py35, py36, lxml23, docs, no-maec +envlist = py27, py34, py35, py36, py37, lxml23, docs, no-maec [testenv] commands = @@ -39,3 +39,4 @@ python = 3.4: py34, no-maec 3.5: py35, no-maec 3.6: py36, no-maec + 3.7: py37, no-maec From 2597b722b2547eb6050178f1bef0b738c8071162 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 6 Sep 2019 15:20:42 -0400 Subject: [PATCH 416/438] Update setup.py add missing Python 3.7 tag --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index c1d83491..6c132dc0 100644 --- a/setup.py +++ b/setup.py @@ -56,5 +56,6 @@ def get_long_description(): 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', ] ) From 722f26a3239f4d6de36e6533b3fb177e3ecd699d Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 6 Sep 2019 15:53:19 -0400 Subject: [PATCH 417/438] update README for version 1.2.0.7 --- CHANGES.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 4ff6a402..2033cf8b 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,7 @@ +Version 1.2.0.7 +2019-09-06 +- Update package requirements + Version 1.2.0.6 2018-04-25 - #347 Property targeted_technical_details missing in VictimTargeting class From 03ffed77ea980d31f418137d300a5e9a3b350f56 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 6 Sep 2019 15:56:10 -0400 Subject: [PATCH 418/438] =?UTF-8?q?Bump=20version:=201.2.0.6=20=E2=86=92?= =?UTF-8?q?=201.2.0.7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/index.rst | 12 ++++++------ stix/version.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 9d61b71d..509c2770 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,17 +22,17 @@ version of STIX. ============ =================== STIX Version python-stix Version ============ =================== -1.2 1.2.0.6 (`PyPI`__) (`GitHub`__) -1.1.1 1.1.1.12 (`PyPI`__) (`GitHub`__) +1.2 1.2.0.7 (`PyPI`__) (`GitHub`__) +1.1.1 1.1.1.13 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) ============ =================== -__ https://pypi.python.org/pypi/stix/1.2.0.6 -__ https://github.com/STIXProject/python-stix/tree/v1.2.0.6 -__ https://pypi.python.org/pypi/stix/1.1.1.12 -__ https://github.com/STIXProject/python-stix/tree/v1.1.1.12 +__ https://pypi.python.org/pypi/stix/1.2.0.7 +__ https://github.com/STIXProject/python-stix/tree/v1.2.0.7 +__ https://pypi.python.org/pypi/stix/1.1.1.13 +__ https://github.com/STIXProject/python-stix/tree/v1.1.1.13 __ https://pypi.python.org/pypi/stix/1.1.0.6 __ https://github.com/STIXProject/python-stix/tree/v1.1.0.6 __ https://pypi.python.org/pypi/stix/1.0.1.1 diff --git a/stix/version.py b/stix/version.py index e146c343..2706c4fa 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.6" +__version__ = "1.2.0.7" From a652f757d59595ed52a7ddbb9f81f7ec9e0f743d Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 6 Sep 2019 16:16:26 -0400 Subject: [PATCH 419/438] Update setup.py --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 6c132dc0..a221ad08 100644 --- a/setup.py +++ b/setup.py @@ -45,6 +45,7 @@ def get_long_description(): url="http://stix.mitre.org", packages=find_packages(), install_requires=install_requires, + license="BSD", classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', From 843abb7fa4afe888df5b79ef18d59603e5b5296a Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 18 Sep 2019 12:18:01 -0400 Subject: [PATCH 420/438] update documentation, add new test environments for harness --- README.rst | 12 ++++++------ setup.cfg | 11 +++++++++++ setup.py | 4 ++-- tox.ini | 12 +++++++++--- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/README.rst b/README.rst index 6df07068..e32edbdd 100644 --- a/README.rst +++ b/README.rst @@ -1,10 +1,10 @@ python-stix =========== -A python library for parsing, manipulating, and generating STIX v1.2 content. +A python library for parsing, manipulating, and generating `Structured Threat Information eXpression (STIX™) `_ v1.2.0 content. :Source: https://github.com/STIXProject/python-stix -:Documentation: http://stix.readthedocs.org +:Documentation: https://stix.readthedocs.io/ :Information: https://stixproject.github.io/ |travis_badge| |landscape_io_badge| |version_badge| @@ -24,7 +24,7 @@ Installation ------------ The python-stix library is hosted on `PyPI -`_ and the most recent stable version can be +`_ and the most recent stable version can be installed with `pip `_: :: @@ -60,13 +60,13 @@ Installation on Windows ~~~~~~~~~~~~~~~~~~~~~~~ Download the Lxml wheel for your version of Python from -http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml, then install it via "pip install +http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml, then install it via "pip install .whl". For example, to install it on 64-bit Windows running Python 2.7: :: - > pip install lxml-3.6.1-cp27-cp27m-win_amd64.whl - > pip install stix + $ pip install lxml-3.6.1-cp27-cp27m-win_amd64.whl + $ pip install stix Versioning ---------- diff --git a/setup.cfg b/setup.cfg index 2be68365..9e2d3895 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,13 @@ +[bumpversion] +current_version = 1.2.0.7 +parse = (?P\d+)\.(?P\d+)\.(?P\d+).(?P\d+) +serialize = {major}.{minor}.{patch}.{revision} +commit = True +tag = True + +[bumpversion:file:stix/version.py] + +[bumpversion:file:docs/index.rst] + [bdist_wheel] universal = True diff --git a/setup.py b/setup.py index a221ad08..b8566137 100644 --- a/setup.py +++ b/setup.py @@ -3,6 +3,7 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. +from io import open # Allow `encoding` kwarg on Python 2.7 from os.path import abspath, dirname, join @@ -22,7 +23,7 @@ def get_version(): def get_long_description(): - with open('README.rst') as f: + with open('README.rst', encoding='utf-8') as f: return f.read() @@ -45,7 +46,6 @@ def get_long_description(): url="http://stix.mitre.org", packages=find_packages(), install_requires=install_requires, - license="BSD", classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', diff --git a/tox.ini b/tox.ini index 6f076952..df43c75d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27, py34, py35, py36, py37, lxml23, docs, no-maec +envlist = py27, py34, py35, py36, py37, lxml23, docs, no-maec, packaging [testenv] commands = @@ -33,10 +33,16 @@ deps = commands = sphinx-build -W -b html -d {envtmpdir}/doctrees docs {envtmpdir}/html +[testenv:packaging] +deps = + readme_renderer +commands = + python setup.py check -r -s + [travis] python = - 2.7: py27, docs, lxml23, no-maec + 2.7: py27, docs, lxml23, no-maec, packaging 3.4: py34, no-maec 3.5: py35, no-maec - 3.6: py36, no-maec + 3.6: py36, no-maec, packaging 3.7: py37, no-maec From 6346e0762ef47149913c7fcf21135a04deca33e2 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 18 Sep 2019 12:31:57 -0400 Subject: [PATCH 421/438] Update setup.py --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index b8566137..ff4e2ded 100644 --- a/setup.py +++ b/setup.py @@ -46,6 +46,7 @@ def get_long_description(): url="http://stix.mitre.org", packages=find_packages(), install_requires=install_requires, + license="BSD", classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', From 7f82b8fc65ebba9b699190ad1fedb76f7c0fcd33 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 18 Sep 2019 13:31:17 -0400 Subject: [PATCH 422/438] Update setup.py --- README.rst | 1 + setup.py | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index e32edbdd..e934477c 100644 --- a/README.rst +++ b/README.rst @@ -6,6 +6,7 @@ A python library for parsing, manipulating, and generating `Structured Threat In :Source: https://github.com/STIXProject/python-stix :Documentation: https://stix.readthedocs.io/ :Information: https://stixproject.github.io/ +:Download: https://pypi.python.org/pypi/stix/ |travis_badge| |landscape_io_badge| |version_badge| diff --git a/setup.py b/setup.py index ff4e2ded..f926379b 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ def get_long_description(): author_email="stix@mitre.org", description="An API for parsing and generating STIX content.", long_description=get_long_description(), - url="http://stix.mitre.org", + url="https://stixproject.github.io/", packages=find_packages(), install_requires=install_requires, license="BSD", @@ -59,5 +59,10 @@ def get_long_description(): 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', - ] + ], + project_urls={ + 'Documentation': 'https://stix.readthedocs.io/', + 'Source Code': 'https://github.com/STIXProject/python-stix/', + 'Bug Tracker': 'https://github.com/STIXProject/python-stix/issues/', + }, ) From 1a82b263d8beb070e334dc952b760ba42305c894 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Sat, 7 Mar 2020 20:07:04 -0500 Subject: [PATCH 423/438] update PersonName to allow xnl:Type add vocabs to PersonName and OrganisationName --- stix/extensions/identity/ciq_identity_3_0.py | 86 +++++++++++++++++-- .../identity/ciq_identity_3_0_test.py | 10 ++- 2 files changed, 90 insertions(+), 6 deletions(-) diff --git a/stix/extensions/identity/ciq_identity_3_0.py b/stix/extensions/identity/ciq_identity_3_0.py index a2d89f08..2010ac8f 100644 --- a/stix/extensions/identity/ciq_identity_3_0.py +++ b/stix/extensions/identity/ciq_identity_3_0.py @@ -1028,13 +1028,53 @@ class PersonName(stix.Entity): _namespace = XML_NS_XNL XML_TAG = "{%s}PersonName" % _namespace - def __init__(self, name_elements=None): + TYPE_ALIAS = 'Alias' + TYPE_LEGAL_NAME = 'LegalName' + TYPE_KNOWN_AS = 'KnownAs' + TYPE_MAIDEN_NAME = 'MaidenName' + TYPE_FORMER_NAME = 'FormerName' + TYPE_COMMON_USE = 'CommonUse' + TYPE_NAME_AT_BIRTH = 'NameAtBirth' + TYPE_PREFERRED_NAME = 'PreferredName' + TYPE_OFFICIAL_NAME = 'OfficialName' + TYPE_UNOFFICIAL_NAME = 'UnofficialName' + TYPE_NICK_NAME = 'NickName' + TYPE_PET_NAME = 'PetName' + + TYPES = ( + TYPE_ALIAS, + TYPE_LEGAL_NAME, + TYPE_KNOWN_AS, + TYPE_MAIDEN_NAME, + TYPE_FORMER_NAME, + TYPE_COMMON_USE, + TYPE_NAME_AT_BIRTH, + TYPE_PREFERRED_NAME, + TYPE_OFFICIAL_NAME, + TYPE_UNOFFICIAL_NAME, + TYPE_NICK_NAME, + TYPE_PET_NAME, + ) + + def __init__(self, name_elements=None, type_=None): self.name_elements = [] + self.type_ = type_ if name_elements: for name_element in name_elements: self.add_name_element(name_element) + @property + def type_(self): + return self._type + + @type_.setter + def type_(self, value): + if value and value not in self.TYPES: + raise ValueError('value must be one of %s: ' % (self.TYPES,)) + + self._type = value + def add_name_element(self, value): if isinstance(value, string_types): self.name_elements.append(PersonNameElement(value=value)) @@ -1050,6 +1090,9 @@ def to_obj(self, return_obj=None, ns_info=None): root_tag = PersonName.XML_TAG return_obj = et.Element(root_tag) + if self.type_: + return_obj.attrib['{%s}Type' % XML_NS_XNL] = self.type_ + for name_element in self.name_elements: return_obj.append(name_element.to_obj(ns_info=ns_info)) @@ -1063,6 +1106,8 @@ def from_obj(cls, obj, return_obj=None): if not return_obj: return_obj = cls() + return_obj.type_ = obj.attrib.get('{%s}Type' % XML_NS_XNL) + name_elements = obj.findall(PersonNameElement.XML_TAG) if name_elements: for name_element_obj in name_elements: @@ -1074,6 +1119,9 @@ def from_obj(cls, obj, return_obj=None): def to_dict(self): d = {} + if self.type_: + d['type'] = self.type_ + if self.name_elements: for ne in self.name_elements: d.setdefault('name_elements', []).append(ne.to_dict()) @@ -1088,6 +1136,8 @@ def from_dict(cls, dict_repr, return_obj=None): if not return_obj: return_obj = cls() + return_obj.type_ = dict_repr.get('type') + ne_dicts = dict_repr.get('name_elements', []) for ne_dict in ne_dicts: @@ -1100,11 +1150,40 @@ class OrganisationName(stix.Entity): _namespace = XML_NS_XNL XML_TAG = "{%s}OrganisationName" % _namespace + TYPE_LEGAL_NAME = 'LegalName' + TYPE_FORMER_NAME = 'FormerName' + TYPE_COMMON_USE = 'CommonUse' + TYPE_PUBLISHING_NAME = 'PublishingName' + TYPE_OFFICIAL_NAME = 'OfficialName' + TYPE_UNOFFICIAL_NAME = 'UnofficialName' + TYPE_UNDEFINED = 'Undefined' + + TYPES = ( + TYPE_LEGAL_NAME, + TYPE_FORMER_NAME, + TYPE_COMMON_USE, + TYPE_PUBLISHING_NAME, + TYPE_OFFICIAL_NAME, + TYPE_UNOFFICIAL_NAME, + TYPE_UNDEFINED, + ) + def __init__(self, name_elements=None, subdivision_names=None, type_=None): self.type_ = type_ self.name_elements = name_elements self.subdivision_names = subdivision_names + @property + def type_(self): + return self._type + + @type_.setter + def type_(self, value): + if value and value not in self.TYPES: + raise ValueError('value must be one of %s: ' % (self.TYPES,)) + + self._type = value + @property def name_elements(self): return self._name_elements @@ -1235,9 +1314,6 @@ def value(self): @value.setter def value(self, value): - # if not value: - # raise ValueError('value cannot be None') - self._value = value @classmethod @@ -1270,8 +1346,8 @@ class PersonNameElement(_BaseNameElement): _namespace = XML_NS_XNL XML_TAG = "{%s}NameElement" % _namespace - TYPE_TITLE = 'Title' TYPE_PRECEDING_TITLE = 'PrecedingTitle' + TYPE_TITLE = 'Title' TYPE_FIRST_NAME = 'FirstName' TYPE_MIDDLE_NAME = 'MiddleName' TYPE_LAST_NAME = 'LastName' diff --git a/stix/test/extensions/identity/ciq_identity_3_0_test.py b/stix/test/extensions/identity/ciq_identity_3_0_test.py index 20d7d101..542371e9 100644 --- a/stix/test/extensions/identity/ciq_identity_3_0_test.py +++ b/stix/test/extensions/identity/ciq_identity_3_0_test.py @@ -40,8 +40,16 @@ class CIQIdentity3_0InstanceTests(EntityTestCase, unittest.TestCase): ], 'person_names': [ { + 'type': 'LegalName', 'name_elements': [ - {'value': 'John Smith'} + { + 'element_type': 'FirstName', + 'value': 'John', + }, + { + 'element_type': 'LastName', + 'value': 'Smith', + } ] }, { From eb251939b32c220571fab53d756b8b609e8687f3 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 9 Mar 2020 12:48:09 -0400 Subject: [PATCH 424/438] update tests per new CybOX release --- stix/test/coa_test.py | 6 +++--- stix/test/core/stix_package_test.py | 6 +++--- stix/test/report_test.py | 6 +++--- stix/test/ttp_test.py | 12 ++++++------ 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/stix/test/coa_test.py b/stix/test/coa_test.py index 9a3c0e17..05d2b905 100644 --- a/stix/test/coa_test.py +++ b/stix/test/coa_test.py @@ -51,9 +51,9 @@ class COATests(EntityTestCase, unittest.TestCase): }, 'objective': ObjectiveTests._full_dict, 'parameter_observables': { - 'major_version': 2, - 'minor_version': 1, - 'update_version': 0, + 'cybox_major_version': '2', + 'cybox_minor_version': '1', + 'cybox_update_version': '0', 'observables': [ { 'idref': "example:Observable-1" diff --git a/stix/test/core/stix_package_test.py b/stix/test/core/stix_package_test.py index 47e31db4..0ce35e13 100644 --- a/stix/test/core/stix_package_test.py +++ b/stix/test/core/stix_package_test.py @@ -101,9 +101,9 @@ class STIXPackageTests(EntityTestCase, unittest.TestCase): 'incidents': IncidentsTests._full_dict, 'indicators': IndicatorsTests._full_dict, 'observables': { - 'major_version': 2, - 'minor_version': 1, - 'update_version': 0, + 'cybox_major_version': '2', + 'cybox_minor_version': '1', + 'cybox_update_version': '0', 'observables': [ { 'idref': "example:Observable-1" diff --git a/stix/test/report_test.py b/stix/test/report_test.py index f99ecb7f..2ce43055 100644 --- a/stix/test/report_test.py +++ b/stix/test/report_test.py @@ -102,9 +102,9 @@ class ReportTests(EntityTestCase, unittest.TestCase): 'incidents': IncidentsTests._full_dict, 'indicators': IndicatorsTests._full_dict, 'observables': { - 'major_version': 2, - 'minor_version': 1, - 'update_version': 0, + 'cybox_major_version': '2', + 'cybox_minor_version': '1', + 'cybox_update_version': '0', 'observables': [ { 'idref': "example:Observable-1" diff --git a/stix/test/ttp_test.py b/stix/test/ttp_test.py index ef43689f..c7c4a339 100644 --- a/stix/test/ttp_test.py +++ b/stix/test/ttp_test.py @@ -52,9 +52,9 @@ class InfrastructureTests(EntityTestCase, unittest.TestCase): 'short_description': 'Short Description', 'types': ['foo', 'bar'], 'observable_characterization': { - 'major_version': 2, - 'minor_version': 1, - 'update_version': 0, + 'cybox_major_version': '2', + 'cybox_minor_version': '1', + 'cybox_update_version': '0', 'observables': [ { 'idref': "example:Observable-1" @@ -188,9 +188,9 @@ class VictimTargetingTests(EntityTestCase, unittest.TestCase): } ], 'targeted_technical_details': { - 'major_version': 2, - 'minor_version': 1, - 'update_version': 0, + 'cybox_major_version': '2', + 'cybox_minor_version': '1', + 'cybox_update_version': '0', 'observables': [ { 'idref': "example:Observable-2" From 70d58329050d61c6d5a2b1abb782963d33926113 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 9 Mar 2020 21:50:51 -0400 Subject: [PATCH 425/438] update CHANGES.txt for v1.2.0.8 --- CHANGES.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 2033cf8b..756b7f15 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,9 @@ +Version 1.2.0.8 +2020-03-09 +- #357 Add xnl:Type to the PersonName element (CIQ) +- Update the allowable values for PersonName and OrganisationName +- Update tests per recent CybOX release + Version 1.2.0.7 2019-09-06 - Update package requirements From 799c13c83b455a14730432ecab0c17d72e7707d0 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 9 Mar 2020 22:04:37 -0400 Subject: [PATCH 426/438] update index.rst --- docs/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 509c2770..d3bbfa9a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -23,7 +23,7 @@ version of STIX. STIX Version python-stix Version ============ =================== 1.2 1.2.0.7 (`PyPI`__) (`GitHub`__) -1.1.1 1.1.1.13 (`PyPI`__) (`GitHub`__) +1.1.1 1.1.1.15 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) @@ -31,8 +31,8 @@ STIX Version python-stix Version __ https://pypi.python.org/pypi/stix/1.2.0.7 __ https://github.com/STIXProject/python-stix/tree/v1.2.0.7 -__ https://pypi.python.org/pypi/stix/1.1.1.13 -__ https://github.com/STIXProject/python-stix/tree/v1.1.1.13 +__ https://pypi.python.org/pypi/stix/1.1.1.15 +__ https://github.com/STIXProject/python-stix/tree/v1.1.1.15 __ https://pypi.python.org/pypi/stix/1.1.0.6 __ https://github.com/STIXProject/python-stix/tree/v1.1.0.6 __ https://pypi.python.org/pypi/stix/1.0.1.1 From 50d9fc4d11beff9415aead591c44603c489dffde Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 9 Mar 2020 22:04:47 -0400 Subject: [PATCH 427/438] =?UTF-8?q?Bump=20version:=201.2.0.7=20=E2=86=92?= =?UTF-8?q?=201.2.0.8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/index.rst | 6 +++--- setup.cfg | 3 ++- stix/version.py | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index d3bbfa9a..aa0447bb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,15 +22,15 @@ version of STIX. ============ =================== STIX Version python-stix Version ============ =================== -1.2 1.2.0.7 (`PyPI`__) (`GitHub`__) +1.2 1.2.0.8 (`PyPI`__) (`GitHub`__) 1.1.1 1.1.1.15 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) ============ =================== -__ https://pypi.python.org/pypi/stix/1.2.0.7 -__ https://github.com/STIXProject/python-stix/tree/v1.2.0.7 +__ https://pypi.python.org/pypi/stix/1.2.0.8 +__ https://github.com/STIXProject/python-stix/tree/v1.2.0.8 __ https://pypi.python.org/pypi/stix/1.1.1.15 __ https://github.com/STIXProject/python-stix/tree/v1.1.1.15 __ https://pypi.python.org/pypi/stix/1.1.0.6 diff --git a/setup.cfg b/setup.cfg index 9e2d3895..d22ecb35 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.2.0.7 +current_version = 1.2.0.8 parse = (?P\d+)\.(?P\d+)\.(?P\d+).(?P\d+) serialize = {major}.{minor}.{patch}.{revision} commit = True @@ -11,3 +11,4 @@ tag = True [bdist_wheel] universal = True + diff --git a/stix/version.py b/stix/version.py index 2706c4fa..377e3a6f 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.7" +__version__ = "1.2.0.8" From 01d2441048734e9fb0f264881c2835a4d11b1b1b Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Thu, 16 Apr 2020 11:52:01 -0400 Subject: [PATCH 428/438] update Tox and Travis CI configuration to add 3.8 in harness --- .travis.yml | 3 ++- setup.py | 1 + tox.ini | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1f090c23..e99e66dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ +os: linux language: python -sudo: false # Since this is an older project, this is not the default. cache: pip dist: xenial python: @@ -8,6 +8,7 @@ python: - "3.5" - "3.6" - "3.7" + - "3.8" install: - pip install -U pip setuptools - pip install tox-travis diff --git a/setup.py b/setup.py index f926379b..fea74856 100644 --- a/setup.py +++ b/setup.py @@ -59,6 +59,7 @@ def get_long_description(): 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', ], project_urls={ 'Documentation': 'https://stix.readthedocs.io/', diff --git a/tox.ini b/tox.ini index df43c75d..275e8bdf 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27, py34, py35, py36, py37, lxml23, docs, no-maec, packaging +envlist = py27, py34, py35, py36, py37, py38, lxml23, docs, no-maec, packaging [testenv] commands = @@ -46,3 +46,4 @@ python = 3.5: py35, no-maec 3.6: py36, no-maec, packaging 3.7: py37, no-maec + 3.8: py38, no-maec From 507f5d65c1912660c562a04827b842e0e8fc37d1 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Thu, 16 Apr 2020 23:03:32 -0400 Subject: [PATCH 429/438] change class TTPs to no longer be EntityList - fixes #357 --- stix/core/stix_package.py | 2 +- stix/core/ttps.py | 18 +++++------------- .../malware/maec_4_1_malware_test.py | 4 ++-- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index 14e9fbb1..c0aa8d1c 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -180,7 +180,7 @@ def add_ttp(self, ttp): """ if self.ttps is None: self.ttps = TTPs() - self.ttps.append(ttp) + self.ttps.ttp.append(ttp) def add_report(self, report): """Adds a :class:`.Report` object to the :attr:`reports` collection. diff --git a/stix/core/ttps.py b/stix/core/ttps.py index d5620509..2688e7ac 100644 --- a/stix/core/ttps.py +++ b/stix/core/ttps.py @@ -5,12 +5,10 @@ from functools import partial # mixbox -from mixbox import entities from mixbox import fields # stix import stix -from stix import utils from stix.ttp import TTP from stix.common.kill_chains import KillChains from stix.bindings import stix_core as core_binding @@ -19,24 +17,18 @@ from stix.utils.deprecated import IdrefDeprecatedList -class TTPs(stix.EntityList): +class TTPs(stix.Entity): _binding = core_binding _binding_class = _binding.TTPsType _namespace = 'http://stix.mitre.org/stix-1' - ttps = fields.TypedField( - name="TTP", - type_=TTP, - multiple=True, - key_name="ttps", - listfunc=partial(IdrefDeprecatedList, type=TTP) - ) - + ttp = fields.TypedField("TTP", TTP, multiple=True, key_name="ttps", listfunc=partial(IdrefDeprecatedList, type=TTP)) kill_chains = fields.TypedField("Kill_Chains", KillChains) def __init__(self, ttps=None): - super(TTPs, self).__init__(ttps) + super(TTPs, self).__init__() + self.ttp = ttps self.kill_chains = KillChains() def add_ttp(self, ttp): - self.append(ttp) + self.ttp.append(ttp) diff --git a/stix/test/extensions/malware/maec_4_1_malware_test.py b/stix/test/extensions/malware/maec_4_1_malware_test.py index 1829246c..30257c3c 100644 --- a/stix/test/extensions/malware/maec_4_1_malware_test.py +++ b/stix/test/extensions/malware/maec_4_1_malware_test.py @@ -134,14 +134,14 @@ def test_parse_malware(self): """Test parsing a normal MalwareInstance from XML """ stix_pkg = STIXPackage.from_xml(self.XML) - mw = stix_pkg.ttps[0].behavior.malware_instances[0].to_dict() + mw = stix_pkg.ttps.ttp[0].behavior.malware_instances[0].to_dict() self.assertTrue('names' in mw) def test_parse_malware_maec(self): """Test parsing a MaecInstance from XML """ stix_pkg = STIXPackage.from_xml(self.XML_MAEC) - mw = stix_pkg.ttps[0].behavior.malware_instances[0].to_dict() + mw = stix_pkg.ttps.ttp[0].behavior.malware_instances[0].to_dict() self.assertTrue('names' in mw) From a9afca16b8810017a0acdcf906c6668b70c853d3 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Thu, 16 Apr 2020 23:31:21 -0400 Subject: [PATCH 430/438] Update CHANGES.txt for v1.2.0.9 --- CHANGES.txt | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 6 +++--- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 756b7f15..8c30f804 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,8 @@ +Version 1.2.0.9 +2020-04-16 +- #364 TTPs would fail to serialize XML Kill_Chains if no TTP was set +- Added Python 3.8 to test harness + Version 1.2.0.8 2020-03-09 - #357 Add xnl:Type to the PersonName element (CIQ) @@ -46,6 +51,52 @@ Version 1.2.0.2 - #302 Correctly handle CIQ Identity objects. - Add additional fields to CIQ Identity object. +Version 1.1.1.16 +2020-04-16 +- #364 TTPs would fail to serialize XML Kill_Chains if no TTP was set +- Added Python 3.8 to test harness + +Version 1.1.1.15 +2020-03-09 +- #357 Add xnl:Type to the PersonName element (CIQ) +- Update the allowable values for PersonName and OrganisationName +- Update tests per recent CybOX release + +Version 1.1.1.14 +2019-11-26 +- #361 fix problem with lookup_extension for TestMechanism + +Version 1.1.1.13 +2019-09-06 +- Update package requirements + +Version 1.1.1.12 +2018-04-25 +- #347 Property targeted_technical_details missing in VictimTargeting class + +Version 1.1.1.11 +2018-03-21 +- Fix issue with PyPI. + +Version 1.1.1.10 +2018-03-06 +- #343 Create separate test environments for when maec is or is not installed +- #339 [Python3 not supported - v1.1/1.2] to_json vaguely broken on some files +- #338 VocabTypes are unhashable in 1.1.1.x on Python 3 +- #325 Bug in Indicator class setter for observables property +- Change stix.ToolInformation to use AttackerToolType vocab +- Removed Python 2.6 environment from CI tests + +Version 1.1.1.9 +2017-05-25 +- Support Python 3.6 +- #321 Fix CIQ extensions. + +Version 1.1.1.8 +2017-01-18 +- Update to support Python 3. +- Convert to use mixbox. + Version 1.1.1.7 2016-10-21 - Improved handling of Industry Sectors in CIQ Identity for AIS Markings diff --git a/docs/index.rst b/docs/index.rst index aa0447bb..a0edca2a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -23,7 +23,7 @@ version of STIX. STIX Version python-stix Version ============ =================== 1.2 1.2.0.8 (`PyPI`__) (`GitHub`__) -1.1.1 1.1.1.15 (`PyPI`__) (`GitHub`__) +1.1.1 1.1.1.16 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) @@ -31,8 +31,8 @@ STIX Version python-stix Version __ https://pypi.python.org/pypi/stix/1.2.0.8 __ https://github.com/STIXProject/python-stix/tree/v1.2.0.8 -__ https://pypi.python.org/pypi/stix/1.1.1.15 -__ https://github.com/STIXProject/python-stix/tree/v1.1.1.15 +__ https://pypi.python.org/pypi/stix/1.1.1.16 +__ https://github.com/STIXProject/python-stix/tree/v1.1.1.16 __ https://pypi.python.org/pypi/stix/1.1.0.6 __ https://github.com/STIXProject/python-stix/tree/v1.1.0.6 __ https://pypi.python.org/pypi/stix/1.0.1.1 From cefbf2f7eeacbb9aa98256807b1202004de42516 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Thu, 16 Apr 2020 23:31:40 -0400 Subject: [PATCH 431/438] =?UTF-8?q?Bump=20version:=201.2.0.8=20=E2=86=92?= =?UTF-8?q?=201.2.0.9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/index.rst | 6 +++--- setup.cfg | 2 +- stix/version.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index a0edca2a..c51440a8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,15 +22,15 @@ version of STIX. ============ =================== STIX Version python-stix Version ============ =================== -1.2 1.2.0.8 (`PyPI`__) (`GitHub`__) +1.2 1.2.0.9 (`PyPI`__) (`GitHub`__) 1.1.1 1.1.1.16 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) ============ =================== -__ https://pypi.python.org/pypi/stix/1.2.0.8 -__ https://github.com/STIXProject/python-stix/tree/v1.2.0.8 +__ https://pypi.python.org/pypi/stix/1.2.0.9 +__ https://github.com/STIXProject/python-stix/tree/v1.2.0.9 __ https://pypi.python.org/pypi/stix/1.1.1.16 __ https://github.com/STIXProject/python-stix/tree/v1.1.1.16 __ https://pypi.python.org/pypi/stix/1.1.0.6 diff --git a/setup.cfg b/setup.cfg index d22ecb35..6b565d4f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.2.0.8 +current_version = 1.2.0.9 parse = (?P\d+)\.(?P\d+)\.(?P\d+).(?P\d+) serialize = {major}.{minor}.{patch}.{revision} commit = True diff --git a/stix/version.py b/stix/version.py index 377e3a6f..4a78cbb6 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.8" +__version__ = "1.2.0.9" From b4213454059d44b68258be8308c56e3d1b9df24a Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 1 May 2020 13:12:30 -0400 Subject: [PATCH 432/438] add checks to initialize References() when missing, prevent empty TTPs tags. closes #366 --- stix/common/information_source.py | 8 +++----- stix/core/stix_package.py | 2 +- stix/core/ttps.py | 5 +++++ stix/exploit_target/vulnerability.py | 12 +++++------- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/stix/common/information_source.py b/stix/common/information_source.py index f7042f27..ef718ba7 100644 --- a/stix/common/information_source.py +++ b/stix/common/information_source.py @@ -22,7 +22,7 @@ class InformationSource(stix.Entity): _binding_class = stix_common_binding.InformationSourceType _namespace = 'http://stix.mitre.org/common-1' - identity = fields.TypedField("Identity", type_=Identity, factory=IdentityFactory) + identity = fields.TypedField("Identity", Identity, factory=IdentityFactory) descriptions = fields.TypedField("Description", StructuredTextList) contributing_sources = fields.TypedField("Contributing_Sources", type_="stix.common.information_source.ContributingSources") time = fields.TypedField("Time", cybox.common.Time) @@ -39,15 +39,15 @@ def __init__(self, description=None, identity=None, time=None, tools=None, contr self.time = time self.tools = tools self.references = references - #self.roles = None def add_contributing_source(self, value): self.contributing_sources.append(value) - def add_reference(self, value): if not value: return + if self.references is None: + self.references = References() # TODO: Check if it's a valid URI? self.references.append(value) @@ -80,7 +80,6 @@ def add_description(self, description): """ self.descriptions.add(description) - def add_role(self, value): self.roles.append(value) @@ -95,4 +94,3 @@ class ContributingSources(stix.EntityList): @classmethod def _dict_as_list(cls): return False - \ No newline at end of file diff --git a/stix/core/stix_package.py b/stix/core/stix_package.py index c0aa8d1c..da2d5643 100644 --- a/stix/core/stix_package.py +++ b/stix/core/stix_package.py @@ -104,7 +104,7 @@ def __init__(self, id_=None, idref=None, timestamp=None, stix_header=None, self.indicators = indicators or Indicators() self.incidents = incidents or Incidents() self.threat_actors = threat_actors or ThreatActors() - self.ttps = ttps or TTPs() + self.ttps = ttps self.related_packages = related_packages self.reports = reports or Reports() self.timestamp = timestamp diff --git a/stix/core/ttps.py b/stix/core/ttps.py index 2688e7ac..9f1cb265 100644 --- a/stix/core/ttps.py +++ b/stix/core/ttps.py @@ -32,3 +32,8 @@ def __init__(self, ttps=None): def add_ttp(self, ttp): self.ttp.append(ttp) + + def add_kill_chain(self, kc): + if self.kill_chains is None: + self.kill_chains = KillChains() + self.kill_chains.kill_chain.append(kc) diff --git a/stix/exploit_target/vulnerability.py b/stix/exploit_target/vulnerability.py index 78e0974a..814c2f19 100644 --- a/stix/exploit_target/vulnerability.py +++ b/stix/exploit_target/vulnerability.py @@ -4,13 +4,10 @@ from mixbox import fields import stix -import stix.utils as utils import stix.bindings.exploit_target as exploit_target_binding -import stix.bindings.stix_common as stix_common_binding -from stix.common import DateTimeWithPrecision, StructuredTextList +from stix.common import DateTimeWithPrecision, References, StructuredTextList from stix.common.related import GenericRelationshipList, RelatedObservable -from mixbox import entities, fields -from stix.common import References + class Vulnerability(stix.Entity): """Implementation of STIX ``Vulnerability``. @@ -44,7 +41,6 @@ def __init__(self, title=None, description=None, short_description=None): self.title = title self.descriptions = StructuredTextList(description) self.short_descriptions = StructuredTextList(short_description) - self.references = [] @property def description(self): @@ -102,9 +98,11 @@ def add_short_description(self, description): def add_reference(self, reference): if not reference: return - + if self.references is None: + self.references = References() self.references.append(reference) + class CVSSVector(stix.Entity): """ Common Vulnerabilit Scoring System object, representing its component measures From dbf8aad367ff16b952f9ed34065a1df90c45c042 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 1 May 2020 13:30:24 -0400 Subject: [PATCH 433/438] update CHANGES.txt for v1.2.0.10 --- CHANGES.txt | 5 +++++ docs/index.rst | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 8c30f804..ff7c6bea 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,8 @@ +Version 1.2.0.10 +2020-05-01 +- #366 Check add_reference methods to prevent NoneType has no attribute 'append' +- Changes to STIXPackage to prevent the empty tag from appearing in serialization + Version 1.2.0.9 2020-04-16 - #364 TTPs would fail to serialize XML Kill_Chains if no TTP was set diff --git a/docs/index.rst b/docs/index.rst index c51440a8..83bd4b52 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -23,7 +23,7 @@ version of STIX. STIX Version python-stix Version ============ =================== 1.2 1.2.0.9 (`PyPI`__) (`GitHub`__) -1.1.1 1.1.1.16 (`PyPI`__) (`GitHub`__) +1.1.1 1.1.1.18 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) @@ -31,8 +31,8 @@ STIX Version python-stix Version __ https://pypi.python.org/pypi/stix/1.2.0.9 __ https://github.com/STIXProject/python-stix/tree/v1.2.0.9 -__ https://pypi.python.org/pypi/stix/1.1.1.16 -__ https://github.com/STIXProject/python-stix/tree/v1.1.1.16 +__ https://pypi.python.org/pypi/stix/1.1.1.18 +__ https://github.com/STIXProject/python-stix/tree/v1.1.1.18 __ https://pypi.python.org/pypi/stix/1.1.0.6 __ https://github.com/STIXProject/python-stix/tree/v1.1.0.6 __ https://pypi.python.org/pypi/stix/1.0.1.1 From c1f46349062921d1ebfed328501e78cd35a658cc Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Fri, 1 May 2020 13:31:42 -0400 Subject: [PATCH 434/438] =?UTF-8?q?Bump=20version:=201.2.0.9=20=E2=86=92?= =?UTF-8?q?=201.2.0.10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/index.rst | 6 +++--- setup.cfg | 2 +- stix/version.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 83bd4b52..dddca2ef 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,15 +22,15 @@ version of STIX. ============ =================== STIX Version python-stix Version ============ =================== -1.2 1.2.0.9 (`PyPI`__) (`GitHub`__) +1.2 1.2.0.10 (`PyPI`__) (`GitHub`__) 1.1.1 1.1.1.18 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) ============ =================== -__ https://pypi.python.org/pypi/stix/1.2.0.9 -__ https://github.com/STIXProject/python-stix/tree/v1.2.0.9 +__ https://pypi.python.org/pypi/stix/1.2.0.10 +__ https://github.com/STIXProject/python-stix/tree/v1.2.0.10 __ https://pypi.python.org/pypi/stix/1.1.1.18 __ https://github.com/STIXProject/python-stix/tree/v1.1.1.18 __ https://pypi.python.org/pypi/stix/1.1.0.6 diff --git a/setup.cfg b/setup.cfg index 6b565d4f..91a53db1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.2.0.9 +current_version = 1.2.0.10 parse = (?P\d+)\.(?P\d+)\.(?P\d+).(?P\d+) serialize = {major}.{minor}.{patch}.{revision} commit = True diff --git a/stix/version.py b/stix/version.py index 4a78cbb6..a60a45d3 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.9" +__version__ = "1.2.0.10" From 73632d7a6f7d9ec86b9500ff0688b235bedfe4a3 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 16 Nov 2020 16:32:15 -0500 Subject: [PATCH 435/438] import changes to prevent deprecation warnings collections module. Fixed #367 --- setup.py | 2 +- stix/base.py | 3 ++- stix/common/profiles.py | 3 ++- stix/common/references.py | 3 ++- stix/common/structured_text.py | 10 ++++++++-- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index fea74856..717d437d 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ def get_long_description(): install_requires = [ 'lxml>=2.2.3 ; python_version == "2.7" or python_version >= "3.5"', 'lxml>=2.2.3,<4.4.0 ; python_version > "2.7" and python_version < "3.5"', - 'mixbox>=1.0.2', + 'mixbox>=1.0.4', 'cybox>=2.1.0.13,<2.1.1.0', 'python-dateutil', ] diff --git a/stix/base.py b/stix/base.py index 14f50a6d..b5c417ee 100644 --- a/stix/base.py +++ b/stix/base.py @@ -8,6 +8,7 @@ from sys import version_info # mixbox +from mixbox import compat from mixbox import idgen from mixbox import entities from mixbox import fields @@ -311,7 +312,7 @@ def istypeof(cls, obj): return isinstance(obj, cls) -class TypedList(TypedCollection, collections.MutableSequence): +class TypedList(TypedCollection, compat.MutableSequence): def __init__(self, *args): TypedCollection.__init__(self, *args) diff --git a/stix/common/profiles.py b/stix/common/profiles.py index a4499d01..1e523b6c 100644 --- a/stix/common/profiles.py +++ b/stix/common/profiles.py @@ -3,13 +3,14 @@ import collections +from mixbox import compat from mixbox import fields import stix from stix.bindings import stix_common as stix_common_binding -class Profiles(collections.MutableSequence, stix.Entity): +class Profiles(compat.MutableSequence, stix.Entity): _binding = stix_common_binding _binding_class = stix_common_binding.ProfilesType _namespace = 'http://stix.mitre.org/common-1' diff --git a/stix/common/references.py b/stix/common/references.py index 45bfbb27..f5c7dc1e 100644 --- a/stix/common/references.py +++ b/stix/common/references.py @@ -2,13 +2,14 @@ # See LICENSE.txt for complete terms. import collections +from mixbox import compat from mixbox import fields import stix from stix.bindings import stix_common as stix_common_binding -class References(collections.MutableSequence, stix.Entity): +class References(compat.MutableSequence, stix.Entity): _binding = stix_common_binding _binding_class = stix_common_binding.ReferencesType _namespace = 'http://stix.mitre.org/common-1' diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index b90c0396..498e5457 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -10,7 +10,13 @@ import stix import stix.utils as utils import stix.bindings.stix_common as stix_common_binding -from mixbox.vendor.six import text_type +from mixbox.vendor.six import PY2, PY3, text_type + + +if PY2: + from collections import Sequence +elif PY3: + from collections.abc import Sequence #: Default ordinality value for StructuredText. @@ -105,7 +111,7 @@ def _unset_default(text): text.ordinality = ordinality -class StructuredTextList(stix.TypedCollection, collections.Sequence): +class StructuredTextList(stix.TypedCollection, Sequence): """A sequence type used to store StructureText objects. Args: From 143b9c30446e17d782c004eea6d254f28d42f149 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 16 Nov 2020 17:21:32 -0500 Subject: [PATCH 436/438] update changes for v1.2.0.11 --- CHANGES.txt | 17 +++++++++++++++++ setup.cfg | 3 +++ 2 files changed, 20 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index ff7c6bea..b22812d1 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,7 @@ +Version 1.2.0.11 +2020-11-16 +- #367 Fix deprecation warning from collections module + Version 1.2.0.10 2020-05-01 - #366 Check add_reference methods to prevent NoneType has no attribute 'append' @@ -56,6 +60,19 @@ Version 1.2.0.2 - #302 Correctly handle CIQ Identity objects. - Add additional fields to CIQ Identity object. +Version 1.1.1.19 +2020-11-16 +- #367 Fix deprecation warning from collections module + +Version 1.1.1.18 +2020-05-01 +- #366 Check add_reference methods to prevent NoneType has no attribute 'append' +- Changes to STIXPackage to prevent the empty tag from appearing in serialization + +Version 1.1.1.17 +2020-04-21 +- #365 AISMarkingStructure not serializing correctly. PY3 compatibility issue + Version 1.1.1.16 2020-04-16 - #364 TTPs would fail to serialize XML Kill_Chains if no TTP was set diff --git a/setup.cfg b/setup.cfg index 91a53db1..861ed732 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,6 +9,9 @@ tag = True [bumpversion:file:docs/index.rst] +[metadata] +license_file = LICENSE.txt + [bdist_wheel] universal = True From 34f24261b70c7d02ddf0f5696d3919e771dbd32f Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 16 Nov 2020 17:22:29 -0500 Subject: [PATCH 437/438] =?UTF-8?q?Bump=20version:=201.2.0.10=20=E2=86=92?= =?UTF-8?q?=201.2.0.11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/index.rst | 6 +++--- setup.cfg | 2 +- stix/version.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index dddca2ef..a650a9fb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,15 +22,15 @@ version of STIX. ============ =================== STIX Version python-stix Version ============ =================== -1.2 1.2.0.10 (`PyPI`__) (`GitHub`__) +1.2 1.2.0.11 (`PyPI`__) (`GitHub`__) 1.1.1 1.1.1.18 (`PyPI`__) (`GitHub`__) 1.1.0 1.1.0.6 (`PyPI`__) (`GitHub`__) 1.0.1 1.0.1.1 (`PyPI`__) (`GitHub`__) 1.0 1.0.0a7 (`PyPI`__) (`GitHub`__) ============ =================== -__ https://pypi.python.org/pypi/stix/1.2.0.10 -__ https://github.com/STIXProject/python-stix/tree/v1.2.0.10 +__ https://pypi.python.org/pypi/stix/1.2.0.11 +__ https://github.com/STIXProject/python-stix/tree/v1.2.0.11 __ https://pypi.python.org/pypi/stix/1.1.1.18 __ https://github.com/STIXProject/python-stix/tree/v1.1.1.18 __ https://pypi.python.org/pypi/stix/1.1.0.6 diff --git a/setup.cfg b/setup.cfg index 861ed732..e383efad 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.2.0.10 +current_version = 1.2.0.11 parse = (?P\d+)\.(?P\d+)\.(?P\d+).(?P\d+) serialize = {major}.{minor}.{patch}.{revision} commit = True diff --git a/stix/version.py b/stix/version.py index a60a45d3..a2a3a195 100644 --- a/stix/version.py +++ b/stix/version.py @@ -1,4 +1,4 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -__version__ = "1.2.0.10" +__version__ = "1.2.0.11" From a29bd7f9f03b49ad2ea7c698447a79d3b2257848 Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Thu, 25 Nov 2021 06:26:44 +1100 Subject: [PATCH 438/438] docs: Fix a few typos There are small typos in: - examples/vuln_affected_software.py - stix/bindings/stix_common.py - stix/common/structured_text.py - stix/indicator/indicator.py Fixes: - Should read `software` rather than `sofware`. - Should read `property` rather than `proeprty`. - Should read `properties` rather than `properies`. - Should read `ordinality` rather than `ordinaity`. - Should read `interfering` rather than `interferring`. --- examples/vuln_affected_software.py | 2 +- stix/bindings/stix_common.py | 2 +- stix/common/structured_text.py | 4 ++-- stix/indicator/indicator.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/vuln_affected_software.py b/examples/vuln_affected_software.py index 3f1d5532..620087c0 100644 --- a/examples/vuln_affected_software.py +++ b/examples/vuln_affected_software.py @@ -28,7 +28,7 @@ # Wrap the Product Object in an Observable instance observable = Observable(software) -# Attach the Product observable to the affected_sofware list of +# Attach the Product observable to the affected_software list of # RelatedObservable instances. This wraps our Observable in a # RelatedObservable layer. vuln = Vulnerability() diff --git a/stix/bindings/stix_common.py b/stix/bindings/stix_common.py index 64cfac7c..8ae31be4 100644 --- a/stix/bindings/stix_common.py +++ b/stix/bindings/stix_common.py @@ -3495,7 +3495,7 @@ class StructuredTextType(GeneratedsSuper): Note that if the markup tags used by this format would be interpreted as XML information (such as the bracket-based tags of HTML) the text area should be enclosed in a CDATA section to prevent the markup from - interferring with XMLvalidation of the CybOX document. If this + interfering with XMLvalidation of the CybOX document. If this attribute is absent, the implication is that no markup is being used.""" subclass = None superclass = None diff --git a/stix/common/structured_text.py b/stix/common/structured_text.py index 498e5457..9dc73b47 100644 --- a/stix/common/structured_text.py +++ b/stix/common/structured_text.py @@ -64,7 +64,7 @@ def to_dict(self): """Converts this object into a dictionary representation. Note: - If no properies or attributes are set other than ``value``, + If no properties or attributes are set other than ``value``, this will return a string. """ @@ -95,7 +95,7 @@ def _unset_default(text): """Unsets the ordinality of the StructuredText object `text` if the ordinality is equal to the DEFAULT_ORDINALITY. - The ordinaity will be returned to its original state after exiting the + The ordinality will be returned to its original state after exiting the context manager. """ diff --git a/stix/indicator/indicator.py b/stix/indicator/indicator.py index 5842209f..fc941045 100644 --- a/stix/indicator/indicator.py +++ b/stix/indicator/indicator.py @@ -470,7 +470,7 @@ def add_related_indicator(self, indicator): ``related_indicators`` list property. Calling this method is the same as calling ``append()`` on the - ``related_indicators`` proeprty. + ``related_indicators`` property. See Also: The :class:`RelatedIndicators` documentation.