diff --git a/bin/web/src/lib/analysis.svelte.ts b/bin/web/src/lib/analysis.svelte.ts
index 24889cb..f402a12 100644
--- a/bin/web/src/lib/analysis.svelte.ts
+++ b/bin/web/src/lib/analysis.svelte.ts
@@ -8,6 +8,13 @@ export type AnalysisReport = {
export type ReportMetadata = {
analyzers: AnalyzerMetadata[];
+ rayhunter: RayhunterMetadata;
+};
+
+export type RayhunterMetadata = {
+ rayhunter_version: string;
+ system_os: string;
+ arch: string;
};
export type AnalyzerMetadata = {
diff --git a/bin/web/src/lib/components/AnalysisStatus.svelte b/bin/web/src/lib/components/AnalysisStatus.svelte
index 86ea7d0..99cbd0e 100644
--- a/bin/web/src/lib/components/AnalysisStatus.svelte
+++ b/bin/web/src/lib/components/AnalysisStatus.svelte
@@ -2,8 +2,9 @@
import { AnalysisStatus } from "$lib/analysisManager.svelte";
import { EventType } from "$lib/analysis.svelte";
import type { ManifestEntry } from "$lib/manifest.svelte";
- let { entry }: {
+ let { entry, onclick }: {
entry: ManifestEntry,
+ onclick: () => void,
} = $props();
let summary = $derived.by(() => {
@@ -32,12 +33,20 @@
} else {
return 'Loading...';
}
+ });
+
+ let ready = $derived.by(() => {
+ let finished = entry.analysis_status === AnalysisStatus.Finished;
+ let report_available = entry.analysis_report !== undefined;
+ return finished && report_available;
})
+
+ let button_class = $derived(ready ? "text-blue-400 underline" : '');
-
+
+
diff --git a/bin/web/src/lib/components/AnalysisTable.svelte b/bin/web/src/lib/components/AnalysisTable.svelte
new file mode 100644
index 0000000..441bc9a
--- /dev/null
+++ b/bin/web/src/lib/components/AnalysisTable.svelte
@@ -0,0 +1,41 @@
+
+
+Warnings
+
+
+
+ | Timestamp |
+ Warning |
+ Severity |
+
+
+
+ {#each report.rows as row, row_idx}
+ {#each row.analysis as analysis}
+ {@const parsed_date = new Date(analysis.timestamp)}
+ {@const warnings = analysis.events.filter(e => e.type === EventType.Warning)}
+ {#each warnings as warning}
+ {@const severity = ['Low', 'Medium', 'High'][warning.severity]}
+ {@const severity_class = ['bg-red-200', 'bg-red-400', 'bg-red-600'][warning.severity]}
+
+ | {date_formatter.format(parsed_date)} |
+ {warning.message} |
+ {severity} |
+
+ {/each}
+ {/each}
+ {/each}
+
+
diff --git a/bin/web/src/lib/components/AnalysisView.svelte b/bin/web/src/lib/components/AnalysisView.svelte
new file mode 100644
index 0000000..2bda260
--- /dev/null
+++ b/bin/web/src/lib/components/AnalysisView.svelte
@@ -0,0 +1,40 @@
+
+
+
+ {#if entry.analysis_report === undefined}
+
Report unavailable, try refreshing.
+ {:else if typeof(entry.analysis_report) === 'string'}
+
Error getting analysis report: {entry.analysis_report}
+ {:else}
+ {@const metadata: ReportMetadata = entry.analysis_report.metadata}
+
+ {#if entry.analysis_report.rows.length > 0}
+
+ {:else}
+
No warnings to display!
+ {/if}
+
+
Metadata
+
Rayhunter version: {metadata.rayhunter.rayhunter_version}
+
Device system OS: {metadata.rayhunter.system_os}
+
Analyzers
+ {#each metadata.analyzers as analyzer}
+
{analyzer.name}: {analyzer.description}
+ {/each}
+
+
+ {/if}
+
diff --git a/bin/web/src/lib/components/ManifestTable.svelte b/bin/web/src/lib/components/ManifestTable.svelte
index 9377942..08032c5 100644
--- a/bin/web/src/lib/components/ManifestTable.svelte
+++ b/bin/web/src/lib/components/ManifestTable.svelte
@@ -8,7 +8,7 @@
let { entries, current_entry }: Props = $props();
-
+
| Name |
@@ -17,16 +17,16 @@
Size (bytes) |
PCAP |
QMDL |
- Analysis Result |
+ Analysis |
Delete |
{#if current_entry !== undefined}
-
+
{/if}
- {#each entries as entry}
-
+ {#each entries as entry, i}
+
{/each}
diff --git a/bin/web/src/lib/components/ManifestTableRow.svelte b/bin/web/src/lib/components/ManifestTableRow.svelte
index f306199..47af51c 100644
--- a/bin/web/src/lib/components/ManifestTableRow.svelte
+++ b/bin/web/src/lib/components/ManifestTableRow.svelte
@@ -3,9 +3,11 @@
import DownloadLink from '$lib/components/DownloadLink.svelte';
import DeleteButton from "$lib/components/DeleteButton.svelte";
import AnalysisStatus from "./AnalysisStatus.svelte";
- let { entry, current }: {
+ import AnalysisView from "./AnalysisView.svelte";
+ let { entry, current, i }: {
entry: ManifestEntry;
current: boolean;
+ i: number
} = $props();
// passing `undefined` as the locale uses the browser default
@@ -13,17 +15,19 @@
timeStyle: "long",
dateStyle: "short",
});
- let row_color = current ? "bg-green-300" : "even:bg-gray-100";
+ let normal_row_color = i % 2 == 0 ? "bg-white" : "bg-gray-100";
+ let row_color = current ? "bg-green-300" : normal_row_color;
+ let analysis_visible = $state(false);
-
+
| {entry.name} |
{date_formatter.format(entry.start_time)} |
{date_formatter.format(entry.last_message_time)} |
{entry.qmdl_size_bytes} |
|
|
- |
+ { analysis_visible = !analysis_visible; }} entry={entry} /> |
{#if current}
|
{:else}
@@ -35,3 +39,9 @@
{/if}
+
+ |
+
+
+ |
+
diff --git a/bin/web/src/routes/+page.svelte b/bin/web/src/routes/+page.svelte
index f4da74a..798f175 100644
--- a/bin/web/src/routes/+page.svelte
+++ b/bin/web/src/routes/+page.svelte
@@ -33,8 +33,8 @@
{#if loaded}
-
+
{:else}
Loading...
{/if}
diff --git a/bin/web/src/routes/entry/[name]/+page.svelte b/bin/web/src/routes/entry/[name]/+page.svelte
deleted file mode 100644
index e69de29..0000000