100 lines
3.0 KiB
TypeScript

import { ImapFlow } from "imapflow";
import { getProfile } from "../../db/profile";
import { getPlanLimits } from "../../utils/plan-features";
import { countMailConnections, upsertMailConnection } from "../../db/mail";
/**
* POST /api/mail/connect
* Body: { email, password }
* Testet IMAP-Verbindung und speichert Credentials verschlüsselt.
*/
export default defineEventHandler(async (event) => {
const user = await requireUser(event);
const {
email,
password,
// Custom-IMAP-Felder (optional, nur wenn User eigenen Server konfiguriert)
imapHost: customImapHost,
imapPort: customImapPort,
useTls,
rejectUnauthorized,
} = await readBody(event);
if (!email || !password) {
throw createError({
statusCode: 400,
message: "Email und Passwort erforderlich",
});
}
// Plan-Limit prüfen
const profile = await getProfile(user.id);
const limits = getPlanLimits(profile?.plan ?? "free");
if (limits.mailAgents !== Infinity) {
const count = await countMailConnections(user.id);
if (count >= limits.mailAgents) {
throw createError({
statusCode: 403,
message: `Dein Plan erlaubt maximal ${limits.mailAgents} Mail-Agent${limits.mailAgents !== 1 ? "en" : ""}`,
});
}
}
// Custom-IMAP: wenn imapHost explizit gesetzt → Provider-Detection überspringen.
// Sonst: automatisch via Email-Domain erkennen.
const provider = detectImapProvider(email);
const resolvedHost = customImapHost?.trim() || provider.host;
const resolvedPort = customImapPort ?? provider.port;
// TLS-Konfiguration ableiten
// useTls=false → STARTTLS (secure=false, requireTLS=true bei ImapFlow)
// useTls=true oder nicht gesetzt → implicit TLS (secure=true)
const useImplicitTls = useTls !== false; // default: true
const tlsRejectUnauthorized = rejectUnauthorized !== false; // default: true
// STARTTLS nur wenn explizit angefordert (useTls === false)
const useStarttls = useTls === false;
// IMAP-Verbindung testen
const client = new ImapFlow({
host: resolvedHost,
port: resolvedPort,
secure: useImplicitTls,
...(useStarttls ? { requireTLS: true } : {}),
auth: { user: email, pass: password },
logger: false,
tls: { rejectUnauthorized: tlsRejectUnauthorized },
});
try {
await client.connect();
await client.logout();
} catch (err: any) {
throw createError({
statusCode: 401,
message: `Verbindung fehlgeschlagen: ${err.message ?? "Ungültige Zugangsdaten"}`,
});
}
// Credentials verschlüsselt speichern
await upsertMailConnection({
userId: user.id,
email,
provider: "imap",
// Bei Custom-Host: Host als providerName, sonst auto-erkannter Name
providerName: customImapHost ? resolvedHost : provider.name,
imapHost: resolvedHost,
imapPort: resolvedPort,
passwordEncrypted: encrypt(password),
rejectUnauthorized: tlsRejectUnauthorized,
useStarttls,
});
return {
connected: true,
email,
provider: customImapHost ? resolvedHost : provider.name,
custom: !!customImapHost,
};
});