diff --git a/public/locales/gsa-de.json b/public/locales/gsa-de.json index 0d2498e56c..63e98a4f62 100644 --- a/public/locales/gsa-de.json +++ b/public/locales/gsa-de.json @@ -204,6 +204,7 @@ "CVE Filter": "CVE-Filter", "CVE List": "CVE-Liste", "CVE Scanner": "CVE-Scanner", + "CVE Severity": "CVE-Schweregrad", "CVE: {{name}}": "CVE: {{name}}", "CVEs": "CVEs", "CVEs by CVSS (Total: {{count}})": "CVEs nach CVSS (Gesamt: {{count}})", @@ -487,6 +488,11 @@ "Duration of last Scan": "Dauer des letzten Scans", "Dynamic": "Dynamisch", "Dynamic Severity": "Dynamischer Schweregrad", + "EPSS": "EPSS", + "EPSS Percentile": "EPSS-Perzentil", + "EPSS Score": "EPSS-Score", + "EPSS (CVE with highest severity)": "EPSS (CVE mit höchstem Schweregrad)", + "EPSS (highest EPSS score)": "EPSS (Höchster EPSS-Score)", "ESXi": "ESXi", "ESXi Credential": "ESXi-Anmeldedaten", "ESXi authentication was successful": "ESXi-Authentifizierung war erfolgreich", @@ -1133,6 +1139,7 @@ "Password only": "Nur Passwort", "Password: Use existing Password": "Passwort: Verwende bestehendes Passwort", "Path": "Pfad", + "Percentile": "Perzentil", "Performance": "Leistungsdaten", "Period": "Zeitintervall", "Permission": "Berechtigung", @@ -1403,6 +1410,7 @@ "Schedules Filter": "Zeitpläne-Filter", "Schedules List": "Zeitplanliste", "Scope": "Reichweite", + "Score": "Score", "Scoring": "Scoring", "Search by content": "Suche nach Inhalt", "SecInfo": "Sicherheitsinfos", diff --git a/src/web/pages/cves/filterdialog.jsx b/src/web/pages/cves/filterdialog.jsx index 24b89fc168..9de784482f 100644 --- a/src/web/pages/cves/filterdialog.jsx +++ b/src/web/pages/cves/filterdialog.jsx @@ -56,6 +56,14 @@ const SORT_FIELDS = [ name: 'severity', displayName: _l('Severity'), }, + { + name: 'epss_score', + displayName: _l('EPSS Score'), + }, + { + name: 'epss_percentile', + displayName: _l('EPSS Percentile'), + }, ]; export default createFilterDialog({ diff --git a/src/web/pages/cves/table.jsx b/src/web/pages/cves/table.jsx index 3bcce860a0..d19695baf9 100644 --- a/src/web/pages/cves/table.jsx +++ b/src/web/pages/cves/table.jsx @@ -91,7 +91,7 @@ const Header = ({ title={_('Severity')} /> - {"EPSS"} + {_("EPSS")} {isDefined(actionsColumn) ? ( actionsColumn diff --git a/src/web/pages/nvts/__tests__/detailspage.jsx b/src/web/pages/nvts/__tests__/detailspage.jsx index bf4af8d931..d99519502c 100644 --- a/src/web/pages/nvts/__tests__/detailspage.jsx +++ b/src/web/pages/nvts/__tests__/detailspage.jsx @@ -67,6 +67,23 @@ const nvt = NVT.fromElement({ _type: 'VendorFix', __text: 'This is a description', }, + epss: { + max_severity: { + score: 0.8765, + percentile: 0.9, + cve: { + _id: 'CVE-2020-1234', + severity: 10.0, + }, + }, + max_epss: { + score: 0.9876, + percentile: 0.8, + cve: { + _id: 'CVE-2020-5678', + }, + }, + }, timeout: '', refs: { ref: [ @@ -308,6 +325,14 @@ describe('Nvt Detailspage tests', () => { expect(element).toHaveTextContent('CVSS Origin'); expect(element).toHaveTextContent('N/A'); + expect(element).toHaveTextContent('EPSS (CVE with highest severity)'); + expect(element).toHaveTextContent('EPSS Score'); + expect(element).toHaveTextContent('0.87650'); + expect(element).toHaveTextContent('EPSS Percentile'); + expect(element).toHaveTextContent('0.90000'); + expect(element).toHaveTextContent('EPSS (highest EPSS score)'); + expect(element).toHaveTextContent('0.98760'); + expect(element).toHaveTextContent('Insight'); expect(element).toHaveTextContent('Foo'); diff --git a/src/web/pages/nvts/__tests__/listpage.jsx b/src/web/pages/nvts/__tests__/listpage.jsx index 51c6f978c9..596e206220 100644 --- a/src/web/pages/nvts/__tests__/listpage.jsx +++ b/src/web/pages/nvts/__tests__/listpage.jsx @@ -45,6 +45,23 @@ const nvt = NVT.fromElement({ _type: 'VendorFix', __text: 'This is a description', }, + epss: { + max_severity: { + score: 0.8765, + percentile: 0.9, + cve: { + _id: 'CVE-2020-1234', + severity: 10.0, + }, + }, + max_epss: { + score: 0.9876, + percentile: 0.8, + cve: { + _id: 'CVE-2020-5678', + }, + }, + }, refs: { ref: [ {_type: 'cve', _id: 'CVE-2020-1234'}, @@ -192,16 +209,21 @@ describe('NvtsPage tests', () => { expect(header[4]).toHaveTextContent('CVE'); expect(header[6]).toHaveTextContent('Severity'); expect(header[7]).toHaveTextContent('QoD'); + expect(header[8]).toHaveTextContent('EPSS'); + expect(header[9]).toHaveTextContent('Score'); + expect(header[10]).toHaveTextContent('Percentile'); const row = baseElement.querySelectorAll('tr'); - expect(row[1]).toHaveTextContent('foo'); - expect(row[1]).toHaveTextContent('bar'); - expect(row[1]).toHaveTextContent('Mon, Jun 24, 2019 1:55 PM CEST'); - expect(row[1]).toHaveTextContent('Mon, Jun 24, 2019 12:12 PM CEST'); - expect(row[1]).toHaveTextContent('CVE-2020-1234'); - expect(row[1]).toHaveTextContent('CVE-2020-5678'); - expect(row[1]).toHaveTextContent('80 %'); + expect(row[2]).toHaveTextContent('foo'); + expect(row[2]).toHaveTextContent('bar'); + expect(row[2]).toHaveTextContent('Mon, Jun 24, 2019 1:55 PM CEST'); + expect(row[2]).toHaveTextContent('Mon, Jun 24, 2019 12:12 PM CEST'); + expect(row[2]).toHaveTextContent('CVE-2020-1234'); + expect(row[2]).toHaveTextContent('CVE-2020-5678'); + expect(row[2]).toHaveTextContent('80 %'); + expect(row[2]).toHaveTextContent('0.87650'); + expect(row[2]).toHaveTextContent('0.90000'); }); test('should allow to bulk action on page contents', async () => { diff --git a/src/web/pages/nvts/__tests__/row.jsx b/src/web/pages/nvts/__tests__/row.jsx index febff4333a..75be014716 100644 --- a/src/web/pages/nvts/__tests__/row.jsx +++ b/src/web/pages/nvts/__tests__/row.jsx @@ -48,6 +48,23 @@ const entity = NVT.fromElement({ _type: 'VendorFix', __text: 'This is a description', }, + epss: { + max_severity: { + score: 0.8765, + percentile: 0.9, + cve: { + _id: 'CVE-2020-1234', + severity: 10.0, + }, + }, + max_epss: { + score: 0.9876, + percentile: 0.8, + cve: { + _id: 'CVE-2020-5678', + }, + }, + }, refs: { ref: [ {_type: 'cve', _id: 'CVE-2020-1234'}, diff --git a/src/web/pages/nvts/details.jsx b/src/web/pages/nvts/details.jsx index 78b3c1b390..0355a4db93 100644 --- a/src/web/pages/nvts/details.jsx +++ b/src/web/pages/nvts/details.jsx @@ -19,7 +19,7 @@ import React from 'react'; import _ from 'gmp/locale'; -import {isDefined} from 'gmp/utils/identity'; +import {isDefined, isNumber} from 'gmp/utils/identity'; import {TAG_NA} from 'gmp/models/nvt'; @@ -44,9 +44,11 @@ import TableRow from 'web/components/table/row'; import References from './references'; import Solution from './solution'; import Pre from './preformatted'; +import CveLink from "web/components/link/cvelink.jsx"; const NvtDetails = ({entity, links = true}) => { const { + epss, tags = {}, severity, qod, @@ -67,6 +69,9 @@ const NvtDetails = ({entity, links = true}) => { + + {_('CVSS')} + {_('CVSS Base')} @@ -104,6 +109,80 @@ const NvtDetails = ({entity, links = true}) => { )} + { isDefined(epss?.max_severity) && + <> + + {_('EPSS (CVE with highest severity)')} + + + {_('EPSS Score')} + + {isNumber(epss?.max_severity?.score) + ? epss?.max_severity?.score.toFixed(5) : _("N/A")} + + + + {_('EPSS Percentile')} + + {isNumber(epss?.max_severity?.percentile) + ? epss?.max_severity?.percentile.toFixed(5) : _("N/A")} + + + + {_('CVE')} + + + {epss?.max_severity?.cve?._id} + + + + + {_('CVE Severity')} + + + + } + { isDefined(epss?.max_epss) && + <> + + {_('EPSS (highest EPSS score)')} + + + {_('EPSS Score')} + + {isNumber(epss?.max_epss?.score) + ? epss?.max_epss?.score.toFixed(5) : _("N/A")} + + + + {_('EPSS Percentile')} + + {isNumber(epss?.max_epss?.percentile) + ? epss?.max_epss?.percentile.toFixed(5) : _("N/A")} + + + + {_('CVE')} + + + {epss?.max_epss?.cve?._id} + + + + + {_('CVE Severity')} + + + + + + } diff --git a/src/web/pages/nvts/filterdialog.jsx b/src/web/pages/nvts/filterdialog.jsx index 1fa7f54a1a..900b887c2d 100644 --- a/src/web/pages/nvts/filterdialog.jsx +++ b/src/web/pages/nvts/filterdialog.jsx @@ -56,6 +56,14 @@ const SORT_FIELDS = [ name: 'qod', displayName: _l('QoD'), }, + { + name: 'epss_score', + displayName: _l('EPSS Score'), + }, + { + name: 'epss_percentile', + displayName: _l('EPSS Percentile'), + }, ]; export default createFilterDialog({ diff --git a/src/web/pages/nvts/row.jsx b/src/web/pages/nvts/row.jsx index 892155c26e..7955065258 100644 --- a/src/web/pages/nvts/row.jsx +++ b/src/web/pages/nvts/row.jsx @@ -20,7 +20,7 @@ import React from 'react'; import Filter from 'gmp/models/filter.js'; -import {isDefined} from 'gmp/utils/identity'; +import {isDefined, isNumber} from 'gmp/utils/identity'; import SeverityBar from 'web/components/bar/severitybar'; @@ -42,6 +42,7 @@ import EntitiesActions from 'web/entities/actions'; import {RowDetailsToggle} from 'web/entities/row'; import PropTypes from 'web/utils/proptypes'; +import {_} from "gmp/locale/lang.js"; const Row = ({ actionsComponent: ActionsComponent = EntitiesActions, @@ -101,6 +102,14 @@ const Row = ({ {entity.qod && } + + {isNumber(entity?.epss?.max_severity?.score) + ? entity.epss?.max_severity?.score.toFixed(5) : _("N/A")} + + + {isNumber(entity?.epss?.max_severity?.percentile) + ? entity.epss?.max_severity?.percentile.toFixed(5) : _("N/A")} + ); diff --git a/src/web/pages/nvts/table.jsx b/src/web/pages/nvts/table.jsx index 9b53df6ae1..c4e10bff3e 100644 --- a/src/web/pages/nvts/table.jsx +++ b/src/web/pages/nvts/table.jsx @@ -51,7 +51,8 @@ const Header = ({ - + {sort ? ( @@ -102,6 +107,7 @@ const Header = ({ + + {_("EPSS")} + {actionsColumn} + + + + ); };