feat(PROJ-18): E-Mail Integritätsprüfung (SHA-256 Verifikation)

- Storage: VerifyIntegrity, GetAllIDs, GetVerifyStatus + DB-Spalten
- main: Hintergrund-Worker alle 5 Minuten (beim Start sofort: 40/40 OK)
- API: verify_ok + verified_at in GET /api/mails/{id} Antwort
- Frontend: Grüner Haken / graues X / rotes X in Mail-Ansicht

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sysops
2026-03-14 21:28:40 +01:00
parent 7e68c7ab02
commit 3c722d0987
7 changed files with 179 additions and 1 deletions
+26
View File
@@ -83,6 +83,32 @@ function MailHeaderGrid({ mail }: { mail: MailDetail }) {
<span className="font-semibold">{mail.subject || "(kein Betreff)"}</span>
<span className="font-medium text-muted-foreground">Größe:</span>
<span>{formatBytes(mail.size)}</span>
{/* Verification status */}
<span className="font-medium text-muted-foreground">Integrität:</span>
<span>
{mail.verify_ok === true ? (
<span className="inline-flex items-center gap-1 text-green-600 text-sm font-medium">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
Verifiziert
</span>
) : mail.verify_ok === false ? (
<span className="inline-flex items-center gap-1 text-red-600 text-sm font-medium">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
Manipuliert!
</span>
) : (
<span className="inline-flex items-center gap-1 text-muted-foreground text-sm">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
Noch nicht geprüft
</span>
)}
</span>
</div>
<button
+2
View File
@@ -112,6 +112,8 @@ export interface MailDetail {
body_plain?: string;
raw_headers: string;
attachments: MailAttachment[];
verify_ok: boolean | null;
verified_at: string | null;
}
export interface AuditEntry {