1use crate::{parse_uri_attribute, CPEName};
5use chrono::{DateTime, Utc};
6use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
7use std::fmt;
8use std::marker::PhantomData;
9use std::str::FromStr;
10#[derive(Deserialize, Serialize, Debug, Clone)]
13#[serde(rename_all = "kebab-case")]
14pub struct CPEList {
15 pub generator: Generator,
16 pub cpe_item: Vec<CPEItem>,
17}
18#[derive(Deserialize, Serialize, Debug, Clone)]
33#[serde(deny_unknown_fields)]
34pub struct CPEItem {
35 #[serde(rename(deserialize = "@name"), deserialize_with = "parse_name")]
36 pub name: String,
37 #[serde(default, rename(serialize = "deprecated", deserialize = "@deprecated"))]
38 pub deprecated: bool,
39 #[serde(
40 default,
41 rename(serialize = "deprecation_date", deserialize = "@deprecation_date"),
42 skip_serializing_if = "Option::is_none"
43 )]
44 pub deprecation_date: Option<DateTime<Utc>>,
45 #[serde(rename(serialize = "cpe23", deserialize = "cpe23-item"))]
46 pub cpe23_item: CPE23Item,
47 #[serde(default)]
48 pub title: Vec<Title>,
49 #[serde(skip_serializing_if = "Option::is_none")]
50 pub notes: Option<Vec<Notes>>,
51 pub references: Option<References>,
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub check: Option<Vec<Check>>,
54}
55
56#[derive(Deserialize, Serialize, Debug, Clone)]
57#[serde(deny_unknown_fields)]
58pub struct Title {
59 #[serde(rename(deserialize = "@lang"))]
60 pub lang: String,
61 #[serde(rename(deserialize = "$value"), deserialize_with = "parse_name")]
62 pub value: String,
63}
64#[derive(Deserialize, Serialize, Debug, Clone)]
69#[serde(deny_unknown_fields)]
70pub struct Notes {
71 #[serde(rename(deserialize = "@lang"))]
72 pub lang: String,
73 #[serde(rename(deserialize = "$value"))]
74 pub value: String,
75}
76#[derive(Debug, Deserialize, Serialize, PartialEq, Clone)]
84#[serde(deny_unknown_fields)]
85pub struct Check {
86 pub system: String,
87 pub href: Option<String>,
88 #[serde(rename(deserialize = "$value"))]
89 pub value: String,
90}
91
92#[derive(Deserialize, Serialize, Debug, Clone)]
93#[serde(deny_unknown_fields)]
94pub struct References {
95 pub reference: Vec<Reference>,
96}
97#[derive(Deserialize, Serialize, Debug, Clone)]
105#[serde(deny_unknown_fields)]
106pub struct Reference {
107 #[serde(rename(deserialize = "@href"))]
108 pub href: String,
109 #[serde(rename(deserialize = "$value"))]
110 pub value: String,
111}
112
113#[derive(Deserialize, Serialize, Debug, Clone)]
114#[serde(deny_unknown_fields)]
115pub struct CPE23Item {
116 #[serde(
117 rename(deserialize = "@name"),
118 deserialize_with = "uri_to_attribute",
119 serialize_with = "attribute_to_uri"
120 )]
121 pub name: CPEName,
122 #[serde(skip_serializing_if = "Option::is_none")]
123 pub deprecation: Option<Deprecation>,
124}
125
126#[derive(Deserialize, Serialize, Debug, Clone, Default)]
127#[serde(deny_unknown_fields)]
128pub struct Deprecation {
129 #[serde(rename(deserialize = "@date"))]
130 pub date: DateTime<Utc>,
131 #[serde(rename(deserialize = "deprecated-by"))]
132 pub deprecated_by: Vec<DeprecatedInfo>,
133}
134
135#[derive(Deserialize, Serialize, Debug, Clone)]
136#[serde(deny_unknown_fields)]
137pub struct DeprecatedInfo {
138 #[serde(
139 rename(deserialize = "@name"),
140 deserialize_with = "uri_to_attribute",
141 serialize_with = "attribute_to_uri"
142 )]
143 pub name: CPEName,
144 #[serde(rename(deserialize = "@type"))]
145 pub r#type: String,
146}
147#[derive(Deserialize, Serialize, Debug, Clone)]
154#[serde(deny_unknown_fields)]
155pub struct Generator {
156 pub product_name: String,
158 pub product_version: String,
160 pub schema_version: String,
162 pub timestamp: DateTime<Utc>,
170}
171
172fn parse_name<'de, D>(deserializer: D) -> Result<String, D::Error>
173where
174 D: Deserializer<'de>,
175{
176 struct ParseString(PhantomData<CPEName>);
177 impl<'de> de::Visitor<'de> for ParseString {
178 type Value = String;
179 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
180 formatter.write_str("parse_name")
181 }
182 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
183 where
184 E: de::Error,
185 {
186 match parse_uri_attribute(value) {
188 Ok(p) => Ok(p),
189 Err(e) => Err(de::Error::custom(e)),
190 }
191 }
192 fn visit_seq<S>(self, visitor: S) -> Result<Self::Value, S::Error>
193 where
194 S: de::SeqAccess<'de>,
195 {
196 Deserialize::deserialize(de::value::SeqAccessDeserializer::new(visitor))
197 }
198 }
199 deserializer.deserialize_any(ParseString(PhantomData))
200}
201
202pub fn uri_to_attribute<'de, D>(deserializer: D) -> Result<CPEName, D::Error>
203where
204 D: Deserializer<'de>,
205{
206 struct UriToAttribute(PhantomData<CPEName>);
207 impl<'de> de::Visitor<'de> for UriToAttribute {
208 type Value = CPEName;
209 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
210 formatter.write_str("uri_to_attribute")
211 }
212 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
213 where
214 E: de::Error,
215 {
216 let value = parse_uri_attribute(value).unwrap_or_default();
219 match CPEName::from_str(value.as_str()) {
220 Ok(p) => Ok(p),
221 Err(e) => Err(de::Error::custom(e)),
222 }
223 }
224 fn visit_seq<S>(self, visitor: S) -> Result<Self::Value, S::Error>
225 where
226 S: de::SeqAccess<'de>,
227 {
228 Deserialize::deserialize(de::value::SeqAccessDeserializer::new(visitor))
229 }
230 }
231 deserializer.deserialize_any(UriToAttribute(PhantomData))
232}
233
234pub fn attribute_to_uri<S>(cpe: &CPEName, s: S) -> Result<S::Ok, S::Error>
235where
236 S: Serializer,
237{
238 s.serialize_str(&cpe.to_string())
239}