1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
//!
#![allow(dead_code)]
use std::collections::BTreeMap;
/// An abstraction for CVSS Components.
pub trait ComponentFromVector {
/// Parses a CVSS vector and returns a component.
fn from_vector(symbol: &str) -> Option<Self> where Self: Sized;
}
/// An abstraction for CVSS Metrics
pub trait FromVector {
/// Creates a CVSS metric from a map of symbols.
fn from_vector(symbols: &BTreeMap<&str, &str>) -> Option<Self> where Self: Sized;
/// Creates a CVSS metric from a cvss standard string.
///
/// # Example
/// ```
/// use scayl::{FromVector, v3_1};
///
/// let metric = v3_1::BaseMetric
/// ::from_vector_string("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H");
/// ```
fn from_vector_string(str: &str) -> Option<Self> where Self: Sized;
/// Creates a CVSS standard string
///
/// # Example
/// ```
/// use scayl::{FromVector, v3_1};
///
/// let metric = v3_1::BaseMetric {
/// attack_vector: v3_1::AttackVector::Network,
/// attack_complexity: v3_1::AttackComplexity::Low,
/// privileges_required: v3_1::PrivilegesRequired::None,
/// user_interaction: v3_1::UserInteraction::None,
/// scope: v3_1::Scope::Unchanged,
/// confidentiality_impact: v3_1::ImpactMetric::None,
/// integrity_impact: v3_1::ImpactMetric::None,
/// availability_impact: v3_1::ImpactMetric::None
/// };
/// let str = metric.cvss_vector();
/// ```
fn cvss_vector(&self) -> String;
}
/// CVSS Component macro
///
/// This macro creates an enum for a CVSS Component and its values.
/// It also creates a `from_vector` method that allows string parsing from a cvss string
///
/// # Examples
/// ```
/// use scayl::cvss_component;
///
/// cvss_component!(AttackVector {
/// Network => N,
/// Adjacent => A,
/// Local => L,
/// Physical => P,
/// });
/// ```
#[macro_export]
macro_rules! cvss_component {
($(#[$m:meta])* $name:ident {
$($(#[$meta:meta])* $variant:ident => $value:ident),*$(,)?
}) => {
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
$(#[$m])*
pub enum $name {
$($(#[$meta])* $variant),*
}
impl $crate::cvss::ComponentFromVector for $name {
/// Parses a string into this component
fn from_vector(symbol: &str) -> std::option::Option<Self> {
match symbol {
$(stringify!($value) => std::option::Option::Some(Self::$variant)),*,
_ => std::option::Option::None,
}
}
}
impl $name {
/// Returns the cvss metric representation of the enum
pub fn vector_value(&self) -> &str {
match self {
$(
Self::$variant => stringify!($value),
)*
}
}
}
}
}
/// A single CVSS metric
#[macro_export]
macro_rules! cvss_score {
($name:ident $(=> $prefix:literal)? {
$($field:ident: $ty:ty => $sym:ident),*$(,)?
}) => {
mod cvss_score_decl {
#![allow(unused, unused_mut, unused_assignments, unused_variables)]
use super::*;
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub struct $name {
$(pub $field: $ty),*
}
const _: () = {
const fn assert_from_vec<T: $crate::cvss::ComponentFromVector>() {}
const fn assert_sized<T: Sized>() {}
$(assert_from_vec::<$ty>();)*
$(assert_sized::<$ty>();)*
};
impl $crate::cvss::FromVector for $name {
fn from_vector(symbols: &::std::collections::BTreeMap<&str, &str>) -> ::std::option::Option<Self> {
::std::option::Option::Some($name {
$($field: <$ty as $crate::cvss::ComponentFromVector>::from_vector(symbols.get(&stringify!($sym))?)?),*
})
}
fn from_vector_string(val: &str) -> ::std::option::Option<Self> {
let mut iter = val.split('/');
$(if iter.next()? != $prefix {
return ::std::option::Option::None;
})?
let map = iter
.map(|v| {
let mut iter = v.split(':');
(iter.next(), iter.next())
})
.filter_map(|(a, b)| a.and_then(|a| b.map(|b| (a, b))))
.collect::<::std::collections::BTreeMap<_, _>>();
<Self as $crate::cvss::FromVector>::from_vector(&map)
}
fn cvss_vector(&self) -> String {
let mut out = String::new();
$(
out.push_str($prefix);
out.push('/');
)?
let mut iota = 0;
$(
// AV:L/M/H
if iota > 0 {
out.push('/');
}
iota += 1;
out.push_str(stringify!($sym));
out.push(':');
out.push_str(self.$field.vector_value());
)*
out
}
}
}
pub use cvss_score_decl::*;
}
}
pub mod v3_1;
pub mod v2_0;