1use super::state::ConstValue;
2use super::*;
3use crate::common::{Description, ProblemType, Product, ProviderMetadata, Reference, Tag};
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use serde_json::Value;
6use std::ops::{Deref, DerefMut};
7use uuid::Uuid;
8
9#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct State;
11
12const STATE_VALUE: &str = "PUBLISHED";
13
14impl Serialize for State {
15 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
16 where
17 S: Serializer,
18 {
19 serializer.serialize_str(STATE_VALUE)
20 }
21}
22
23impl<'de> Deserialize<'de> for State {
24 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
25 where
26 D: Deserializer<'de>,
27 {
28 deserializer
29 .deserialize_str(ConstValue(STATE_VALUE))
30 .map(|()| State)
31 }
32}
33
34#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
35#[serde(rename_all = "camelCase")]
36pub struct Metadata {
37 pub state: State,
38
39 #[serde(flatten)]
40 pub common: common::Metadata,
41}
42
43impl Deref for Metadata {
44 type Target = common::Metadata;
45
46 fn deref(&self) -> &Self::Target {
47 &self.common
48 }
49}
50
51impl DerefMut for Metadata {
52 fn deref_mut(&mut self) -> &mut Self::Target {
53 &mut self.common
54 }
55}
56
57#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
58#[serde(rename_all = "camelCase")]
59pub struct Containers {
60 pub cna: CnaContainer,
61
62 #[serde(default, skip_serializing_if = "Vec::is_empty")]
63 pub adp: Vec<AdpContainer>,
64}
65
66#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
67#[serde(rename_all = "camelCase")]
68pub struct CnaContainer {
69 #[serde(flatten)]
70 pub common: common::CnaContainer,
71
72 #[serde(default, skip_serializing_if = "Option::is_none")]
74 pub date_assigned: Option<Timestamp>,
75
76 #[serde(default, skip_serializing_if = "Option::is_none")]
78 pub date_public: Option<Timestamp>,
79
80 #[serde(default, skip_serializing_if = "Option::is_none")]
82 pub title: Option<String>,
83
84 pub descriptions: Vec<Description>,
86
87 pub affected: Vec<Product>,
89
90 #[serde(default, skip_serializing_if = "Vec::is_empty")]
92 pub problem_types: Vec<ProblemType>,
93
94 #[serde(default, skip_serializing_if = "Vec::is_empty")]
95 pub references: Vec<Reference>,
96
97 #[serde(default, skip_serializing_if = "Vec::is_empty")]
99 pub impacts: Vec<Impact>,
100
101 #[serde(default, skip_serializing_if = "Vec::is_empty")]
103 pub metrics: Vec<Metric>,
104
105 #[serde(default, skip_serializing_if = "Vec::is_empty")]
107 pub configurations: Vec<Description>,
108
109 #[serde(default, skip_serializing_if = "Vec::is_empty")]
111 pub workarounds: Vec<Description>,
112
113 #[serde(default, skip_serializing_if = "Vec::is_empty")]
115 pub solutions: Vec<Description>,
116
117 #[serde(default, skip_serializing_if = "Vec::is_empty")]
119 pub exploits: Vec<Description>,
120
121 #[serde(default, skip_serializing_if = "Vec::is_empty")]
123 pub timeline: Vec<Timeline>,
124
125 #[serde(default, skip_serializing_if = "Vec::is_empty")]
127 pub credits: Vec<Credit>,
128
129 #[serde(default, skip_serializing_if = "Option::is_none")]
131 pub source: Option<Value>,
132
133 #[serde(default, skip_serializing_if = "Vec::is_empty")]
134 pub tags: Vec<Tag>,
135
136 #[serde(default, skip_serializing_if = "Vec::is_empty")]
138 pub taxonomy_mappings: Vec<TaxonomyMapping>,
139}
140
141#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
142#[serde(rename_all = "camelCase")]
143pub struct Impact {
144 #[serde(default, skip_serializing_if = "Option::is_none")]
146 pub capec_id: Option<String>,
147
148 #[serde(default, skip_serializing_if = "Vec::is_empty")]
150 pub descriptions: Vec<Description>,
151}
152
153#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
155#[serde(rename_all = "camelCase")]
156pub struct Metric {
157 #[serde(default, skip_serializing_if = "Option::is_none")]
159 pub format: Option<String>,
160
161 #[serde(default, skip_serializing_if = "Vec::is_empty")]
163 pub scenarios: Vec<Scenario>,
164
165 #[serde(default, skip_serializing_if = "Option::is_none")]
166 #[serde(rename = "cvssV4_0")]
167 pub cvss_v4_0: Option<Value>,
168
169 #[serde(default, skip_serializing_if = "Option::is_none")]
170 #[serde(rename = "cvssV3_1")]
171 pub cvss_v3_1: Option<Value>,
172
173 #[serde(default, skip_serializing_if = "Option::is_none")]
174 #[serde(rename = "cvssV3_0")]
175 pub cvss_v3_0: Option<Value>,
176
177 #[serde(default, skip_serializing_if = "Option::is_none")]
178 #[serde(rename = "cvssV2_0")]
179 pub cvss_v2_0: Option<Value>,
180
181 #[serde(default, skip_serializing_if = "Option::is_none")]
182 pub other: Option<OtherMetric>,
183}
184
185#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
187#[serde(rename_all = "camelCase")]
188pub struct OtherMetric {
189 pub r#type: String,
191 pub content: Value,
193}
194
195#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
196#[serde(rename_all = "camelCase")]
197pub struct Scenario {
198 #[serde(rename = "lang")]
199 pub language: String,
200
201 #[serde(default = "Scenario::default_value")]
203 pub value: String,
204}
205
206impl Scenario {
207 pub fn default_value() -> String {
208 "GENERAL".to_string()
209 }
210}
211
212#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
213#[serde(rename_all = "camelCase")]
214pub struct Timeline {
215 pub time: Timestamp,
217
218 #[serde(rename = "lang")]
220 pub language: String,
221
222 pub value: String,
224}
225
226#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
227#[serde(rename_all = "camelCase")]
228pub struct Credit {
229 #[serde(rename = "lang")]
231 pub language: String,
232
233 pub value: String,
234
235 #[serde(default, skip_serializing_if = "Option::is_none")]
237 pub user: Option<Uuid>,
238
239 #[serde(default, skip_serializing_if = "is_default_credit_type")]
241 pub r#type: CreditType,
242}
243
244fn is_default_credit_type(value: &CreditType) -> bool {
245 *value == CreditType::Finder
246}
247
248#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
250#[serde(rename_all = "lowercase")]
251pub enum CreditType {
252 #[default]
254 Finder,
255 Reporter,
257 Analyst,
259 Coordinator,
261 #[serde(rename = "remediation developer")]
263 RemediationDeveloper,
264 #[serde(rename = "remediation reviewer")]
266 RemediationReviewer,
267 #[serde(rename = "remediation verifier")]
269 RemediationVerifier,
270 Tool,
272 Sponsor,
274 Other,
275}
276
277#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
278#[serde(rename_all = "camelCase")]
279pub struct TaxonomyMapping {
280 #[serde(rename = "taxonomyName")]
282 pub name: String,
283
284 #[serde(default, skip_serializing_if = "Option::is_none")]
286 #[serde(rename = "taxonomyVersion")]
287 pub version: Option<String>,
288
289 #[serde(rename = "taxonomyRelations")]
291 pub relations: Vec<TaxonomyRelation>,
292}
293
294#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
295#[serde(rename_all = "camelCase")]
296pub struct TaxonomyRelation {
297 #[serde(rename = "taxonomyId")]
299 pub id: String,
300
301 #[serde(rename = "relationshipName")]
303 pub name: String,
304
305 #[serde(rename = "relationshipValue")]
307 pub value: String,
308}
309
310#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
311#[serde(rename_all = "camelCase")]
312pub struct AdpContainer {
313 pub provider_metadata: ProviderMetadata,
314
315 #[serde(default, skip_serializing_if = "Option::is_none")]
317 pub date_public: Option<Timestamp>,
318
319 #[serde(default, skip_serializing_if = "Option::is_none")]
321 pub title: Option<String>,
322
323 #[serde(default, skip_serializing_if = "Vec::is_empty")]
325 pub descriptions: Vec<Description>,
326
327 #[serde(default, skip_serializing_if = "Vec::is_empty")]
329 pub affected: Vec<Product>,
330
331 #[serde(default, skip_serializing_if = "Vec::is_empty")]
333 pub problem_types: Vec<ProblemType>,
334
335 #[serde(default, skip_serializing_if = "Vec::is_empty")]
336 pub references: Vec<Reference>,
337
338 #[serde(default, skip_serializing_if = "Vec::is_empty")]
340 pub impacts: Vec<Impact>,
341
342 #[serde(default, skip_serializing_if = "Vec::is_empty")]
344 pub metrics: Vec<Metric>,
345
346 #[serde(default, skip_serializing_if = "Vec::is_empty")]
348 pub configurations: Vec<Description>,
349
350 #[serde(default, skip_serializing_if = "Vec::is_empty")]
352 pub workarounds: Vec<Description>,
353
354 #[serde(default, skip_serializing_if = "Vec::is_empty")]
356 pub solutions: Vec<Description>,
357
358 #[serde(default, skip_serializing_if = "Vec::is_empty")]
360 pub exploits: Vec<Description>,
361
362 #[serde(default, skip_serializing_if = "Vec::is_empty")]
364 pub timeline: Vec<Timeline>,
365
366 #[serde(default, skip_serializing_if = "Vec::is_empty")]
368 pub credits: Vec<Credit>,
369
370 #[serde(default, skip_serializing_if = "Option::is_none")]
372 pub source: Option<Value>,
373
374 #[serde(default, skip_serializing_if = "Vec::is_empty")]
375 pub tags: Vec<Tag>,
376
377 #[serde(default, skip_serializing_if = "Vec::is_empty")]
379 pub taxonomy_mappings: Vec<TaxonomyMapping>,
380}
381
382#[cfg(test)]
383mod test {
384 use super::*;
385
386 #[test]
387 fn parse_metadata() {
388 let input = r#"
389{
390 "assignerOrgId": "8254265b-2729-46b6-b9e3-3dfca2d5bfca",
391 "assignerShortName": "mitre",
392 "cveId": "CVE-2013-7088",
393 "datePublished": "2019-11-15T14:19:48",
394 "dateReserved": "2013-12-12T00:00:00",
395 "dateUpdated": "2019-11-15T14:19:48",
396 "state": "PUBLISHED"
397}
398
399"#;
400 let _metadata: Metadata = serde_json::from_str(input).unwrap();
401 }
402
403 #[test]
404 fn default_value_returns_general() {
405 let value = Scenario::default_value();
406 assert_eq!(value, "GENERAL");
407 }
408}