OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

_cve_table.php

6 KB
<?php
// Erwartet: $tableCves (array), $sevClass/$sevLabel (Closures aus index.php)
// Optional: $bsiByCveMap (CVE-ID => Advisory) für das 🇩🇪 BSI-Badge.
// Optional: $sortUrl (Closure), $sortCol, $sortDir für sortierbare Spalten.
$bsiByCveMap = $bsiByCveMap ?? [];

$sortUrlFn = $sortUrl ?? null;
$curCol    = $sortCol ?? '';
$curDir    = $sortDir ?? 'desc';

// Sortierbare Kopfzelle; ohne $sortUrl reiner Text (robust bei Wiederverwendung).
$th = function (string $label, string $col, string $style = '') use ($sortUrlFn, $curCol, $curDir): string {
    $e = static fn($s) => htmlspecialchars((string)$s, ENT_QUOTES);
    if ($sortUrlFn === null) {
        return '<th style="' . $e($style) . '">' . $e($label) . '</th>';
    }
    $active = $curCol === $col;
    $arrow  = $active
        ? ($curDir === 'asc' ? ' &#9650;' : ' &#9660;')
        : ' <span style="color:var(--gray-300);">&#8693;</span>';
    return '<th style="' . $e($style) . '">'
        . '<a href="' . $e($sortUrlFn($col)) . '"'
        . ' style="display:inline-flex;align-items:center;gap:.15rem;color:inherit;text-decoration:none;white-space:nowrap;cursor:pointer;' . ($active ? 'font-weight:700;' : '') . '"'
        . ' title="Nach ' . $e($label) . ' sortieren"'
        . ' onclick="event.stopPropagation();">' . $e($label) . $arrow . '</a></th>';
};
?>
<div class="table-wrapper">
    <table class="data-table">
        <thead>
            <tr>
                <?= $th('Schweregrad', 'severity', 'width:110px;') ?>
                <?= $th('CVSS', 'cvss', 'width:70px;') ?>
                <?= $th('CVE-ID', 'cve_id', 'width:140px;') ?>
                <th scope="col"><?= $this->te('Beschreibung') ?></th>
                <?= $th('Veröffentlicht', 'published', 'width:100px;') ?>
                <th scope="col" style="width:24px;"></th>
            </tr>
        </thead>
        <tbody>
        <?php foreach ($tableCves as $cve):
            $sev      = strtoupper($cve['severity'] ?? 'NONE');
            $score    = $cve['cvss_score'] !== null ? number_format((float)$cve['cvss_score'], 1) : '–';
            $pubDate  = !empty($cve['published']) ? date('d.m.Y', strtotime($cve['published'])) : '–';
            $affected = json_decode($cve['affected'] ?? '[]', true) ?: [];
            $rowId    = $this->e($cve['cve_id']);
        ?>
        <tr data-cve="<?= $rowId ?>" class="clickable" title="<?= $this->te('Details anzeigen') ?>">
            <td><span class="status-pill <?= $sevClass($sev) ?>"><?= $sevLabel($sev) ?></span></td>
            <td style="font-weight:700;color:<?= match($sev) {
                'CRITICAL' => '#dc2626', 'HIGH' => '#ea580c', 'MEDIUM' => '#d97706', default => '#6b7280' } ?>;">
                <?= $this->e($score) ?>
            </td>
            <td style="font-size:.8rem;font-weight:600;color:var(--gray-700);white-space:nowrap;">
                <?= $this->e($cve['cve_id']) ?>
                <?php $bsiAdv = $bsiByCveMap[strtoupper($cve['cve_id'])] ?? null; ?>
                <?php if ($bsiAdv): ?>
                    <a href="<?= $this->e($bsiAdv['url'] ?: '/cve?q=' . urlencode($cve['cve_id'])) ?>"
                       <?= !empty($bsiAdv['url']) ? 'target="_blank" rel="noopener"' : '' ?>
                       class="cve-bsi-badge"
                       title="BSI CERT-Bund-Warnung: <?= $this->e($bsiAdv['title'] ?? '') ?>"
                       onclick="event.stopPropagation();"><?= $this->te('&#127465;&#127466; BSI') ?></a>
                <?php endif; ?>
            </td>
            <td style="color:var(--gray-700);max-width:460px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;"
                title="<?= $this->e($cve['description'] ?? '') ?>">
                <?= $this->e(mb_strimwidth($cve['description'] ?? '', 0, 120, '…')) ?>
            </td>
            <td style="white-space:nowrap;color:var(--gray-500);font-size:.8rem;"><?= $pubDate ?></td>
            <td style="color:var(--gray-400);font-size:.8rem;">&#9660;</td>
        </tr>
        <tr id="cve-det-<?= $rowId ?>" class="cve-detail-row">
            <td class="cve-detail-cell" colspan="6">
                <div class="cve-detail-inner">
                    <p style="margin:0 0 .5rem;"><?= nl2br($this->e($cve['description'] ?? '')) ?></p>
                    <div style="display:flex;flex-wrap:wrap;gap:.5rem 1.5rem;font-size:.8rem;color:var(--gray-500);margin-bottom:.5rem;">
                        <?php if (!empty($cve['cvss_vector'])): ?>
                        <span><strong style="color:var(--gray-700);"><?= $this->te('Vektor:') ?></strong> <?= $this->e($cve['cvss_vector']) ?></span>
                        <?php endif; ?>
                        <?php if (!empty($cve['published'])): ?>
                        <span><strong style="color:var(--gray-700);"><?= $this->te('Ver&ouml;ffentlicht:') ?></strong>
                            <?= date('d.m.Y H:i', strtotime($cve['published'])) ?> UTC</span>
                        <?php endif; ?>
                    </div>
                    <?php if (!empty($affected)): ?>
                    <div style="margin-bottom:.5rem;">
                        <strong style="font-size:.78rem;color:var(--gray-700);"><?= $this->te('Betroffen:') ?></strong>
                        <?php foreach ($affected as $prod): ?>
                        <span class="cve-affected-chip"><?= $this->e($prod) ?></span>
                        <?php endforeach; ?>
                    </div>
                    <?php endif; ?>
                    <a href="https://nvd.nist.gov/vuln/detail/<?= urlencode($cve['cve_id']) ?>"
                       target="_blank" rel="noopener"
                       style="font-size:.8rem;color:var(--color-primary);text-decoration:none;"
                       onclick="event.stopPropagation();">
                        <?= $this->te('&#8599; Vollst&auml;ndigen NVD-Eintrag &ouml;ffnen') ?>
                    </a>
                </div>
            </td>
        </tr>
        <?php endforeach; ?>
        </tbody>
    </table>
</div>