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:
+29
-16
@@ -2,35 +2,48 @@
|
||||
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { getMe, type MeResponse } from "@/lib/api";
|
||||
import { getMe } from "@/lib/api";
|
||||
import { getCachedUser, setCachedUser } from "@/lib/auth-cache";
|
||||
|
||||
interface AuthState {
|
||||
user: MeResponse | null;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
}
|
||||
export { clearAuthCache } from "@/lib/auth-cache";
|
||||
|
||||
export function useAuth(requireRole?: "admin" | "auditor") {
|
||||
const router = useRouter();
|
||||
const [state, setState] = useState<AuthState>({
|
||||
user: null,
|
||||
loading: true,
|
||||
error: null,
|
||||
});
|
||||
const cached = getCachedUser();
|
||||
const [user, setUser] = useState(cached);
|
||||
const [loading, setLoading] = useState(cached === null);
|
||||
|
||||
const checkAuth = useCallback(async () => {
|
||||
const cached = getCachedUser();
|
||||
if (cached !== null) {
|
||||
if (requireRole === "admin" && cached.role !== "admin") {
|
||||
router.replace("/search");
|
||||
return;
|
||||
}
|
||||
if (requireRole === "auditor" && cached.role !== "auditor" && cached.role !== "admin") {
|
||||
router.replace("/search");
|
||||
return;
|
||||
}
|
||||
setUser(cached);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const user = await getMe();
|
||||
if (requireRole === "admin" && user.role !== "admin") {
|
||||
const me = await getMe();
|
||||
setCachedUser(me);
|
||||
if (requireRole === "admin" && me.role !== "admin") {
|
||||
router.replace("/search");
|
||||
return;
|
||||
}
|
||||
if (requireRole === "auditor" && user.role !== "auditor" && user.role !== "admin") {
|
||||
if (requireRole === "auditor" && me.role !== "auditor" && me.role !== "admin") {
|
||||
router.replace("/search");
|
||||
return;
|
||||
}
|
||||
setState({ user, loading: false, error: null });
|
||||
setUser(me);
|
||||
setLoading(false);
|
||||
} catch {
|
||||
setCachedUser(null);
|
||||
router.replace("/");
|
||||
}
|
||||
}, [router, requireRole]);
|
||||
@@ -39,5 +52,5 @@ export function useAuth(requireRole?: "admin" | "auditor") {
|
||||
checkAuth();
|
||||
}, [checkAuth]);
|
||||
|
||||
return state;
|
||||
return { user, loading };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user