Skip to content

Commit

Permalink
chore: Minimize the impact of code changes
Browse files Browse the repository at this point in the history
  • Loading branch information
bxf12315 committed Oct 12, 2024
1 parent 484e253 commit add6fa1
Show file tree
Hide file tree
Showing 33 changed files with 397 additions and 351 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
platforms/**/Cargo.lock
target
.idea/
.gitignore
27 changes: 2 additions & 25 deletions cvss/src/metric.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! CVSS metrics.

use crate::v3::Base;
use crate::{Error, Result};
use alloc::borrow::ToOwned;
use core::{
Expand All @@ -19,7 +18,7 @@ pub trait Metric: Copy + Clone + Debug + Display + Eq + FromStr + Ord {
}

/// Get CVSS v3.1 score for this metric.
// fn score(self) -> f64;
fn score(self) -> f64;

/// Get `str` describing this metric's value
fn as_str(self) -> &'static str;
Expand Down Expand Up @@ -53,7 +52,7 @@ pub enum MetricType {
/// User Interaction (UI)
UI,

/// Exploit Code Maturity (E
/// Exploit Code Maturity (E)
E,

/// Report Confidence (RC)
Expand Down Expand Up @@ -191,25 +190,3 @@ impl FromStr for MetricType {
}
}
}

/// Get CVSS v3.1 score for this metric.
pub trait MetricScore {
fn score(self) -> f64;
}

pub trait ScopedScore {
fn scoped_score(self, is_changed: bool) -> f64;
}

/// Modified Base Metrics
/// https://www.first.org/cvss/v3.1/specification-document#4-2-Modified-Base-Metrics
/// These metrics enable the analyst to override individual Base metrics based on specific characteristics of a user’s environment. Characteristics that affect Exploitability, Scope, or Impact can be reflected via an appropriately modified Environmental Score.
pub trait ModifiedScore {
/// Get CVSS v3.1 score for this metric.
fn modified_score(self, base: &Base) -> f64;
}

/// Score when accounting for scope change
pub trait IsChanged {
fn is_changed(self) -> bool;
}
3 changes: 3 additions & 0 deletions cvss/src/v3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
// TODO(tarcieri): Environmental and Temporal Metrics

pub mod base;
#[allow(missing_docs)]
pub mod cvss;
#[allow(missing_docs)]
pub mod environmental;
mod score;
#[allow(missing_docs)]
pub mod temporal;

pub use self::{base::Base, score::Score};
110 changes: 104 additions & 6 deletions cvss/src/v3/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,22 @@ pub use self::{
pr::PrivilegesRequired, s::Scope, ui::UserInteraction,
};

use crate::{Metric, PREFIX};
use alloc::borrow::ToOwned;
use super::Score;
use crate::{Error, Metric, MetricType, Result, PREFIX};
use alloc::{borrow::ToOwned, vec::Vec};
use core::{fmt, str::FromStr};

use crate::metric::{IsChanged, MetricScore, ScopedScore};
#[cfg(feature = "serde")]
use {
alloc::string::ToString,
serde::{Deserialize, Serialize},
alloc::string::{String, ToString},
serde::{de, ser, Deserialize, Serialize},
};

use crate::v3::Score;
#[cfg(feature = "std")]
use crate::Severity;

pub use crate::v3::base;

/// CVSS v3.1 Base Metric Group
///
/// Described in CVSS v3.1 Specification: Section 2:
Expand Down Expand Up @@ -196,3 +197,100 @@ impl fmt::Display for Base {
Ok(())
}
}

impl FromStr for Base {
type Err = Error;

fn from_str(s: &str) -> Result<Self> {
let component_vec = s
.split('/')
.map(|component| {
let mut parts = component.split(':');

let id = parts.next().ok_or_else(|| Error::InvalidComponent {
component: component.to_owned(),
})?;

let value = parts.next().ok_or_else(|| Error::InvalidComponent {
component: component.to_owned(),
})?;

if parts.next().is_some() {
return Err(Error::InvalidComponent {
component: component.to_owned(),
});
}

Ok((id, value))
})
.collect::<Result<Vec<_>>>()?;

let mut components = component_vec.iter();
let &(id, version_string) = components.next().ok_or(Error::InvalidPrefix {
prefix: s.to_owned(),
})?;

if id != PREFIX {
return Err(Error::InvalidPrefix {
prefix: id.to_owned(),
});
}

let mut metrics = Self {
minor_version: match version_string {
"3.0" => 0,
"3.1" => 1,
_ => {
return Err(Error::UnsupportedVersion {
version: version_string.to_owned(),
})
}
},
..Default::default()
};

for &component in components {
let id = component.0.to_ascii_uppercase();
let value = component.1.to_ascii_uppercase();

match id.parse::<MetricType>()? {
MetricType::AV => metrics.av = Some(value.parse()?),
MetricType::AC => metrics.ac = Some(value.parse()?),
MetricType::PR => metrics.pr = Some(value.parse()?),
MetricType::UI => metrics.ui = Some(value.parse()?),
MetricType::S => metrics.s = Some(value.parse()?),
MetricType::C => metrics.c = Some(value.parse()?),
MetricType::I => metrics.i = Some(value.parse()?),
MetricType::A => metrics.a = Some(value.parse()?),
_ => {
unimplemented!()
}
}
}

Ok(metrics)
}
}

#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<'de> Deserialize<'de> for Base {
fn deserialize<D: de::Deserializer<'de>>(
deserializer: D,
) -> core::result::Result<Self, D::Error> {
String::deserialize(deserializer)?
.parse()
.map_err(de::Error::custom)
}
}

