| //! Vulnerabilities represent the intersection of the [`Advisory`] database |
| //! and a particular `Cargo.lock` file. |
| |
| use crate::{ |
| advisory::{self, affected::FunctionPath, Advisory}, |
| package::Package, |
| }; |
| use serde::{Deserialize, Serialize}; |
| |
| /// A vulnerable package and the associated advisory |
| #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] |
| pub struct Vulnerability { |
| /// Security advisory for which the package is vulnerable |
| pub advisory: advisory::Metadata, |
| |
| /// Versions impacted by this vulnerability |
| pub versions: advisory::Versions, |
| |
| /// More specific information about what this advisory affects (if available) |
| pub affected: Option<advisory::Affected>, |
| |
| /// Vulnerable package |
| pub package: Package, |
| } |
| |
| impl Vulnerability { |
| /// Create `Vulnerability` about a given [`Advisory`] and [`Package`] |
| pub fn new(advisory: &Advisory, package: &Package) -> Self { |
| Self { |
| advisory: advisory.metadata.clone(), |
| versions: advisory.versions.clone(), |
| affected: advisory.affected.clone(), |
| package: package.clone(), |
| } |
| } |
| |
| /// Get the set of functions affected by this vulnerability (if available) |
| pub fn affected_functions(&self) -> Option<Vec<FunctionPath>> { |
| self.affected.as_ref().and_then(|affected| { |
| if affected.functions.is_empty() { |
| None |
| } else { |
| let mut result = vec![]; |
| for (path, versions) in &affected.functions { |
| if versions |
| .iter() |
| .any(|req| req.matches(&self.package.version.clone())) |
| { |
| result.push(path.clone()); |
| } |
| } |
| Some(result) |
| } |
| }) |
| } |
| } |