-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
15 changed files
with
703 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
[package] | ||
name = "collector-nvd" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
actix-web = "4" | ||
trustification-auth = { path = "../../auth" } | ||
trustification-infrastructure = { path = "../../infrastructure" } | ||
collectorist-api = { path = "../../collectorist/api"} | ||
collectorist-client = { path = "../../collectorist/client"} | ||
collector-client = { path = "../client" } | ||
v11y-client = { path = "../../v11y/client" } | ||
clap = { version = "4", features = ["derive"] } | ||
anyhow = "1" | ||
derive_more = "0.99" | ||
futures = "0.3" | ||
log = "0.4" | ||
utoipa = { version = "3", features = ["actix_extras"] } | ||
utoipa-swagger-ui = { version = "3", features = ["actix-web"] } | ||
serde = { version = "1.0", features = ["derive"] } | ||
serde_json = "1.0.68" | ||
tokio = { version = "1.0", features = ["full"] } | ||
guac = "0.1" | ||
packageurl = "0.3.0" | ||
#guac = { path = "../../../guac-rs/lib" } | ||
#sqlx = { version = "0.7.0", features = [ "runtime-tokio", "sqlite", "chrono"] } | ||
reqwest = "0.11.18" | ||
#osv = { version = "0.1.3" } | ||
chrono = "0.4.26" | ||
#typify = { version = "0.0.13", path = "../../../typify/typify" } | ||
#schemafy = "0.6.0" | ||
#chrono = "0.4.26" | ||
#humantime = "2" | ||
#humantime-serde = "1.1.1" | ||
|
||
|
||
[dev-dependencies] | ||
env_logger = "0.10" | ||
test-with = { version = "0.10", features = ["runtime"] } | ||
libtest-with = { version = "0.6.1-0", features = ["net", "resource", "user", "executable"] } | ||
|
||
|
||
[build-dependencies] | ||
#schemafy_lib = "0.6.0" | ||
#tonic-build = "0.9.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct Cvss2Data { | ||
pub base_score: f32, | ||
pub vector_string: String, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct Cvss30Data { | ||
pub base_score: f32, | ||
pub vector_string: String, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct Cvss31Data { | ||
pub base_score: f32, | ||
pub vector_string: String, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
use reqwest::Url; | ||
|
||
use crate::client::schema::{QueryResponse, Vulnerability}; | ||
|
||
pub mod cvss2; | ||
pub mod cvss30; | ||
pub mod cvss31; | ||
pub mod schema; | ||
|
||
pub struct NvdUrl(&'static str); | ||
|
||
impl NvdUrl { | ||
const fn new(base: &'static str) -> Self { | ||
Self(base) | ||
} | ||
|
||
fn url(&self) -> Url { | ||
Url::parse(self.0).unwrap() | ||
} | ||
} | ||
|
||
const NVD_URL: NvdUrl = NvdUrl::new("https://services.nvd.nist.gov/rest/json/cves/2.0"); | ||
|
||
pub struct NvdClient { | ||
api_key: String, | ||
client: reqwest::Client, | ||
} | ||
|
||
impl NvdClient { | ||
pub fn new(api_token: &str) -> Self { | ||
Self { | ||
api_key: api_token.to_string(), | ||
client: reqwest::Client::new(), | ||
} | ||
} | ||
|
||
pub async fn get_cve(&self, cve_id: &str) -> Result<Option<Vulnerability>, anyhow::Error> { | ||
let response = self | ||
.client | ||
.get(NVD_URL.url()) | ||
.header("apiKey", &self.api_key) | ||
.query(&[("cveId", cve_id)]) | ||
.send() | ||
.await?; | ||
|
||
if response.status() != 200 { | ||
return Ok(None); | ||
} | ||
|
||
let response: QueryResponse = response.json().await?; | ||
|
||
Ok(Some(response.vulnerabilities[0].clone())) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use crate::client::NvdClient; | ||
|
||
pub fn client() -> Result<NvdClient, anyhow::Error> { | ||
let api_key = std::env::var("NVD_API_KEY")?; | ||
|
||
Ok(NvdClient::new(&api_key)) | ||
} | ||
|
||
#[test_with::env(NVD_API_KEY)] | ||
#[tokio::test] | ||
async fn get_valid() -> Result<(), anyhow::Error> { | ||
let vuln = client()?.get_cve("CVE-2019-1010218").await?; | ||
|
||
assert!(vuln.is_some()); | ||
Ok(()) | ||
} | ||
|
||
#[test_with::env(NVD_API_KEY)] | ||
#[tokio::test] | ||
async fn get_invalid() -> Result<(), anyhow::Error> { | ||
let vuln = client()?.get_cve("CVE-NOT-2019-1010218").await?; | ||
assert!(vuln.is_none()); | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
use crate::client::cvss2::Cvss2Data; | ||
use crate::client::cvss30::Cvss30Data; | ||
use crate::client::cvss31::Cvss31Data; | ||
use chrono::NaiveDateTime; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct QueryResponse { | ||
pub vulnerabilities: Vec<Vulnerability>, | ||
} | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct Vulnerability { | ||
pub cve: Cve, | ||
} | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct Cve { | ||
pub id: String, | ||
pub source_identifier: Option<String>, | ||
pub published: NaiveDateTime, | ||
pub last_modified: NaiveDateTime, | ||
pub evaluator_comment: Option<String>, | ||
pub evaluator_solution: Option<String>, | ||
pub evaluator_impact: Option<String>, | ||
pub descriptions: Vec<LangString>, | ||
pub references: Vec<Reference>, | ||
pub metrics: Option<Metrics>, | ||
} | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct LangString { | ||
pub lang: String, | ||
pub value: String, | ||
} | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct Reference { | ||
pub url: String, | ||
pub source: Option<String>, | ||
pub tags: Vec<String>, | ||
} | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct Metrics { | ||
#[serde(default = "Vec::default")] | ||
pub cvss_metric_v31: Vec<CvssV31>, | ||
#[serde(default = "Vec::default")] | ||
pub cvss_metric_v30: Vec<CvssV30>, | ||
#[serde(default = "Vec::default")] | ||
pub cvss_metric_v2: Vec<CvssV2>, | ||
} | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct CvssV31 { | ||
pub source: String, | ||
pub r#type: String, | ||
pub cvss_data: Cvss31Data, | ||
} | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct CvssV30 { | ||
pub source: String, | ||
pub r#type: String, | ||
pub cvss_data: Cvss30Data, | ||
} | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct CvssV2 { | ||
pub source: String, | ||
pub r#type: String, | ||
pub cvss_data: Cvss2Data, | ||
} |
Oops, something went wrong.