@neuralegion/cvss
Version:
The Common Vulnerability Scoring System ([CVSS](https://www.first.org/cvss/)) [base](https://www.first.org/cvss/specification-document#Base-Metrics) [score](https://www.first.org/cvss/specification-document#1-2-Scoring) calculator and validator library wr
86 lines (85 loc) • 3.45 kB
JavaScript
import { baseMetricValues, baseMetrics, environmentalMetricValues, environmentalMetrics, temporalMetricValues, temporalMetrics } from './models';
import { humanizeBaseMetric, humanizeBaseMetricValue } from './humanizer';
import { parseMetricsAsMap, parseVector, parseVersion } from './parser';
export const validateVersion = (versionStr) => {
if (!versionStr) {
throw new Error('Invalid CVSS string. Example: CVSS:3.0/AV:A/AC:H/PR:H/UI:R/S:U/C:N/I:N/A:L');
}
if (versionStr !== '3.0' && versionStr !== '3.1') {
throw new Error(`Unsupported CVSS version: ${versionStr}. Only 3.0 and 3.1 are supported`);
}
};
const validateVector = (vectorStr) => {
if (!vectorStr || vectorStr.includes('//')) {
throw new Error('Invalid CVSS string. Example: CVSS:3.0/AV:A/AC:H/PR:H/UI:R/S:U/C:N/I:N/A:L');
}
};
const checkUnknownMetrics = (metricsMap, knownMetrics) => {
const allKnownMetrics = knownMetrics || [
...baseMetrics,
...temporalMetrics,
...environmentalMetrics
];
[...metricsMap.keys()].forEach((userMetric) => {
if (!allKnownMetrics.includes(userMetric)) {
throw new Error(`Unknown CVSS metric "${userMetric}". Allowed metrics: ${allKnownMetrics.join(', ')}`);
}
});
};
const checkMandatoryMetrics = (metricsMap, metrics = baseMetrics) => {
metrics.forEach((metric) => {
if (!metricsMap.has(metric)) {
// eslint-disable-next-line max-len
throw new Error(`Missing mandatory CVSS metric ${metrics} (${humanizeBaseMetric(metric)})`);
}
});
};
const checkMetricsValues = (metricsMap, metrics, metricsValues) => {
metrics.forEach((metric) => {
const userValue = metricsMap.get(metric);
if (!userValue) {
return;
}
if (!metricsValues[metric].includes(userValue)) {
const allowedValuesHumanized = metricsValues[metric]
.map((value) => `${value} (${humanizeBaseMetricValue(value, metric)})`)
.join(', ');
throw new Error(`Invalid value for CVSS metric ${metric} (${humanizeBaseMetric(metric)})${userValue ? `: ${userValue}` : ''}. Allowed values: ${allowedValuesHumanized}`);
}
});
};
/**
* Validate that the given string is a valid cvss vector
* @param cvssStr
*/
export const validate = (cvssStr) => {
if (!cvssStr || !cvssStr.startsWith('CVSS:')) {
throw new Error('CVSS vector must start with "CVSS:"');
}
const allKnownMetrics = [
...baseMetrics,
...temporalMetrics,
...environmentalMetrics
];
const allKnownMetricsValues = {
...baseMetricValues,
...temporalMetricValues,
...environmentalMetricValues
};
const versionStr = parseVersion(cvssStr);
validateVersion(versionStr);
const vectorStr = parseVector(cvssStr);
validateVector(vectorStr);
const metricsMap = parseMetricsAsMap(cvssStr);
checkMandatoryMetrics(metricsMap);
checkUnknownMetrics(metricsMap, allKnownMetrics);
checkMetricsValues(metricsMap, allKnownMetrics, allKnownMetricsValues);
const isTemporal = [...metricsMap.keys()].some((metric) => temporalMetrics.includes(metric));
const isEnvironmental = [...metricsMap.keys()].some((metric) => environmentalMetrics.includes(metric));
return {
metricsMap,
isTemporal,
isEnvironmental,
versionStr
};
};