1# Copyright (c) 2017, The MITRE Corporation. All rights reserved. 2# See LICENSE.txt for complete terms. 3 4# stdlib 5import functools 6 7# mixbox 8from mixbox import fields 9from mixbox import typedlist 10 11# cybox 12from cybox.core import Observable 13 14# internal 15import stix 16import stix.bindings.stix_common as common_binding 17import stix.bindings.stix_core as core_binding 18import stix.bindings.report as report_binding 19 20# deprecation warnings 21from stix.utils import deprecated 22 23# relative 24from .vocabs import VocabField 25from .information_source import InformationSource 26from .confidence import Confidence 27 28 29ALLOWED_SCOPE = ('inclusive', 'exclusive') 30 31 32def validate_scope(instance, value): 33 if not value: 34 return 35 elif value in ALLOWED_SCOPE: 36 return 37 else: 38 msg = "Scope must be one of {0}. Received '{1}'" 39 msg = msg.format(ALLOWED_SCOPE, value) 40 raise ValueError(msg) 41 42 43class GenericRelationship(stix.Entity): 44 _namespace = "http://stix.mitre.org/common-1" 45 _binding = common_binding 46 _binding_class = common_binding.GenericRelationshipType 47 48 confidence = fields.TypedField("Confidence", Confidence) 49 information_source = fields.TypedField("Information_Source", InformationSource) 50 relationship = VocabField("Relationship") 51 52 def __init__(self, confidence=None, information_source=None, relationship=None): 53 super(GenericRelationship, self).__init__() 54 55 self.confidence = confidence 56 self.information_source = information_source 57 self.relationship = relationship 58 59 60class RelatedPackageRef(GenericRelationship): 61 _namespace = "http://stix.mitre.org/common-1" 62 _binding = common_binding 63 _binding_class = common_binding.RelatedPackageRefType 64 65 idref = fields.IdrefField("idref") 66 timestamp = fields.DateTimeField("timestamp") 67 68 def __init__(self, idref=None, timestamp=None, confidence=None, 69 information_source=None, relationship=None): 70 71 super(RelatedPackageRef, self).__init__( 72 confidence=confidence, 73 information_source=information_source, 74 relationship=relationship 75 ) 76 77 self.idref = idref 78 self.timestamp = timestamp 79 80 81class GenericRelationshipEntity(stix.Entity): 82 _namespace = "http://stix.mitre.org/common-1" 83 _binding = common_binding 84 _binding_class = _binding.GenericRelationshipListType 85 86 _ALLOWED_SCOPE = ('inclusive', 'exclusive') 87 88 scope = fields.TypedField("scope") 89 90 def __init__(self, scope=None, *args): 91 92 super(GenericRelationshipEntity, self).__init__(*args) 93 self.scope = scope 94 95 def __nonzero__(self): 96 return ( 97 super(GenericRelationshipList, self).__nonzero__() or 98 bool(self.scope) 99 ) 100 101 102class GenericRelationshipList(stix.EntityList): 103 """Base class for concrete GenericRelationshipList types. 104 105 Note: 106 Subclasses must supply exactly one multiple TypedField. 107 """ 108 109 _namespace = "http://stix.mitre.org/common-1" 110 _binding = common_binding 111 _binding_class = _binding.GenericRelationshipListType 112 113 scope = fields.TypedField("scope", preset_hook=validate_scope) 114 115 def __init__(self, scope=None, *args): 116 super(GenericRelationshipList, self).__init__(*args) 117 self.scope = scope 118 119 def __nonzero__(self): 120 return (super(GenericRelationshipList, self).__nonzero__() or 121 bool(self.scope)) 122 123 @classmethod 124 def _dict_as_list(cls): 125 return False 126 127 128class _RelatedPackageList(typedlist.TypedList): 129 def __init__(self, *args): 130 super(_RelatedPackageList, self).__init__(type=RelatedPackageRef, *args) 131 132 def _fix_value(self, value): 133 from stix.core import STIXPackage 134 135 if isinstance(value, STIXPackage) and value.id_: 136 return RelatedPackageRef(idref=value.id_, timestamp=value.timestamp) 137 138 fmt = ("Cannot add type '{0}' to RelatedPackageRefs collection. " 139 "Expected RelatedPackageRef or STIXPackage") 140 error = fmt.format(type(value)) 141 raise TypeError(error) 142 143 def _is_valid(self, value): 144 deprecated.warn(value) 145 return super(_RelatedPackageList, self)._is_valid(value) 146 147 148class RelatedPackageRefs(stix.EntityList): 149 _namespace = 'http://stix.mitre.org/common-1' 150 _binding = common_binding 151 _binding_class = common_binding.RelatedPackageRefsType 152 153 package = fields.TypedField( 154 name="Package_Reference", 155 type_=RelatedPackageRef, 156 multiple=True, 157 key_name="packages", 158 listfunc=_RelatedPackageList 159 ) 160 161 @classmethod 162 def _dict_as_list(cls): 163 return False 164 165 166class _BaseRelated(GenericRelationship): 167 """A base class for related types. 168 169 This class is not a real STIX type and should not be directly instantiated. 170 171 Note: 172 Subclasses must supply a TypedField named `item`! 173 """ 174 175 item = None # override in subclass. 176 177 def __init__(self, item=None, confidence=None, 178 information_source=None, relationship=None): 179 180 super(_BaseRelated, self).__init__( 181 confidence, 182 information_source, 183 relationship 184 ) 185 186 self.item = item 187 188 189class RelatedCampaign(_BaseRelated): 190 _namespace = "http://stix.mitre.org/common-1" 191 _binding = common_binding 192 _binding_class = common_binding.RelatedCampaignType 193 194 # _BaseRelated requires an "item" field. 195 item = fields.TypedField("Campaign", type_="stix.campaign.Campaign") 196 197 198class RelatedCOA(_BaseRelated): 199 _namespace = "http://stix.mitre.org/common-1" 200 _binding = common_binding 201 _binding_class = common_binding.RelatedCourseOfActionType 202 203 # _BaseRelated requires an "item" field. 204 item = fields.TypedField("Course_Of_Action", type_="stix.coa.CourseOfAction") 205 206 207class RelatedExploitTarget(_BaseRelated): 208 _namespace = "http://stix.mitre.org/common-1" 209 _binding = common_binding 210 _binding_class = common_binding.RelatedExploitTargetType 211 212 # _BaseRelated requires an "item" field. 213 item = fields.TypedField("Exploit_Target", type_="stix.exploit_target.ExploitTarget") 214 215 216class RelatedIdentity(_BaseRelated): 217 _namespace = 'http://stix.mitre.org/common-1' 218 _binding = common_binding 219 _binding_class = common_binding.RelatedIdentityType 220 221 # _BaseRelated requires an "item" field. 222 item = fields.TypedField("Identity", type_="stix.common.identity.Identity", factory="stix.common.identity.IdentityFactory") 223 224 225class RelatedIncident(_BaseRelated): 226 _namespace = "http://stix.mitre.org/common-1" 227 _binding = common_binding 228 _binding_class = common_binding.RelatedIncidentType 229 230 # _BaseRelated requires an "item" field. 231 item = fields.TypedField("Incident", type_="stix.incident.Incident") 232 233class RelatedIndicator(_BaseRelated): 234 _namespace = "http://stix.mitre.org/common-1" 235 _binding = common_binding 236 _binding_class = common_binding.RelatedIndicatorType 237 238 # _BaseRelated requires an "item" field. 239 item = fields.TypedField("Indicator", type_="stix.indicator.Indicator") 240 241 242class RelatedObservable(_BaseRelated): 243 _namespace = "http://stix.mitre.org/common-1" 244 _binding = common_binding 245 _binding_class = common_binding.RelatedObservableType 246 247 # _BaseRelated requires an "item" field. 248 item = fields.TypedField("Observable", type_=Observable) 249 250class RelatedThreatActor(_BaseRelated): 251 _namespace = "http://stix.mitre.org/common-1" 252 _binding = common_binding 253 _binding_class = common_binding.RelatedThreatActorType 254 255 # _BaseRelated requires an "item" field. 256 item = fields.TypedField("Threat_Actor", type_="stix.threat_actor.ThreatActor") 257 258 259class RelatedTTP(_BaseRelated): 260 _namespace = "http://stix.mitre.org/common-1" 261 _binding = common_binding 262 _binding_class = common_binding.RelatedTTPType 263 264 # _BaseRelated requires an "item" field. 265 item = fields.TypedField("TTP", type_="stix.ttp.TTP") 266 267 268class RelatedPackage(_BaseRelated): 269 _namespace = "http://stix.mitre.org/stix-1" 270 _binding = core_binding 271 _binding_class = core_binding.RelatedPackageType 272 273 # _BaseRelated requires an "item" field. 274 item = fields.TypedField("Package", type_="stix.core.STIXPackage", preset_hook=deprecated.field) 275 276 277class RelatedReport(_BaseRelated): 278 _namespace = "http://stix.mitre.org/common-1" 279 _binding = common_binding 280 _binding_class = common_binding.RelatedReportType 281 282 # _BaseRelated requires an "item" field. 283 item = fields.TypedField("Report", type_="stix.report.Report") 284 285 286class RelatedCampaignRef(_BaseRelated): 287 _namespace = "http://stix.mitre.org/common-1" 288 _binding = common_binding 289 _binding_class = _binding.RelatedCampaignReferenceType 290 291 # _BaseRelated requires an "item" field. 292 item = fields.TypedField("Campaign", type_="stix.common.CampaignRef") 293 294 295class RelatedPackages(GenericRelationshipList): 296 _namespace = 'http://stix.mitre.org/stix-1' 297 _binding = core_binding 298 _binding_class = core_binding.RelatedPackagesType 299 300 related_package = fields.TypedField("Related_Package", RelatedPackage, multiple=True, key_name="related_packages") 301 302 303class RelatedReports(GenericRelationshipList): 304 _namespace = 'http://stix.mitre.org/Report-1' 305 _binding = report_binding 306 _binding_class = report_binding.RelatedReportsType 307 308 related_report = fields.TypedField("Related_Report", RelatedReport, multiple=True, key_name="related_reports") 309