1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//! Vulnerabilities represent the interesection of the [`Advisory`] database
//! and a particular [`Lockfile`].

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().into()))
                    {
                        result.push(path.clone());
                    }
                }
                Some(result)
            }
        })
    }
}