#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl Serialize for Base {
fn serialize<S: ser::Serializer>(
&self,
serializer: S,
) -> core::result::Result<S::Ok, S::Error> {
self.to_string().serialize(serializer)
}
}
25 changes: 7 additions & 18 deletions cvss/src/v3/base/a.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Availability Impact (A)

use crate::metric::MetricScore;
use crate::{Error, Metric, MetricType, Result};
use alloc::borrow::ToOwned;
use core::{fmt, str::FromStr};
Expand Down Expand Up @@ -60,13 +59,13 @@ pub enum Availability {
impl Metric for Availability {
const TYPE: MetricType = MetricType::A;

// fn score(self) -> f64 {
// match self {
// Availability::None => 0.0,
// Availability::Low => 0.22,
// Availability::High => 0.56,
// }
// }
fn score(self) -> f64 {
match self {
Availability::None => 0.0,
Availability::Low => 0.22,
Availability::High => 0.56,
}
}

fn as_str(self) -> &'static str {
match self {
Expand All @@ -77,16 +76,6 @@ impl Metric for Availability {
}
}

impl MetricScore for Availability {
fn score(self) -> f64 {
match self {
Availability::None => 0.0,
Availability::Low => 0.22,
Availability::High => 0.56,
}
}
}

impl fmt::Display for Availability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", Self::name(), self.as_str())
Expand Down
15 changes: 6 additions & 9 deletions cvss/src/v3/base/ac.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Attack Complexity (AC)

use crate::metric::MetricScore;
use crate::{Error, Metric, MetricType, Result};
use alloc::borrow::ToOwned;
use core::{fmt, str::FromStr};
Expand Down Expand Up @@ -60,19 +59,17 @@ impl Default for AttackComplexity {
impl Metric for AttackComplexity {
const TYPE: MetricType = MetricType::AC;

fn as_str(self) -> &'static str {
fn score(self) -> f64 {
match self {
AttackComplexity::High => "H",
AttackComplexity::Low => "L",
AttackComplexity::High => 0.44,
AttackComplexity::Low => 0.77,
}
}
}

impl MetricScore for AttackComplexity {
fn score(self) -> f64 {
fn as_str(self) -> &'static str {
match self {
AttackComplexity::High => 0.44,
AttackComplexity::Low => 0.77,
AttackComplexity::High => "H",
AttackComplexity::Low => "L",
}
}
}
Expand Down
21 changes: 9 additions & 12 deletions cvss/src/v3/base/av.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! CVSS v3.1 Base Metric Group - Attack Vector (AV)

use crate::metric::MetricScore;
use crate::{Error, Metric, MetricType};
use alloc::borrow::ToOwned;
use core::{fmt, str::FromStr};
Expand Down Expand Up @@ -73,17 +72,6 @@ pub enum AttackVector {
impl Metric for AttackVector {
const TYPE: MetricType = MetricType::AV;

fn as_str(self) -> &'static str {
match self {
AttackVector::Physical => "P",
AttackVector::Local => "L",
AttackVector::Adjacent => "A",
AttackVector::Network => "N",
}
}
}

impl MetricScore for AttackVector {
fn score(self) -> f64 {
match self {
AttackVector::Physical => 0.20,
Expand All @@ -92,6 +80,15 @@ impl MetricScore for AttackVector {
AttackVector::Network => 0.85,
}
}

fn as_str(self) -> &'static str {
match self {
AttackVector::Physical => "P",
AttackVector::Local => "L",
AttackVector::Adjacent => "A",
AttackVector::Network => "N",
}
}
}

impl fmt::Display for AttackVector {
Expand Down
19 changes: 8 additions & 11 deletions cvss/src/v3/base/c.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Confidentiality Impact (C)

use crate::metric::MetricScore;
use crate::{Error, Metric, MetricType};
use alloc::borrow::ToOwned;
use core::{fmt, str::FromStr};
Expand Down Expand Up @@ -46,23 +45,21 @@ pub enum Confidentiality {
impl Metric for Confidentiality {
const TYPE: MetricType = MetricType::C;

fn as_str(self) -> &'static str {
match self {
Confidentiality::None => "N",
Confidentiality::Low => "L",
Confidentiality::High => "H",
}
}
}

impl MetricScore for Confidentiality {
fn score(self) -> f64 {
match self {
Confidentiality::None => 0.0,
Confidentiality::Low => 0.22,
Confidentiality::High => 0.56,
}
}

fn as_str(self) -> &'static str {
match self {
Confidentiality::None => "N",
Confidentiality::Low => "L",
Confidentiality::High => "H",
}
}
}

impl fmt::Display for Confidentiality {
Expand Down
19 changes: 8 additions & 11 deletions cvss/src/v3/base/i.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Integrity Impact (I)

use crate::metric::MetricScore;
use crate::{Error, Metric, MetricType, Result};
use alloc::borrow::ToOwned;
use core::{fmt, str::FromStr};
Expand Down Expand Up @@ -42,23 +41,21 @@ pub enum Integrity {
impl Metric for Integrity {
const TYPE: MetricType = MetricType::I;

fn as_str(self) -> &'static str {
match self {
Integrity::None => "N",
Integrity::Low => "L",
Integrity::High => "H",
}
}
}

impl MetricScore for Integrity {
fn score(self) -> f64 {
match self {
Integrity::None => 0.0,
Integrity::Low => 0.22,
Integrity::High => 0.56,
}
}

fn as_str(self) -> &'static str {
match self {
Integrity::None => "N",
Integrity::Low => "L",
Integrity::High => "H",
}
}
}

impl fmt::Display for Integrity {
Expand Down
Loading

0 comments on commit add6fa1

Please sign in to comment.