Skip to content

Commit 12e5154

Browse files
committed
fix for SADP product display
1 parent 19df19d commit 12e5154

2 files changed

Lines changed: 242 additions & 17 deletions

File tree

src/components/AdpVulnerabilityEnrichment.vue

Lines changed: 241 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
<div :id="`${organizationId}-panel`" v-if="usecveRecordStore.accordionState[organizationId]"
2727
class="pl-3 pr-3 pt-2 pb-5 cve-container-accordion-panel">
2828
<div>
29-
<p v-if="dateUpdated.length > 0 && roleName !== 'cna'">
29+
<p v-if="dateUpdated.length > 0 && isCna() && !isSadp()">
3030
<span class="has-text-weight-semibold">Updated: </span>
3131
<time>{{dateUpdated}}</time>
3232
</p>
@@ -36,11 +36,11 @@
3636
This container includes required additional information provided by the CVE Program for this vulnerability.
3737
</p>
3838
</div>
39-
<div v-if="roleName === 'adp'">
39+
<div v-if="isAdp()">
4040
<p class="cve-help-text">SSVC and KEV, plus CVSS and CWE if not provided by the CNA.</p>
4141
</div>
42-
<div v-if="roleName === 'adp'">
43-
<div id="cve-ssvcs" v-if="ssvcs.length > 0 && roleName === 'adp'" class="mt-5">
42+
<div v-if="isAdp()">
43+
<div id="cve-ssvcs" v-if="ssvcs.length > 0" class="mt-5">
4444
<h4 class="title mb-0">SSVC <span class="tag is-normal">{{ ssvcs.length }} Total</span></h4>
4545
<div class="cve-learn-more mb-5">
4646
<router-link to="/CVERecord/UserGuide/#cve-ssvc" class="cve-learn-more-link">Learn more</router-link>
@@ -74,7 +74,7 @@
7474
</div>
7575
</div>
7676
</div>
77-
<div id="cve-kevs" v-if="kevs.length > 0 && roleName === 'adp'" class="mt-5">
77+
<div id="cve-kevs" v-if="kevs.length > 0" class="mt-5">
7878
<h4 class="title mb-0">KEV <span class="tag is-normal">{{ kevs.length }} Total</span></h4>
7979
<div class="cve-learn-more ">
8080
<router-link to="/CVERecord/UserGuide/#cve-kev" class="cve-learn-more-link">Learn more</router-link>
@@ -88,25 +88,25 @@
8888
</div>
8989
</div>
9090
</div>
91-
<div v-if="roleName === 'cna'" id="cve-cna-container-start">
91+
<div v-if="isCna()" id="cve-cna-container-start">
9292
<div id="cve-record-general-info-container" class="content">
9393
<nav id="cve-record-assginer-dates-container" class="level mb-0">
9494
<div class="level-left">
95-
<div v-if="cveFieldList.datePublishedCveMetadata.length > 0" class="level-item">
95+
<div v-if="cveFieldList?.datePublishedCveMetadata.length > 0" class="level-item">
9696
<span>
9797
<span class="has-text-weight-semibold">Published: </span>
98-
<time>{{cveFieldList.datePublishedCveMetadata}}</time>
98+
<time>{{cveFieldList?.datePublishedCveMetadata}}</time>
9999
</span>
100100
</div>
101-
<div v-if="cveFieldList.dateUpdatedCveMetadata.length > 0" class="level-item">
101+
<div v-if="cveFieldList?.dateUpdatedCveMetadata.length > 0" class="level-item">
102102
<span>
103103
<span class="has-text-weight-semibold">Updated: </span>
104-
<time>{{cveFieldList.dateUpdatedCveMetadata}}</time>
104+
<time>{{cveFieldList?.dateUpdatedCveMetadata}}</time>
105105
</span>
106106
</div>
107107
</div>
108108
</nav>
109-
<nav v-if="cveFieldList.title.length > 0" id="cve-record-title-container" class="level mb-0">
109+
<nav v-if="cveFieldList?.title.length > 0" id="cve-record-title-container" class="level mb-0">
110110
<div class="level-left cve-w-100">
111111
<div class="level-item cve-w-100 cve-title">
112112
<p class="mb-0">
@@ -116,7 +116,7 @@
116116
</div>
117117
</div>
118118
</nav>
119-
<nav v-if="cveFieldList.tags.length > 0" id="cve-record-title-tags-container" class="level mb-0">
119+
<nav v-if="cveFieldList?.tags.length > 0" id="cve-record-title-tags-container" class="level mb-0">
120120
<div class="level-right">
121121
<div class="level-item">
122122
<span class="has-text-weight-semibold mr-1">Tags: </span>
@@ -131,9 +131,9 @@
131131
</nav>
132132
</div>
133133

