mirror of
https://github.com/0xMarcio/cve.git
synced 2026-04-21 22:26:12 +02:00
Highlight PoC-heavy CVEs and filter KEV lists
This commit is contained in:
@@ -6,14 +6,12 @@
|
||||
const titleEl = document.getElementById("cve-title");
|
||||
const summaryEl = document.getElementById("cve-summary");
|
||||
const metaEl = document.getElementById("cve-meta");
|
||||
const descEl = document.getElementById("cve-description");
|
||||
const factsEl = document.getElementById("cve-facts");
|
||||
const pocRowsEl = document.getElementById("cve-poc-rows");
|
||||
const kevRowsEl = document.getElementById("kev-rows");
|
||||
|
||||
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";
|
||||
@@ -133,14 +131,6 @@
|
||||
titleEl.textContent = data.cve || cveId;
|
||||
const desc = getDescriptionText(data);
|
||||
summaryEl.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);
|
||||
@@ -157,14 +147,6 @@
|
||||
titleEl.textContent = fallback.cve;
|
||||
const desc = getDescriptionText(fallback);
|
||||
summaryEl.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);
|
||||
@@ -176,7 +158,6 @@
|
||||
notFoundSection.style.display = "";
|
||||
detailSection.style.display = "none";
|
||||
metaEl.innerHTML = "";
|
||||
descriptionBlock.style.display = "none";
|
||||
titleEl.textContent = cveId;
|
||||
summaryEl.textContent = "No data found for this CVE.";
|
||||
}
|
||||
|
||||
+105
-10
@@ -1,15 +1,110 @@
|
||||
(function(){
|
||||
const filterInputs = document.querySelectorAll('[data-filter-table]');
|
||||
filterInputs.forEach(input => {
|
||||
const tableId = input.dataset.filterTable;
|
||||
const table = document.getElementById(tableId);
|
||||
if (!table) return;
|
||||
input.addEventListener('input', () => {
|
||||
const term = input.value.trim().toLowerCase();
|
||||
for (const row of table.querySelectorAll('tbody tr')) {
|
||||
const text = row.innerText.toLowerCase();
|
||||
row.style.display = text.includes(term) ? '' : 'none';
|
||||
let datasetPromise = null;
|
||||
let pocSet = null;
|
||||
|
||||
function fetchDataset() {
|
||||
if (datasetPromise) return datasetPromise;
|
||||
const candidates = [
|
||||
new URL('/CVE_list.json', window.location.origin).href,
|
||||
new URL('CVE_list.json', window.location.href).href,
|
||||
new URL('../CVE_list.json', window.location.href).href
|
||||
];
|
||||
datasetPromise = (async () => {
|
||||
for (const url of candidates) {
|
||||
try {
|
||||
const res = await fetch(url, { cache: 'no-store' });
|
||||
if (!res.ok) continue;
|
||||
const data = await res.json();
|
||||
return Array.isArray(data) ? data : [];
|
||||
} catch (err) {
|
||||
console.warn('Dataset fetch failed', err);
|
||||
}
|
||||
}
|
||||
return [];
|
||||
})();
|
||||
return datasetPromise;
|
||||
}
|
||||
|
||||
async function ensurePocSet() {
|
||||
if (pocSet) return pocSet;
|
||||
const dataset = await fetchDataset();
|
||||
pocSet = new Set(
|
||||
dataset
|
||||
.filter(item => Array.isArray(item.poc) && item.poc.length > 0)
|
||||
.map(item => (item.cve || '').toUpperCase())
|
||||
);
|
||||
return pocSet;
|
||||
}
|
||||
|
||||
function bindColumnFilters() {
|
||||
const filterInputs = document.querySelectorAll('[data-filter-table]');
|
||||
filterInputs.forEach(input => {
|
||||
const tableId = input.dataset.filterTable;
|
||||
const table = document.getElementById(tableId);
|
||||
if (!table) return;
|
||||
input.addEventListener('input', () => {
|
||||
const term = input.value.trim().toLowerCase();
|
||||
for (const row of table.querySelectorAll('tbody tr')) {
|
||||
const text = row.innerText.toLowerCase();
|
||||
row.style.display = text.includes(term) ? '' : 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function filterTablesByPoc() {
|
||||
const set = await ensurePocSet();
|
||||
document.querySelectorAll('table[data-require-poc]').forEach(table => {
|
||||
for (const row of Array.from(table.querySelectorAll('tbody tr'))) {
|
||||
const link = row.querySelector('a');
|
||||
const idText = (link ? link.textContent : row.textContent || '').trim().toUpperCase();
|
||||
if (!set.has(idText)) {
|
||||
row.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function truncate(text, limit = 140) {
|
||||
if (!text) return '';
|
||||
return text.length > limit ? `${text.slice(0, limit - 1)}…` : text;
|
||||
}
|
||||
|
||||
async function renderTrending() {
|
||||
const container = document.querySelector('[data-trending]');
|
||||
const tbody = document.getElementById('trending-body');
|
||||
if (!container || !tbody) return;
|
||||
|
||||
const data = await fetchDataset();
|
||||
const trending = data
|
||||
.filter(item => item && item.cve && Array.isArray(item.poc) && item.poc.length > 0)
|
||||
.map(item => ({ cve: item.cve, desc: item.desc || 'No description available.', poc: item.poc }))
|
||||
.sort((a, b) => {
|
||||
const delta = (b.poc?.length || 0) - (a.poc?.length || 0);
|
||||
if (delta !== 0) return delta;
|
||||
return (b.cve || '').localeCompare(a.cve || '');
|
||||
})
|
||||
.slice(0, 12);
|
||||
|
||||
if (trending.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="3" class="muted">No PoCs found yet.</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
tbody.innerHTML = trending.map(item => {
|
||||
const pocCount = item.poc ? item.poc.length : 0;
|
||||
const safeDesc = truncate(item.desc, 160);
|
||||
return `<tr>
|
||||
<td class="cve-cell"><a href="/cve/?id=${item.cve}">${item.cve}</a></td>
|
||||
<td>${pocCount}</td>
|
||||
<td>${safeDesc}</td>
|
||||
</tr>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
bindColumnFilters();
|
||||
filterTablesByPoc();
|
||||
renderTrending();
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -31,13 +31,6 @@
|
||||
<h2>Overview</h2>
|
||||
<div class="subtle-grid" id="cve-facts"></div>
|
||||
|
||||
<div id="cve-description-block" style="display:none;">
|
||||
<h2>CVE detail</h2>
|
||||
<div class="detail-card">
|
||||
<p id="cve-description" class="muted"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>PoC Links</h2>
|
||||
<div id="cve-pocs" class="table-responsive">
|
||||
<table class="list">
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<span class="muted">Only the recent additions</span>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<table data-require-poc>
|
||||
<thead><tr><th>CVE</th><th>Vendor</th><th>Product</th><th>EPSS</th><th>Percentile</th><th>Date Added</th><th>Due</th></tr></thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
@@ -203,4 +203,4 @@
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+19
-2
@@ -54,13 +54,30 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-header">
|
||||
<h1>Trending PoCs</h1>
|
||||
<span class="muted">Most linked PoCs across the catalog</span>
|
||||
</div>
|
||||
<div class="table-wrap" data-trending>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>CVE</th><th>PoCs</th><th>Description</th></tr>
|
||||
</thead>
|
||||
<tbody id="trending-body">
|
||||
<tr><td colspan="3" class="muted">Loading trending PoCs…</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-header">
|
||||
<h1>Latest KEV additions</h1>
|
||||
<span class="muted">Last 30 days</span>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<table data-require-poc>
|
||||
<thead>
|
||||
<tr><th>CVE</th><th>Vendor</th><th>Product</th><th>EPSS</th><th>Percentile</th><th>Date Added</th><th>Due</th></tr>
|
||||
</thead>
|
||||
@@ -458,4 +475,4 @@
|
||||
</footer>
|
||||
<script src="/logic.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+2
-2
@@ -27,7 +27,7 @@
|
||||
</div>
|
||||
<input type="search" placeholder="Filter CVE, vendor, product" data-filter-table="kev-table" class="filter" />
|
||||
<div class="table-responsive">
|
||||
<table class="list" id="kev-table">
|
||||
<table class="list" id="kev-table" data-require-poc>
|
||||
<thead>
|
||||
<tr><th>CVE</th><th>Vendor</th><th>Product</th><th>EPSS</th><th>Percentile</th><th>Date Added</th><th>Due</th></tr>
|
||||
</thead>
|
||||
@@ -13346,4 +13346,4 @@
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user