@@ -71,9 +71,9 @@ class Vector {
71
71
} ,
72
72
// Environmental (14 metrics)
73
73
ENVIRONMENTAL : {
74
- "CR" : [ "X" , "H" , "M" , "L" ] ,
75
- "IR" : [ "X" , "H" , "M" , "L" ] ,
76
- "AR" : [ "X" , "H" , "M" , "L" ] ,
74
+ "CR" : [ "X" , "H" , "M" , "L" ] ,
75
+ "IR" : [ "X" , "H" , "M" , "L" ] ,
76
+ "AR" : [ "X" , "H" , "M" , "L" ] ,
77
77
"MAV" : [ "X" , "N" , "A" , "L" , "P" ] ,
78
78
"MAC" : [ "X" , "L" , "H" ] ,
79
79
"MAT" : [ "X" , "N" , "P" ] ,
@@ -88,12 +88,12 @@ class Vector {
88
88
} ,
89
89
// Supplemental (6 metrics)
90
90
SUPPLEMENTAL : {
91
- "S" : [ "X" , "N" , "P" ] ,
91
+ "S" : [ "X" , "N" , "P" ] ,
92
92
"AU" : [ "X" , "N" , "Y" ] ,
93
- "R" : [ "X" , "A" , "U" , "I" ] ,
94
- "V" : [ "X" , "D" , "C" ] ,
93
+ "R" : [ "X" , "A" , "U" , "I" ] ,
94
+ "V" : [ "X" , "D" , "C" ] ,
95
95
"RE" : [ "X" , "L" , "M" , "H" ] ,
96
- "U" : [ "X" , "Clear" , "Green" , "Amber" , "Red" ] ,
96
+ "U" : [ "X" , "Clear" , "Green" , "Amber" , "Red" ] ,
97
97
}
98
98
} ;
99
99
@@ -381,39 +381,48 @@ class Vector {
381
381
382
382
// Check if the prefix is correct
383
383
if ( metrics . shift ( ) !== "CVSS:4.0" ) {
384
- console . error ( "Error: invalid vector, missing CVSS v4.0 prefix from vector: " + vector ) ;
385
- return false ;
384
+ throw new Error ( `Invalid vector, missing \`CVSS:4.0 prefix\` from vector: \`${ vector } \`` ) ;
386
385
}
387
386
388
- const expectedMetrics = Object . entries ( Vector . ALL_METRICS ) ;
389
- let mandatoryMetricIndex = 0 ;
387
+ const malformedMetric = metrics . find ( metric => metric . split ( ':' ) . length !== 2 ) ;
390
388
391
- for ( let metric of metrics ) {
392
- const [ key , value ] = metric . split ( ':' ) ;
389
+ if ( malformedMetric ) {
390
+ throw new Error ( `Invalid vector, malformed substring \`${ malformedMetric } \` in vector: \`${ vector } \`` ) ;
391
+ }
393
392
394
- // Check if there are too many metric values
395
- if ( ! expectedMetrics [ mandatoryMetricIndex ] ) {
396
- console . error ( "Error: invalid vector, too many metric values" ) ;
397
- return false ;
398
- }
393
+ const metricsLookup = metrics . reduce ( ( lookup , metric ) => {
394
+ const [ metricType , metricValue ] = metric . split ( ':' ) ;
395
+ lookup [ metricType ] = metricValue ;
396
+ return lookup ;
397
+ } , { } ) ;
399
398
400
- // Find the current expected metric
401
- while ( expectedMetrics [ mandatoryMetricIndex ] && expectedMetrics [ mandatoryMetricIndex ] [ 0 ] !== key ) {
402
- // Check for missing mandatory metrics
403
- if ( mandatoryMetricIndex < 11 ) {
404
- console . error ( "Error: invalid vector, missing mandatory metrics" ) ;
405
- return false ;
406
- }
407
- mandatoryMetricIndex ++ ;
408
- }
399
+ const requiredMetrics = Object . keys ( Vector . METRICS . BASE ) ;
400
+
401
+ if ( ! requiredMetrics . every ( metricType => metricType in metricsLookup ) ) {
402
+ throw new Error ( `Invalid CVSS v4.0 vector: Missing required metrics in \`${ vector } \`` ) ;
403
+ }
409
404
410
- // Check if the value is valid for the given metric
411
- if ( ! expectedMetrics [ mandatoryMetricIndex ] [ 1 ] . includes ( value ) ) {
412
- console . error ( `Error: invalid vector, for key ${ key } , value ${ value } is not in ${ expectedMetrics [ mandatoryMetricIndex ] [ 1 ] } ` ) ;
413
- return false ;
405
+ if ( metrics . length > Object . keys ( metricsLookup ) . length ) {
406
+ throw new Error ( `Invalid CVSS v4.0 vector: Duplicated metric types in \`${ vector } \`` ) ;
407
+ }
408
+
409
+ const definedMetrics = Vector . ALL_METRICS ;
410
+
411
+ if ( metrics . length > Object . keys ( definedMetrics ) . length ) {
412
+ // This was here before but probably is impossible to reach because of the previous checks for duplicated and undefined keys
413
+ throw new Error ( `Invalid CVSS v4.0 vector: Unknown/excessive metric types in \`${ vector } \`` ) ;
414
+ }
415
+
416
+ for ( let [ metricType , metricValue ] of Object . entries ( metricsLookup ) ) {
417
+
418
+ if ( ! metricType in Vector . ALL_METRICS ) {
419
+ throw new Error ( `Invalid CVSS v4.0 vector: Unknown metric \`${ metricType } \` in \`${ vector } \`` ) ;
414
420
}
415
421
416
- mandatoryMetricIndex ++ ;
422
+ // Check if the value is valid for the given metric type
423
+ if ( ! definedMetrics [ metricType ] . includes ( metricValue ) ) {
424
+ throw new Error ( `Invalid CVSS v4.0 vector \`${ vector } \`: For metricType \`${ metricType } \`, value \`${ metricValue } \` is invalid. Valid, defined metric values for \`${ metricType } \` are: ${ definedMetrics [ metricType ] } .` ) ;
425
+ }
417
426
}
418
427
419
428
return true ;
@@ -437,13 +446,10 @@ class Vector {
437
446
*/
438
447
updateMetricsFromVectorString ( vector ) {
439
448
if ( ! vector ) {
440
- throw new Error ( " The vector string cannot be null, undefined, or empty." ) ;
449
+ throw new Error ( ` The vector string cannot be null, undefined, or empty in ${ vector } ` ) ;
441
450
}
442
451
443
- // Validate the CVSS v4.0 string vector
444
- if ( ! this . validateStringVector ( vector ) ) {
445
- throw new Error ( "Invalid CVSS v4.0 vector: " + vector ) ;
446
- }
452
+ this . validateStringVector ( vector ) ;
447
453
448
454
let metrics = vector . split ( '/' ) ;
449
455
@@ -780,21 +786,21 @@ class CVSS40 {
780
786
// It is used when looking for the highest vector part of the
781
787
// combinations produced by the MacroVector respective highest
782
788
static METRIC_LEVELS = {
783
- "AV" : { "N" : 0.0 , "A" : 0.1 , "L" : 0.2 , "P" : 0.3 } ,
784
- "PR" : { "N" : 0.0 , "L" : 0.1 , "H" : 0.2 } ,
785
- "UI" : { "N" : 0.0 , "P" : 0.1 , "A" : 0.2 } ,
786
- "AC" : { 'L' : 0.0 , 'H' : 0.1 } ,
787
- "AT" : { 'N' : 0.0 , 'P' : 0.1 } ,
788
- "VC" : { 'H' : 0.0 , 'L' : 0.1 , 'N' : 0.2 } ,
789
- "VI" : { 'H' : 0.0 , 'L' : 0.1 , 'N' : 0.2 } ,
790
- "VA" : { 'H' : 0.0 , 'L' : 0.1 , 'N' : 0.2 } ,
791
- "SC" : { 'H' : 0.1 , 'L' : 0.2 , 'N' : 0.3 } ,
792
- "SI" : { 'S' : 0.0 , 'H' : 0.1 , 'L' : 0.2 , 'N' : 0.3 } ,
793
- "SA" : { 'S' : 0.0 , 'H' : 0.1 , 'L' : 0.2 , 'N' : 0.3 } ,
794
- "CR" : { 'H' : 0.0 , 'M' : 0.1 , 'L' : 0.2 } ,
795
- "IR" : { 'H' : 0.0 , 'M' : 0.1 , 'L' : 0.2 } ,
796
- "AR" : { 'H' : 0.0 , 'M' : 0.1 , 'L' : 0.2 } ,
797
- "E" : { 'U' : 0.2 , 'P' : 0.1 , 'A' : 0 }
789
+ "AV" : { "N" : 0.0 , "A" : 0.1 , "L" : 0.2 , "P" : 0.3 } ,
790
+ "PR" : { "N" : 0.0 , "L" : 0.1 , "H" : 0.2 } ,
791
+ "UI" : { "N" : 0.0 , "P" : 0.1 , "A" : 0.2 } ,
792
+ "AC" : { 'L' : 0.0 , 'H' : 0.1 } ,
793
+ "AT" : { 'N' : 0.0 , 'P' : 0.1 } ,
794
+ "VC" : { 'H' : 0.0 , 'L' : 0.1 , 'N' : 0.2 } ,
795
+ "VI" : { 'H' : 0.0 , 'L' : 0.1 , 'N' : 0.2 } ,
796
+ "VA" : { 'H' : 0.0 , 'L' : 0.1 , 'N' : 0.2 } ,
797
+ "SC" : { 'H' : 0.1 , 'L' : 0.2 , 'N' : 0.3 } ,
798
+ "SI" : { 'S' : 0.0 , 'H' : 0.1 , 'L' : 0.2 , 'N' : 0.3 } ,
799
+ "SA" : { 'S' : 0.0 , 'H' : 0.1 , 'L' : 0.2 , 'N' : 0.3 } ,
800
+ "CR" : { 'H' : 0.0 , 'M' : 0.1 , 'L' : 0.2 } ,
801
+ "IR" : { 'H' : 0.0 , 'M' : 0.1 , 'L' : 0.2 } ,
802
+ "AR" : { 'H' : 0.0 , 'M' : 0.1 , 'L' : 0.2 } ,
803
+ "E" : { 'U' : 0.2 , 'P' : 0.1 , 'A' : 0 }
798
804
} ;
799
805
800
806
static MAX_COMPOSED = {
@@ -880,7 +886,7 @@ class CVSS40 {
880
886
// If the input is a string, create a new Vector object from the string
881
887
this . vector = new Vector ( input ) ;
882
888
} else {
883
- throw new Error ( " Invalid input type for CVSS40 constructor. Expected a string or a Vector object." ) ;
889
+ throw new Error ( ` Invalid input type for CVSSv4.0 constructor. Expected a string or a Vector object in ${ vector } ` ) ;
884
890
}
885
891
886
892
// Calculate the score
@@ -1208,4 +1214,3 @@ if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
1208
1214
window . CVSS40 = CVSS40 ;
1209
1215
window . Vector = Vector ;
1210
1216
}
1211
-
0 commit comments