Skip to content

Commit bb72b4d

Browse files
dbfxclaude
andcommitted
feat(cve): show only critical/high vulns, add descriptions and NVD links
Focus the CVE scanner UI on critical and high severity vulnerabilities, add vulnerability description field, installed version display, and direct NVD detail links. Also parallelizes the translation script across all languages and adds patch-package for systeminformation fix. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent da4ca99 commit bb72b4d

39 files changed

+671
-226
lines changed

package-lock.json

Lines changed: 351 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"translate": "node scripts/translate.js",
2424
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
2525
"release": "node scripts/release.js",
26-
"postinstall": "electron-rebuild -w better-sqlite3",
26+
"postinstall": "patch-package && electron-rebuild -w better-sqlite3",
2727
"prepare": "husky"
2828
},
2929
"keywords": [
@@ -62,6 +62,7 @@
6262
"electron-builder": "^26.8.1",
6363
"electron-vite": "^5.0.0",
6464
"husky": "^9.1.7",
65+
"patch-package": "^8.0.1",
6566
"react": "^19.2.4",
6667
"react-dom": "^19.2.4",
6768
"tailwindcss": "^4.2.1",
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
diff --git a/node_modules/systeminformation/lib/util.js b/node_modules/systeminformation/lib/util.js
2+
index f8b854d..773dc42 100644
3+
--- a/node_modules/systeminformation/lib/util.js
4+
+++ b/node_modules/systeminformation/lib/util.js
5+
@@ -571,12 +571,15 @@ function getCodepage() {
6+
if (_windows) {
7+
if (!codepage) {
8+
try {
9+
- const stdout = execSync('chcp', execOptsWin);
10+
- const lines = stdout.toString().split('\r\n');
11+
- const parts = lines[0].split(':');
12+
- codepage = parts.length > 1 ? parts[1].replace('.', '').trim() : '';
13+
+ // Avoid execSync('chcp') which triggers Sigma rule "Console CodePage Lookup Via CHCP".
14+
+ // Use the Win32 API via PowerShell type reflection instead — no cmd.exe, no chcp.com.
15+
+ const stdout = execSync(
16+
+ 'powershell.exe -NoProfile -NonInteractive -Command "[Console]::OutputEncoding.CodePage"',
17+
+ execOptsWin
18+
+ );
19+
+ codepage = stdout.toString().trim() || '65001';
20+
} catch {
21+
- codepage = '437';
22+
+ codepage = '65001';
23+
}
24+
}
25+
return codepage;
26+
@@ -665,8 +668,13 @@ function execWin(cmd, opts, callback) {
27+
callback = opts;
28+
opts = execOptsWin;
29+
}
30+
- let newCmd = 'chcp 65001 > nul && cmd /C ' + cmd + ' && chcp ' + codepage + ' > nul';
31+
- exec(newCmd, opts, (error, stdout) => {
32+
+ // Avoid chcp calls that trigger Sigma rule "Console CodePage Lookup Via CHCP".
33+
+ // Force UTF-8 output via environment variable instead of chcp 65001 / chcp <restore>.
34+
+ // Node on Windows respects this when decoding child stdout.
35+
+ let newCmd = 'cmd /D /C ' + cmd;
36+
+ const env = Object.assign({}, opts.env || process.env);
37+
+ const patchedOpts = Object.assign({}, opts, { env });
38+
+ exec(newCmd, patchedOpts, (error, stdout) => {
39+
callback(error, stdout);
40+
});
41+
}

scripts/translate.js

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const LOCALES_DIR = path.resolve(__dirname, '../src/renderer/src/locales')
2121
const CHECKSUMS_PATH = path.join(LOCALES_DIR, '.checksums.json')
2222
const SOURCE_LANG = 'en'
2323
const MODEL = 'gpt-5.4'
24-
const MAX_CONCURRENT = 3
24+
const MAX_CONCURRENT = 10
2525
const MAX_RETRIES = 3
2626

2727
const TARGET_LANGUAGES = {
@@ -305,18 +305,15 @@ async function main() {
305305
let translated = 0
306306
let skipped = 0
307307

308-
// Process each language sequentially
308+
// Build all tasks across all languages and namespaces
309+
const tasks = []
310+
309311
for (const [langCode, langName] of languages) {
310312
const langDir = path.join(LOCALES_DIR, langCode)
311313
if (!fs.existsSync(langDir)) {
312314
fs.mkdirSync(langDir, { recursive: true })
313315
}
314316

315-
console.log(`\n── ${langName} (${langCode}) ──`)
316-
317-
// Build tasks for this language (namespaces to translate)
318-
const tasks = []
319-
320317
for (const ns of nsFiles) {
321318
const enPath = path.join(enDir, `${ns}.json`)
322319
const enContent = fs.readFileSync(enPath, 'utf-8')
@@ -327,14 +324,14 @@ async function main() {
327324
if (!force && checksums[checksumKey] === enHash) {
328325
const outPath = path.join(langDir, `${ns}.json`)
329326
if (fs.existsSync(outPath)) {
330-
console.log(` [skip] ${ns}.json (unchanged)`)
327+
console.log(` [skip] ${langCode}/${ns}.json (unchanged)`)
331328
skipped++
332329
continue
333330
}
334331
}
335332

336333
if (dryRun) {
337-
console.log(` [would translate] ${ns}.json`)
334+
console.log(` [would translate] ${langCode}/${ns}.json`)
338335
continue
339336
}
340337

@@ -352,56 +349,58 @@ async function main() {
352349
// Auto-repair dropped interpolation variables (common with RTL languages)
353350
const repaired = repairTranslation(englishJson, result)
354351
if (repaired > 0) {
355-
console.log(` [repair] ${ns}.json — re-inserted ${repaired} dropped variable(s)`)
352+
console.log(` [repair] ${langCode}/${ns}.json — re-inserted ${repaired} dropped variable(s)`)
356353
}
357354

358355
// Validate
359356
const errors = validateTranslation(englishJson, result, langCode, ns)
360357
if (errors.length > 0) {
361358
if (attempt < MAX_RETRIES) {
362-
console.log(` [retry] ${ns}.json — validation errors: ${errors[0]}`)
359+
console.log(` [retry] ${langCode}/${ns}.json — validation errors: ${errors[0]}`)
363360
continue
364361
}
365-
console.warn(` [warn] ${ns}.json — validation issues: ${errors.join('; ')}`)
362+
console.warn(` [warn] ${langCode}/${ns}.json — validation issues: ${errors.join('; ')}`)
366363
}
367364

368365
// Write output
369366
const outPath = path.join(langDir, `${ns}.json`)
370367
fs.writeFileSync(outPath, JSON.stringify(result, null, 2) + '\n', 'utf-8')
371368

372-
// Update checksum
369+
// Update checksum (saved to disk after all tasks complete)
373370
checksums[checksumKey] = enHash
374-
saveChecksums(checksums)
375371

376372
const elapsed = ((Date.now() - start) / 1000).toFixed(1)
377-
console.log(` [done] ${ns}.json (${elapsed}s)`)
373+
console.log(` [done] ${langCode}/${ns}.json (${elapsed}s)`)
378374
translated++
379375
return
380376
} catch (err) {
381377
lastError = err
382378
if (err.message?.includes('429') && attempt < MAX_RETRIES) {
383379
const delay = Math.pow(2, attempt) * 1000
384-
console.log(` [rate-limited] ${ns}.json — retrying in ${delay / 1000}s...`)
380+
console.log(` [rate-limited] ${langCode}/${ns}.json — retrying in ${delay / 1000}s...`)
385381
await sleep(delay)
386382
} else if (attempt < MAX_RETRIES) {
387-
console.log(` [retry] ${ns}.json — ${err.message}`)
383+
console.log(` [retry] ${langCode}/${ns}.json — ${err.message}`)
388384
await sleep(1000)
389385
}
390386
}
391387
}
392388

393-
console.error(` [FAILED] ${ns}.json — ${lastError?.message}`)
389+
console.error(` [FAILED] ${langCode}/${ns}.json — ${lastError?.message}`)
394390
failures.push(`${langCode}/${ns}: ${lastError?.message}`)
395391
})()
396392
)
397393
}
394+
}
398395

399-
// Run namespace translations concurrently within each language
400-
if (tasks.length > 0) {
401-
await withConcurrency(tasks, MAX_CONCURRENT)
402-
}
396+
// Run all translations concurrently across all languages and namespaces
397+
if (tasks.length > 0) {
398+
await withConcurrency(tasks, MAX_CONCURRENT)
403399
}
404400

401+
// Save checksums once after all tasks complete (avoids concurrent file writes)
402+
saveChecksums(checksums)
403+
405404
// Summary
406405
console.log(`\n${'─'.repeat(50)}`)
407406
console.log(`Translation complete!`)

src/main/services/cloud-agent.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ class CloudAgentService {
203203
severity: (typeof item.severity === 'string' && validSeverities.has(item.severity) ? item.severity : 'none') as import('../../shared/types').CveSeverity,
204204
cvssScore: !isNaN(cvss) ? cvss : null,
205205
fixedIn: typeof item.fixed_in === 'string' ? item.fixed_in : null,
206+
description: typeof item.description === 'string' ? item.description : null,
206207
firstDetectedAt: typeof item.first_detected_at === 'string' ? item.first_detected_at : '',
207208
lastScannedAt: typeof item.last_scanned_at === 'string' ? item.last_scanned_at : '',
208209
}

src/renderer/src/locales/.checksums.json

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -608,33 +608,33 @@
608608
"he/gameMode": "45fe8d7baa2dc5c5fd60acb5c659286414a27b6d9b5c6da104586cf32a8f958d",
609609
"hu/duplicates": "165718f82076f04ad0b87fac1c05f04b13e907c9ecb1da426bac61bc85e964cc",
610610
"hu/gameMode": "45fe8d7baa2dc5c5fd60acb5c659286414a27b6d9b5c6da104586cf32a8f958d",
611-
"es/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
612-
"fr/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
613-
"de/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
614-
"pt/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
615-
"it/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
616-
"ja/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
617-
"ko/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
618-
"zh-CN/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
619-
"zh-TW/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
620-
"ru/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
621-
"ar/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
622-
"hi/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
623-
"tr/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
624-
"nl/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
625-
"pl/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
626-
"sv/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
627-
"no/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
628-
"da/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
629-
"fi/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
630-
"cs/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
631-
"th/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
632-
"vi/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
633-
"id/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
634-
"ms/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
635-
"uk/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
636-
"ro/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
637-
"el/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
638-
"he/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8",
639-
"hu/cveScanner": "35592585b229a37c63e3e552ea911ba1cd31d733e187b0c84a299d5d58edecd8"
611+
"es/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
612+
"fr/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
613+
"de/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
614+
"pt/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
615+
"it/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
616+
"ja/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
617+
"ko/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
618+
"zh-CN/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
619+
"zh-TW/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
620+
"ru/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
621+
"ar/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
622+
"hi/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
623+
"tr/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
624+
"nl/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
625+
"pl/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
626+
"sv/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
627+
"no/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
628+
"da/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
629+
"fi/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
630+
"cs/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
631+
"th/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
632+
"vi/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
633+
"id/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
634+
"ms/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
635+
"uk/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
636+
"ro/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
637+
"el/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
638+
"he/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d",
639+
"hu/cveScanner": "c5b4fe568dedac25a5324aa3a91d0d43e0772cfb333feabebef66d4632fafb1d"
640640
}

src/renderer/src/locales/ar/cveScanner.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
{
22
"pageTitle": "الثغرات الأمنية",
3-
"pageDescription": "اعرض الثغرات الأمنية المعروفة المكتشفة في البرامج المثبتة لديك",
3+
"pageDescription": "اعرض الثغرات الأمنية المعروفة التي تم اكتشافها في البرامج المثبتة لديك",
44
"loading": "جارٍ تحميل الثغرات الأمنية...",
55
"refetchButton": "تحديث",
66
"cloudNotConfigured": {
77
"title": "يلزم Cloud Agent",
8-
"description": "يتطلب فحص CVE ربط Cloud Agent. انتقل إلى الإعدادات → السحابة لتوصيل جهازك."
8+
"description": "يتطلب فحص CVE ربط Cloud Agent. انتقل إلى الإعدادات ← Cloud لتوصيل جهازك."
99
},
1010
"cloudNotConnected": {
1111
"title": "Cloud Agent غير متصل",
12-
"description": "Cloud Agent غير متصل حاليًا. تحقق من الاتصال في الإعدادات → السحابة."
12+
"description": "Cloud Agent غير متصل حاليًا. تحقق من اتصالك في الإعدادات ← Cloud."
1313
},
1414
"emptyState": {
1515
"title": "لم يتم اكتشاف أي ثغرات أمنية",
@@ -43,9 +43,10 @@
4343
"fixAvailable": "الإصلاح: {{version}}",
4444
"noFix": "لا يتوفر إصلاح",
4545
"cvss": "CVSS {{score}}",
46-
"firstDetected": "أول اكتشاف: {{date}}",
46+
"firstDetected": "تم الاكتشاف لأول مرة: {{date}}",
4747
"lastScanned": "آخر فحص: {{date}}",
48-
"updateViaSoftwareUpdater": "حدّث عبر محدّث البرامج"
48+
"viewDetails": "عرض تفاصيل CVE",
49+
"checkForUpdates": "التحقق من وجود تحديثات"
4950
},
5051
"pagination": {
5152
"previous": "السابق",

src/renderer/src/locales/cs/cveScanner.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"refetchButton": "Obnovit",
66
"cloudNotConfigured": {
77
"title": "Vyžadován Cloud Agent",
8-
"description": "Skenování CVE vyžaduje propojený Cloud Agent. Přejděte do Nastavení → Cloud a připojte své zařízení."
8+
"description": "Kontrola CVE vyžaduje propojený Cloud Agent. Přejděte do Nastavení → Cloud a připojte své zařízení."
99
},
1010
"cloudNotConnected": {
1111
"title": "Cloud Agent není připojen",
@@ -44,8 +44,9 @@
4444
"noFix": "Není k dispozici žádná oprava",
4545
"cvss": "CVSS {{score}}",
4646
"firstDetected": "Poprvé zjištěno: {{date}}",
47-
"lastScanned": "Naposledy skenováno: {{date}}",
48-
"updateViaSoftwareUpdater": "Aktualizovat pomocí Aktualizace softwaru"
47+
"lastScanned": "Naposledy zkontrolováno: {{date}}",
48+
"viewDetails": "Zobrazit podrobnosti CVE",
49+
"checkForUpdates": "Zkontrolovat aktualizace"
4950
},
5051
"pagination": {
5152
"previous": "Předchozí",

src/renderer/src/locales/da/cveScanner.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
{
22
"pageTitle": "Sårbarheder",
3-
"pageDescription": "Se kendte sårbarheder fundet i din installerede software",
3+
"pageDescription": "Se kendte sårbarheder, der er registreret i din installerede software",
44
"loading": "Indlæser sårbarheder...",
55
"refetchButton": "Opdater",
66
"cloudNotConfigured": {
7-
"title": "Cloud Agent kræves",
7+
"title": "Cloud Agent påkrævet",
88
"description": "CVE-scanning kræver, at Cloud Agent er tilknyttet. Gå til Indstillinger → Cloud for at forbinde din enhed."
99
},
1010
"cloudNotConnected": {
1111
"title": "Cloud Agent er ikke forbundet",
1212
"description": "Cloud Agent er ikke forbundet i øjeblikket. Kontrollér din forbindelse under Indstillinger → Cloud."
1313
},
1414
"emptyState": {
15-
"title": "Ingen sårbarheder fundet",
15+
"title": "Ingen sårbarheder registreret",
1616
"description": "Der blev ikke fundet nogen kendte CVE'er i din installerede software. Dit system ser sikkert ud!"
1717
},
1818
"severity": {
@@ -43,9 +43,10 @@
4343
"fixAvailable": "Rettelse: {{version}}",
4444
"noFix": "Ingen rettelse tilgængelig",
4545
"cvss": "CVSS {{score}}",
46-
"firstDetected": "Først fundet: {{date}}",
46+
"firstDetected": "Først registreret: {{date}}",
4747
"lastScanned": "Senest scannet: {{date}}",
48-
"updateViaSoftwareUpdater": "Opdater via Software Updater"
48+
"viewDetails": "Vis CVE-detaljer",
49+
"checkForUpdates": "Søg efter opdateringer"
4950
},
5051
"pagination": {
5152
"previous": "Forrige",

0 commit comments

Comments
 (0)