import { getUserFromToken, hasRole, readUsers, isHiddenUser } from '../../utils/auth.js' import { fingerprintResetEmail, normalizeResetEmail, PASSWORD_RESET_LOG_RETENTION_HOURS, readPasswordResetLogs } from '../../utils/password-reset-log.js' function summarizeAttempts(entries) { const attemptsById = new Map() for (const entry of [...entries].reverse()) { const attempt = attemptsById.get(entry.requestId) || { requestId: entry.requestId, startedAt: entry.ts, emailMasked: entry.emailMasked, ip: entry.ip, userId: entry.userId || null, steps: [], failed: false } attempt.startedAt = attempt.startedAt || entry.ts attempt.userId = attempt.userId || entry.userId || null attempt.steps.push({ ts: entry.ts, step: entry.step, status: entry.status, reason: entry.reason || null, errorCode: entry.errorCode || entry.error || null, errorMessage: entry.errorMessage || null }) if ( entry.status === 'failed' || entry.status === 'not_found' || entry.status === 'no_account' || entry.reason === 'smtp_credentials_missing' ) { attempt.failed = true } attemptsById.set(entry.requestId, attempt) } return [...attemptsById.values()] .sort((a, b) => String(b.startedAt).localeCompare(String(a.startedAt))) } export default defineEventHandler(async (event) => { const token = getCookie(event, 'auth_token') || getHeader(event, 'authorization')?.replace(/^Bearer\s+/i, '') const currentUser = token ? await getUserFromToken(token) : null if (!currentUser || !hasRole(currentUser, 'admin')) { throw createError({ statusCode: 403, message: 'Zugriff verweigert' }) } const query = getQuery(event) const email = normalizeResetEmail(query.email) const failedOnly = query.failedOnly !== 'false' const users = await readUsers() const visibleUsers = users.filter(user => !isHiddenUser(user)) const hiddenEmailFingerprints = new Set(users.filter(isHiddenUser).map(user => fingerprintResetEmail(user.email)).filter(Boolean)) const logs = await readPasswordResetLogs() const filteredLogs = (email ? logs.filter(entry => entry.emailFingerprint === fingerprintResetEmail(email)) : logs) .filter(entry => !hiddenEmailFingerprints.has(entry.emailFingerprint)) const attempts = summarizeAttempts(filteredLogs) .filter(attempt => !failedOnly || attempt.failed) let matchingUsers = [] if (email) { const term = email.toLowerCase() matchingUsers = visibleUsers .filter(user => { const userEmail = normalizeResetEmail(user.email) const name = String(user.name || '').toLowerCase() return userEmail.includes(term) || name.includes(term) }) .slice(0, 20) .map(user => ({ id: user.id, name: user.name, email: user.email, active: user.active !== false, lastLogin: user.lastLogin || null })) } return { retentionHours: PASSWORD_RESET_LOG_RETENTION_HOURS, searchedEmail: email, matchingUsers, attempts } })