Show summarized security events above raw export
This commit is contained in:
@@ -171,22 +171,32 @@ def device(machine_name):
|
||||
abort(404)
|
||||
|
||||
payload = report[12]
|
||||
ninja = payload.get("NinjaOne") or payload.get("ninjaOne") or {}
|
||||
runtime = payload.get("Runtime") or payload.get("runtime") or {}
|
||||
raw_export = {
|
||||
"organization_name": ninja.get("OrganizationName") or ninja.get("organizationName") or "Nicht zugeordnet",
|
||||
"organization_id": ninja.get("OrganizationId") or ninja.get("organizationId") or "-",
|
||||
"generated_at": payload.get("GeneratedAtUtc") or payload.get("generatedAtUtc") or report[4],
|
||||
"client_version": payload.get("ClientVersion") or payload.get("clientVersion") or report[3] or "-",
|
||||
"upload_status": runtime.get("UploadStatus") or runtime.get("uploadStatus") or "unbekannt",
|
||||
"error_count": len(payload.get("Errors") or payload.get("errors") or []),
|
||||
}
|
||||
event_groups = {}
|
||||
for entry in payload.get("Events") or payload.get("events") or []:
|
||||
event_type = entry.get("Target") or entry.get("target") or "Sicherheitsereignis"
|
||||
account = entry.get("Username") or entry.get("username") or "-"
|
||||
source_ip = entry.get("SourceIp") or entry.get("sourceIp") or "-"
|
||||
key = (event_type, account, source_ip)
|
||||
group = event_groups.setdefault(
|
||||
key,
|
||||
{"type": event_type, "account": account, "source_ip": source_ip, "count": 0, "latest": "-"},
|
||||
)
|
||||
group["count"] += 1
|
||||
timestamp = entry.get("Timestamp") or entry.get("timestamp") or "-"
|
||||
if timestamp > group["latest"]:
|
||||
group["latest"] = timestamp
|
||||
|
||||
security_events = sorted(
|
||||
event_groups.values(),
|
||||
key=lambda entry: (entry["latest"], entry["count"]),
|
||||
reverse=True,
|
||||
)[:25]
|
||||
return render_template(
|
||||
"device.html",
|
||||
report=report,
|
||||
event=event_metadata(payload),
|
||||
payload=payload,
|
||||
raw_export=raw_export,
|
||||
security_events=security_events,
|
||||
payload_pretty=json.dumps(payload, indent=2, ensure_ascii=False),
|
||||
)
|
||||
|
||||
|
||||
@@ -27,4 +27,4 @@ table { width:100%; border-collapse:collapse; font-family:'Roboto',sans-serif; f
|
||||
.recipient-form input:focus,.recipient-form select:focus { outline:2px solid rgba(36,90,133,.25); border-color:#245a85; }
|
||||
.rule-actions .button-secondary { border-color:var(--line); background:#f8fbfd; }
|
||||
.recipient-intro { max-width:720px; margin:6px 0 28px; }.recipient-intro h1 { margin:9px 0 10px; font-size:46px; line-height:1; letter-spacing:-.055em; }.recipient-intro p { margin:0; color:var(--muted); font-size:16px; line-height:1.55; }.recipient-intro strong { color:var(--ink); }.recipient-create-panel { margin-top:0; border-color:#c8dbe8; }.recipient-create-panel .panel-heading h2,.recipient-rules-panel .panel-heading h2 { margin:7px 0 8px; }.recipient-create-panel .panel-heading p { margin:0 0 20px; }.recipient-form button { white-space:nowrap; }.recipient-rules-panel { padding-bottom:12px; }.recipient-rules-panel .panel-heading { display:flex; align-items:end; justify-content:space-between; gap:16px; }.recipient-rules-panel .panel-heading h2 { margin-bottom:20px; }.recipient-rules-panel .panel-heading small { display:inline-block; margin-left:7px; padding:4px 7px; border-radius:12px; background:#edf4f8; color:#4d687b; font-size:10px; font-weight:700; letter-spacing:.04em; vertical-align:middle; }.recipient-table td { height:64px; }.recipient-table tr:last-child td { border-bottom:0; }.recipient-email { color:#245a85; font-weight:500; }.actions-heading { text-align:right; }.recipient-table .rule-actions { justify-content:flex-end; }.empty-state { padding:30px 10px !important; color:var(--muted); text-align:center; }
|
||||
.compact-metrics { grid-template-columns:repeat(5,1fr); }.compact-metrics article { min-height:108px; }.compact-metrics article small { display:block; margin-top:6px; color:var(--muted); font:500 11px 'Roboto',sans-serif; }.raw-export-card { border-color:#c8dbe8 !important; background:#f2f8fb !important; }.raw-export-panel { margin-top:8px; }.raw-export-panel .panel-heading h2 { margin:7px 0 8px; }.raw-export-panel .panel-heading p { margin:0 0 20px; }.raw-export-summary { display:grid; grid-template-columns:repeat(4,1fr); gap:10px; }.raw-export-summary article { padding:15px; border:1px solid #dce6ee; border-radius:6px; background:#f8fbfd; }.raw-export-summary span,.raw-export-summary small { display:block; color:var(--muted); font:700 10px 'Roboto',sans-serif; letter-spacing:.07em; text-transform:uppercase; }.raw-export-summary strong { display:block; margin:8px 0 4px; color:var(--ink); font-size:16px; overflow-wrap:anywhere; }.raw-export-summary small { font-weight:500; letter-spacing:0; text-transform:none; }.raw-json { margin-top:18px; border-top:1px solid var(--line); }.raw-json summary { padding:14px 0; color:#245a85; cursor:pointer; font:700 12px 'Roboto',sans-serif; }.raw-json pre { margin-bottom:0; } @media (max-width:850px) { .compact-metrics,.raw-export-summary { grid-template-columns:repeat(2,1fr); }.compact-metrics article:last-child { grid-column:span 2; } }
|
||||
.compact-metrics { grid-template-columns:repeat(4,1fr); }.event-summary-panel { margin-top:8px; }.event-summary-panel .panel-heading h2,.raw-export-panel .panel-heading h2 { margin:7px 0 8px; }.event-summary-panel .panel-heading p,.raw-export-panel .panel-heading p { margin:0 0 20px; }.event-count { display:inline-grid; min-width:28px; min-height:28px; place-items:center; border-radius:14px; background:#fff0d7; color:var(--amber); font:700 12px 'Roboto',sans-serif; }.raw-export-panel { margin-top:8px; }.raw-json { margin-top:18px; border-top:1px solid var(--line); }.raw-json summary { padding:14px 0; color:#245a85; cursor:pointer; font:700 12px 'Roboto',sans-serif; }.raw-json pre { margin-bottom:0; } @media (max-width:850px) { .compact-metrics { grid-template-columns:repeat(2,1fr); }.compact-metrics article:last-child { grid-column:span 2; } }
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
{% block title %}{{ report[0] }} - OC Sentinel{% endblock %}
|
||||
{% block content %}
|
||||
<section class="panel"><div class="panel-heading"><h2>{{ report[0] }}</h2><span class="state {{ report[6] }}">{{ report[6] }}</span>{% if report[8] %}<span class="state {{ 'current' if event.is_current else 'historic' }}">{{ 'aktuell' if event.is_current else 'historisch' }}: {{ event.label }}</span>{% endif %}</div></section>
|
||||
<section class="metrics compact-metrics"><article><span>Ereignisse</span><strong>{{ report[8] }}</strong></article><article><span>Quell-IPs</span><strong>{{ report[9] }}</strong></article><article><span>CVEs</span><strong>{{ report[10] }}</strong></article><article><span>Kritische CVEs</span><strong class="critical">{{ report[11] }}</strong></article><article class="raw-export-card"><span>Roh-Export</span><strong>JSON</strong><small>{{ raw_export.upload_status }}</small></article></section>
|
||||
<section class="panel raw-export-panel"><div class="panel-heading"><span class="eyebrow">Technische Daten</span><h2>Roh-Export</h2><p>Zusammenfassung der zuletzt eingegangenen Clientdaten.</p></div><div class="raw-export-summary"><article><span>Organisation</span><strong>{{ raw_export.organization_name }}</strong><small>ID {{ raw_export.organization_id }}</small></article><article><span>Erstellt</span><strong>{{ raw_export.generated_at }}</strong><small>UTC-Zeitstempel des Clients</small></article><article><span>Client</span><strong>{{ raw_export.client_version }}</strong><small>Upload: {{ raw_export.upload_status }}</small></article><article><span>Scanner-Hinweise</span><strong>{{ raw_export.error_count }}</strong><small>gemeldete Fehler</small></article></div><details class="raw-json"><summary>Vollstaendigen JSON-Export anzeigen</summary><pre>{{ payload_pretty }}</pre></details></section>
|
||||
<section class="metrics compact-metrics"><article><span>Ereignisse</span><strong>{{ report[8] }}</strong></article><article><span>Quell-IPs</span><strong>{{ report[9] }}</strong></article><article><span>CVEs</span><strong>{{ report[10] }}</strong></article><article><span>Kritische CVEs</span><strong class="critical">{{ report[11] }}</strong></article></section>
|
||||
<section class="panel event-summary-panel"><div class="panel-heading"><span class="eyebrow">Schnelluebersicht</span><h2>Erkannte Sicherheitsereignisse</h2><p>Fehlgeschlagene Anmeldungen und weitere Vorfaelle aus dem letzten Scan, nach Konto und Quell-IP zusammengefasst.</p></div><div class="table-wrap"><table><thead><tr><th>Vorfall</th><th>Konto</th><th>Quell-IP</th><th>Letzter Zeitpunkt</th><th>Anzahl</th></tr></thead><tbody>{% for entry in security_events %}<tr><td><strong>{{ entry.type }}</strong></td><td>{{ entry.account }}</td><td>{{ entry.source_ip }}</td><td>{{ entry.latest }}</td><td><span class="event-count">{{ entry.count }}</span></td></tr>{% else %}<tr><td colspan="5" class="empty-state">Keine sicherheitsrelevanten Ereignisse im letzten Scan.</td></tr>{% endfor %}</tbody></table></div></section>
|
||||
<section class="panel raw-export-panel"><div class="panel-heading"><span class="eyebrow">Technische Daten</span><h2>Roh-Export</h2><p>Vollstaendige, unveraenderte Nutzlast des zuletzt eingegangenen Scans.</p></div><details class="raw-json" open><summary>JSON-Rohdaten</summary><pre>{{ payload_pretty }}</pre></details></section>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user