7
7
-}
8
8
module Security.CVSS (
9
9
-- * Type
10
- CVSS ,
10
+ CVSS (cvssVersion ),
11
+ CVSSVersion (.. ),
11
12
Rating (.. ),
12
13
parseCVSS ,
13
14
14
15
-- * Helpers
16
+ cvssVectorString ,
17
+ cvssVectorStringOrdered ,
15
18
cvssScore ,
16
19
cvssInfo ,
17
20
) where
@@ -23,25 +26,33 @@ import Data.Text (Text)
23
26
import Data.Text qualified as Text
24
27
import GHC.Float (powerFloat )
25
28
26
- data CVSSVersion = CVSS31
29
+ -- | The CVSS version.
30
+ data CVSSVersion
31
+ = -- | Version 3.1: https://www.first.org/cvss/v3-1/
32
+ CVSS31
27
33
28
- -- | Parsed CVSS string obtained with 'parseCVSS'
34
+ -- | Parsed CVSS string obtained with 'parseCVSS'.
29
35
data CVSS = CVSS
30
36
{ cvssVersion :: CVSSVersion
37
+ -- ^ The CVSS Version.
31
38
, cvssMetrics :: [Metric ]
32
39
-- ^ The metrics are stored as provided by the user
33
40
}
34
41
42
+ instance Show CVSS where
43
+ show = Text. unpack . cvssVectorString
44
+
35
45
-- | CVSS Rating obtained with 'cvssScore'
36
46
data Rating = None | Low | Medium | High | Critical
37
47
deriving (Enum , Eq , Ord , Show )
38
48
49
+ -- | Implementation of Section 5. "Qualitative Severity Rating Scale"
39
50
toRating :: Float -> Rating
40
51
toRating score
41
52
| score <= 0 = None
42
- | score <= 3.9 = Low
43
- | score <= 6.9 = Medium
44
- | score <= 8. 9 = High
53
+ | score < 4 = Low
54
+ | score < 7 = Medium
55
+ | score < 9 = High
45
56
| otherwise = Critical
46
57
47
58
type Metric = (Text , Char )
@@ -77,6 +88,25 @@ cvssInfo :: CVSS -> [Text]
77
88
cvssInfo cvss = case cvssVersion cvss of
78
89
CVSS31 -> cvss31info (cvssMetrics cvss)
79
90
91
+ -- | Format the CVSS back to its original string.
92
+ cvssVectorString :: CVSS -> Text
93
+ cvssVectorString = cvssShow False
94
+
95
+ -- | Format the CVSS to the prefered ordered vector string.
96
+ cvssVectorStringOrdered :: CVSS -> Text
97
+ cvssVectorStringOrdered = cvssShow True
98
+
99
+ cvssShow :: Bool -> CVSS -> Text
100
+ cvssShow ordered cvss = case cvssVersion cvss of
101
+ CVSS31 -> Text. intercalate " /" (" CVSS:3.1" : map toComponent (cvss31Order (cvssMetrics cvss)))
102
+ where
103
+ toComponent (name, value) = Text. snoc (name <> " :" ) value
104
+ cvss31Order xs
105
+ | ordered = mapMaybe getMetric allMetrics
106
+ | otherwise = xs
107
+ where
108
+ getMetric mi = find (\ (name, _) -> miShortName mi == name) xs
109
+
80
110
-- | Description of a metric group.
81
111
data MetricGroup = MetricGroup
82
112
{ mgName :: Text
@@ -200,6 +230,7 @@ cvss31info = map showMetricInfo
200
230
allMetrics :: [MetricInfo ]
201
231
allMetrics = concatMap mgMetrics cvss31
202
232
233
+ -- | Implementation of the Appendix A - "Floating Point Rounding"
203
234
roundup :: Float -> Float
204
235
roundup input
205
236
| int_input `mod` 10000 == 0 = fromIntegral int_input / 100000
0 commit comments