134-
<div id="cve-description">
134+
<div id="cve-description" v-if="!isSadp()">
135135
<h4 class="title is-size-5">Description</h4>
136-
<p class="content cve-x-scroll" v-for="description in cveFieldList.descriptions" :key="description">{{description}}</p>
136+
<p class="content cve-x-scroll" v-for="description in cveFieldList?.descriptions" :key="description">{{description}}</p>
137137
</div>
138138
</div>
139139
<div v-if="roleName !== 'cveProgram'">
@@ -190,7 +190,7 @@
190190
</div>
191191
</div>
192192
</div>
193-
<div v-if="roleName === 'cna'" id="cve-cna-container-end" class="mt-5">
193+
<div v-if="isCna()" id="cve-cna-container-end" class="mt-5">
194194
<div id="cve-product-status-container" class="content">
195195
<ProductStatus role="cna" :productStatusList="cveFieldList.productsStatus.cna"></ProductStatus>
196196
</div>
@@ -223,6 +223,7 @@
223223
</template>
224224

225225
<script>
226+
import _ from 'lodash';
226227
import { usecveRecordStore } from '@/stores/cveRecord.ts';
227228
import { usePartnerStore } from '@/stores/partners';
228229
import { useGenericGlobalsStore } from '@/stores/genericGlobals';
@@ -263,7 +264,7 @@ export default {
263264
kevs: [],
264265
ssvcs: [],
265266
cveProgramReferences: [],
266-
roleName: this.role,
267+
roleName: this.role.toLocaleLowerCase(),
267268
organizationId: this.orgId,
268269
sectionAnchorId: this.anchorId,
269270
cveFieldList: this.selectedCnaData,
@@ -435,8 +436,232 @@ export default {
435436
const [date] = dateTime.split('T');
436437
return date;
437438
},
439+
getSadpData() {
440+
441+
if (!this.isSadp())
442+
return;
443+
444+
this.cveFieldList = {
445+
cveId: '',
446+
credits: [],
447+
descriptions: [],
448+
productsStatus: {
449+
cna: [],
450+
adp: {}
451+
},
452+
title: '',
453+
state: '',
454+
assigner: '',
455+
dateUpdatedCveMetadata: '',
456+
datePublishedCveMetadata: '',
457+
references: [],
458+
tags: [],
459+
};
460+
461+
const sadp = this.containerObject;
462+
463+
this.cveFieldList.dateUpdatedCveMetadata = sadp.providerMetadata.dateUpdated;
464+
465+
const prodStatusTemplate = {
466+
vendor: '',
467+
product: '',
468+
platforms: [],
469+
cpes: [],
470+
defaultStatus: '',
471+
versionsColumns: [],
472+
};
473+
474+
const affectedList = sadp.affected;
475+
476+
affectedList.forEach((affectedObj) => {
477+
const prodStatus = _.cloneDeep(prodStatusTemplate);
478+
// Building column 1
479+
if (this.hasData(affectedObj?.vendor)) prodStatus.vendor = affectedObj.vendor;
480+
if (this.hasData(affectedObj?.product)) prodStatus.product = affectedObj.product;
481+
if (this.hasData(affectedObj?.platforms)) prodStatus.platforms = _.cloneDeep(affectedObj.platforms);
482+
if (this.hasData(affectedObj?.cpes)) {
483+
prodStatus.cpes = affectedObj.cpes;
484+
}
485+
486+
// Building column 2: an affected/unaffected/unknown subcolumn(s) for each product version in containers.cna.affected[i].versions[].
487+
const versionsColumns = [];
488+
// https://github.com/Vulnogram/seaview/blob/main/script.js#L175-L216
489+
if (this.hasData(affectedObj?.versions)) {
490+
491+
const tableRowTemplate = {
492+
versionRange: {
493+
parentVersion: [],
494+
parentVersionRange: [],
495+
parentVersionStatus: '',
496+
versionsChanges: [],
497+
},
498+
};
499+
500+
affectedObj.versions.forEach((versionObj) => {
501+
const tableRow = _.cloneDeep(tableRowTemplate);
502+
class versionsAndChangesTemplate {
503+
versions = [];
504+
changes = [];
505+
changeColorList = [];
506+
};
507+
const productVersion = `${versionObj?.version || '(no version provided)'}`;
508+
const versionStatus = versionObj?.status || 'noVersionStatus'; // affected, unaffected, OR unknown
509+
510+
if (this.hasData(versionObj?.changes)) {
511+
let range = [];
512+
513+
if (productVersion !== 'unspecified' && productVersion !== 0) {
514+
range.push('from');
515+
range.push(productVersion);
516+
}
517+
518+
if (versionObj?.lessThan) {
519+
let rangeEnd = ['before', `${versionObj?.lessThan || '(no lessThan version provided)'}`];
520+
if (this.isUnspecifiedOrWildCard(versionObj, 'lessThan')) rangeEnd = [];
521+
if ((rangeEnd.length > 0) && (versionObj.lessThan !== productVersion)) {
522+
range = range.concat(rangeEnd);
523+
}
524+
} else if (versionObj?.lessThanOrEqual) {
525+
let rangeEnd = ['through', `${versionObj?.lessThanOrEqual || '(no lessThan version provided)'}`];
526+
if (this.isUnspecifiedOrWildCard(versionObj, 'lessThanOrEqual')) rangeEnd = '';
527+
if ((rangeEnd.length > 0) && (versionObj.lessThanOrEqual !== productVersion)) {
528+
range = range.concat(rangeEnd);
529+
}
530+
} else {
531+
range = [productVersion];
532+
}
533+
534+
// save the version changes
535+
const versionsAndChangesCopy = _.cloneDeep(versionsAndChangesTemplate);
536+
537+
// Build a temp 'changes' object by going through container.cna.affected[x].versions[x].changes[]
538+
// and categorize by 'status' (affected, unaffected, or unknown)
539+
// which can be different from the main 'status' (container.cna.affected[x].versions[x].status).
540+
versionObj.changes.forEach((change) => {
541+
versionsAndChangesCopy.changeColorList.push([change.status, 'from', change.at]);
542+
});
543+
544+
tableRow.versionRange.parentVersionStatus = versionStatus;
545+
tableRow.versionRange.parentVersion = ['from', productVersion];
546+
tableRow.versionRange.parentVersionRange = range;
547+
tableRow.versionRange.versionsChanges = versionsAndChangesCopy.changeColorList;
548+
} else {
549+
let rangeStart = [];
550+
if (productVersion !== 'unspecified' && productVersion !== '*') rangeStart = ['from', productVersion];
551+
552+
tableRow.versionRange.parentVersion = [productVersion];
553+
if (this.hasData(versionObj?.lessThan)) {
554+
let range = [];
555+
let rangeEnd = ['before', `${versionObj?.lessThan || '(no version.lessThan provided)'}`];
556+
if (this.isUnspecifiedOrWildCard(versionObj, 'lessThan')) rangeEnd = [];
557+
if (rangeEnd.length > 0) {
558+
range = range.concat(rangeStart, rangeEnd);
559+
} else {
560+
range = rangeStart;
561+
}
562+
tableRow.versionRange.parentVersionStatus = versionStatus;
563+
tableRow.versionRange.parentVersionRange = range;
564+
} else if (this.hasData(versionObj?.lessThanOrEqual)) {
565+
let range = [];
566+
let rangeEnd = ['through', `${versionObj?.lessThanOrEqual || '(no version.lessThan provided)'}`];
567+
if (this.isUnspecifiedOrWildCard(versionObj, 'lessThanOrEqual')) rangeEnd = [];
568+
range = range.concat(rangeStart, rangeEnd);
569+
tableRow.versionRange.parentVersionStatus = versionStatus;
570+
tableRow.versionRange.parentVersionRange = range;
571+
} else {
572+
tableRow.versionRange.parentVersionStatus = versionStatus;
573+
tableRow.versionRange.parentVersion = ['at', productVersion];
574+
tableRow.versionRange.parentVersionRange = ['at', productVersion];
575+
}
576+
}
577+
versionsColumns.push(tableRow.versionRange);
578+
});
579+
580+
if (this.hasData(affectedObj?.defaultStatus)) {
581+
prodStatus.defaultStatus = `${affectedObj.defaultStatus}`;
582+
}
583+
} else {
584+
prodStatus.defaultStatus = this.hasData(affectedObj?.defaultStatus) ? `All versions are ${affectedObj.defaultStatus}` : '';
585+
}
586+
prodStatus.versionsColumns = this.create2DTable(versionsColumns);
587+
this.cveFieldList.productsStatus.cna.push(prodStatus);
588+
});
589+
590+
const value = sadp.references;
591+
592+
if (this.hasData(value)) {
593+
const filteredReferences = [];
594+
const regex = /^x_refsource/;
595+
596+
value.forEach((reference) => {
597+
let newReference = {};
598+
const filteredTags = [];
599+
600+
if (reference?.tags) {
601+
reference.tags.forEach((tag) => {
602+
if (!regex.test(tag)) filteredTags.push(tag);
603+
});
604+
}
605+
newReference = _.cloneDeep(reference);
606+
newReference.tags = filteredTags;
607+
if (newReference?.name && newReference.name.length > 0)
608+
newReference.hostname = (new URL(newReference.url)).hostname.replace('www.', '');
609+
filteredReferences.push(newReference);
610+
});
611+
612+
this.cveFieldList.references = filteredReferences;
613+
}
614+
615+
},
616+
hasData(value) {
617+
if (typeof value !== 'undefined' && value.length > 0) {
618+
return true;
619+
}
620+
621+
return false;
622+
},
623+
isAdp() {
624+
625+
return this.roleName === 'adp';
626+
},
627+
isCna() {
628+
629+
return this.roleName === 'cna' || this.isSadp();
630+
},
631+
isSadp() {
632+
633+
return this.roleName === 'sadp';
634+
},
635+
isUnspecifiedOrWildCard(field, key) {
636+
return (field[key] === 'unspecified' || field[key] === '*');
637+
},
638+
create2DTable(affectedUnaffectedUnknownTable) {
639+
const tableWithHeaders = {
640+
headers: [],
641+
twoDTable: {},
642+
};
643+
644+
// Build table headers: affected, and/or unaffected, and/or unknown
645+
affectedUnaffectedUnknownTable.forEach((row) => {
646+
if (tableWithHeaders.headers.indexOf(row.parentVersionStatus) < 0) tableWithHeaders.headers.push(row.parentVersionStatus);
647+
});
648+
tableWithHeaders.headers.sort();
649+
650+
// Build 2D table w/ 'version'&'changes' or '' for table cell w/ no value
651+
affectedUnaffectedUnknownTable.forEach((row) => {
652+
// for each row fill in 'version'&'changes' or ''
653+
if (Object.prototype.hasOwnProperty.call(tableWithHeaders.twoDTable, row.parentVersionStatus)) {
654+
tableWithHeaders.twoDTable[row.parentVersionStatus].push(row);
655+
} else {
656+
tableWithHeaders.twoDTable[row.parentVersionStatus] = [row];
657+
}
658+
});
659+
return tableWithHeaders;
660+
},
661+
438662
},
439663
beforeMount() {
664+
this.getSadpData();
440665
this.getCvsssCwes();
441666
this.getCveProgramReferences();
442667
this.getUpdatedDate();

src/views/CVERecord/PublishedRecord.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114
</div>
115115
</div>
116116
<div class="cve-sadp-container">
117-
<AdpVulnerabilityEnrichment role="adp" :selectedCnaData="{}"
117+
<AdpVulnerabilityEnrichment role="sadp" :selectedCnaData="{}"
118118
:containerObject="sadpContainer" :orgId="`sadp-${sadpContainer.providerMetadata.orgId}`"
119119
:anchorId="sadpContainerAnchor()">
120120
<h1 class="mb-1 has-text-white cve-capitalize-first-letter">

0 commit comments

Comments
 (0)