(config)
| 12431 | <p>Error loading service intelligence</p> |
| 12432 | <p class="text-sm text-gray-500 mt-2">${error.message}</p> |
| 12433 | </div> |
| 12434 | `; |
| 12435 | } |
| 12436 | } |
| 12437 | |
| 12438 | function displayVulnerabilityIntel(scans) { |
| 12439 | const container = document.getElementById('vulnerability-intel-container'); |
| 12440 | |
| 12441 | if (!scans || scans.length === 0) { |
| 12442 | container.innerHTML = ` |
| 12443 | <div class="text-center text-gray-400 py-8"> |
| 12444 | <svg class="w-12 h-12 mx-auto mb-3 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| 12445 | <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path> |
| 12446 | </svg> |
| 12447 | <p>No interesting intelligence found</p> |
| 12448 | <p class="text-sm text-gray-500 mt-2">Scanned hosts without interesting data are filtered out</p> |
| 12449 | </div> |
| 12450 | `; |
| 12451 | return; |
| 12452 | } |
| 12453 | |
| 12454 | let html = '<div class="space-y-4">'; |
| 12455 | |
| 12456 | scans.forEach(scan => { |
| 12457 | const serviceCount = scan.total_services || 0; |
| 12458 | const scriptCount = scan.services.reduce((sum, svc) => sum + (svc.scripts?.length || 0), 0); |
| 12459 | |
| 12460 | html += ` |
| 12461 | <div class="bg-slate-800 bg-opacity-50 rounded-lg border border-slate-700 overflow-hidden"> |
| 12462 | <div class="px-4 py-3 bg-slate-900 bg-opacity-50 flex items-center justify-between cursor-pointer hover:bg-opacity-70 transition-colors" onclick="toggleVulnHost('${scan.ip}')"> |
| 12463 | <div class="flex items-center space-x-3"> |
| 12464 | <svg class="w-5 h-5 text-cyan-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| 12465 | <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path> |
| 12466 | </svg> |
| 12467 | <div> |
| 12468 | <div class="font-semibold text-lg">${escapeHtml(scan.hostname)}</div> |
| 12469 | <div class="text-sm text-gray-400">${escapeHtml(scan.ip)}</div> |
| 12470 | </div> |
| 12471 | </div> |
| 12472 | <div class="flex items-center space-x-4"> |
| 12473 | ${scan.download_url ? ` |
| 12474 | <a href="${scan.download_url}" target="_blank" rel="noopener noreferrer" |
| 12475 | class="text-xs px-3 py-1 rounded-full bg-cyan-900/60 text-cyan-200 border border-cyan-500/40 hover:bg-cyan-800/80 transition"> |
| 12476 | ${scan.scan_type === 'lynis' ? 'Download full report' : 'View full report'} |
| 12477 | </a> |
| 12478 | ` : ''} |
| 12479 | ${(scan.log_url && scan.log_url !== scan.download_url) ? ` |
| 12480 | <a href="${scan.log_url}" target="_blank" rel="noopener noreferrer" |
| 12481 | class="text-xs px-3 py-1 rounded-full bg-slate-900/60 text-slate-200 border border-slate-500/40 hover:bg-slate-800/80 transition"> |
| 12482 | View audit log |
| 12483 | </a> |
| 12484 | ` : ''} |
| 12485 | <span class="text-sm text-cyan-400">📡 ${serviceCount} services</span> |
| 12486 | ${scriptCount > 0 ? `<span class="text-sm text-purple-400">📜 ${scriptCount} scripts</span>` : ''} |
| 12487 | <span class="text-xs text-gray-500">${scan.scan_date}</span> |
| 12488 | <svg id="vuln-chevron-${scan.ip.replace(/\./g, '-')}" class="w-5 h-5 text-gray-400 transform transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| 12489 | <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path> |
| 12490 | </svg> |
no test coverage detected