Thanks to visit codestin.com
Credit goes to docs.rs

rustsec/
advisory.rs

1//! Security advisories in the RustSec database
2
3pub mod affected;
4mod category;
5mod date;
6mod id;
7mod informational;
8mod keyword;
9mod license;
10pub mod linter;
11mod metadata;
12mod parts;
13pub(crate) mod versions;
14
15pub use self::{
16    affected::Affected,
17    category::Category,
18    date::Date,
19    id::{Id, IdKind},
20    informational::Informational,
21    keyword::Keyword,
22    license::License,
23    linter::Linter,
24    metadata::Metadata,
25    parts::Parts,
26    versions::Versions,
27};
28pub use cvss::Severity;
29
30use crate::{
31    error::{Error, ErrorKind},
32    fs,
33};
34use serde::{Deserialize, Serialize};
35use std::{ffi::OsStr, path::Path, str::FromStr};
36
37/// RustSec Security Advisories
38#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
39pub struct Advisory {
40    /// The `[advisory]` section of a RustSec advisory
41    #[serde(rename = "advisory")]
42    pub metadata: Metadata,
43
44    /// The (optional) `[affected]` section of a RustSec advisory
45    pub affected: Option<Affected>,
46
47    /// Versions related to this advisory which are patched or unaffected.
48    pub versions: Versions,
49}
50
51impl Advisory {
52    /// Load an advisory from a `RUSTSEC-20XX-NNNN.md` file
53    pub fn load_file(path: impl AsRef<Path>) -> Result<Self, Error> {
54        let path = path.as_ref();
55
56        let advisory_data = fs::read_to_string(path)
57            .map_err(|e| format_err!(ErrorKind::Io, "couldn't open {}: {}", path.display(), e))?;
58
59        advisory_data
60            .parse()
61            .map_err(|e| format_err!(ErrorKind::Parse, "error parsing {}: {}", path.display(), e))
62    }
63
64    /// Get advisory ID
65    pub fn id(&self) -> &Id {
66        &self.metadata.id
67    }
68
69    /// Get advisory title
70    pub fn title(&self) -> &str {
71        self.metadata.title.as_ref()
72    }
73
74    /// Get advisory description
75    pub fn description(&self) -> &str {
76        self.metadata.description.as_ref()
77    }
78
79    /// Get the date the underlying issue was reported on
80    pub fn date(&self) -> &Date {
81        &self.metadata.date
82    }
83
84    /// Get the severity of this advisory if it has a CVSS v3 associated
85    pub fn severity(&self) -> Option<Severity> {
86        self.metadata.cvss.as_ref().map(|cvss| cvss.severity())
87    }
88
89    /// Whether the advisory has been withdrawn, i.e. soft-deleted
90    pub fn withdrawn(&self) -> bool {
91        self.metadata.withdrawn.is_some()
92    }
93
94    /// Whether the given `path` represents a draft advisory
95    pub fn is_draft(path: &Path) -> bool {
96        matches!(
97            path.file_name().and_then(OsStr::to_str),
98            Some(name) if name.starts_with("RUSTSEC-0000-0000."),
99        )
100    }
101}
102
103impl FromStr for Advisory {
104    type Err = Error;
105
106    fn from_str(advisory_data: &str) -> Result<Self, Error> {
107        let parts = Parts::parse(advisory_data)?;
108
109        // V4 advisories omit the leading `[advisory]` TOML table
110        let front_matter = if parts.front_matter.starts_with("[advisory]") {
111            parts.front_matter.to_owned()
112        } else {
113            String::from("[advisory]\n") + parts.front_matter
114        };
115
116        let mut advisory: Self = toml::from_str(&front_matter).map_err(Error::from_toml)?;
117
118        if !advisory.metadata.title.is_empty() {
119            fail!(
120                ErrorKind::Parse,
121                "invalid `title` attribute in advisory TOML"
122            );
123        }
124
125        if !advisory.metadata.description.is_empty() {
126            fail!(
127                ErrorKind::Parse,
128                "invalid `description` attribute in advisory TOML"
129            );
130        }
131
132        #[allow(clippy::assigning_clones)]
133        {
134            advisory.metadata.title = parts.title.to_owned();
135            advisory.metadata.description = parts.description.to_owned();
136        }
137
138        Ok(advisory)
139    }
140}