@shubhambattoo/look-see 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/advisories/nvd.js +23 -11
- package/src/cli.js +1 -1
package/package.json
CHANGED
package/src/advisories/nvd.js
CHANGED
|
@@ -4,6 +4,7 @@ const NVD_URL = 'https://services.nvd.nist.gov/rest/json/cves/2.0';
|
|
|
4
4
|
const CACHE_TTL = 7 * 24 * 60 * 60 * 1000;
|
|
5
5
|
const NVD_API_KEY = process.env.NVD_API_KEY;
|
|
6
6
|
const MIN_INTERVAL_MS = NVD_API_KEY ? 700 : 6_100;
|
|
7
|
+
const MAX_CVES_PER_REQUEST = 100;
|
|
7
8
|
|
|
8
9
|
function cveIdsFrom(vulnerabilities) {
|
|
9
10
|
const ids = new Set();
|
|
@@ -16,15 +17,17 @@ function cveIdsFrom(vulnerabilities) {
|
|
|
16
17
|
return [...ids].sort();
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
async function
|
|
20
|
+
async function fetchCves(cveIds) {
|
|
20
21
|
const url = new URL(NVD_URL);
|
|
21
|
-
url.searchParams.set('
|
|
22
|
+
url.searchParams.set('cveIds', cveIds.join(','));
|
|
22
23
|
const headers = { accept: 'application/json' };
|
|
23
24
|
if (NVD_API_KEY) headers.apiKey = NVD_API_KEY;
|
|
24
25
|
const response = await fetch(url, { headers, signal: AbortSignal.timeout(30_000) });
|
|
25
26
|
if (!response.ok) throw new Error(`NVD returned HTTP ${response.status}`);
|
|
26
27
|
const body = await response.json();
|
|
27
|
-
return body.vulnerabilities
|
|
28
|
+
return new Map((body.vulnerabilities ?? [])
|
|
29
|
+
.map(({ cve }) => [cve?.id, cve])
|
|
30
|
+
.filter(([id]) => id));
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
export async function queryNvd(vulnerabilities, { onProgress } = {}) {
|
|
@@ -33,6 +36,7 @@ export async function queryNvd(vulnerabilities, { onProgress } = {}) {
|
|
|
33
36
|
const errors = [];
|
|
34
37
|
let lastRequestAt = 0;
|
|
35
38
|
let completed = 0;
|
|
39
|
+
const missing = [];
|
|
36
40
|
onProgress?.({ stage: 'nvd', completed, total: ids.length });
|
|
37
41
|
for (const cveId of ids) {
|
|
38
42
|
const cacheKey = `nvd:${cveId}`;
|
|
@@ -41,21 +45,29 @@ export async function queryNvd(vulnerabilities, { onProgress } = {}) {
|
|
|
41
45
|
byCve.set(cveId, cached && Object.hasOwn(cached, 'cve') ? cached.cve : cached);
|
|
42
46
|
completed += 1;
|
|
43
47
|
onProgress?.({ stage: 'nvd', completed, total: ids.length });
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
} else missing.push(cveId);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
for (let offset = 0; offset < missing.length; offset += MAX_CVES_PER_REQUEST) {
|
|
52
|
+
const batch = missing.slice(offset, offset + MAX_CVES_PER_REQUEST);
|
|
46
53
|
const waitMs = Math.max(0, MIN_INTERVAL_MS - (Date.now() - lastRequestAt));
|
|
47
54
|
if (waitMs) await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
48
55
|
try {
|
|
49
|
-
const
|
|
56
|
+
const cves = await fetchCves(batch);
|
|
50
57
|
lastRequestAt = Date.now();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
await Promise.all(batch.map(async (cveId) => {
|
|
59
|
+
const cve = cves.get(cveId) ?? null;
|
|
60
|
+
byCve.set(cveId, cve);
|
|
61
|
+
await setCached(`nvd:${cveId}`, { cve });
|
|
62
|
+
}));
|
|
63
|
+
completed += batch.length;
|
|
54
64
|
onProgress?.({ stage: 'nvd', completed, total: ids.length });
|
|
55
65
|
} catch (error) {
|
|
56
66
|
lastRequestAt = Date.now();
|
|
57
|
-
|
|
58
|
-
|
|
67
|
+
for (const cveId of batch) {
|
|
68
|
+
errors.push({ source: 'NVD', cveId, message: error.message });
|
|
69
|
+
}
|
|
70
|
+
completed += batch.length;
|
|
59
71
|
onProgress?.({ stage: 'nvd', completed, total: ids.length });
|
|
60
72
|
if (/HTTP 403|HTTP 429/.test(error.message)) {
|
|
61
73
|
errors.push({ source: 'NVD', message: 'Stopped further NVD lookups after a rate-limit response.' });
|
package/src/cli.js
CHANGED
|
@@ -26,7 +26,7 @@ Environment:
|
|
|
26
26
|
NVD_API_KEY Optional NVD API key for higher request limits
|
|
27
27
|
LOOK_SEE_CACHE_DIR Override the local advisory cache directory`;
|
|
28
28
|
|
|
29
|
-
const VERSION = '0.1
|
|
29
|
+
const VERSION = '0.2.1';
|
|
30
30
|
const SEVERITY_RANK = { UNKNOWN: 0, LOW: 1, MEDIUM: 2, HIGH: 3, CRITICAL: 4 };
|
|
31
31
|
|
|
32
32
|
function parseArgs(args) {
|