use crate::error::{CVSSError, Result};
use crate::metric::{Help, Metric, MetricType, MetricTypeV3, Worth};
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use std::str::FromStr;
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum PrivilegesRequiredType {
High,
Low,
None,
}
impl Display for PrivilegesRequiredType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", Self::name(), self.as_str())
}
}
impl PrivilegesRequiredType {
pub fn metric_help(&self) -> Help {
self.help()
}
}
impl Metric for PrivilegesRequiredType {
const TYPE: MetricType = MetricType::V3(MetricTypeV3::PR);
fn help(&self) -> Help {
match self {
Self::High => {Help{ worth: Worth::Bad, des: "The attacker requires privileges that provide significant (e.g., administrative) control over the vulnerable component allowing access to component-wide settings and files.".to_string() }}
Self::Low => {Help{ worth: Worth::Worse, des: "The attacker requires privileges that provide basic user capabilities that could normally affect only settings and files owned by a user. Alternatively, an attacker with Low privileges has the ability to access only non-sensitive resources.".to_string() }}
Self::None => {Help{ worth: Worth::Worst, des: "The attacker is unauthorized prior to attack, and therefore does not require any access to settings or files of the vulnerable system to carry out an attack.".to_string() }}
}
}
fn score(&self) -> f32 {
self.scoped_score(false)
}
fn as_str(&self) -> &'static str {
match self {
Self::High => "H",
Self::Low => "L",
Self::None => "N",
}
}
}
impl FromStr for PrivilegesRequiredType {
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('N') => Ok(Self::None),
Some('L') => Ok(Self::Low),
Some('H') => Ok(Self::High),
_ => Err(CVSSError::InvalidCVSS {
key: name.to_string(),
value: format!("{:?}", c),
expected: "N,L,H".to_string(),
}),
}
}
}
impl PrivilegesRequiredType {
pub fn scoped_score(&self, scope_change: bool) -> f32 {
if scope_change {
match self {
PrivilegesRequiredType::High => 0.5,
PrivilegesRequiredType::Low => 0.68,
PrivilegesRequiredType::None => 0.85,
}
} else {
match self {
PrivilegesRequiredType::High => 0.27,
PrivilegesRequiredType::Low => 0.62,
PrivilegesRequiredType::None => 0.85,
}
}
}
}