use crate::csaf::traits::util::extract_references::{
ExtractGroupReferences, ExtractProductReferences, define_reference_accessors,
};
use crate::csaf::traits::util::impl_optional_str_field_getter;
use crate::csaf::traits::util::not_present_20::NotPresentInCsaf20;
use crate::csaf::traits::vulnerabilities::product_status_trait::ProductStatusTrait;
use crate::csaf::types::csaf_datetime::CsafDateTime;
use crate::csaf_traits::{
Cwe, FirstKnownExploitationDatesTrait, FlagTrait, InvolvementTrait, MetricTrait, NoteTrait, RemediationTrait,
ThreatTrait, VulnerabilityIdTrait,
};
use crate::schema::csaf2_0::schema::{
Flag as Flag20, Id as Id20, Involvement as Involvement20, Note as Note20, ProductStatus as ProductStatus20,
Remediation as Remediation20, Score as Score20, Threat as Threat20, Vulnerability as Vulnerability20,
};
use crate::schema::csaf2_1::schema::{
FirstKnownExploitationDate as FirstKnownExploitationDate21, Flag as Flag21, Id as Id21,
Involvement as Involvement21, Metric as Metric21, Note as Note21, ProductStatus as ProductStatus21,
Remediation as Remediation21, Threat as Threat21, Vulnerability as Vulnerability21,
};
pub(crate) fn collect_references<V: VulnerabilityTrait>(
vulnerabilities: &[V],
extractor: impl Fn(&V) -> Vec<(String, String)>,
) -> Vec<(String, String)> {
vulnerabilities
.iter()
.enumerate()
.flat_map(|(i, v)| {
extractor(v)
.into_iter()
.map(move |(id, path)| (id, format!("/vulnerabilities/{i}/{path}")))
})
.collect()
}
pub trait VulnerabilityTrait {
type RemediationType: RemediationTrait;
type ProductStatusType: ProductStatusTrait;
type MetricType: MetricTrait;
type ThreatType: ThreatTrait;
type FlagType: FlagTrait;
type InvolvementType: InvolvementTrait;
type VulnerabilityIdType: VulnerabilityIdTrait;
type NoteType: NoteTrait;
type FirstKnownExploitationDatesType: FirstKnownExploitationDatesTrait;
fn get_remediations(&self) -> &Vec<Self::RemediationType>;
fn get_product_status(&self) -> Option<&Self::ProductStatusType>;
fn get_product_status_product_references(&self) -> Vec<(String, String)> {
if let Some(product_status) = self.get_product_status() {
product_status.get_all_product_references()
} else {
Vec::new()
}
}
fn get_metrics(&self) -> Option<&Vec<Self::MetricType>>;
fn get_metrics_path(&self) -> &str;
fn get_metrics_product_references(&self) -> Vec<(String, String)> {
let mut ids: Vec<(String, String)> = Vec::new();
if let Some(metrics) = self.get_metrics() {
let metric_path = self.get_metrics_path();
for (metric_i, metric) in metrics.iter().enumerate() {
for (x_i, x) in metric.get_products().enumerate() {
ids.push((x.to_owned(), format!("{metric_path}/{metric_i}/products/{x_i}")));
}
}
}
ids
}
fn get_threats(&self) -> &Vec<Self::ThreatType>;
fn get_disclosure_date(&self) -> Option<CsafDateTime>;
fn get_discovery_date(&self) -> Option<CsafDateTime>;
fn get_flags(&self) -> Option<&Vec<Self::FlagType>>;
fn get_involvements(&self) -> Option<&Vec<Self::InvolvementType>>;
fn get_cve(&self) -> Option<&str>;
fn get_cwe(&self) -> Option<Vec<Cwe>>;
fn get_ids(&self) -> Option<&Vec<Self::VulnerabilityIdType>>;
fn get_notes(&self) -> Option<&Vec<Self::NoteType>>;
fn get_first_known_exploitation_dates(&self) -> Option<&Vec<Self::FirstKnownExploitationDatesType>>;
define_reference_accessors! {
both: [
(get_remediations_group_references, get_remediations_product_references, get_remediations, "remediations"),
(get_threats_group_references, get_threats_product_references, get_threats, "threats"),
(get_flags_group_references, get_flags_product_references, get_flags, "flags"),
(get_involvements_group_references, get_involvements_product_references, get_involvements, "involvements"),
(get_notes_group_references, get_notes_product_references, get_notes, "notes"),
(get_first_known_exploitation_dates_group_references, get_first_known_exploitation_dates_product_references, get_first_known_exploitation_dates, "first_known_exploitation_dates"),
],
custom_group_extraction: [],
custom_product_extraction: [
get_product_status_product_references,
get_metrics_product_references,
],
}
}
impl VulnerabilityTrait for Vulnerability20 {
type RemediationType = Remediation20;
type ProductStatusType = ProductStatus20;
type MetricType = Score20;
type ThreatType = Threat20;
type FlagType = Flag20;
type InvolvementType = Involvement20;
type VulnerabilityIdType = Id20;
type NoteType = Note20;
type FirstKnownExploitationDatesType = NotPresentInCsaf20;
fn get_remediations(&self) -> &Vec<Self::RemediationType> {
&self.remediations
}
fn get_product_status(&self) -> Option<&Self::ProductStatusType> {
self.product_status.as_ref()
}
fn get_metrics(&self) -> Option<&Vec<Self::MetricType>> {
Some(&self.scores)
}
fn get_metrics_path(&self) -> &str {
"scores"
}
fn get_threats(&self) -> &Vec<Self::ThreatType> {
&self.threats
}
fn get_disclosure_date(&self) -> Option<CsafDateTime> {
self.release_date.as_ref().map(CsafDateTime::from)
}
fn get_discovery_date(&self) -> Option<CsafDateTime> {
self.discovery_date.as_ref().map(CsafDateTime::from)
}
fn get_flags(&self) -> Option<&Vec<Self::FlagType>> {
self.flags.as_ref()
}
fn get_involvements(&self) -> Option<&Vec<Self::InvolvementType>> {
self.involvements.as_ref()
}
impl_optional_str_field_getter!(get_cve, cve);
fn get_cwe(&self) -> Option<Vec<Cwe>> {
self.cwe.as_ref().map(|cwe| vec![Cwe::from(cwe)])
}
fn get_ids(&self) -> Option<&Vec<Self::VulnerabilityIdType>> {
self.ids.as_ref()
}
fn get_notes(&self) -> Option<&Vec<Self::NoteType>> {
self.notes.as_deref()
}
fn get_first_known_exploitation_dates(&self) -> Option<&Vec<Self::FirstKnownExploitationDatesType>> {
None
}
}
impl VulnerabilityTrait for Vulnerability21 {
type RemediationType = Remediation21;
type ProductStatusType = ProductStatus21;
type MetricType = Metric21;
type ThreatType = Threat21;
type FlagType = Flag21;
type InvolvementType = Involvement21;
type VulnerabilityIdType = Id21;
type NoteType = Note21;
type FirstKnownExploitationDatesType = FirstKnownExploitationDate21;
fn get_remediations(&self) -> &Vec<Self::RemediationType> {
&self.remediations
}
fn get_product_status(&self) -> Option<&Self::ProductStatusType> {
self.product_status.as_ref()
}
fn get_metrics(&self) -> Option<&Vec<Self::MetricType>> {
self.metrics.as_ref()
}
fn get_metrics_path(&self) -> &str {
"metrics"
}
fn get_threats(&self) -> &Vec<Self::ThreatType> {
&self.threats
}
fn get_disclosure_date(&self) -> Option<CsafDateTime> {
self.disclosure_date.as_ref().map(CsafDateTime::from)
}
fn get_discovery_date(&self) -> Option<CsafDateTime> {
self.discovery_date.as_ref().map(CsafDateTime::from)
}
fn get_flags(&self) -> Option<&Vec<Self::FlagType>> {
self.flags.as_ref()
}
fn get_involvements(&self) -> Option<&Vec<Self::InvolvementType>> {
self.involvements.as_ref()
}
impl_optional_str_field_getter!(get_cve, cve);
fn get_cwe(&self) -> Option<Vec<Cwe>> {
self.cwes.as_ref().map(|cwes| cwes.iter().map(Cwe::from).collect())
}
fn get_ids(&self) -> Option<&Vec<Self::VulnerabilityIdType>> {
self.ids.as_ref()
}
fn get_notes(&self) -> Option<&Vec<Self::NoteType>> {
self.notes.as_deref()
}
fn get_first_known_exploitation_dates(&self) -> Option<&Vec<Self::FirstKnownExploitationDatesType>> {
self.first_known_exploitation_dates.as_ref()
}
}