92 lines
2.3 KiB
TypeScript
92 lines
2.3 KiB
TypeScript
import { createServiceClient } from "@/lib/supabase";
|
|
|
|
export interface AuditLogEntry {
|
|
id: string;
|
|
email: string;
|
|
ip_addr: string;
|
|
user_agent: string;
|
|
success: boolean;
|
|
timestamp: string;
|
|
reason?: string;
|
|
}
|
|
|
|
export async function logLoginAttempt(
|
|
email: string,
|
|
ipAddr: string,
|
|
success: boolean,
|
|
userAgent: string,
|
|
reason?: string
|
|
): Promise<void> {
|
|
try {
|
|
const db = createServiceClient();
|
|
await db.from("admin_audit_logs").insert({
|
|
email: email.toLowerCase().trim(),
|
|
ip_addr: ipAddr,
|
|
user_agent: userAgent,
|
|
success,
|
|
reason,
|
|
timestamp: new Date().toISOString(),
|
|
});
|
|
} catch (error) {
|
|
console.error("Fehler beim Audit-Logging:", error);
|
|
}
|
|
}
|
|
|
|
export async function getFailedLoginCount(
|
|
emailOrIp: string,
|
|
type: "email" | "ip" = "email",
|
|
timeWindowMinutes = 60
|
|
): Promise<number> {
|
|
try {
|
|
const db = createServiceClient();
|
|
const since = new Date(Date.now() - timeWindowMinutes * 60 * 1000).toISOString();
|
|
const column = type === "email" ? "email" : "ip_addr";
|
|
const { count } = await db
|
|
.from("admin_audit_logs")
|
|
.select("id", { count: "exact" })
|
|
.eq(column, emailOrIp)
|
|
.eq("success", false)
|
|
.gt("timestamp", since);
|
|
return count || 0;
|
|
} catch {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
export async function getAuditLogs(options?: {
|
|
email?: string;
|
|
ipAddr?: string;
|
|
successOnly?: boolean;
|
|
limit?: number;
|
|
offset?: number;
|
|
}): Promise<AuditLogEntry[]> {
|
|
try {
|
|
const db = createServiceClient();
|
|
const limit = options?.limit ?? 100;
|
|
const offset = options?.offset ?? 0;
|
|
|
|
let query = db
|
|
.from("admin_audit_logs")
|
|
.select("*")
|
|
.order("timestamp", { ascending: false })
|
|
.range(offset, offset + limit - 1);
|
|
|
|
if (options?.email) query = query.eq("email", options.email.toLowerCase().trim());
|
|
if (options?.ipAddr) query = query.eq("ip_addr", options.ipAddr);
|
|
if (options?.successOnly !== undefined) query = query.eq("success", options.successOnly);
|
|
|
|
const { data, error } = await query;
|
|
if (error) return [];
|
|
return (data ?? []).map((row) => ({ ...row, reason: row.reason ?? undefined }));
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export async function sendSecurityAlert(
|
|
subject: string,
|
|
message: string
|
|
): Promise<void> {
|
|
console.warn(`⚠️ SECURITY ALERT: ${subject}\n${message}`);
|
|
}
|