security: Zufallspasswörter beim Erststart, kryptographisch sichere JTI-Generierung

- seedDefaultUsers: generiert kryptographisch zufällige Passwörter (crypto/rand)
  statt hartkodiertes "archivmailrockz" — Passwörter werden einmalig im Terminal
  angezeigt und können danach nicht wiederhergestellt werden
- generateJTI: verwendet crypto/rand (16 Byte, hex) statt time.UnixNano XOR deadbeef

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sysops
2026-03-17 01:19:24 +01:00
parent 7e165c8eed
commit bb963a796f
25 changed files with 471 additions and 111 deletions
+10 -3
View File
@@ -1,3 +1,5 @@
import { clearAuthCache } from "@/lib/auth-cache";
const API_BASE = process.env.NEXT_PUBLIC_API_URL || "";
async function request<T>(
@@ -16,9 +18,7 @@ async function request<T>(
});
if (res.status === 401) {
if (typeof window !== "undefined") {
window.location.href = "/";
}
clearAuthCache();
throw new Error("Unauthorized");
}
@@ -81,6 +81,8 @@ export interface SearchHit {
to?: string;
subject?: string;
date?: string;
size?: number;
has_attachments?: boolean;
}
export interface SearchResponse {
@@ -155,6 +157,7 @@ export async function getMe(): Promise<MeResponse> {
}
export async function logout(): Promise<void> {
clearAuthCache();
await request<void>("/api/auth/logout", { method: "POST" });
}
@@ -164,6 +167,8 @@ export async function searchEmails(params: {
to?: string;
date_from?: string;
date_to?: string;
sort?: string;
has_attachment?: boolean;
page?: number;
page_size?: number;
}): Promise<SearchResponse> {
@@ -173,6 +178,8 @@ export async function searchEmails(params: {
if (params.to) sp.set("to", params.to);
if (params.date_from) sp.set("date_from", params.date_from);
if (params.date_to) sp.set("date_to", params.date_to);
if (params.sort) sp.set("sort", params.sort);
if (params.has_attachment !== undefined) sp.set("has_attachment", String(params.has_attachment));
if (params.page) sp.set("page", String(params.page));
if (params.page_size) sp.set("page_size", String(params.page_size));
return request<SearchResponse>(`/api/search?${sp.toString()}`);