1use std::hash::{Hash, Hasher};
2use std::rc::Rc;
3
4use serde::Deserialize;
5
6use crate::cwe::content_history::ContentHistory;
7use crate::cwe::notes::Notes;
8use crate::cwe::structured_text::{StructuredCode, StructuredText};
9
10#[derive(Debug, Deserialize)]
11#[serde(deny_unknown_fields)]
12pub struct Weaknesses {
13 #[serde(rename = "Weakness", default)]
14 pub weaknesses: Vec<Rc<Weakness>>,
15}
16
17#[derive(Debug, Deserialize)]
18#[serde(rename = "Weakness")]
19#[serde(deny_unknown_fields)]
20pub struct Weakness {
21 #[serde(rename = "@ID")]
22 pub id: i64,
23 #[serde(rename = "@Name")]
24 pub name: String,
25 #[serde(rename = "@Abstraction")]
26 pub abstraction: String,
27 #[serde(rename = "@Structure")]
28 pub structure: String,
29 #[serde(rename = "@Status")]
30 pub status: String,
31 #[serde(rename = "Description")]
32 pub description: String,
33 #[serde(rename = "Extended_Description")]
34 pub extended_description: Option<StructuredText>,
35 #[serde(rename = "Related_Weaknesses")]
36 pub related_weaknesses: Option<RelatedWeaknesses>,
37 #[serde(rename = "Demonstrative_Examples")]
38 pub demonstrative_examples: Option<DemonstrativeExamples>,
39 #[serde(rename = "Weakness_Ordinalities")]
40 pub weakness_ordinalities: Option<WeaknessOrdinalities>,
41 #[serde(rename = "Applicable_Platforms")]
42 pub applicable_platforms: Option<ApplicablePlatforms>,
43 #[serde(rename = "Background_Details")]
44 pub background_details: Option<BackgroundDetails>,
45 #[serde(rename = "Modes_Of_Introduction")]
46 pub modes_of_introduction: Option<ModesOfIntroduction>,
47 #[serde(rename = "Likelihood_Of_Exploit")]
48 pub likelihood_of_exploit: Option<String>,
49 #[serde(rename = "Alternate_Terms")]
50 pub alternate_terms: Option<AlternateTerms>,
51 #[serde(rename = "Common_Consequences")]
52 pub common_consequences: Option<CommonConsequences>,
53 #[serde(rename = "Detection_Methods")]
54 pub detection_methods: Option<DetectionMethods>,
55 #[serde(rename = "Potential_Mitigations")]
56 pub potential_mitigations: Option<PotentialMitigations>,
57 #[serde(rename = "Observed_Examples")]
58 pub observed_examples: Option<ObservedExamples>,
59 #[serde(rename = "Related_Attack_Patterns")]
60 pub related_attack_patterns: Option<RelatedAttackPatterns>,
61 #[serde(rename = "References")]
62 pub references: Option<References>,
63 #[serde(rename = "Content_History")]
64 pub content_history: ContentHistory,
65 #[serde(rename = "Exploitation_Factors")]
66 pub exploitation_factors: Option<ExploitationFactors>,
67 #[serde(rename = "Functional_Areas")]
68 pub functional_areas: Option<FunctionalAreas>,
69 #[serde(rename = "Affected_Resources")]
70 pub affected_resources: Option<AffectedResources>,
71 #[serde(rename = "Taxonomy_Mappings")]
72 pub taxonomy_mappings: Option<TaxonomyMappings>,
73 #[serde(rename = "Notes")]
74 pub notes: Option<Notes>,
75 #[serde(rename = "Mapping_Notes")]
76 pub mapping_notes: Option<MappingNotes>,
77}
78
79impl PartialEq<Self> for Weakness {
80 fn eq(&self, other: &Self) -> bool {
81 self.id == other.id
82 }
83}
84
85impl Eq for Weakness {}
86
87impl Hash for Weakness {
88 fn hash<H: Hasher>(&self, state: &mut H) {
89 state.write_i64(self.id)
90 }
91}
92
93impl Weakness {
94 pub fn direct_ancestors(&self) -> Vec<i64> {
97 let mut ancestors = Vec::new();
98 if let Some(related_weaknesses) = &self.related_weaknesses {
99 for related_weakness in &related_weaknesses.related_weaknesses {
100 if related_weakness.nature == RelatedNature::ChildOf {
101 ancestors.push(related_weakness.cwe_id);
102 }
103 }
104 }
105 ancestors
106 }
107}
108
109#[derive(Debug, Deserialize, PartialEq)]
110#[serde(deny_unknown_fields)]
111pub enum RelatedNature {
112 ChildOf,
113 ParentOf,
114 StartsWith,
115 CanFollow,
116 CanPrecede,
117 RequiredBy,
118 Requires,
119 CanAlsoBe,
120 PeerOf,
121}
122
123#[derive(Debug, Deserialize)]
124#[serde(deny_unknown_fields)]
125pub struct WeaknessOrdinalities {
126 #[serde(rename = "$value")]
127 pub weakness_ordinalities: Vec<WeaknessOrdinality>,
128}
129
130#[derive(Debug, Deserialize)]
131#[serde(deny_unknown_fields)]
132pub struct WeaknessOrdinality {
133 #[serde(rename = "Ordinality")]
134 pub ordinality: Option<String>,
135 #[serde(rename = "Description")]
136 pub description: Option<String>,
137}
138
139#[derive(Debug, Deserialize)]
140#[serde(rename = "Related_Weaknesses")]
141#[serde(deny_unknown_fields)]
142pub struct RelatedWeaknesses {
143 #[serde(rename = "Related_Weakness", default)]
144 pub related_weaknesses: Vec<RelatedWeakness>,
145}
146
147#[derive(Debug, Deserialize)]
148#[serde(rename = "Related_Weakness")]
149#[serde(deny_unknown_fields)]
150pub struct RelatedWeakness {
151 #[serde(rename = "@Nature")]
152 pub nature: RelatedNature,
153 #[serde(rename = "@CWE_ID")]
154 pub cwe_id: i64,
155 #[serde(rename = "@View_ID")]
156 pub view_id: i64,
157 #[serde(rename = "@Chain_ID")]
158 pub chain_id: Option<i64>,
159 #[serde(rename = "@Ordinal")]
160 pub ordinal: Option<String>,
161}
162
163#[derive(Debug, Deserialize)]
164pub struct MappingNotes {
165}
166
167#[derive(Debug, Deserialize)]
168#[serde(deny_unknown_fields)]
169pub struct TaxonomyMappings {
170 #[serde(rename = "$value")]
171 pub taxonomy_mappings: Vec<TaxonomyMapping>,
172}
173
174#[derive(Debug, Deserialize)]
175#[serde(deny_unknown_fields)]
176pub struct TaxonomyMapping {
177 #[serde(rename = "@Taxonomy_Name")]
178 pub taxonomy_name: String,
179 #[serde(rename = "Entry_ID")]
180 pub entry_id: Option<String>,
181 #[serde(rename = "Entry_Name")]
182 pub entry_name: Option<String>,
183 #[serde(rename = "Mapping_Fit")]
184 pub mapping_fit: Option<String>,
185}
186
187#[derive(Debug, Deserialize)]
188#[serde(deny_unknown_fields)]
189pub struct FunctionalAreas {
190 #[serde(rename = "$value")]
191 pub functional_areas: Vec<String>,
192}
193
194#[derive(Debug, Deserialize)]
195#[serde(deny_unknown_fields)]
196pub struct AffectedResources {
197 #[serde(rename = "$value")]
198 pub affected_resources: Vec<String>,
199}
200
201#[derive(Debug, Deserialize)]
202#[serde(deny_unknown_fields)]
203pub struct References {
204 #[serde(rename = "$value")]
205 pub references: Vec<Reference>,
206}
207
208#[derive(Debug, Deserialize)]
209#[serde(deny_unknown_fields)]
210pub struct Reference {
211 #[serde(rename = "@External_Reference_ID")]
212 pub external_reference_id: String,
213 #[serde(rename = "@Section")]
214 pub section: Option<String>,
215}
216
217#[derive(Debug, Deserialize)]
218#[serde(deny_unknown_fields)]
219pub struct RelatedAttackPatterns {
220 #[serde(rename = "$value")]
221 pub related_attack_patterns: Vec<RelatedAttackPattern>,
222}
223
224#[derive(Debug, Deserialize)]
225#[serde(deny_unknown_fields)]
226pub struct RelatedAttackPattern {
227 #[serde(rename = "@CAPEC_ID")]
228 pub caped_id: i64,
229}
230
231#[derive(Debug, Deserialize)]
232#[serde(deny_unknown_fields)]
233pub struct ObservedExamples {
234 #[serde(rename = "$value")]
235 pub observed_examples: Vec<ObservedExample>,
236}
237
238#[derive(Debug, Deserialize)]
239#[serde(deny_unknown_fields)]
240pub struct ObservedExample {
241 #[serde(rename = "Reference")]
242 pub reference: String,
243 #[serde(rename = "Description")]
244 pub description: String,
245 #[serde(rename = "Link")]
246 pub link: String,
247}
248
249#[derive(Debug, Deserialize)]
250#[serde(deny_unknown_fields)]
251pub struct DemonstrativeExamples {
252 #[serde(rename = "Demonstrative_Example")]
253 pub examples: Vec<DemonstrativeExample>,
254}
255
256#[derive(Debug, Deserialize)]
257#[serde(deny_unknown_fields)]
258pub struct DemonstrativeExample {
259 #[serde(rename = "@Demonstrative_Example_ID")]
260 pub demonstrative_example_id: Option<String>,
261 #[serde(rename = "$value")]
262 pub children: Vec<DemonstrativeExampleChild>,
263}
264
265#[derive(Debug, Deserialize)]
266#[serde(deny_unknown_fields)]
267pub enum DemonstrativeExampleChild {
268 #[serde(rename = "Title_Text")]
269 TitleText(String),
270 #[serde(rename = "Intro_Text")]
271 IntroText(StructuredText),
272 #[serde(rename = "Body_Text")]
273 BodyText(StructuredText),
274 #[serde(rename = "Example_Code")]
275 ExampleCode(StructuredCode),
276 #[serde(rename = "References")]
277 References {
278 #[serde(rename = "$value")]
279 children: Vec<Reference>,
280 },
281}
282
283#[derive(Debug, Deserialize)]
284#[serde(deny_unknown_fields)]
285pub struct PotentialMitigations {
286 #[serde(rename = "$value")]
287 pub potential_mitigations: Vec<PotentialMitigation>,
288}
289
290#[derive(Debug, Deserialize)]
291#[serde(deny_unknown_fields)]
292pub struct PotentialMitigation {
293 #[serde(rename = "@Mitigation_ID")]
294 pub mitigation_id: Option<String>,
295 #[serde(rename = "$value")]
296 pub children: Vec<PotentialMitigationChild>,
297}
298
299#[derive(Debug, Deserialize)]
300#[serde(deny_unknown_fields)]
301pub enum PotentialMitigationChild {
302 #[serde(rename = "Phase")]
303 Phase(String),
304 #[serde(rename = "Strategy")]
305 Strategy(String),
306 #[serde(rename = "Description")]
307 Description(StructuredText),
308 #[serde(rename = "Effectiveness")]
309 Effectiveness(String),
310 #[serde(rename = "Effectiveness_Notes")]
311 EffectivenessNotes(StructuredText),
312}
313
314#[derive(Debug, Deserialize)]
315#[serde(deny_unknown_fields)]
316pub struct DetectionMethods {
317 #[serde(rename = "$value")]
318 pub detection_methods: Vec<DetectionMethod>,
319}
320
321#[derive(Debug, Deserialize)]
322#[serde(deny_unknown_fields)]
323pub struct DetectionMethod {
324 #[serde(rename = "@Detection_Method_ID")]
325 pub detection_method_id: Option<String>,
326 #[serde(rename = "$value")]
327 pub children: Vec<DetectionMethodChild>,
328}
329
330#[derive(Debug, Deserialize)]
331#[serde(deny_unknown_fields)]
332pub enum DetectionMethodChild {
333 #[serde(rename = "Method")]
334 Method(String),
335 #[serde(rename = "Description")]
336 Description(StructuredText),
337 #[serde(rename = "Effectiveness")]
338 Effectiveness(String),
339 #[serde(rename = "Effectiveness_Notes")]
340 EffectivenessNotes(String),
341}
342
343#[derive(Debug, Deserialize)]
344#[serde(deny_unknown_fields)]
345pub struct CommonConsequences {
346 #[serde(rename = "$value")]
347 pub common_consequences: Vec<Consequence>,
348}
349
350#[derive(Debug, Deserialize)]
351#[serde(deny_unknown_fields)]
352pub struct Consequence {
353 #[serde(rename = "$value")]
354 pub children: Vec<ConsequenceChild>,
355}
356
357#[derive(Debug, Deserialize)]
358#[serde(deny_unknown_fields)]
359pub enum ConsequenceChild {
360 #[serde(rename = "Scope")]
361 Scope(String),
362 #[serde(rename = "Impact")]
363 Impact(String),
364 #[serde(rename = "Note")]
365 Note(String),
366 #[serde(rename = "Likelihood")]
367 Likelihood(String),
368}
369
370#[derive(Debug, Deserialize)]
371#[serde(deny_unknown_fields)]
372pub struct AlternateTerms {
373 #[serde(rename = "$value")]
374 pub alternate_terms: Vec<AlternateTerm>,
375}
376
377#[derive(Debug, Deserialize)]
378#[serde(deny_unknown_fields)]
379pub struct ExploitationFactors {
380 #[serde(rename = "$value")]
381 pub children: Vec<StructuredText>,
382}
383
384#[derive(Debug, Deserialize)]
385#[serde(deny_unknown_fields)]
386pub struct AlternateTerm {
387 #[serde(rename = "Term")]
388 pub term: String,
389 #[serde(rename = "Description")]
390 pub description: Option<StructuredText>,
391}
392
393#[derive(Debug, Deserialize)]
394#[serde(deny_unknown_fields)]
395pub struct ModesOfIntroduction {
396 #[serde(rename = "$value")]
397 pub introductions: Vec<Introduction>,
398}
399
400#[derive(Debug, Deserialize)]
401#[serde(deny_unknown_fields)]
402pub struct Introduction {
403 #[serde(rename = "Phase")]
404 pub phase: String,
405 #[serde(rename = "Note")]
406 pub note: Option<StructuredText>,
407}
408
409#[derive(Debug, Deserialize)]
410#[serde(deny_unknown_fields)]
411pub struct BackgroundDetails {
412 #[serde(rename = "$value", default)]
413 pub background_details: Vec<StructuredText>,
414}
415
416#[derive(Debug, Deserialize)]
417#[serde(deny_unknown_fields)]
418pub struct ApplicablePlatforms {
419 #[serde(rename = "$value")]
420 pub applicable_platforms: Vec<ApplicablePlatform>,
421}
422
423#[derive(Debug, Deserialize)]
424#[serde(deny_unknown_fields)]
425pub enum ApplicablePlatform {
426 Language {
427 #[serde(rename = "@Class")]
428 class: Option<String>,
429 #[serde(rename = "@Name")]
430 name: Option<String>,
431 #[serde(rename = "@Prevalence")]
432 prevalence: String,
433 },
434 Technology {
435 #[serde(rename = "@Name")]
436 name: Option<String>,
437 #[serde(rename = "@Class")]
438 class: Option<String>,
439 #[serde(rename = "@Prevalence")]
440 prevalence: String,
441 },
442 #[serde(rename = "Operating_System")]
443 OperatingSystem {
444 #[serde(rename = "@Name")]
445 name: Option<String>,
446 #[serde(rename = "@Version")]
447 version: Option<String>,
448 #[serde(rename = "@CPE_ID")]
449 cpe_id: Option<String>,
450 #[serde(rename = "@Class")]
451 class: Option<String>,
452 #[serde(rename = "@Prevalence")]
453 prevalence: String,
454 },
455 #[serde(rename = "Architecture")]
456 Architecture {
457 #[serde(rename = "@Name")]
458 name: Option<String>,
459 #[serde(rename = "@Class")]
460 class: Option<String>,
461 #[serde(rename = "@Prevalence")]
462 prevalence: String,
463 },
464}