Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"prettier": "^3.6.2",
"sass-embedded": "^1.93.2",
"typescript": "~5.3.0",
"vite": "^5.4.20",
"vite": "^5.4.21",
"vue-tsc": "^1.8.27"
}
}
2 changes: 0 additions & 2 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import PrimaryNavigation from './components/PrimaryNavigation.vue';
import NotificationBannerModule from './components/NotificationBannerModule.vue';
import FooterModule from './components/FooterModule.vue';
import NotFound from './views/NotFound.vue';
import { usePartnerStore } from '@/stores/partners';
import { useSeoMeta } from '@unhead/vue';

export default {
Expand All @@ -35,7 +34,6 @@ export default {
}
},
beforeMount() {
usePartnerStore().populatePartnerShortLongNameMap();
useSeoMeta({
title: 'CVE: Common Vulnerabilities and Exposures',
description: 'At cve.org, we provide the authoritative '
Expand Down
24 changes: 13 additions & 11 deletions src/components/AdpVulnerabilityEnrichment.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<p class="cve-help-text">
This container includes required additional information provided by the CVE Program for this vulnerability.
</p>
</div>
</div>
<div v-if="roleName === 'adp'">
<p class="cve-help-text">SSVC and KEV, plus CVSS and CWE if not provided by the CNA.</p>
</div>
Expand Down Expand Up @@ -84,7 +84,7 @@
</ul>
</div>
</div>
</div>
</div>
<div v-if="roleName === 'cna'" id="cve-cna-container-start">
<div id="cve-record-general-info-container" class="content">
<nav id="cve-record-assginer-dates-container" class="level mb-0">
Expand Down Expand Up @@ -152,7 +152,7 @@
</div>
<div id="cve-cvsss" v-if="cvsss.length > 0" class="mt-5">
<h4 class="title mb-0">CVSS <span class="tag">{{ cvsss.length }} Total</span></h4>

<div class="cve-learn-more mb-3">
<router-link to="/CVERecord/UserGuide/#cve-cvss" class="cve-learn-more-link">Learn more</router-link>
</div>
Expand Down Expand Up @@ -194,23 +194,24 @@
</ul>
</div>

<CveRecordReferences id="cve-references"
<CveRecordReferences id="cve-references"
v-if="cveFieldList.references.length > 0" :references="cveFieldList.references"
>
</CveRecordReferences>
</div>

<CveRecordReferences id="cve-program-references"
<CveRecordReferences id="cve-program-references"
v-if="cveProgramReferences.length > 0" :references="cveProgramReferences"
>
</CveRecordReferences>
</div>
</div>
</div>
</template>

<script>
import { usecveRecordStore } from '@/stores/cveRecord.ts';
import { usePartnerStore } from '@/stores/partners';
import { useGenericGlobalsStore } from '@/stores/genericGlobals';
import ProductStatus from '@/components/ProductStatus.vue';
import CveRecordReferences from './CveRecordReferences.vue';
Expand Down Expand Up @@ -258,6 +259,7 @@ export default {
dateUpdated: '',
cveServicesBaseUrl: useGenericGlobalsStore().currentServicesUrl,
usecveRecordStore: usecveRecordStore(),
partnerStore: usePartnerStore(),
}
},
methods: {
Expand Down Expand Up @@ -301,7 +303,7 @@ export default {

if (metricObj[cvssVersion]?.version) cvss.version = metricObj[cvssVersion].version;
if (metricObj[cvssVersion]?.vectorString) cvss.vectorString = metricObj[cvssVersion]?.vectorString;

this.cvsss.push(cvss);
}
});
Expand Down Expand Up @@ -407,14 +409,14 @@ export default {
}
},
getCveProgramReferences(){
if (this.containerObject.providerMetadata.shortName?.toLowerCase() !== usecveRecordStore().cveProgramShortName) return;
if (this.containerObject.providerMetadata.shortName?.toLowerCase() !== this.partnerStore.cveProgramShortName) return;
this.cveProgramReferences = usecveRecordStore().getReferences(this.containerObject.references);
},
getUpdatedDate() {
if(this.containerObject.providerMetadata?.dateUpdated) {
this.dateUpdated = this.getDate(this.containerObject.providerMetadata?.dateUpdated);
}

},
getDate(dateTime) {
const [date] = dateTime.split('T');
Expand All @@ -430,7 +432,7 @@ export default {
</script>

<style lang="scss">
@import '@/assets/style/globals.scss';
@import '@/assets/style/globals.scss';
</style>

<!-- Add "scoped" attribute to limit CSS to this component only -->
Expand All @@ -442,7 +444,7 @@ export default {
cursor: pointer;
width: 100%;
}

.cve-container-accordion-panel {
border: 1px solid $theme-color-primary-darker;
}
Expand Down
4 changes: 2 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { library } from '@fortawesome/fontawesome-svg-core';
import { fab } from '@fortawesome/free-brands-svg-icons';
import {
faAngleDoubleLeft, faAngleDoubleRight, faAngleLeft, faAngleRight, faArrowRight, faBlog, faBook, faCaretDown, faCaretUp, faInfoCircle, faCheckCircle,
faExclamationCircle, faFileCode, faTriangleExclamation, faUpRightFromSquare, faLightbulb, faLink, faMinus, faPassport, faPlus, faPodcast, faIdCard,
faExclamationCircle, faFileCode, faTriangleExclamation, faUpRightFromSquare, faLightbulb, faLink, faMinus, faPassport, faPlus, faPodcast, faIdCard,
faSearch, faHandshake, faUsersCog, faLaptopCode, faPoll, faTimes, faToolbox, faSitemap, faUser, faUserShield, faBullhorn, faWindowMaximize,
} from '@fortawesome/free-solid-svg-icons';
import { faArrowAltCircleRight, faClipboard, faNewspaper } from '@fortawesome/free-regular-svg-icons';
Expand All @@ -41,7 +41,7 @@ app.use(pinia);
app.use(head);
app.mixin(VueHeadMixin);

usePartnerStore().populatePartnerCounts();
usePartnerStore().initialize();

app.use(VueGtag, {
config: { id: import.meta.env.VITE_GOOGLE_ANALYTICS_PROPERTY_ID },
Expand Down
3 changes: 1 addition & 2 deletions src/stores/cveRecord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import _ from 'lodash';


export const usecveRecordStore = defineStore('cveRecord', {
state: () => {
state: () => {
return {
cveId: '',
cveIdRegex: /^CVE-\d{4}-\d{4,7}$/i,
Expand All @@ -27,7 +27,6 @@ export const usecveRecordStore = defineStore('cveRecord', {
submenu: {}
},
orgIdAndLongNameMap: {},
cveProgramShortName: 'cve'
}
},
actions: {
Expand Down
106 changes: 91 additions & 15 deletions src/stores/partners.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,30 @@ import PartnerData from '@/assets/data/CNAsList.json';
import axios from 'axios';

export const usePartnerStore = defineStore('partner', {
state: () => {
state: () => {
return {
cveProgramShortName: 'cve',
partnerCounts: {},
partnerShortLongNameMap: {},
uuid2LongNameMap: {},
selectedPartnerCountry: "",
selectedCountryInternalChange: true, //Used to track if a country was selected from the PartnerMap or the CNAs.vue list
// Used to track if a country was selected from the PartnerMap or the
// CNAs.vue list:
selectedCountryInternalChange: true,
short2FullNameMap: {},
}
},
actions: {
initialize() {

this.populatePartnerCounts();
this.populateUuid2LongNameMap();
this.createShort2FullNameMap();
},
populatePartnerCounts () {
const partnerCounts = {
type: {}, role: {}, totalPartners: 0, countries: {}, countriesCount: 0,
};

PartnerData.forEach((partner) => {
if (partner.CNA.roles.length > 0) {
partner.CNA.roles.forEach((roleObj) => {
Expand All @@ -29,12 +39,12 @@ export const usePartnerStore = defineStore('partner', {
}
});
}

if (partner.CNA.type.length > 0) {
partner.CNA.type.forEach((type) => {
let newType = '';
if (new RegExp(/^(Vulnerability Researcher)/, 'i').test(type)) { newType = 'Vulnerability Researcher(s)'; } else { newType = type; }

if (newType.toLowerCase() !== 'n/a') {
if (Object.prototype.hasOwnProperty.call(partnerCounts.type, newType)) {
partnerCounts.type[newType] += 1;
Expand All @@ -44,35 +54,101 @@ export const usePartnerStore = defineStore('partner', {
}
});
}

if (Object.prototype.hasOwnProperty.call(partnerCounts.countries, partner.country)) {
partnerCounts.countries[partner.country] += 1;
} else {
partnerCounts.countries[partner.country] = 1;
}
});

partnerCounts.totalPartners = PartnerData.length;
Object.keys(partnerCounts.countries).forEach((country)=>{
if (country !== 'n/a') partnerCounts.countriesCount += 1;
});

partnerCounts.countries['No country affiliation'] = partnerCounts.countries['n/a'];
delete partnerCounts.countries['n/a'];

this.partnerCounts = partnerCounts;
},
async populatePartnerShortLongNameMap () {
async populateUuid2LongNameMap () {

const url = `${import.meta.env.VITE_API_BASE_URL}cve-partner-name-map.json`;

try {
const url = `${import.meta.env.VITE_API_BASE_URL}cve-partner-name-map.json`;
const response = await axios.get(url, { timeout: 30000 });

this.partnerShortLongNameMap = response?.data || {};
this.uuid2LongNameMap = response?.data || {};

} catch (error) {
throw new Error(`Error fetching ${import.meta.env.VITE_API_BASE_URL}cve-partner-name-map.json`);
console.log(`Unavailable: ${url}`);
}
}
},
createShort2FullNameMap() {

// This creates a mapping of **lowercased** short names to long names,
// based on the static CNA list data stored locally. At present,
// there is no other way to get a long name given a short name.

const short2FullNameMap = new Map();

PartnerData.forEach((entry) => {
short2FullNameMap.set(entry.shortName.toLowerCase(),
entry.organizationName);
});

this.short2FullNameMap = short2FullNameMap;
},
getOrganizationName(assignerName, assignerUUID, ownerName) {

// Given the assigner name and UUID, as well as the owner name (optional),
// return the appropriate name string to display as the CNA for the
// published record. In almost all cases, this will be the long name
// obtained by using the UUID to get the name from the map. When the
// assigner and owner name are different, the owner's name is displayed
// (it's assumed the ownership has changed and the assigner name does NOT
// reflect the change).

if (assignerName === undefined && assignerUUID === undefined
&& ownerName === undefined)
return 'Name Unavailable';

const assignerNameLower = assignerName?.toLowerCase();
const ownerNameLower = ownerName?.toLowerCase();

if (ownerName && assignerNameLower !== ownerNameLower) {

// Display the owner name - try to get the full name using the
// static CNA list. Otherwise, the owner's short name is displayed.

return this.short2FullNameMap.get(ownerNameLower)
|| this.short2DisplayName(ownerName);
}

// The displayed name is based on the assigner.

return this.uuid2LongNameMap[assignerUUID]
|| (assignerNameLower === this.cveProgramShortName)
? 'CVE Program' : this.short2FullNameMap.get(assignerNameLower)
|| this.short2DisplayName(assignerName);
},
short2DisplayName(shortName) {

// Modify a given "short name" for display - replace any underscores
// with a space and capitalize each word.

return this.capitalize(shortName.replace('_', ' '));
},
capitalize(str) {

// Capitalize each word in the given string. The 3rd part of the "OR"
// in the regular expression allows for the word starting with various
// "openings", which isn't really needed, but left for possible use
// elsewhere.

return str.replace(/(?:^|\s|["'([{])+\S/g, match => match.toUpperCase());
},

},
});
13 changes: 10 additions & 3 deletions src/views/CVERecord/CVERecord.vue
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ export default {
this.handleServerError();
}
} finally {
if (!usecveRecordStore().serverError && !usecveRecordStore().isPublished
&& !usecveRecordStore().isReserved && !usecveRecordStore().isRejected) {
if (!usecveRecordStore().serverError && !usecveRecordStore().isReserved
&& !usecveRecordStore().isRejected) {
await this.getIdData();
}
}
Expand Down Expand Up @@ -289,7 +289,14 @@ export default {
} else if (usecveRecordStore().recordData.cveMetadata.state === 'REJECTED') {
usecveRecordStore().isRejected = true;
}
this.handleIsIdOrRecordFound(true);

// For published records, hold off on marking the record found until
// after we've also retrieved the ID record. Both record and ID data
// is needed for a published record to determine if the owner of the
// CVE record is the same as the assigner.

if (!usecveRecordStore().isPublished)
this.handleIsIdOrRecordFound(true);
}
},
handleServerError() {
Expand Down
Loading
Loading