diff --git a/CHANGELOG.md b/CHANGELOG.md
index 130a3e9ecc..44a4ed474c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [9.0.0] - unreleased
### Added
+- List NVT of the found CVEs at the report details page [#1673](https://github.com/greenbone/gsa/pull/1673)
- Added links for GOS 6 manual for audits, policies and TLS certificates [#1657](https://github.com/greenbone/gsa/pull/1657)
- Added OSP Sensor type to GSA [#1646](https://github.com/greenbone/gsa/pull/1646)
- Added TLS certificate filter type [#1630](https://github.com/greenbone/gsa/pull/1630)
@@ -67,6 +68,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
requests in gsad [#1355](https://github.com/greenbone/gsa/pull/1355)
### Fixed
+- Fixed parsing report details data [#1673](https://github.com/greenbone/gsa/pull/1673)
- Fixed scanconfig clone icon tooltip does not show if permission is denied [#1664](https://github.com/greenbone/gsa/pull/1664)
- Fixed feed status page does not render [#1628](https://github.com/greenbone/gsa/pull/1628)
- fixed secinfo severitybars not displaying severity.[#1530](https://github.com/greenbone/gsa/pull/1530)
@@ -98,7 +100,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed
- Removed Clone and Verify functionalities for report formats [#1650](https://github.com/greenbone/gsa/pull/1650)
- Use new [React context API](https://reactjs.org/docs/context.html#api) [#1637](https://github.com/greenbone/gsa/pull/1637)
-- Update response data parsing in Model classes [#1633](https://github.com/greenbone/gsa/pull/1633)
+- Update response data parsing in Model classes
+ [#1633](https://github.com/greenbone/gsa/pull/1633),
+ [#1668](https://github.com/greenbone/gsa/pull/1668)
- Fix statusbar content can be more than 100% and add progressbar colors to theme [1621](https://github.com/greenbone/gsa/pull/1621)
- Allow to overwrite details=1 for command results.get() [#1618](https://github.com/greenbone/gsa/pull/1618)
- Ensure not to request the report details when loading a list of reports [#1617](https://github.com/greenbone/gsa/pull/1617)
diff --git a/gsa/CMakeLists.txt b/gsa/CMakeLists.txt
index 427f7e7318..2a00a9b9db 100644
--- a/gsa/CMakeLists.txt
+++ b/gsa/CMakeLists.txt
@@ -156,7 +156,6 @@ set (GSA_JS_SRC_FILES
${GSA_SRC_DIR}/src/gmp/models/report/report.js
${GSA_SRC_DIR}/src/gmp/models/report/task.js
${GSA_SRC_DIR}/src/gmp/models/report/tlscertificate.js
- ${GSA_SRC_DIR}/src/gmp/models/report/vulnerability.js
${GSA_SRC_DIR}/src/gmp/models/result.js
${GSA_SRC_DIR}/src/gmp/models/role.js
${GSA_SRC_DIR}/src/gmp/models/scanconfig.js
diff --git a/gsa/src/gmp/__tests__/parser.js b/gsa/src/gmp/__tests__/parser.js
index 0541f0ce85..933d2bbcd9 100644
--- a/gsa/src/gmp/__tests__/parser.js
+++ b/gsa/src/gmp/__tests__/parser.js
@@ -330,6 +330,13 @@ describe('setProperties tests', () => {
expect(obj.lorem).toEqual('ipsum');
expect(Object.keys(obj)).toEqual(expect.arrayContaining(['foo', 'lorem']));
+ });
+
+ test('should not allow to override set properties', () => {
+ const obj = setProperties({
+ foo: 'bar',
+ lorem: 'ipsum',
+ });
expect(() => {
obj.foo = 'a';
@@ -339,6 +346,26 @@ describe('setProperties tests', () => {
}).toThrow();
});
+ test('should allow to override set properties if requested', () => {
+ const obj = setProperties(
+ {
+ foo: 'bar',
+ lorem: 'ipsum',
+ },
+ {},
+ {writable: true},
+ );
+
+ expect(obj.foo).toEqual('bar');
+ expect(obj.lorem).toEqual('ipsum');
+
+ obj.foo = 'a';
+ obj.lorem = 'b';
+
+ expect(obj.foo).toEqual('a');
+ expect(obj.lorem).toEqual('b');
+ });
+
test('should skip properties starting with underscore', () => {
const obj = setProperties({
foo: 'bar',
diff --git a/gsa/src/gmp/models/__tests__/nvt.js b/gsa/src/gmp/models/__tests__/nvt.js
index 6783a6f564..3adb8cf489 100644
--- a/gsa/src/gmp/models/__tests__/nvt.js
+++ b/gsa/src/gmp/models/__tests__/nvt.js
@@ -19,7 +19,7 @@
/* eslint-disable max-len */
-import Nvt from 'gmp/models/nvt';
+import Nvt, {getRefs, hasRefType, getFilteredRefIds} from 'gmp/models/nvt';
import Info from 'gmp/models/info';
import {testModelFromElement, testModelMethods} from 'gmp/models/testing';
@@ -30,11 +30,14 @@ describe('nvt Model tests', () => {
test('should parse NVT oid as id', () => {
const nvt1 = Nvt.fromElement({_oid: '42.1337'});
const nvt2 = Nvt.fromElement({});
+ const nvt3 = Nvt.fromElement({nvt: {_oid: '1.2.3'}});
expect(nvt1.id).toEqual('42.1337');
expect(nvt1.oid).toEqual('42.1337');
expect(nvt2.id).toBeUndefined();
expect(nvt2.oid).toBeUndefined();
+ expect(nvt3.oid).toEqual('1.2.3');
+ expect(nvt3.id).toEqual('1.2.3');
});
test('should not allow to overwrite id', () => {
@@ -52,14 +55,17 @@ describe('nvt Model tests', () => {
});
test('should parse nvt_type', () => {
- const nvt = Nvt.fromElement({_type: 'foo'});
+ const nvt1 = Nvt.fromElement({_type: 'foo'});
+ const nvt2 = Nvt.fromElement({nvt: {_type: 'foo'}});
- expect(nvt.nvtType).toEqual('foo');
+ expect(nvt1.nvtType).toEqual('foo');
+ expect(nvt2.nvtType).toEqual('foo');
});
test('should parse tags', () => {
const nvt1 = Nvt.fromElement({tags: 'bv=/A:P|st=vf'});
const nvt2 = Nvt.fromElement({});
+ const nvt3 = Nvt.fromElement({nvt: {tags: 'bv=/A:P|st=vf'}});
const res = {
bv: '/A:P',
st: 'vf',
@@ -67,6 +73,7 @@ describe('nvt Model tests', () => {
expect(nvt1.tags).toEqual(res);
expect(nvt2.tags).toEqual({});
+ expect(nvt3.tags).toEqual(res);
});
test('should parse refs', () => {
@@ -110,6 +117,7 @@ describe('nvt Model tests', () => {
};
const nvt1 = Nvt.fromElement(elem);
const nvt2 = Nvt.fromElement({});
+ const nvt3 = Nvt.fromElement({nvt: elem});
expect(nvt1.cves).toEqual(['cveId', 'cve_idId']);
expect(nvt2.cves).toEqual([]);
@@ -123,15 +131,28 @@ describe('nvt Model tests', () => {
expect(nvt2.certs).toEqual([]);
expect(nvt1.xrefs).toEqual([{ref: 'customId', type: 'custom-type'}]);
expect(nvt2.xrefs).toEqual([]);
+
+ expect(nvt3.cves).toEqual(['cveId', 'cve_idId']);
+ expect(nvt3.bids).toEqual(['bidId', 'bugtraq_idId']);
+ expect(nvt3.certs).toEqual([
+ {id: 'dfn-certId', type: 'dfn-cert'},
+ {id: 'DFN-certId', type: 'dfn-cert'},
+ {id: 'cert-bundId', type: 'cert-bund'},
+ ]);
+ expect(nvt3.xrefs).toEqual([{ref: 'customId', type: 'custom-type'}]);
});
test('should parse severity', () => {
const nvt1 = Nvt.fromElement({cvss_base: '8.5'});
const nvt2 = Nvt.fromElement({cvss_base: ''});
+ const nvt3 = Nvt.fromElement({nvt: {cvss_base: '9.5'}});
expect(nvt1.severity).toEqual(8.5);
expect(nvt1.cvss_base).toBeUndefined();
expect(nvt2.severity).toBeUndefined();
+ expect(nvt2.cvss_base).toBeUndefined();
+ expect(nvt3.cvss_base).toBeUndefined();
+ expect(nvt3.severity).toEqual(9.5);
});
test('should parse preferences', () => {
@@ -154,9 +175,11 @@ describe('nvt Model tests', () => {
];
const nvt1 = Nvt.fromElement({});
const nvt2 = Nvt.fromElement(elem);
+ const nvt3 = Nvt.fromElement({nvt: elem});
expect(nvt1.preferences).toEqual([]);
expect(nvt2.preferences).toEqual(res);
+ expect(nvt3.preferences).toEqual(res);
});
test('should parse xrefs with correct protocol', () => {
@@ -175,6 +198,11 @@ describe('nvt Model tests', () => {
refs: {ref: [{_type: 'URL', _id: 'ftps://42'}]},
});
const nvt7 = Nvt.fromElement({refs: {ref: [{_id: 'ftps://42'}]}});
+ const nvt8 = Nvt.fromElement({
+ nvt: {
+ refs: {ref: [{_type: 'URL', _id: 'https://42'}]},
+ },
+ });
expect(nvt1.xrefs).toEqual([{ref: '42', type: 'other'}]);
expect(nvt2.xrefs).toEqual([{ref: 'http://42', type: 'url'}]);
@@ -184,6 +212,7 @@ describe('nvt Model tests', () => {
expect(nvt6.xrefs).toEqual([{ref: 'ftps://42', type: 'url'}]);
expect(nvt7.xrefs).toEqual([{ref: 'ftps://42', type: 'other'}]);
expect(nvt7.xref).toBeUndefined();
+ expect(nvt8.xrefs).toEqual([{ref: 'https://42', type: 'url'}]);
});
test('should parse qod', () => {
@@ -193,6 +222,7 @@ describe('nvt Model tests', () => {
const nvt4 = Nvt.fromElement({qod: {type: ''}});
const nvt5 = Nvt.fromElement({qod: {type: 'foo'}});
const nvt6 = Nvt.fromElement({qod: {value: '75.5', type: 'foo'}});
+ const nvt7 = Nvt.fromElement({nvt: {qod: {value: '75.5', type: 'foo'}}});
expect(nvt1.qod).toBeUndefined();
expect(nvt2.qod.value).toBeUndefined();
@@ -200,26 +230,183 @@ describe('nvt Model tests', () => {
expect(nvt4.qod.type).toBeUndefined();
expect(nvt5.qod.type).toEqual('foo');
expect(nvt6.qod).toEqual({value: 75.5, type: 'foo'});
+ expect(nvt7.qod).toEqual({value: 75.5, type: 'foo'});
});
test('should parse default_timeout', () => {
const nvt1 = Nvt.fromElement({});
const nvt2 = Nvt.fromElement({default_timeout: ''});
const nvt3 = Nvt.fromElement({default_timeout: '123'});
+ const nvt4 = Nvt.fromElement({nvt: {default_timeout: '123'}});
expect(nvt1.defaultTimeout).toBeUndefined();
expect(nvt2.defaultTimeout).toBeUndefined();
expect(nvt3.defaultTimeout).toEqual(123);
expect(nvt3.default_timeout).toBeUndefined();
+ expect(nvt4.defaultTimeout).toEqual(123);
+ expect(nvt4.default_timeout).toBeUndefined();
});
test('should parse timeout', () => {
const nvt1 = Nvt.fromElement({});
const nvt2 = Nvt.fromElement({timeout: ''});
const nvt3 = Nvt.fromElement({timeout: '123'});
+ const nvt4 = Nvt.fromElement({nvt: {timeout: '123'}});
expect(nvt1.timeout).toBeUndefined();
expect(nvt2.timeout).toBeUndefined();
expect(nvt3.timeout).toEqual(123);
+ expect(nvt4.timeout).toEqual(123);
+ });
+});
+
+describe('getRefs tests', () => {
+ test('should return empty array for undefined element', () => {
+ const refs = getRefs();
+
+ expect(refs).toEqual([]);
+ });
+
+ test('should return empty array for empty object', () => {
+ const refs = getRefs({});
+
+ expect(refs).toEqual([]);
+ });
+
+ test('should return empty array for empty refs', () => {
+ const refs = getRefs({refs: {}});
+
+ expect(refs).toEqual([]);
+ });
+
+ test('should return refs ref', () => {
+ const refs = getRefs({
+ refs: {
+ ref: [],
+ },
+ });
+
+ expect(refs).toEqual([]);
+ });
+
+ test('should return array for single ref', () => {
+ const refs = getRefs({
+ refs: {
+ ref: [
+ {
+ foo: 'bar',
+ },
+ ],
+ },
+ });
+
+ expect(refs.length).toEqual(1);
+ expect(refs[0]).toEqual({foo: 'bar'});
+ });
+
+ test('should return all refs', () => {
+ const refs = getRefs({
+ refs: {
+ ref: [
+ {
+ foo: 'bar',
+ },
+ {
+ lorem: 'ipsum',
+ },
+ ],
+ },
+ });
+
+ expect(refs.length).toEqual(2);
+ expect(refs[0]).toEqual({foo: 'bar'});
+ expect(refs[1]).toEqual({lorem: 'ipsum'});
+ });
+});
+
+describe('hasRefType tests', () => {
+ test('should return false for undefined ref', () => {
+ expect(hasRefType('foo')()).toEqual(false);
+ });
+
+ test('should return false for empty ref', () => {
+ expect(hasRefType('foo')({})).toEqual(false);
+ });
+
+ test('should return false for non string type', () => {
+ expect(hasRefType('foo')({_type: 1})).toEqual(false);
+ });
+
+ test('should return false when searching for other type', () => {
+ expect(hasRefType('foo')({_type: 'bar'})).toEqual(false);
+ });
+
+ test('should return true when searching for same type', () => {
+ expect(hasRefType('foo')({_type: 'foo'})).toEqual(true);
+ });
+
+ test('should ignore case for type', () => {
+ expect(hasRefType('foo')({_type: 'Foo'})).toEqual(true);
+ expect(hasRefType('foo')({_type: 'FOO'})).toEqual(true);
+ expect(hasRefType('foo')({_type: 'FoO'})).toEqual(true);
+ });
+});
+
+describe('getFilteredRefIds tests', () => {
+ test('should return empty array for undefined refs', () => {
+ const refs = getFilteredRefIds(undefined, 'foo');
+
+ expect(refs).toEqual([]);
+ });
+
+ test('should return empty array for for emtpy refs', () => {
+ const refs = getFilteredRefIds([], 'foo');
+
+ expect(refs).toEqual([]);
+ });
+
+ test('should return empty array when searching for other ref types', () => {
+ const refs = getFilteredRefIds(
+ [
+ {
+ _type: 'bar',
+ _id: '1',
+ },
+ {
+ _type: 'ipsum',
+ _id: '2',
+ },
+ ],
+ 'foo',
+ );
+
+ expect(refs).toEqual([]);
+ });
+
+ test('should return ids of same type only', () => {
+ const refs = getFilteredRefIds(
+ [
+ {
+ _type: 'bar',
+ _id: '1',
+ },
+ {
+ _type: 'foo',
+ _id: '2',
+ },
+ {
+ _type: 'ipsum',
+ _id: '3',
+ },
+ {
+ _type: 'foo',
+ _id: '4',
+ },
+ ],
+ 'foo',
+ );
+
+ expect(refs.length).toEqual(2);
+ expect(refs).toEqual(['2', '4']);
});
});
diff --git a/gsa/src/gmp/models/nvt.js b/gsa/src/gmp/models/nvt.js
index 9acfd5abaf..e7738a626d 100644
--- a/gsa/src/gmp/models/nvt.js
+++ b/gsa/src/gmp/models/nvt.js
@@ -42,40 +42,52 @@ const parse_tags = tags => {
return newtags;
};
-const getFilteredRefIds = (refs, type) => {
- const filteredRefs = refs.filter(ref => ref._type === type);
+export const getRefs = element => {
+ if (
+ !isDefined(element) ||
+ !isDefined(element.refs) ||
+ !isDefined(element.refs.ref)
+ ) {
+ return [];
+ }
+ if (isArray(element.refs.ref)) {
+ return element.refs.ref;
+ }
+ return [element.refs.ref];
+};
+
+export const hasRefType = refType => (ref = {}) =>
+ isString(ref._type) && ref._type.toLowerCase() === refType;
+
+export const getFilteredRefIds = (refs = [], type) => {
+ const filteredRefs = refs.filter(hasRefType(type));
return filteredRefs.map(ref => ref._id);
};
-const getFilteredRefs = (refs, type) => {
- const filteredRefs = refs.filter(ref => {
- const rtype = isString(ref._type) ? ref._type.toLowerCase() : undefined;
- return rtype === type;
- });
- const returnRefs = filteredRefs.map(ref => {
+const getFilteredUrlRefs = refs => {
+ return refs.filter(hasRefType('url')).map(ref => {
let id = ref._id;
- if (type === 'url') {
- if (
- !id.startsWith('http://') &&
- !id.startsWith('https://') &&
- !id.startsWith('ftp://') &&
- !id.startsWith('ftps://')
- ) {
- id = 'http://' + id;
- }
- return {
- ref: id,
- type: type,
- };
+ if (
+ !id.startsWith('http://') &&
+ !id.startsWith('https://') &&
+ !id.startsWith('ftp://') &&
+ !id.startsWith('ftps://')
+ ) {
+ id = 'http://' + id;
}
return {
- id: id,
- type: type,
+ ref: id,
+ type: 'url',
};
});
- return returnRefs;
};
+const getFilteredRefs = (refs, type) =>
+ refs.filter(hasRefType(type)).map(ref => ({
+ id: ref._id,
+ type,
+ }));
+
const getOtherRefs = refs => {
const filteredRefs = refs.filter(ref => {
const rtype = isString(ref._type) ? ref._type.toLowerCase() : undefined;
@@ -104,18 +116,13 @@ class Nvt extends Info {
static parseElement(element) {
const ret = super.parseElement(element, 'nvt');
- ret.nvtType = element._type;
+ ret.nvtType = ret._type;
ret.oid = isEmpty(ret._oid) ? undefined : ret._oid;
ret.id = ret.oid;
- ret.tags = parse_tags(element.tags);
+ ret.tags = parse_tags(ret.tags);
- let refs = [];
- if (isDefined(element.refs) && isArray(element.refs.ref)) {
- refs = ret.refs.ref;
- } else if (isDefined(element.refs) && isDefined(element.refs.ref)) {
- refs = [ret.refs.ref];
- }
+ const refs = getRefs(ret);
ret.cves = getFilteredRefIds(refs, 'cve').concat(
getFilteredRefIds(refs, 'cve_id'),
@@ -128,14 +135,14 @@ class Nvt extends Info {
getFilteredRefs(refs, 'cert-bund'),
);
- ret.xrefs = getFilteredRefs(refs, 'url').concat(getOtherRefs(refs));
+ ret.xrefs = getFilteredUrlRefs(refs, 'url').concat(getOtherRefs(refs));
delete ret.refs;
- ret.severity = parseSeverity(element.cvss_base);
+ ret.severity = parseSeverity(ret.cvss_base);
delete ret.cvss_base;
- if (isDefined(element.preferences)) {
+ if (isDefined(ret.preferences)) {
ret.preferences = map(ret.preferences.preference, preference => {
const pref = {...preference};
delete pref.nvt;
@@ -145,29 +152,29 @@ class Nvt extends Info {
ret.preferences = [];
}
- if (isDefined(element.qod)) {
- if (isEmpty(element.qod.value)) {
+ if (isDefined(ret.qod)) {
+ if (isEmpty(ret.qod.value)) {
delete ret.qod.value;
} else {
- ret.qod.value = parseFloat(element.qod.value);
+ ret.qod.value = parseFloat(ret.qod.value);
}
- if (isEmpty(element.qod.type)) {
+ if (isEmpty(ret.qod.type)) {
delete ret.qod.type;
}
}
- if (isEmpty(element.default_timeout)) {
+ if (isEmpty(ret.default_timeout)) {
delete ret.default_timeout;
} else {
- ret.defaultTimeout = parseFloat(element.default_timeout);
+ ret.defaultTimeout = parseFloat(ret.default_timeout);
delete ret.default_timeout;
}
- if (isEmpty(element.timeout)) {
+ if (isEmpty(ret.timeout)) {
delete ret.timeout;
} else {
- ret.timeout = parseFloat(element.timeout);
+ ret.timeout = parseFloat(ret.timeout);
}
return ret;
diff --git a/gsa/src/gmp/models/report/__tests__/app.js b/gsa/src/gmp/models/report/__tests__/app.js
new file mode 100644
index 0000000000..6477223f9b
--- /dev/null
+++ b/gsa/src/gmp/models/report/__tests__/app.js
@@ -0,0 +1,107 @@
+/* Copyright (C) 2019 Greenbone Networks GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+import App from '../app';
+
+describe('App tests', () => {
+ test('should initialize hosts', () => {
+ const app1 = new App();
+
+ expect(app1.hosts).toBeDefined();
+ expect(app1.hosts.hostsByIp).toBeDefined();
+ expect(app1.hosts.count).toEqual(0);
+
+ const app2 = App.fromElement();
+
+ expect(app2.hosts).toBeDefined();
+ expect(app2.hosts.hostsByIp).toBeDefined();
+ expect(app2.hosts.count).toEqual(0);
+ });
+
+ test('should initialize occurrences', () => {
+ const app1 = new App();
+
+ expect(app1.occurrences).toBeDefined();
+ expect(app1.occurrences.details).toEqual(0);
+ expect(app1.occurrences.total).toEqual(0);
+ expect(app1.occurrences.withoutDetails).toEqual(0);
+
+ const app2 = App.fromElement();
+ expect(app2.occurrences).toBeDefined();
+ expect(app2.occurrences.details).toEqual(0);
+ expect(app2.occurrences.total).toEqual(0);
+ expect(app2.occurrences.withoutDetails).toEqual(0);
+ });
+
+ test('should parse cpe', () => {
+ const app = App.fromElement({value: 'foo'});
+
+ expect(app.id).toEqual('foo');
+ expect(app.name).toEqual('foo');
+ });
+
+ test('should parse severity', () => {
+ const app = App.fromElement({severity: '5.5'});
+
+ expect(app.severity).toEqual(5.5);
+ });
+
+ test('should add hosts', () => {
+ const app = App.fromElement();
+
+ expect(app.hosts).toBeDefined();
+ expect(app.hosts.hostsByIp).toEqual({});
+ expect(app.hosts.count).toEqual(0);
+
+ const host = {name: 'foo', ip: '1.2.3.4'};
+ app.addHost(host);
+
+ expect(app.hosts.hostsByIp['1.2.3.4']).toEqual(host);
+ expect(app.hosts.count).toEqual(1);
+ });
+
+ test('should allow to add occurrence with details', () => {
+ const app = App.fromElement();
+
+ expect(app.occurrences).toBeDefined();
+ expect(app.occurrences.details).toEqual(0);
+ expect(app.occurrences.total).toEqual(0);
+ expect(app.occurrences.withoutDetails).toEqual(0);
+
+ app.addOccurence(5);
+
+ expect(app.occurrences.details).toEqual(5);
+ expect(app.occurrences.total).toEqual(5);
+ expect(app.occurrences.withoutDetails).toEqual(0);
+ });
+
+ test('should allow to add occurrence without details', () => {
+ const app = App.fromElement();
+
+ expect(app.occurrences).toBeDefined();
+ expect(app.occurrences.details).toEqual(0);
+ expect(app.occurrences.total).toEqual(0);
+ expect(app.occurrences.withoutDetails).toEqual(0);
+
+ app.addOccurence();
+
+ expect(app.occurrences.details).toEqual(0);
+ expect(app.occurrences.total).toEqual(1);
+ expect(app.occurrences.withoutDetails).toEqual(1);
+ });
+});
diff --git a/gsa/src/gmp/models/report/__tests__/cve.js b/gsa/src/gmp/models/report/__tests__/cve.js
index 8a23e8887b..e7ea8b56b5 100644
--- a/gsa/src/gmp/models/report/__tests__/cve.js
+++ b/gsa/src/gmp/models/report/__tests__/cve.js
@@ -19,6 +19,30 @@
import ReportCve from '../cve';
describe('ReportCve tests', () => {
+ test('should initialize hosts', () => {
+ const cve1 = new ReportCve();
+
+ expect(cve1.hosts).toBeDefined();
+ expect(cve1.hosts.hostsByIp).toBeDefined();
+ expect(cve1.hosts.count).toEqual(0);
+
+ const cve2 = ReportCve.fromElement();
+
+ expect(cve2.hosts).toBeDefined();
+ expect(cve2.hosts.hostsByIp).toBeDefined();
+ expect(cve2.hosts.count).toEqual(0);
+ });
+
+ test('should initialize occurrences', () => {
+ const cve1 = new ReportCve();
+
+ expect(cve1.occurrences).toEqual(0);
+
+ const cve2 = ReportCve.fromElement();
+
+ expect(cve2.occurrences).toEqual(0);
+ });
+
test('should parse cves', () => {
const reportcve1 = ReportCve.fromElement({});
const elem = {
@@ -51,21 +75,21 @@ describe('ReportCve tests', () => {
});
test('should add hosts', () => {
- const reportcve = new ReportCve();
+ const reportcve = ReportCve.fromElement();
expect(reportcve.hosts).toBeDefined();
- expect(reportcve.hosts.hosts_by_ip).toEqual({});
+ expect(reportcve.hosts.hostsByIp).toEqual({});
expect(reportcve.hosts.count).toEqual(0);
const host = {name: 'foo', ip: '1.2.3.4'};
reportcve.addHost(host);
- expect(reportcve.hosts.hosts_by_ip['1.2.3.4']).toEqual(host);
+ expect(reportcve.hosts.hostsByIp['1.2.3.4']).toEqual(host);
expect(reportcve.hosts.count).toEqual(1);
});
test('should add result', () => {
- const reportcve = new ReportCve();
+ const reportcve = ReportCve.fromElement();
expect(reportcve.occurrences).toEqual(0);
expect(reportcve.severity).toBeUndefined();
@@ -85,4 +109,11 @@ describe('ReportCve tests', () => {
expect(reportcve.occurrences).toEqual(3);
expect(reportcve.severity).toEqual(9.0);
});
+
+ test('should parse nvtName', () => {
+ const reportcve = ReportCve.fromElement({
+ nvt: {_oid: '1.2.3', name: 'Foo'},
+ });
+ expect(reportcve.nvtName).toEqual('Foo');
+ });
});
diff --git a/gsa/src/gmp/models/report/__tests__/host.js b/gsa/src/gmp/models/report/__tests__/host.js
new file mode 100644
index 0000000000..d035faf0b6
--- /dev/null
+++ b/gsa/src/gmp/models/report/__tests__/host.js
@@ -0,0 +1,227 @@
+/* Copyright (C) 2019 Greenbone Networks GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+import ReportHost from '../host';
+import {isDate} from 'gmp/models/date';
+
+describe('ReportHost tests', () => {
+ test('should initialize result counts', () => {
+ const host1 = new ReportHost();
+
+ expect(host1.result_counts).toBeDefined();
+ expect(host1.result_counts.false_positive).toEqual(0);
+ expect(host1.result_counts.high).toEqual(0);
+ expect(host1.result_counts.info).toEqual(0);
+ expect(host1.result_counts.log).toEqual(0);
+ expect(host1.result_counts.warning).toEqual(0);
+ expect(host1.result_counts.total).toEqual(0);
+
+ const host2 = ReportHost.fromElement();
+
+ expect(host2.result_counts).toBeDefined();
+ expect(host2.result_counts.false_positive).toEqual(0);
+ expect(host2.result_counts.high).toEqual(0);
+ expect(host2.result_counts.info).toEqual(0);
+ expect(host2.result_counts.log).toEqual(0);
+ expect(host2.result_counts.warning).toEqual(0);
+ expect(host2.result_counts.total).toEqual(0);
+ });
+
+ test('should initialize details', () => {
+ const host1 = new ReportHost();
+
+ expect(host1.details).toEqual({});
+
+ const host2 = ReportHost.fromElement();
+
+ expect(host2.details).toEqual({});
+ });
+
+ test('should initialize authSuccess', () => {
+ const host1 = new ReportHost();
+
+ expect(host1.authSuccess).toEqual({});
+
+ const host2 = ReportHost.fromElement();
+
+ expect(host2.authSuccess).toEqual({});
+ });
+
+ test('should parse asset', () => {
+ const host = ReportHost.fromElement({
+ asset: {
+ _asset_id: 'a1',
+ },
+ });
+
+ expect(host.asset).toBeDefined();
+ expect(host.asset.id).toEqual('a1');
+ });
+
+ test('should parse port count', () => {
+ const host1 = ReportHost.fromElement({
+ port_count: {},
+ });
+
+ expect(host1.port_count).toEqual(0);
+
+ const host2 = ReportHost.fromElement({
+ port_count: {
+ page: '2',
+ },
+ });
+
+ expect(host2.port_count).toEqual(2);
+ });
+
+ test('should parse result counts', () => {
+ const host1 = ReportHost.fromElement({
+ result_count: {
+ hole: {},
+ warning: {},
+ info: {},
+ log: {},
+ false_positive: {},
+ },
+ });
+
+ expect(host1.result_counts.total).toEqual(0);
+ expect(host1.result_counts.high).toEqual(0);
+ expect(host1.result_counts.warning).toEqual(0);
+ expect(host1.result_counts.info).toEqual(0);
+ expect(host1.result_counts.log).toEqual(0);
+ expect(host1.result_counts.false_positive).toEqual(0);
+
+ expect(host1.result_count).toBeUndefined();
+
+ const host2 = ReportHost.fromElement({
+ result_count: {
+ page: '6',
+ hole: {
+ page: '1',
+ },
+ warning: {
+ page: '2',
+ },
+ info: {
+ page: '3',
+ },
+ log: {
+ page: '4',
+ },
+ false_positive: {
+ page: '5',
+ },
+ },
+ });
+
+ expect(host2.result_counts.total).toEqual(6);
+ expect(host2.result_counts.high).toEqual(1);
+ expect(host2.result_counts.warning).toEqual(2);
+ expect(host2.result_counts.info).toEqual(3);
+ expect(host2.result_counts.log).toEqual(4);
+ expect(host2.result_counts.false_positive).toEqual(5);
+
+ expect(host2.result_count).toBeUndefined();
+ });
+
+ test('should parse start and end dates', () => {
+ const host = ReportHost.fromElement({
+ start: '2019-10-02T12:17:10+02:00',
+ end: '2019-10-02T12:29:22+02:00',
+ });
+
+ expect(host.start).toBeDefined();
+ expect(isDate(host.start)).toEqual(true);
+ expect(host.end).toBeDefined();
+ expect(isDate(host.end)).toEqual(true);
+ });
+
+ test('should parse auth success information', () => {
+ const host = ReportHost.fromElement({
+ detail: [
+ {
+ name: 'Auth-SNMP-Failure',
+ },
+ {
+ name: 'Auth-SSH-Success',
+ },
+ ],
+ });
+
+ expect(host.authSuccess.snmp).toEqual(false);
+ expect(host.authSuccess.ssh).toEqual(true);
+ expect(host.detail).toBeUndefined();
+ });
+
+ test('should parse app information', () => {
+ const host = ReportHost.fromElement({
+ detail: [
+ {
+ name: 'App',
+ value: 'cpe1',
+ },
+ {
+ name: 'App',
+ value: 'cpe2',
+ },
+ ],
+ });
+
+ expect(host.details.appsCount).toEqual(2);
+ expect(host.detail).toBeUndefined();
+ });
+
+ test('should parse detail information', () => {
+ const host = ReportHost.fromElement({
+ detail: [
+ {
+ name: 'hostname',
+ value: 'foo.bar',
+ },
+ {
+ name: 'best_os_cpe',
+ value: 'cpe:/foo/bar',
+ },
+ {
+ name: 'best_os_txt',
+ value: 'Foo OS',
+ },
+ {
+ name: 'traceroute',
+ value: '1.1.1.1,2.2.2.2,3.3.3.3',
+ },
+ ],
+ });
+
+ expect(host.detail).toBeUndefined();
+ expect(host.hostname).toEqual('foo.bar');
+ expect(host.details.best_os_cpe).toEqual('cpe:/foo/bar');
+ expect(host.details.best_os_txt).toEqual('Foo OS');
+ expect(host.details.distance).toEqual(2);
+ });
+
+ test('should parse ip as id', () => {
+ const host = ReportHost.fromElement({
+ ip: '1.2.3.4',
+ });
+
+ expect(host.ip).toEqual('1.2.3.4');
+ expect(host.id).toEqual('1.2.3.4');
+ });
+});
diff --git a/gsa/src/gmp/models/report/__tests__/os.js b/gsa/src/gmp/models/report/__tests__/os.js
new file mode 100644
index 0000000000..df3e566013
--- /dev/null
+++ b/gsa/src/gmp/models/report/__tests__/os.js
@@ -0,0 +1,79 @@
+/* Copyright (C) 2019 Greenbone Networks GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+import ReportOperatingSystem from '../os';
+
+describe('ReportOperatingSystem tests', () => {
+ test('should initialize hosts', () => {
+ const os1 = new ReportOperatingSystem();
+
+ expect(os1.hosts).toBeDefined();
+ expect(os1.hosts.hostsByIp).toBeDefined();
+ expect(os1.hosts.count).toEqual(0);
+
+ const os2 = ReportOperatingSystem.fromElement();
+
+ expect(os2.hosts).toBeDefined();
+ expect(os2.hosts.hostsByIp).toBeDefined();
+ expect(os2.hosts.count).toEqual(0);
+ });
+
+ test('should add host', () => {
+ const os = ReportOperatingSystem.fromElement();
+
+ expect(os.hosts).toBeDefined();
+ expect(os.hosts.hostsByIp).toEqual({});
+ expect(os.hosts.count).toEqual(0);
+
+ const host = {name: 'foo', ip: '1.2.3.4'};
+ os.addHost(host);
+
+ expect(os.hosts.hostsByIp['1.2.3.4']).toEqual(host);
+ expect(os.hosts.count).toEqual(1);
+ });
+
+ test('should allow to set severity', () => {
+ const os = ReportOperatingSystem.fromElement();
+
+ expect(os.severity).toBeUndefined();
+
+ os.setSeverity(5.5);
+
+ expect(os.severity).toEqual(5.5);
+
+ os.setSeverity(3.5);
+
+ expect(os.severity).toEqual(5.5);
+
+ os.setSeverity(9.5);
+
+ expect(os.severity).toEqual(9.5);
+ });
+
+ test('should parse best os', () => {
+ const os = ReportOperatingSystem.fromElement({
+ best_os_cpe: 'cpe:/foo/bar',
+ best_os_txt: 'Foo OS',
+ });
+
+ expect(os.name).toEqual('Foo OS');
+ expect(os.id).toEqual('cpe:/foo/bar');
+ expect(os.cpe).toEqual('cpe:/foo/bar');
+ });
+});
diff --git a/gsa/src/gmp/models/report/__tests__/parser.js b/gsa/src/gmp/models/report/__tests__/parser.js
index 3e08010a8d..a6fbee54b2 100644
--- a/gsa/src/gmp/models/report/__tests__/parser.js
+++ b/gsa/src/gmp/models/report/__tests__/parser.js
@@ -17,10 +17,17 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-import {parseHosts} from '../parser';
+import {
+ parseHosts,
+ parsePorts,
+ parseApps,
+ parseOperatingSystems,
+ parseTlsCertificates,
+ parseCves,
+} from '../parser';
describe('report parser tests', () => {
- test('parse_hosts tests', () => {
+ test('should parse hosts', () => {
const hosts = {
host: [
{
@@ -78,6 +85,663 @@ describe('report parser tests', () => {
expect(parsedHosts.counts).toEqual(countsResult);
expect(parsedHosts.filter).toEqual('foo=bar');
});
+
+ test('should parse empty hosts', () => {
+ const filterString = 'foo=bar';
+ const hosts = parseHosts({}, filterString);
+ const counts = {
+ first: 0,
+ all: 0,
+ filtered: 0,
+ length: 0,
+ rows: 0,
+ last: 0,
+ };
+
+ expect(hosts.entities.length).toEqual(0);
+ expect(hosts.counts).toEqual(counts);
+ expect(hosts.filter).toEqual('foo=bar');
+ });
+
+ test('should parse ports', () => {
+ const filterString = 'foo=bar rows=5';
+ const report = {
+ ports: {
+ count: 123,
+ port: [
+ {__text: '123/tcp', host: '1.2.3.4', severity: 5.5, threat: 'Medium'},
+ {__text: '234/udp', host: '1.2.3.5', severity: 1.0, threat: 'Log'},
+ {__text: '234/udp', host: '1.2.3.6', severity: 9.0, threat: 'High'},
+ {__text: '234/udp', host: '1.2.3.5', severity: 7.5, threat: 'High'},
+ {
+ __text: 'general/tcp',
+ host: '1.2.3.4',
+ severity: 5,
+ threat: 'Medium',
+ },
+ {host: '1.2.3.4', severity: 9, threat: 'High'},
+ ],
+ },
+ };
+ const counts = {
+ first: 1,
+ all: 123,
+ filtered: 2,
+ length: 2,
+ rows: 2,
+ last: 2,
+ };
+ const ports = parsePorts(report, filterString);
+
+ expect(ports.entities.length).toEqual(2);
+ expect(ports.counts).toEqual(counts);
+ expect(ports.filter).toEqual('foo=bar rows=5');
+
+ const [port1, port2] = ports.entities;
+
+ expect(port1.id).toEqual('123/tcp');
+ expect(port1.threat).toEqual('Medium');
+ expect(port1.severity).toEqual(5.5);
+ expect(port1.number).toEqual(123);
+ expect(port1.protocol).toEqual('tcp');
+ expect(port1.hosts.count).toEqual(1);
+
+ expect(port2.id).toEqual('234/udp');
+ expect(port2.threat).toEqual('Log');
+ expect(port2.severity).toEqual(9.0);
+ expect(port2.number).toEqual(234);
+ expect(port2.protocol).toEqual('udp');
+ expect(port2.hosts.count).toEqual(2);
+ });
+
+ test('should parse empty ports', () => {
+ const filterString = 'foo=bar';
+ const report = {};
+ const counts = {
+ first: 0,
+ all: 0,
+ filtered: 0,
+ length: 0,
+ rows: 0,
+ last: 0,
+ };
+ const ports = parsePorts(report, filterString);
+
+ expect(ports.entities.length).toEqual(0);
+ expect(ports.counts).toEqual(counts);
+ expect(ports.filter).toEqual('foo=bar');
+ });
+
+ test('should parse apps', () => {
+ const filterString = 'foo=bar rows=5';
+ const report = {
+ // apps are gathered from the host details
+ host: [
+ {
+ detail: [
+ {
+ name: 'App',
+ value: 'cpe:/a:foo:bar',
+ },
+ ],
+ ip: '1.1.1.1',
+ },
+ {
+ detail: [
+ {
+ name: 'App',
+ value: 'cpe:/a:foo:bar',
+ },
+ {
+ name: 'cpe:/a:foo:bar',
+ value: '123/tcp',
+ },
+ ],
+ ip: '2.2.2.2',
+ },
+ {
+ detail: [
+ {
+ name: 'App',
+ value: 'cpe:/a:lorem:ipsum',
+ },
+ ],
+ ip: '1.1.1.1',
+ },
+ ],
+ apps: {
+ count: '123',
+ },
+ // results are used to get the app severity
+ results: {
+ result: [
+ {
+ severity: '5.5',
+ detection: {
+ result: {
+ details: {
+ detail: [
+ {
+ name: 'foo', // another details that gets ignored
+ value: 'foo/bar',
+ },
+ {
+ name: 'product',
+ value: 'cpe:/a:foo:bar',
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ severity: '7.5',
+ detection: {
+ result: {
+ details: {
+ detail: [
+ {
+ name: 'product',
+ value: 'cpe:/a:foo:bar',
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ severity: '4.5',
+ detection: {
+ result: {
+ details: {
+ detail: [
+ {
+ name: 'product',
+ value: 'cpe:/a:foo:bar',
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ severity: '5.5',
+ detection: {
+ result: {
+ details: {
+ detail: [
+ {
+ name: 'product',
+ value: 'cpe:/a:lorem:ipsum',
+ },
+ ],
+ },
+ },
+ },
+ },
+ ],
+ },
+ };
+ const counts = {
+ first: 1,
+ all: 123,
+ filtered: 2,
+ length: 2,
+ rows: 2,
+ last: 2,
+ };
+ const apps = parseApps(report, filterString);
+
+ expect(apps.entities.length).toEqual(2);
+ expect(apps.counts).toEqual(counts);
+ expect(apps.filter).toEqual('foo=bar rows=5');
+
+ const [app1, app2] = apps.entities;
+
+ expect(app1.id).toEqual('cpe:/a:foo:bar');
+ expect(app1.name).toEqual('cpe:/a:foo:bar');
+ expect(app1.severity).toEqual(7.5);
+ expect(app1.hosts.count).toEqual(2);
+ expect(app1.occurrences.details).toEqual(1);
+ expect(app1.occurrences.withoutDetails).toEqual(0);
+ expect(app1.occurrences.total).toEqual(1);
+
+ expect(app2.id).toEqual('cpe:/a:lorem:ipsum');
+ expect(app2.name).toEqual('cpe:/a:lorem:ipsum');
+ expect(app2.severity).toEqual(5.5);
+ expect(app2.hosts.count).toEqual(1);
+ expect(app2.occurrences.details).toEqual(0);
+ expect(app2.occurrences.withoutDetails).toEqual(1);
+ expect(app2.occurrences.total).toEqual(1);
+ });
+
+ test('should parse empty apps', () => {
+ const filterString = 'foo=bar rows=5';
+ const report = {};
+ const counts = {
+ first: 0,
+ all: 0,
+ filtered: 0,
+ length: 0,
+ rows: 0,
+ last: 0,
+ };
+ const apps = parseApps(report, filterString);
+
+ expect(apps.entities.length).toEqual(0);
+ expect(apps.counts).toEqual(counts);
+ expect(apps.filter).toEqual('foo=bar rows=5');
+ });
+
+ test('should parse operating systems', () => {
+ const filterString = 'foo=bar rows=5';
+ const report = {
+ os: {
+ count: '123',
+ },
+ // os severities are parsed from the results of a host
+ results: {
+ result: [
+ {
+ host: {
+ __text: '1.1.1.1',
+ },
+ severity: '5.5',
+ },
+ {
+ host: {
+ __text: '1.1.1.1',
+ },
+ severity: '9.5',
+ },
+ {
+ host: {
+ __text: '1.1.1.1',
+ },
+ severity: '3.5',
+ },
+ {
+ host: {
+ __text: '2.2.2.2',
+ },
+ severity: '5.5',
+ },
+ {
+ host: {
+ __text: '3.3.3.3',
+ },
+ severity: '6.5',
+ },
+ ],
+ },
+ host: [
+ {
+ ip: '1.1.1.1',
+ detail: [
+ {
+ name: 'best_os_cpe',
+ value: 'cpe:/foo/os',
+ },
+ {
+ name: 'best_os_txt',
+ value: 'Foo OS',
+ },
+ {
+ // will be ignored
+ name: 'foo',
+ value: 'bar',
+ },
+ ],
+ },
+ {
+ ip: '2.2.2.2',
+ detail: [
+ {
+ name: 'best_os_cpe',
+ value: 'cpe:/foo/os',
+ },
+ {
+ name: 'best_os_txt',
+ value: 'Foo OS',
+ },
+ ],
+ },
+ {
+ ip: '3.3.3.3',
+ detail: [
+ {
+ name: 'best_os_cpe',
+ value: 'cpe:/bar/os',
+ },
+ {
+ name: 'best_os_txt',
+ value: 'Bar OS',
+ },
+ ],
+ },
+ ],
+ };
+ const counts = {
+ first: 1,
+ all: 123,
+ filtered: 2,
+ length: 2,
+ rows: 2,
+ last: 2,
+ };
+ const operatingSystems = parseOperatingSystems(report, filterString);
+
+ expect(operatingSystems.entities.length).toEqual(2);
+ expect(operatingSystems.counts).toEqual(counts);
+ expect(operatingSystems.filter).toEqual('foo=bar rows=5');
+
+ const [os1, os2] = operatingSystems.entities;
+
+ expect(os1.name).toEqual('Foo OS');
+ expect(os1.id).toEqual('cpe:/foo/os');
+ expect(os1.cpe).toEqual('cpe:/foo/os');
+ expect(os1.severity).toEqual(9.5);
+ expect(os1.hosts.count).toEqual(2);
+
+ expect(os2.name).toEqual('Bar OS');
+ expect(os2.id).toEqual('cpe:/bar/os');
+ expect(os2.cpe).toEqual('cpe:/bar/os');
+ expect(os2.severity).toEqual(6.5);
+ expect(os2.hosts.count).toEqual(1);
+ });
+
+ test('should parse empty operating systems', () => {
+ const filterString = 'foo=bar rows=5';
+ const report = {};
+ const counts = {
+ first: 0,
+ all: 0,
+ filtered: 0,
+ length: 0,
+ rows: 0,
+ last: 0,
+ };
+ const operatingSystems = parseOperatingSystems(report, filterString);
+
+ expect(operatingSystems.entities.length).toEqual(0);
+ expect(operatingSystems.counts).toEqual(counts);
+ expect(operatingSystems.filter).toEqual('foo=bar rows=5');
+ });
+
+ test('should parse tls certificates', () => {
+ const filterString = 'foo=bar rows=5';
+ const report = {
+ host: [
+ {
+ ip: '1.1.1.1',
+ detail: [
+ {
+ name: 'SSLInfo',
+ value: '123::fingerprint1',
+ },
+ {
+ name: 'SSLDetails:fingerprint1',
+ value:
+ 'issuer:CN=Foo Bar,O=Foo Bar,C=BM|serial:foobar|notBefore:20150930T144006|notAfter:20120930T145000',
+ },
+ {
+ name: 'Cert:fingerprint1',
+ value: 'x509:foobar',
+ },
+ {
+ name: 'hostname',
+ value: 'foo.bar',
+ },
+ ],
+ },
+
+ {
+ ip: '2.2.2.2',
+ detail: [
+ {
+ name: 'SSLInfo',
+ value: '123::fingerprint2',
+ },
+ {
+ name: 'SSLInfo',
+ value: '234::fingerprint2',
+ },
+ {
+ name: 'SSLInfo',
+ value: '234::fingerprint1',
+ },
+ ],
+ },
+ ],
+ ssl_certs: {count: '123'},
+ };
+ const counts = {
+ first: 1,
+ all: 123,
+ filtered: 4,
+ length: 4,
+ rows: 4,
+ last: 4,
+ };
+ const tlsCerts = parseTlsCertificates(report, filterString);
+
+ expect(tlsCerts.entities.length).toEqual(4);
+ expect(tlsCerts.counts).toEqual(counts);
+ expect(tlsCerts.filter).toEqual('foo=bar rows=5');
+
+ const [cert1, cert2, cert3, cert4] = tlsCerts.entities;
+
+ expect(cert1.fingerprint).toEqual('fingerprint1');
+ expect(cert1.hostname).toEqual('foo.bar');
+ expect(cert1.ip).toEqual('1.1.1.1');
+ expect(cert1.data).toEqual('foobar');
+ expect(cert1._data).toEqual('x509:foobar');
+ expect(cert1.ports).toBeUndefined();
+ expect(cert1.port).toEqual(123);
+
+ expect(cert2.fingerprint).toEqual('fingerprint2');
+ expect(cert2.hostname).toBeUndefined();
+ expect(cert2.ip).toEqual('2.2.2.2');
+ expect(cert2.data).toBeUndefined();
+ expect(cert2._data).toBeUndefined();
+ expect(cert2.ports).toBeUndefined();
+ expect(cert2.port).toEqual(123);
+
+ expect(cert3.fingerprint).toEqual('fingerprint2');
+ expect(cert3.hostname).toBeUndefined();
+ expect(cert3.ip).toEqual('2.2.2.2');
+ expect(cert3.data).toBeUndefined();
+ expect(cert3._data).toBeUndefined();
+ expect(cert3.ports).toBeUndefined();
+ expect(cert3.port).toEqual(234);
+
+ expect(cert4.fingerprint).toEqual('fingerprint1');
+ expect(cert4.ip).toEqual('2.2.2.2');
+ expect(cert4.data).toBeUndefined();
+ expect(cert4._data).toBeUndefined();
+ expect(cert4.ports).toBeUndefined();
+ expect(cert4.port).toEqual(234);
+ });
+
+ test('should parse empty tls certificates', () => {
+ const filterString = 'foo=bar rows=5';
+ const report = {};
+ const counts = {
+ first: 0,
+ all: 0,
+ filtered: 0,
+ length: 0,
+ rows: 0,
+ last: 0,
+ };
+ const tlsCerts = parseTlsCertificates(report, filterString);
+
+ expect(tlsCerts.entities.length).toEqual(0);
+ expect(tlsCerts.counts).toEqual(counts);
+ expect(tlsCerts.filter).toEqual('foo=bar rows=5');
+ });
+
+ test('should parse empty cves', () => {
+ const filterString = 'foo=bar rows=5';
+ const report = {};
+ const counts = {
+ first: 0,
+ all: 0,
+ filtered: 0,
+ length: 0,
+ rows: 0,
+ last: 0,
+ };
+ const cves = parseCves(report, filterString);
+
+ expect(cves.entities.length).toEqual(0);
+ expect(cves.counts).toEqual(counts);
+ expect(cves.filter).toEqual('foo=bar rows=5');
+ });
+
+ test('should parse cves', () => {
+ const filterString = 'foo=bar rows=5';
+ const report = {
+ results: {
+ result: [
+ {
+ nvt: {
+ refs: {
+ ref: [{}],
+ },
+ },
+ },
+ {
+ nvt: {
+ refs: {
+ ref: [
+ {
+ _type: '',
+ },
+ ],
+ },
+ },
+ },
+ {
+ nvt: {
+ _oid: '1.2.3',
+ name: 'Foo',
+ refs: {
+ ref: [
+ {
+ _type: 'cve',
+ _id: 'CVE-123',
+ },
+ ],
+ },
+ },
+ host: {
+ __text: '1.1.1.1',
+ },
+ severity: '4.5',
+ },
+ {
+ nvt: {
+ _oid: '1.2.3',
+ name: 'Foo',
+ refs: {
+ ref: [
+ {
+ _type: 'cve',
+ _id: 'CVE-123',
+ },
+ {
+ _type: 'foo',
+ _id: 'foo1',
+ },
+ ],
+ },
+ },
+ host: {
+ __text: '2.2.2.2',
+ },
+ severity: '9.5',
+ },
+ {
+ nvt: {
+ _oid: '2.2.3',
+ name: 'Bar',
+ refs: {
+ ref: [
+ {
+ _type: 'cve',
+ _id: 'CVE-234',
+ },
+ ],
+ },
+ },
+ host: {
+ __text: '1.1.1.1',
+ },
+ severity: '5.5',
+ },
+ {
+ nvt: {
+ _oid: '2.3.3',
+ name: 'Ipsum',
+ refs: {
+ ref: [
+ {
+ _type: 'cve',
+ _id: 'CVE-234',
+ },
+ {
+ _type: 'cve',
+ _id: 'CVE-334',
+ },
+ ],
+ },
+ },
+ host: {
+ __text: '1.1.1.1',
+ },
+ severity: '6.5',
+ },
+ ],
+ },
+ };
+ const counts = {
+ first: 1,
+ all: 3,
+ filtered: 3,
+ length: 3,
+ rows: 3,
+ last: 3,
+ };
+ const cves = parseCves(report, filterString);
+
+ expect(cves.entities.length).toEqual(3);
+ expect(cves.counts).toEqual(counts);
+ expect(cves.filter).toEqual('foo=bar rows=5');
+
+ const [cve1, cve2, cve3] = cves.entities;
+
+ expect(cve1.id).toEqual('1.2.3');
+ expect(cve1.nvtName).toEqual('Foo');
+ expect(cve1.cves).toEqual(['CVE-123']);
+ expect(cve1.severity).toEqual(9.5);
+ expect(cve1.hosts.count).toEqual(2);
+ expect(cve1.occurrences).toEqual(2);
+
+ expect(cve2.id).toEqual('2.2.3');
+ expect(cve2.nvtName).toEqual('Bar');
+ expect(cve2.cves).toEqual(['CVE-234']);
+ expect(cve2.severity).toEqual(5.5);
+ expect(cve2.hosts.count).toEqual(1);
+ expect(cve2.occurrences).toEqual(1);
+
+ expect(cve3.id).toEqual('2.3.3');
+ expect(cve3.nvtName).toEqual('Ipsum');
+ expect(cve3.cves).toEqual(['CVE-234', 'CVE-334']);
+ expect(cve3.severity).toEqual(6.5);
+ expect(cve3.hosts.count).toEqual(1);
+ expect(cve3.occurrences).toEqual(1);
+ });
});
// vim: set ts=2 sw=2 tw=80:
diff --git a/gsa/src/gmp/models/report/__tests__/port.js b/gsa/src/gmp/models/report/__tests__/port.js
new file mode 100644
index 0000000000..255b933b92
--- /dev/null
+++ b/gsa/src/gmp/models/report/__tests__/port.js
@@ -0,0 +1,97 @@
+/* Copyright (C) 2019 Greenbone Networks GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+import ReportPort from '../port';
+
+describe('ReportPort tests', () => {
+ test('should initialize hosts', () => {
+ const port1 = new ReportPort();
+
+ expect(port1.hosts).toBeDefined();
+ expect(port1.hosts.hostsByIp).toBeDefined();
+ expect(port1.hosts.count).toEqual(0);
+
+ const port2 = ReportPort.fromElement();
+
+ expect(port2.hosts).toBeDefined();
+ expect(port2.hosts.hostsByIp).toBeDefined();
+ expect(port2.hosts.count).toEqual(0);
+ });
+
+ test('should add hosts', () => {
+ const port = ReportPort.fromElement();
+
+ expect(port.hosts).toBeDefined();
+ expect(port.hosts.hostsByIp).toEqual({});
+ expect(port.hosts.count).toEqual(0);
+
+ const host = {name: 'foo', ip: '1.2.3.4'};
+ port.addHost(host);
+
+ expect(port.hosts.hostsByIp['1.2.3.4']).toEqual(host);
+ expect(port.hosts.count).toEqual(1);
+ });
+
+ test('should allow to set severity', () => {
+ const port = ReportPort.fromElement();
+
+ expect(port.severity).toBeUndefined();
+
+ port.setSeverity(5.5);
+
+ expect(port.severity).toEqual(5.5);
+
+ port.setSeverity(3.5);
+
+ expect(port.severity).toEqual(5.5);
+
+ port.setSeverity(9.5);
+
+ expect(port.severity).toEqual(9.5);
+ });
+
+ test('should parse severity', () => {
+ const port = ReportPort.fromElement({severity: '5.5'});
+
+ expect(port.severity).toEqual(5.5);
+ });
+
+ test('should parse threat', () => {
+ const port = ReportPort.fromElement({threat: 'Low'});
+
+ expect(port.threat).toEqual('Low');
+ });
+
+ test('should parse port information', () => {
+ const port1 = ReportPort.fromElement({
+ __text: '123/tcp',
+ });
+
+ expect(port1.id).toEqual('123/tcp');
+ expect(port1.number).toEqual(123);
+ expect(port1.protocol).toEqual('tcp');
+
+ const port2 = ReportPort.fromElement({
+ __text: 'general/tcp',
+ });
+
+ expect(port2.id).toEqual('general/tcp');
+ expect(port2.number).toEqual(0);
+ expect(port2.protocol).toEqual('tcp');
+ });
+});
diff --git a/gsa/src/gmp/models/report/__tests__/task.js b/gsa/src/gmp/models/report/__tests__/task.js
new file mode 100644
index 0000000000..b4cf4e6723
--- /dev/null
+++ b/gsa/src/gmp/models/report/__tests__/task.js
@@ -0,0 +1,55 @@
+/* Copyright (C) 2019 Greenbone Networks GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+import ReportTask from '../task';
+
+describe('ReportTask tests', () => {
+ test('should parse id', () => {
+ const task = ReportTask.fromElement({_id: 't1'});
+
+ expect(task.id).toEqual('t1');
+ });
+
+ test('should be container task without target', () => {
+ const task = ReportTask.fromElement();
+
+ expect(task.isContainer()).toEqual(true);
+ });
+
+ test('should parse target', () => {
+ const task = ReportTask.fromElement({
+ target: {
+ _id: 't1',
+ },
+ });
+
+ expect(task.target).toBeDefined();
+ expect(task.target.id).toEqual('t1');
+ expect(task.isContainer()).toEqual(false);
+ });
+
+ test('should parse progress', () => {
+ const task1 = ReportTask.fromElement({progress: {}});
+
+ expect(task1.progress).toEqual(0);
+
+ const task2 = ReportTask.fromElement({progress: {__text: '99'}});
+
+ expect(task2.progress).toEqual(99);
+ });
+});
diff --git a/gsa/src/gmp/models/report/__tests__/tlscertificate.js b/gsa/src/gmp/models/report/__tests__/tlscertificate.js
new file mode 100644
index 0000000000..badbb52fa4
--- /dev/null
+++ b/gsa/src/gmp/models/report/__tests__/tlscertificate.js
@@ -0,0 +1,93 @@
+/* Copyright (C) 2019 Greenbone Networks GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+import ReportTlsCertificate from '../tlscertificate';
+
+describe('ReportTlsCertificate tests', () => {
+ test('should init ports', () => {
+ const cert1 = new ReportTlsCertificate();
+
+ expect(cert1.ports).toBeDefined();
+ expect(cert1.ports.length).toEqual(0);
+
+ const cert2 = ReportTlsCertificate.fromElement();
+
+ expect(cert2.ports).toBeDefined();
+ expect(cert2.ports.length).toEqual(0);
+ });
+
+ test('should create new ReportTlsCertificate from fingerprint', () => {
+ const cert = ReportTlsCertificate.fromElement({fingerprint: 'foo'});
+
+ expect(cert.fingerprint).toEqual('foo');
+ expect(cert.ports).toEqual([]);
+
+ /* test properties which are set during parsing */
+ expect(cert.port).toBeUndefined();
+ expect(cert.ip).toBeUndefined();
+ expect(cert.details).toBeUndefined();
+ expect(cert.data).toBeUndefined();
+ expect(cert._data).toBeUndefined();
+ expect(cert.hostname).toBeUndefined();
+ });
+
+ test('should allow to set id data', () => {
+ const cert = ReportTlsCertificate.fromElement({fingerprint: 'foo'});
+
+ cert.ip = '1.2.3.4';
+ cert.port = '123';
+
+ expect(cert.id).toEqual('1.2.3.4:123:foo');
+ });
+
+ test('should allow to copy a tls certificate', () => {
+ const cert = ReportTlsCertificate.fromElement({fingerprint: 'foo'});
+
+ cert.ip = '1.2.3.4';
+ cert.port = '123';
+ cert.data = {foo: 'bar'};
+ cert._data = {a: 1};
+ cert.hostname = 'foo.bar';
+ cert.details = {lorem: 2};
+
+ const cert2 = cert.copy();
+
+ expect(cert.ip).toEqual('1.2.3.4');
+ expect(cert.port).toEqual('123');
+ expect(cert.data).toEqual({foo: 'bar'});
+ expect(cert._data).toEqual({a: 1});
+ expect(cert.hostname).toEqual('foo.bar');
+ expect(cert.details).toEqual({lorem: 2});
+ expect(cert2.id).toEqual('1.2.3.4:123:foo');
+ });
+
+ test('should allow to add a port', () => {
+ const cert = ReportTlsCertificate.fromElement({fingerprint: 'foo'});
+
+ cert.ip = '1.2.3.4';
+ cert.port = '123';
+
+ expect(cert.id).toEqual('1.2.3.4:123:foo');
+
+ cert.addPort('234');
+
+ expect(cert.port).toEqual('123');
+ expect(cert.ports.length).toEqual(1);
+ expect(cert.ports[0]).toEqual(234);
+ });
+});
diff --git a/gsa/src/gmp/models/report/app.js b/gsa/src/gmp/models/report/app.js
index 54bc37215d..3875104364 100644
--- a/gsa/src/gmp/models/report/app.js
+++ b/gsa/src/gmp/models/report/app.js
@@ -21,48 +21,53 @@ import {isDefined} from 'gmp/utils/identity';
import {parseSeverity, setProperties} from 'gmp/parser';
class App {
- constructor(elem) {
- const properties = this.parseProperties(elem);
- setProperties(properties, this);
+ constructor() {
+ this.hosts = {
+ hostsByIp: {},
+ count: 0,
+ };
+
+ this.occurrences = {
+ details: 0,
+ withoutDetails: 0,
+ total: 0,
+ };
}
addHost(host) {
- if (!(host.ip in this.hosts.hosts_by_ip)) {
- this.hosts.hosts_by_ip[host.ip] = host;
+ if (!(host.ip in this.hosts.hostsByIp)) {
+ this.hosts.hostsByIp[host.ip] = host;
this.hosts.count++;
}
}
addOccurence(count) {
if (isDefined(count)) {
- this.occurrences.detail += count;
+ this.occurrences.details += count;
this.occurrences.total += count;
} else {
- this.occurrences.without_details += 1;
+ this.occurrences.withoutDetails += 1;
this.occurrences.total += 1;
}
}
- parseProperties(elem) {
+ static fromElement(element) {
+ const app = new App();
+
+ setProperties(this.parseElement(element), app);
+
+ return app;
+ }
+
+ static parseElement(element = {}) {
const copy = {};
- const {value: cpe} = elem;
+ const {value: cpe} = element;
copy.id = cpe;
copy.name = cpe;
- copy.hosts = {
- hosts_by_ip: {},
- count: 0,
- };
-
- copy.occurrences = {
- detail: 0,
- without_detail: 0,
- total: 0,
- };
-
- copy.severity = parseSeverity(elem.severity);
+ copy.severity = parseSeverity(element.severity);
return copy;
}
diff --git a/gsa/src/gmp/models/report/cve.js b/gsa/src/gmp/models/report/cve.js
index e6b0c1aec6..6ae5ed60c3 100644
--- a/gsa/src/gmp/models/report/cve.js
+++ b/gsa/src/gmp/models/report/cve.js
@@ -27,7 +27,7 @@ class ReportCve {
this.occurrences = 0;
this.hosts = {
- hosts_by_ip: {},
+ hostsByIp: {},
count: 0,
};
}
@@ -41,8 +41,8 @@ class ReportCve {
}
addHost(host) {
- if (!(host.ip in this.hosts.hosts_by_ip)) {
- this.hosts.hosts_by_ip[host.ip] = host;
+ if (!(host.ip in this.hosts.hostsByIp)) {
+ this.hosts.hostsByIp[host.ip] = host;
this.hosts.count++;
}
}
@@ -63,6 +63,7 @@ class ReportCve {
const nvt = Nvt.fromElement(element);
copy.id = nvt.id;
+ copy.nvtName = nvt.name;
copy.cves = nvt.cves;
return copy;
diff --git a/gsa/src/gmp/models/report/host.js b/gsa/src/gmp/models/report/host.js
index fe37b68610..df1e0f90b7 100644
--- a/gsa/src/gmp/models/report/host.js
+++ b/gsa/src/gmp/models/report/host.js
@@ -39,14 +39,31 @@ const parse_page_count = value => {
};
class Host {
- constructor(elem) {
- this.parseProperties(elem);
+ constructor() {
+ this.authSuccess = {};
+ this.details = {};
+ this.result_counts = {
+ false_positive: 0,
+ high: 0,
+ info: 0,
+ log: 0,
+ warning: 0,
+ total: 0,
+ };
}
- parseProperties(elem) {
- const copy = {...elem};
+ static fromElement(element) {
+ const host = new Host();
- const {asset = {}, port_count = {}, result_count} = elem;
+ setProperties(this.parseElement(element), host);
+
+ return host;
+ }
+
+ static parseElement(element = {}) {
+ const copy = {...element};
+
+ const {asset = {}, port_count = {}, result_count} = element;
if (isEmpty(asset._asset_id)) {
delete copy.asset;
@@ -55,11 +72,11 @@ class Host {
copy.asset.id = asset._asset_id;
}
- copy.port_count = parse_page_count(port_count.page);
+ copy.port_count = parse_page_count(port_count);
if (isDefined(result_count)) {
copy.result_counts = {
- hole: parse_page_count(result_count.hole),
+ high: parse_page_count(result_count.hole),
warning: parse_page_count(result_count.warning),
info: parse_page_count(result_count.info),
log: parse_page_count(result_count.log),
@@ -77,17 +94,17 @@ class Host {
};
}
- copy.start = parseDate(elem.start);
- copy.end = parseDate(elem.end);
+ copy.start = parseDate(element.start);
+ copy.end = parseDate(element.end);
delete copy.result_count;
copy.authSuccess = {};
copy.details = {};
- if (isArray(elem.detail)) {
+ if (isArray(element.detail)) {
let appsCount = 0;
- elem.detail.forEach(details => {
+ element.detail.forEach(details => {
const {name, value} = details;
switch (name) {
case 'hostname':
@@ -119,11 +136,9 @@ class Host {
delete copy.detail;
- copy.id = elem.ip; // use ip as id. we need an id for react key prop
-
- setProperties(copy, this);
+ copy.id = element.ip; // use ip as id. we need an id for react key prop
- return this;
+ return copy;
}
}
diff --git a/gsa/src/gmp/models/report/os.js b/gsa/src/gmp/models/report/os.js
index 1a555d9f9d..97889ab403 100644
--- a/gsa/src/gmp/models/report/os.js
+++ b/gsa/src/gmp/models/report/os.js
@@ -21,38 +21,43 @@ import {isDefined} from 'gmp/utils/identity';
import {setProperties} from 'gmp/parser';
class OperatingSystem {
- constructor(elem) {
- const properties = this.parseProperties(elem);
- setProperties(properties, this);
+ constructor() {
+ this.hosts = {
+ hostsByIp: {},
+ count: 0,
+ };
}
addHost(host) {
- if (!(host.ip in this.hosts.hosts_by_ip)) {
- this.hosts.hosts_by_ip[host.ip] = host;
+ if (!(host.ip in this.hosts.hostsByIp)) {
+ this.hosts.hostsByIp[host.ip] = host;
this.hosts.count++;
}
}
- addSeverity(severity) {
+ setSeverity(severity) {
if (!isDefined(this.severity) || this.severity < severity) {
this.severity = severity;
}
}
- parseProperties(elem) {
+ static fromElement(element) {
+ const os = new OperatingSystem();
+
+ setProperties(this.parseElement(element), os);
+
+ return os;
+ }
+
+ static parseElement(element = {}) {
const copy = {};
- const {best_os_cpe, best_os_txt} = elem;
+ const {best_os_cpe, best_os_txt} = element;
copy.name = best_os_txt;
copy.id = best_os_cpe;
copy.cpe = best_os_cpe;
- copy.hosts = {
- hosts_by_ip: {},
- count: 0,
- };
-
return copy;
}
}
diff --git a/gsa/src/gmp/models/report/parser.js b/gsa/src/gmp/models/report/parser.js
index 095fbf4671..c789098189 100644
--- a/gsa/src/gmp/models/report/parser.js
+++ b/gsa/src/gmp/models/report/parser.js
@@ -41,9 +41,9 @@ import ReportHost from './host';
import ReportOperatingSystem from './os';
import ReportPort from './port';
import ReportTLSCertificate from './tlscertificate';
-import ReportVulnerability from './vulnerability';
import Result from '../result';
+import {getRefs, hasRefType} from '../nvt';
const emptyCollectionList = filter => {
return {
@@ -57,7 +57,7 @@ const getTlsCertificate = (certs, fingerprint) => {
let cert = certs[fingerprint];
if (!isDefined(cert)) {
- cert = new ReportTLSCertificate(fingerprint);
+ cert = ReportTLSCertificate.fromElement({fingerprint});
certs[fingerprint] = cert;
}
return cert;
@@ -189,7 +189,7 @@ export const parsePorts = (report, filter) => {
tport.setSeverity(severity);
} else {
- tport = new ReportPort(port);
+ tport = ReportPort.fromElement(port);
temp_ports[id] = tport;
}
@@ -215,55 +215,6 @@ export const parsePorts = (report, filter) => {
};
};
-export const parseVulnerabilities = (report, filter) => {
- const temp_vulns = {};
- const {vulns, results = {}} = report;
-
- if (!isDefined(vulns)) {
- return emptyCollectionList(filter);
- }
-
- const {count: full_count} = vulns;
-
- forEach(results.result, result => {
- const {nvt = {}, host} = result;
- const {_oid: oid} = nvt;
-
- if (isDefined(oid)) {
- const severity = parseSeverity(result.severity);
-
- let vuln = temp_vulns[oid];
-
- if (isDefined(vuln)) {
- vuln.addResult(results);
- } else {
- vuln = new ReportVulnerability(result);
- temp_vulns[oid] = vuln;
- }
-
- vuln.setSeverity(severity);
- vuln.addHost(host);
- }
- });
-
- const vulns_array = Object.values(temp_vulns);
- const filtered_count = vulns_array.length;
-
- const counts = new CollectionCounts({
- all: full_count,
- filtered: filtered_count,
- first: 1,
- length: filtered_count,
- rows: filtered_count,
- });
-
- return {
- entities: vulns_array,
- filter: isDefined(filter) ? filter : parseFilter(report),
- counts,
- };
-};
-
export const parseApps = (report, filter) => {
const {host: hosts, apps, results = {}} = report;
const apps_temp = {};
@@ -318,7 +269,7 @@ export const parseApps = (report, filter) => {
let app = apps_temp[cpe];
if (!isDefined(app)) {
- app = new ReportApp({...detail, severity: severities[cpe]});
+ app = ReportApp.fromElement({...detail, severity: severities[cpe]});
apps_temp[cpe] = app;
}
@@ -417,14 +368,16 @@ export const parseOperatingSystems = (report, filter) => {
const severity = severities[ip];
if (!isDefined(os)) {
- os = operating_systems[best_os_cpe] = new ReportOperatingSystem({
+ os = operating_systems[
+ best_os_cpe
+ ] = ReportOperatingSystem.fromElement({
best_os_cpe,
best_os_txt,
});
}
os.addHost(host);
- os.addSeverity(severity);
+ os.setSeverity(severity);
}
}
});
@@ -459,7 +412,11 @@ export const parseHosts = (report, filter) => {
const hosts_array = map(hosts, host => {
const {port_count = {}} = host;
const severity = severities[host.ip];
- return new ReportHost({...host, severity, portsCount: port_count.page});
+ return ReportHost.fromElement({
+ ...host,
+ severity,
+ portsCount: port_count.page,
+ });
});
const {length: filtered_count} = hosts_array;
@@ -657,30 +614,27 @@ export const parseCves = (report, filter) => {
const cves = {};
- const results_with_cve = filter_func(
- results.result,
- result => result.nvt.cve !== 'NOCVE' && !isEmpty(result.nvt.cve),
- );
+ const results_with_cve = filter_func(results.result, result => {
+ const refs = getRefs(result.nvt);
+ return refs.some(hasRefType('cve'));
+ });
results_with_cve.forEach(result => {
- const {host = {}, nvt = {}} = result;
- const {cve: id} = nvt;
+ const {host = {}, nvt} = result;
+ const {_oid: id} = nvt;
+ let cve = cves[id];
- if (isDefined(id)) {
- let cve = cves[id];
-
- if (!isDefined(cve)) {
- cve = ReportCve.fromElement(nvt);
- cves[id] = cve;
- }
+ if (!isDefined(cve)) {
+ cve = ReportCve.fromElement(nvt);
+ cves[id] = cve;
+ }
- const {__text: ip} = host;
+ const {__text: ip} = host;
- if (isDefined(ip)) {
- cve.addHost({ip});
- }
- cve.addResult(result);
+ if (isDefined(ip)) {
+ cve.addHost({ip});
}
+ cve.addResult(result);
});
const cves_array = Object.values(cves);
diff --git a/gsa/src/gmp/models/report/port.js b/gsa/src/gmp/models/report/port.js
index 971f093d7e..7947f73b1a 100644
--- a/gsa/src/gmp/models/report/port.js
+++ b/gsa/src/gmp/models/report/port.js
@@ -23,31 +23,43 @@ import {isDefined} from '../../utils/identity';
import {setProperties, parseInt, parseSeverity} from '../../parser';
class ReportPort {
- constructor(elem) {
- this.parseProperties(elem);
+ constructor() {
+ this.hosts = {
+ hostsByIp: {},
+ count: 0,
+ };
}
addHost(host) {
- if (!(host.ip in this.hosts.hosts_by_ip)) {
- this.hosts.hosts_by_ip[host.ip] = host;
+ if (!(host.ip in this.hosts.hostsByIp)) {
+ this.hosts.hostsByIp[host.ip] = host;
this.hosts.count++;
}
}
setSeverity(severity) {
- if (severity > this.severity) {
- this._severity = severity;
+ if (!isDefined(this.severity) || this.severity < severity) {
+ this.severity = severity;
}
}
- parseProperties(elem) {
+ static fromElement(element) {
+ const port = new ReportPort();
+
+ /* use writable=true to allow overriding severity */
+ setProperties(this.parseElement(element), port, {writable: true});
+
+ return port;
+ }
+
+ static parseElement(element = {}) {
const copy = {};
- const {__text: name} = elem;
+ const {__text: name} = element;
copy.id = name;
- copy.threat = elem.threat;
+ copy.threat = element.threat;
- if (name.includes('/')) {
+ if (isDefined(name) && name.includes('/')) {
const [number, protocol] = name.split('/');
copy.number = parseInt(number);
@@ -60,21 +72,10 @@ class ReportPort {
copy.protocol = protocol;
}
- copy.hosts = {
- hosts_by_ip: {},
- count: 0,
- };
-
- setProperties(copy, this);
-
- this._severity = parseSeverity(elem.severity);
+ copy.severity = parseSeverity(element.severity);
return copy;
}
-
- get severity() {
- return this._severity;
- }
}
export default ReportPort;
diff --git a/gsa/src/gmp/models/report/report.js b/gsa/src/gmp/models/report/report.js
index 4304693666..41d9b96a92 100644
--- a/gsa/src/gmp/models/report/report.js
+++ b/gsa/src/gmp/models/report/report.js
@@ -37,7 +37,6 @@ import {
parsePorts,
parseResults,
parseTlsCertificates,
- parseVulnerabilities,
} from './parser';
class ReportReport extends Model {
@@ -89,8 +88,6 @@ class ReportReport extends Model {
copy.applications = parseApps(element, filter);
- copy.vulnerabilities = parseVulnerabilities(element, filter);
-
copy.operatingsystems = parseOperatingSystems(element, filter);
copy.ports = parsePorts(element, filter);
diff --git a/gsa/src/gmp/models/report/task.js b/gsa/src/gmp/models/report/task.js
index 70db51118b..d45041c3bd 100644
--- a/gsa/src/gmp/models/report/task.js
+++ b/gsa/src/gmp/models/report/task.js
@@ -30,10 +30,6 @@ import Model, {parseModelFromElement} from '../../model';
class ReportTask extends Model {
static entityType = 'task';
- parseProperties(element) {
- return ReportTask.parseElement(element);
- }
-
static parseElement(element) {
const copy = super.parseElement(element);
diff --git a/gsa/src/gmp/models/report/tlscertificate.js b/gsa/src/gmp/models/report/tlscertificate.js
index d4fccb7eef..a49d88bdc6 100644
--- a/gsa/src/gmp/models/report/tlscertificate.js
+++ b/gsa/src/gmp/models/report/tlscertificate.js
@@ -18,37 +18,54 @@
*/
import 'core-js/features/object/entries';
-import {isDefined} from '../../utils/identity';
+import {isDefined} from 'gmp/utils/identity';
-import {parseInt} from '../../parser';
+import {setProperties, parseInt} from 'gmp/parser';
class TLSCertificate {
- constructor(fingerprint) {
- this.fingerprint = fingerprint;
+ constructor() {
this.ports = [];
}
addPort(port) {
- let c_port = parseInt(port);
- if (!isDefined(c_port)) {
+ let parsedPort = parseInt(port);
+ if (!isDefined(parsedPort)) {
// port wasn't a number
- c_port = port;
+ parsedPort = port;
}
- this.ports.push(port);
+ this.ports.push(parsedPort);
}
copy() {
- const cert = new TLSCertificate(this.fingerprint);
+ const cert = TLSCertificate.fromElement({fingerprint: this.fingerprint});
+
for (const [key, value] of Object.entries(this)) {
+ if (key === 'fingerprint') {
+ continue;
+ }
cert[key] = value;
}
+
return cert;
}
get id() {
return this.ip + ':' + this.port + ':' + this.fingerprint;
}
+
+ static fromElement(element) {
+ const cert = new TLSCertificate();
+
+ setProperties(this.parseElement(element), cert);
+
+ return cert;
+ }
+
+ static parseElement(element = {}) {
+ const {fingerprint} = element;
+ return {fingerprint};
+ }
}
export default TLSCertificate;
diff --git a/gsa/src/gmp/models/report/vulnerability.js b/gsa/src/gmp/models/report/vulnerability.js
deleted file mode 100644
index 004355bcef..0000000000
--- a/gsa/src/gmp/models/report/vulnerability.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/* Copyright (C) 2017-2019 Greenbone Networks GmbH
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-import {isDefined} from 'gmp/utils/identity';
-
-import {parseQod} from 'gmp/parser';
-
-import Vulnerability from 'gmp/models/vulnerability';
-
-class RfpVulnerability extends Vulnerability {
- addHost(host) {
- if (!(host.ip in this.hosts.hosts_by_ip)) {
- this.hosts.hosts_by_ip[host.ip] = host;
- this.hosts.count++;
- }
- }
-
- addResult(result) {
- this.results.count += 1;
- }
-
- setSeverity(severity) {
- if (
- isDefined(severity) &&
- (!isDefined(this.severity) || severity > this.severity)
- ) {
- this.severity = severity;
- }
- }
-
- parseProperties(element) {
- return RfpVulnerability.parseElement(element);
- }
-
- static parseElement(element) {
- const copy = {};
-
- const {nvt = {}, name, qod = {}} = element;
- const {_oid: oid} = nvt;
-
- copy.id = oid;
- copy.name = name;
- copy.qod = parseQod(qod);
-
- copy.hosts = {
- hosts_by_ip: {},
- count: 0,
- };
-
- copy.results = {
- count: 1,
- };
-
- return copy;
- }
-}
-
-export default RfpVulnerability;
-
-// vim: set ts=2 sw=2 tw=80:
diff --git a/gsa/src/gmp/parser.js b/gsa/src/gmp/parser.js
index 799896860d..411fdf53c8 100644
--- a/gsa/src/gmp/parser.js
+++ b/gsa/src/gmp/parser.js
@@ -166,13 +166,17 @@ export const parseProperties = (element = {}, object = {}) => {
return copy;
};
-export const setProperties = (properties, object = {}) => {
+export const setProperties = (
+ properties,
+ object = {},
+ {writable = false} = {},
+) => {
if (isDefined(properties)) {
for (const [key, value] of Object.entries(properties)) {
if (!key.startsWith('_')) {
Object.defineProperty(object, key, {
value,
- writable: false,
+ writable,
enumerable: true,
});
}
diff --git a/gsa/src/web/pages/reports/cvestable.js b/gsa/src/web/pages/reports/cvestable.js
index 40d597dff1..cb9ba2a3b5 100644
--- a/gsa/src/web/pages/reports/cvestable.js
+++ b/gsa/src/web/pages/reports/cvestable.js
@@ -20,6 +20,8 @@ import React from 'react';
import {_, _l} from 'gmp/locale/lang';
+import {shorten} from 'gmp/utils/string';
+
import PropTypes from 'web/utils/proptypes';
import SeverityBar from 'web/components/bar/severitybar';
@@ -27,6 +29,7 @@ import SeverityBar from 'web/components/bar/severitybar';
import Divider from 'web/components/layout/divider';
import CveLink from 'web/components/link/cvelink';
+import DetailsLink from 'web/components/link/detailslink';
import TableData from 'web/components/table/data';
import TableHead from 'web/components/table/head';
@@ -42,30 +45,41 @@ const Header = ({currentSortDir, currentSortBy, sort = true, onSortChange}) => (
currentSortDir={currentSortDir}
currentSortBy={currentSortBy}
sortBy={sort ? 'cve' : false}
- onSortChange={onSortChange}
title={_('CVE')}
+ width="50%"
+ onSortChange={onSortChange}
/>
+
@@ -79,7 +93,7 @@ Header.propTypes = {
};
const Row = ({entity}) => {
- const {cves, hosts, occurrences, severity} = entity;
+ const {cves, hosts, occurrences, severity, id, nvtName} = entity;
return (
@@ -89,6 +103,11 @@ const Row = ({entity}) => {
))}
+
+
+ {shorten(nvtName, 80)}
+
+
{hosts.count}
{occurrences}
diff --git a/gsa/src/web/pages/reports/sort.js b/gsa/src/web/pages/reports/sort.js
index d474934545..1552c0a500 100644
--- a/gsa/src/web/pages/reports/sort.js
+++ b/gsa/src/web/pages/reports/sort.js
@@ -42,6 +42,7 @@ export const closedCvesSortFunctions = {
export const cvesSortFunctions = {
cve: makeCompareString(entity => entity.cves.join(' ')),
hosts: makeCompareNumber(entity => entity.hosts.count),
+ nvt: makeCompareString(entity => entity.nvtName),
occurrences: makeCompareNumber(entity => entity.occurrences),
severity: makeCompareSeverity(),
};
@@ -107,14 +108,4 @@ export const tlsCertificatesSortFunctions = {
port: makeCompareString('port'),
};
-export const vulnerabilitiesSortFunctions = {
- name: makeCompareString('name'),
- oldest: makeCompareDate(entity => entity.results.oldest),
- newest: makeCompareDate(entity => entity.results.newest),
- qod: makeCompareNumber(entity => entity.qod.value),
- results: makeCompareNumber(entity => entity.results.count),
- hosts: makeCompareNumber(entity => entity.hosts.count),
- severity: makeCompareSeverity(),
-};
-
// vim: set ts=2 sw=2 tw=80: