diff --git a/docs/assets/cve.js b/docs/assets/cve.js index dd749042e1..ed1b8d49a7 100644 --- a/docs/assets/cve.js +++ b/docs/assets/cve.js @@ -13,6 +13,7 @@ const detailSection = document.getElementById("cve-details"); const notFoundSection = document.getElementById("not-found"); + const descriptionBlock = document.getElementById("cve-description-block"); function setLoading(message) { titleEl.textContent = cveId || "CVE details"; @@ -27,14 +28,37 @@ return "No description available."; } + function hasKevData(kev) { + if (!kev || typeof kev !== "object") return false; + return Boolean( + (kev.short_description && kev.short_description.trim()) || + kev.date_added || + kev.due_date || + kev.required_action || + kev.notes + ); + } + function renderFacts(data) { + const pocCount = data.poc_count ?? (Array.isArray(data.poc_links) ? data.poc_links.length : Array.isArray(data.poc) ? data.poc.length : undefined); const items = []; - if (data.vendor) items.push({ label: "Vendor", value: data.vendor }); - if (data.product) items.push({ label: "Product", value: data.product }); - if (data.epss !== undefined && data.epss !== null) items.push({ label: "EPSS", value: data.epss.toFixed(3) }); - if (data.percentile !== undefined && data.percentile !== null) items.push({ label: "Percentile", value: `${Math.round(data.percentile * 100)}th` }); - if (data.poc_count !== undefined) items.push({ label: "PoCs", value: data.poc_count }); - if (data.kev) items.push({ label: "KEV status", value: data.kev.date_added ? `Added ${data.kev.date_added}` : "Listed" }); + const vendorValue = data.vendor || "Unknown vendor"; + const productValue = data.product || "Unknown product"; + const epssValue = typeof data.epss === "number" ? data.epss.toFixed(3) : "n/a"; + const percentileValue = typeof data.percentile === "number" ? `${Math.round(data.percentile * 100)}th` : "n/a"; + const pocValue = pocCount ?? 0; + + items.push({ label: "Vendor", value: vendorValue }); + items.push({ label: "Product", value: productValue }); + items.push({ label: "EPSS", value: epssValue }); + items.push({ label: "Percentile", value: percentileValue }); + items.push({ label: "PoCs", value: pocValue }); + if (hasKevData(data.kev)) items.push({ label: "KEV status", value: data.kev.date_added ? `Added ${data.kev.date_added}` : "Listed" }); + + if (items.length === 0) { + factsEl.innerHTML = `
No overview data yet.
`; + return; + } factsEl.innerHTML = items .map((item) => `
${item.value}${item.label}
`) @@ -56,13 +80,13 @@ const pills = []; if (data.vendor) pills.push(`Vendor: ${data.vendor}`); if (data.product) pills.push(`Product: ${data.product}`); - if (data.kev) pills.push("On KEV list"); + if (hasKevData(data.kev)) pills.push("On KEV list"); metaEl.innerHTML = pills.map((text) => `${text}`).join(""); } function renderKev(kev) { - if (!kev) { + if (!hasKevData(kev)) { document.getElementById("kev-section").style.display = "none"; return; } @@ -109,7 +133,14 @@ titleEl.textContent = data.cve || cveId; const desc = getDescriptionText(data); summaryEl.textContent = desc; - descEl.textContent = desc; + const hasDescContent = desc && desc !== "No description available."; + if (hasDescContent) { + descEl.textContent = desc; + descriptionBlock.style.display = ""; + } else { + descEl.textContent = ""; + descriptionBlock.style.display = "none"; + } renderFacts(data); renderPocs(data.poc_links || data.poc || []); renderKev(data.kev); @@ -126,7 +157,14 @@ titleEl.textContent = fallback.cve; const desc = getDescriptionText(fallback); summaryEl.textContent = desc; - descEl.textContent = desc; + const hasDescContent = desc && desc !== "No description available."; + if (hasDescContent) { + descEl.textContent = desc; + descriptionBlock.style.display = ""; + } else { + descEl.textContent = ""; + descriptionBlock.style.display = "none"; + } renderFacts(fallback); renderPocs(fallback.poc_links || fallback.poc || []); renderKev(null); @@ -138,6 +176,7 @@ notFoundSection.style.display = ""; detailSection.style.display = "none"; metaEl.innerHTML = ""; + descriptionBlock.style.display = "none"; titleEl.textContent = cveId; summaryEl.textContent = "No data found for this CVE."; } diff --git a/docs/cve/index.html b/docs/cve/index.html index 66f9792ba2..0da06dcfa0 100644 --- a/docs/cve/index.html +++ b/docs/cve/index.html @@ -31,9 +31,11 @@

Overview

-

CVE detail

-
-

+

PoC Links

diff --git a/docs/logic.js b/docs/logic.js index 1b204f0525..b8c50d7f49 100644 --- a/docs/logic.js +++ b/docs/logic.js @@ -54,6 +54,19 @@ function getCveLink(cveId) { return `${cveId}`; } +function prepareDataset(raw) { + if (!Array.isArray(raw)) return []; + const descKeyCleaned = (entry) => { + const base = entry.desc || ''; + return replaceStrings.reduce((desc, str) => desc.replace(str, ''), base); + }; + return raw.map(entry => { + const descCleaned = descKeyCleaned(entry); + const searchText = `${entry.cve || ''} ${descCleaned}`.toLowerCase(); + return { ...entry, _searchText: searchText }; + }); +} + const controls = { oldColor: '', displayResults(results, resultsTableHideable) { @@ -70,8 +83,7 @@ const controls = { const negmatch = words.filter(word => word[0] === '-').map(word => word.substring(1)); return dataset.filter(e => { - const description = replaceStrings.reduce((desc, str) => desc.replace(str, ''), e.desc).toLowerCase(); - const combinedText = (e.cve + description).toLowerCase(); + const combinedText = e._searchText || ''; const positiveMatch = posmatch.every(word => combinedText.includes(word)); const negativeMatch = negmatch.some(word => combinedText.includes(word)); @@ -95,17 +107,14 @@ const controls = { noResults.style.display = 'none'; resultsTableHideable.classList.remove('hide'); - const fragment = document.createDocumentFragment(); - results.forEach(r => { - const el = searchResultFormat + const html = results.map(r => { + const desc = r.desc || ''; + return searchResultFormat .replace('$cve', getCveLink(r.cve)) - .replace('$description', escapeHTML(r.desc)) - .replace('$poc', convertLinksToList(r.poc)); - const wrapper = document.createElement('table'); - wrapper.innerHTML = el; - fragment.appendChild(wrapper.querySelector('tr')); - }); - loc.appendChild(fragment); + .replace('$description', escapeHTML(desc)) + .replace('$poc', convertLinksToList(r.poc || [])); + }).join(''); + loc.innerHTML = html; } }, setColor(loc, indicator) { @@ -176,7 +185,7 @@ document.addEventListener('DOMContentLoaded', () => { throw new Error(`Failed to load ${url} (${res.status})`); } const data = await res.json(); - window.dataset = Array.isArray(data) ? data : []; + window.dataset = prepareDataset(data); currentSet = window.dataset; controls.hideResults(results, resultsTableHideable); noResults.style.display = 'none';