From 89c831a48b3cd3f823dcca6cd5f2cfa8e6f474fd Mon Sep 17 00:00:00 2001 From: Jia Chao Date: Tue, 11 Jun 2024 15:31:52 +0800 Subject: [PATCH] =?UTF-8?q?CVRF:=20=E5=A4=84=E7=90=86=20vulnerabilities?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jia Chao --- src/lib.rs | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/test.rs | 48 +++++++++++++ 2 files changed, 245 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 495d2b0..f9fabb1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -95,7 +95,7 @@ impl XmlReader { } #[derive(Debug, Clone, Serialize, Deserialize)] -struct CVRF { +pub struct CVRF { // pub documenttitle: String, @@ -118,7 +118,7 @@ struct CVRF { pub producttree: ProductTree, // - pub vulnerability: Vulnerability, + pub vulnerabilities: Vec, } impl CVRF { @@ -133,7 +133,7 @@ impl CVRF { documentnotes: vec![], documentreferences: vec![], producttree: ProductTree::new(), - vulnerability: Vulnerability::new(), + vulnerabilities: vec![], } } @@ -163,6 +163,7 @@ impl CVRF { "DocumentNotes" => self.handle_notes(xmlreader), "DocumentReferences" => self.handle_references(xmlreader), "ProductTree" => self.producttree.load_from_xmlreader(xmlreader), + "Vulnerability" => self.handle_vulnerabilities(xmlreader), _ => {} }, Err(e) => { @@ -199,6 +200,14 @@ impl CVRF { self.documentreferences.push(reference); } } + + fn handle_vulnerabilities(&mut self, xmlreader: &mut XmlReader) { + let mut vulnerability = Vulnerability::new(); + vulnerability.load_from_xmlreader(xmlreader); + if vulnerability.cve != "" { + self.vulnerabilities.push(vulnerability); + } + } } // depth = 2 @@ -628,7 +637,6 @@ impl ProductTree { _type.clear(); _name.clear(); } - } #[instrument(skip(self, xmlreader))] @@ -756,6 +764,84 @@ impl Vulnerability { remediations: Vec::new(), } } + + #[instrument(skip(self, xmlreader))] + fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) { + loop { + let key = if let Some(key) = xmlreader.next_start_name_under_depth(1) { + key + } else { + break; + }; + + match key.as_str() { + "Notes" => self.handle_notes(xmlreader), + "ReleaseDate" => self.releasedate = xmlreader.next_characters(), + "CVE" => self.cve = xmlreader.next_characters(), + "ProductStatuses" => self.handle_productstatuses(xmlreader), + "Threats" => self.handle_threats(xmlreader), + "CVSSScoreSets" => self.handle_cvssscoresets(xmlreader), + "Remediations" => self.handle_remediations(xmlreader), + _ => {} + } + } + } + + fn handle_notes(&mut self, xmlreader: &mut XmlReader) { + loop { + let mut note = Note::new(); + note.load_from_xmlreader(xmlreader); + + if xmlreader.depth < 3 { + break; + } + self.notes.push(note); + } + } + + fn handle_productstatuses(&mut self, xmlreader: &mut XmlReader) { + loop { + let mut status = ProductStatus::new(); + status.load_from_xmlreader(xmlreader); + if xmlreader.depth < 3 { + break; + } + self.productstatuses.push(status); + } + } + + fn handle_threats(&mut self, xmlreader: &mut XmlReader) { + loop { + let mut threat = Threat::new(); + threat.load_from_xmlreader(xmlreader); + if xmlreader.depth < 3 { + break; + } + self.threats.push(threat); + } + } + + fn handle_cvssscoresets(&mut self, xmlreader: &mut XmlReader) { + loop { + let mut scoreset = ScoreSet::new(); + scoreset.load_from_xmlreader(xmlreader); + if xmlreader.depth < 3 { + break; + } + self.cvssscoresets.push(scoreset); + } + } + + fn handle_remediations(&mut self, xmlreader: &mut XmlReader) { + loop { + let mut remediation = Remediation::new(); + remediation.load_from_xmlreader(xmlreader); + if xmlreader.depth < 3 { + break; + } + self.remediations.push(remediation); + } + } } // depth = 4 @@ -779,6 +865,30 @@ impl ProductStatus { products: Vec::new(), } } + + #[instrument(skip(self, xmlreader))] + fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) { + loop { + match xmlreader.next() { + Ok(XmlEvent::StartElement { attributes, .. }) => { + if xmlreader.depth == 4 { + self.status = attributes[0].value.clone(); + } + self.products.push(xmlreader.next_characters()); + } + Ok(XmlEvent::EndElement { .. }) => { + if xmlreader.depth < 4 { + break; + } + } + Err(e) => { + error!("XmlReader Error: {e}"); + break; + } + _ => {} + } + } + } } // depth = 4 @@ -801,6 +911,31 @@ impl Threat { description: String::new(), } } + + #[instrument(skip(self, xmlreader))] + fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) { + loop { + match xmlreader.next() { + Ok(XmlEvent::StartElement { attributes, .. }) => { + if xmlreader.depth == 4 { + self.r#type = attributes[0].value.clone(); + } else { + self.description = xmlreader.next_characters(); + } + } + Ok(XmlEvent::EndElement { .. }) => { + if xmlreader.depth < 4 { + break; + } + } + Err(e) => { + error!("XmlReader Error: {e}"); + break; + } + _ => {} + } + } + } } // depth = 4 @@ -824,6 +959,23 @@ impl ScoreSet { vector: String::new(), } } + + #[instrument(skip(self, xmlreader))] + fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) { + loop { + let key = if let Some(key) = xmlreader.next_start_name_under_depth(3) { + key + } else { + break; + }; + + match key.as_str() { + "BaseScore" => self.basescore = xmlreader.next_characters(), + "Vector" => self.vector = xmlreader.next_characters(), + _ => {} + } + } + } } // depth = 4 @@ -858,4 +1010,45 @@ impl Remediation { url: String::new(), } } + + #[instrument(skip(self, xmlreader))] + fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) { + // 读取类型 + loop { + match xmlreader.next() { + Ok(XmlEvent::StartElement { attributes, .. }) => { + if xmlreader.depth == 4 { + self.r#type = attributes[0].value.clone(); + } + break; + } + Ok(XmlEvent::EndElement { .. }) => { + if xmlreader.depth < 4 { + break; + } + } + Err(e) => { + error!("XmlReader Error: {e}"); + break; + } + _ => {} + } + } + + // 其它字段 + loop { + let key = if let Some(key) = xmlreader.next_start_name_under_depth(3) { + key + } else { + break; + }; + + match key.as_str() { + "Description" => self.description = xmlreader.next_characters(), + "DATE" => self.date = xmlreader.next_characters(), + "URL" => self.url = xmlreader.next_characters(), + _ => {} + } + } + } } diff --git a/src/test.rs b/src/test.rs index a9baac3..6e7edc0 100644 --- a/src/test.rs +++ b/src/test.rs @@ -84,4 +84,52 @@ fn cvrf_works() { cvrf.producttree.packages.get(producttree_src).unwrap()[2].content, producttree_src_content ); + + // vulnerabilities + let cvrf_vulner_releasedate = "2024-04-19"; + let cvrf_vulner_cve = "CVE-2023-45288"; + let cvrf_vulner_productstatues_status = "Fixed"; + let cvrf_vulner_productstatues_product = "openEuler-22.03-LTS"; + let cvrf_vulner_basescore = "7.5"; + let cvrf_vulner_vector = "AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"; + let cvrf_vulner_remedition_type = "Vendor Fix"; + let cvrf_vulner_remedition_descrition = "golang security update"; + let cvrf_vulner_remedition_date = "2024-04-19"; + let cvrf_vulner_remedition_url = "https://www.openeuler.org/en/security/safety-bulletin/detail.html?id=openEuler-SA-2024-1488"; + + assert_eq!(cvrf.vulnerabilities[0].notes.len(), 1); + assert_eq!(cvrf.vulnerabilities[0].releasedate, cvrf_vulner_releasedate); + assert_eq!(cvrf.vulnerabilities[0].cve, cvrf_vulner_cve); + assert_eq!( + cvrf.vulnerabilities[0].productstatuses[0].status, + cvrf_vulner_productstatues_status + ); + assert_eq!( + cvrf.vulnerabilities[0].productstatuses[0].products[2], + cvrf_vulner_productstatues_product + ); + assert_eq!( + cvrf.vulnerabilities[0].cvssscoresets[0].basescore, + cvrf_vulner_basescore + ); + assert_eq!( + cvrf.vulnerabilities[0].cvssscoresets[0].vector, + cvrf_vulner_vector + ); + assert_eq!( + cvrf.vulnerabilities[0].remediations[0].r#type, + cvrf_vulner_remedition_type + ); + assert_eq!( + cvrf.vulnerabilities[0].remediations[0].description, + cvrf_vulner_remedition_descrition + ); + assert_eq!( + cvrf.vulnerabilities[0].remediations[0].date, + cvrf_vulner_remedition_date + ); + assert_eq!( + cvrf.vulnerabilities[0].remediations[0].url, + cvrf_vulner_remedition_url + ); }