import { writeConsentRevoke } from "../../db/consent"; import { deleteMailConnection } from "../../db/mail"; import { usePrisma } from "../../utils/prisma"; /** * DELETE /api/mail-connections/:id * * Trennt eine MailConnection mit korrekter DSGVO-Compliance: * 1. Widerruf-Eintrag in consent_logs (Art. 7 Abs. 1 DSGVO — Beweislog) * 2. Für OAuth-Connections (Outlook): Token-Revoke bei MS — best-effort, * max 3 Retries, dann trotzdem löschen (DSB-Memo Abschnitt 5.1). * NOCH NICHT implementiert — Placeholder für OAuth-Phase. * Tracking: TODO mo — OAuth Token-Revoke, siehe consent-gap-plan.md * 3. DB-Row löschen * * Param: :id = MailConnection.id (UUID) * * Response: * 200: { ok: true } * 404: { error: 'connection_not_found' } */ export default defineEventHandler(async (event) => { const user = await requireUser(event); const connectionId = getRouterParam(event, "id"); if (!connectionId) { throw createError({ statusCode: 400, data: { error: "missing_id" }, }); } // Verbindung holen (brauchen wir für Consent-Version + authMethod) const db = usePrisma(); const connection = await db.mailConnection.findFirst({ where: { id: connectionId, userId: user.id }, select: { id: true, consentVersion: true, authMethod: true, email: true, }, }); if (!connection) { throw createError({ statusCode: 404, data: { error: "connection_not_found" }, }); } const now = new Date(); const ipAddress = getHeader(event, "x-forwarded-for")?.split(",")[0]?.trim() ?? getHeader(event, "x-real-ip") ?? null; const userAgent = getHeader(event, "user-agent") ?? null; // ── Widerruf in consent_logs (Art. 7) ──────────────────────────────────── // Nur wenn jemals eine Consent-Version gesetzt war (Bestandsrows ohne Consent // haben consentVersion=null — wir loggen mit Marker-Version "none"). await writeConsentRevoke({ userId: user.id, consentType: "art9-mail", consentVersion: connection.consentVersion ?? "none", revokedAt: now, revokeReason: "user_disconnect", mailConnectionId: connection.id, ipAddress, userAgent, }); // ── OAuth Token-Revoke (Placeholder für MS-OAuth-Phase) ────────────────── // TODO (mo — Mail-Stack): Wenn authMethod === 'oauth2_microsoft': // 1. oauthRefreshToken aus DB lesen (decrypt) // 2. POST https://login.microsoftonline.com/common/oauth2/v2.0/logout // mit grant_type=revoke, token=, client_id, client_secret // 3. Max 3 Retries mit Exponential-Backoff // 4. Audit-Log-Eintrag "token_revoked_at_ms: success/failure" // 5. Trotzdem löschen wenn Revoke fehlschlägt (DSB-Memo Abschnitt 5.1) // Tracking: consent-gap-plan.md TODO #2 // ── DB-Row löschen ──────────────────────────────────────────────────────── await deleteMailConnection(user.id, connectionId); return { ok: true }; });