nvd-cvss 0.1.1

A rust implementation of the nvd-cvss.
Documentation
use crate::error::{CVSSError, Result};
use crate::metric::{Help, Metric, MetricType, MetricTypeV4, Worth};
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use std::str::FromStr;

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(rename_all = "UPPERCASE")]
pub enum ExploitMaturity {
  /// NotDefined(X) 未定义 ;可靠的威胁情报无法确定漏洞利用成熟度特征。这是默认值,在假设最坏情况的情况下计算分数时,等效于Attacked(A)。
  NotDefined,
  /// Attacked(A) 已报告针对此漏洞的攻击;简化利用该漏洞的尝试解决方案已公开(或私下可用)。
  Attacked,
  /// POC(P) POC已公开;且未感知到针对此漏洞的利用尝试;且未感知到简化利用该漏洞的尝试的公开可用解决方案
  Poc,
  /// Unreported(U) 未感知到POC公开;且未感知到针对此漏洞的利用尝试;且未感知到简化利用该漏洞的尝试的公开可用解决方案。
  Unreported,
}

impl Default for ExploitMaturity {
  fn default() -> Self {
    // If E=X it will default to the worst case (i.e., E=A).
    Self::Attacked
  }
}
impl ExploitMaturity {
  // EQ5: 0-E:A
  //      1-E:P
  //      2-E:U
  pub(crate) fn eq5(&self) -> Option<u32> {
    match self {
      Self::NotDefined => None,
      Self::Attacked => Some(0),
      Self::Poc => Some(1),
      Self::Unreported => Some(2),
    }
  }
}

impl FromStr for ExploitMaturity {
  type Err = CVSSError;

  fn from_str(s: &str) -> Result<Self> {
    let name = Self::name();
    let s = s.to_uppercase();
    let (_name, v) = s
      .split_once(&format!("{}:", name))
      .ok_or(CVSSError::InvalidCVSS {
        key: name.to_string(),
        value: s.to_string(),
        expected: name.to_string(),
      })?;
    let c = v.chars().next();
    match c {
      Some('A') => Ok(Self::Attacked),
      Some('P') => Ok(Self::Poc),
      Some('U') => Ok(Self::Unreported),
      Some('X') => Ok(Self::NotDefined),
      _ => Err(CVSSError::InvalidCVSS {
        key: name.to_string(),
        value: format!("{:?}", c),
        expected: "A,P,U,X".to_string(),
      }),
    }
  }
}

impl Display for ExploitMaturity {
  fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    write!(f, "{}:{}", Self::name(), self.as_str())
  }
}

impl Metric for ExploitMaturity {
  const TYPE: MetricType = MetricType::V4(MetricTypeV4::E);

  fn help(&self) -> Help {
    match self {
      Self::NotDefined => Help {
        worth: Worth::Worst,
        des: "".to_string(),
      },
      Self::Attacked => Help {
        worth: Worth::Worst,
        des: "".to_string(),
      },
      Self::Poc => Help {
        worth: Worth::Worst,
        des: "".to_string(),
      },
      Self::Unreported => Help {
        worth: Worth::Worst,
        des: "".to_string(),
      },
    }
  }

  fn score(&self) -> f32 {
    match self {
      Self::NotDefined => 0.0,
      Self::Attacked => 0.0,
      Self::Poc => 0.1,
      Self::Unreported => 0.2,
    }
  }

  fn as_str(&self) -> &'static str {
    match self {
      Self::NotDefined => "X",
      Self::Attacked => "A",
      Self::Poc => "P",
      Self::Unreported => "N",
    }
  }
}