feat: add forensic sample analysis
This commit is contained in:
@@ -101,6 +101,49 @@
|
||||
{% endcall %}
|
||||
</div>
|
||||
|
||||
{% call card() %}
|
||||
{% call card_header() %}
|
||||
<div class="flex flex-col gap-2 md:flex-row md:items-start md:justify-between">
|
||||
<div>
|
||||
{% call card_title() %}Sample Analysis{% endcall %}
|
||||
{% call card_description() %}Grouped investigation hints from redacted forensic metadata{% endcall %}
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<span class="badge badge-error badge-outline">High <span x-text="analysis.priority_counts?.high || 0"></span></span>
|
||||
<span class="badge badge-warning badge-outline">Medium <span x-text="analysis.priority_counts?.medium || 0"></span></span>
|
||||
</div>
|
||||
</div>
|
||||
{% endcall %}
|
||||
{% call card_content() %}
|
||||
<template x-if="analysis.groups.length === 0">
|
||||
<p class="text-base-content/60">No failure samples are available for analysis.</p>
|
||||
</template>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4" x-show="analysis.groups.length > 0">
|
||||
<template x-for="group in analysis.groups.slice(0, 3)" :key="group.key">
|
||||
<div class="border border-base-300 rounded-md p-4 space-y-3">
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div class="min-w-0">
|
||||
<p class="font-semibold break-words" x-text="group.domain"></p>
|
||||
<p class="text-sm font-mono text-base-content/70" x-text="group.source_ip"></p>
|
||||
</div>
|
||||
<span class="badge uppercase" :class="priorityClass(group.priority)" x-text="group.priority"></span>
|
||||
</div>
|
||||
<p class="text-sm" x-text="group.diagnosis"></p>
|
||||
<ul class="text-sm space-y-1 list-disc pl-4">
|
||||
<template x-for="action in group.recommendations.slice(0, 2)" :key="action">
|
||||
<li x-text="action"></li>
|
||||
</template>
|
||||
</ul>
|
||||
<div class="flex items-center justify-between text-xs text-base-content/60">
|
||||
<span><span x-text="group.count"></span> samples</span>
|
||||
<span class="uppercase" x-text="group.auth_failure"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
{% endcall %}
|
||||
{% endcall %}
|
||||
|
||||
{% call card() %}
|
||||
{% call card_header() %}
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
@@ -173,6 +216,7 @@ function forensicReportsApp() {
|
||||
uploadError: false,
|
||||
selectedFile: null,
|
||||
reports: [],
|
||||
analysis: { groups: [], priority_counts: {}, failure_counts: {}, result_counts: {}, samples: [] },
|
||||
domainOptions: [],
|
||||
total: 0,
|
||||
filters: {
|
||||
@@ -220,6 +264,7 @@ function forensicReportsApp() {
|
||||
const data = await response.json();
|
||||
this.reports = data.reports || [];
|
||||
this.total = data.total || 0;
|
||||
await this.fetchAnalysis(params);
|
||||
if (!this.filters.domain) {
|
||||
this.domainOptions = [...new Set(this.reports.map((report) => report.domain || report.reported_domain).filter(Boolean))].sort();
|
||||
}
|
||||
@@ -229,6 +274,11 @@ function forensicReportsApp() {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async fetchAnalysis(params) {
|
||||
const response = await fetch(`/api/v1/forensics/analysis?${params.toString()}`);
|
||||
if (!response.ok) throw new Error('Unable to analyze forensic reports');
|
||||
this.analysis = await response.json();
|
||||
},
|
||||
async uploadReport() {
|
||||
if (!this.selectedFile) return;
|
||||
this.uploading = true;
|
||||
@@ -262,6 +312,11 @@ function forensicReportsApp() {
|
||||
const date = new Date(value);
|
||||
return Number.isNaN(date.getTime()) ? value : date.toLocaleString();
|
||||
},
|
||||
priorityClass(priority) {
|
||||
if (priority === 'high') return 'badge-error';
|
||||
if (priority === 'medium') return 'badge-warning';
|
||||
return 'badge-ghost';
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user