480 lines
17 KiB
JavaScript
480 lines
17 KiB
JavaScript
"use strict";
|
|
// ==================== EMAIL PROVIDER SERVICE ====================
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.getAllProviderConfigs = getAllProviderConfigs;
|
|
exports.getProviderConfigById = getProviderConfigById;
|
|
exports.getDefaultProviderConfig = getDefaultProviderConfig;
|
|
exports.getActiveProviderConfig = getActiveProviderConfig;
|
|
exports.createProviderConfig = createProviderConfig;
|
|
exports.updateProviderConfig = updateProviderConfig;
|
|
exports.deleteProviderConfig = deleteProviderConfig;
|
|
exports.checkEmailExists = checkEmailExists;
|
|
exports.provisionEmail = provisionEmail;
|
|
exports.provisionEmailWithMailbox = provisionEmailWithMailbox;
|
|
exports.enableMailboxForExistingEmail = enableMailboxForExistingEmail;
|
|
exports.updateMailboxPassword = updateMailboxPassword;
|
|
exports.getImapSmtpSettings = getImapSmtpSettings;
|
|
exports.deprovisionEmail = deprovisionEmail;
|
|
exports.renameProvisionedEmail = renameProvisionedEmail;
|
|
exports.getProviderDomain = getProviderDomain;
|
|
exports.testProviderConnection = testProviderConnection;
|
|
const client_1 = require("@prisma/client");
|
|
const encryption_js_1 = require("../../utils/encryption.js");
|
|
const pleskProvider_js_1 = require("./pleskProvider.js");
|
|
const prisma = new client_1.PrismaClient();
|
|
// Factory-Funktion um den richtigen Provider zu erstellen
|
|
function createProvider(config) {
|
|
switch (config.type) {
|
|
case 'PLESK':
|
|
return new pleskProvider_js_1.PleskEmailProvider(config);
|
|
case 'CPANEL':
|
|
// TODO: cPanel Provider implementieren
|
|
throw new Error('cPanel Provider noch nicht implementiert');
|
|
case 'DIRECTADMIN':
|
|
// TODO: DirectAdmin Provider implementieren
|
|
throw new Error('DirectAdmin Provider noch nicht implementiert');
|
|
default:
|
|
throw new Error(`Unbekannter Provider-Typ: ${config.type}`);
|
|
}
|
|
}
|
|
// ==================== CONFIG CRUD ====================
|
|
async function getAllProviderConfigs() {
|
|
return prisma.emailProviderConfig.findMany({
|
|
orderBy: [{ isDefault: 'desc' }, { name: 'asc' }],
|
|
});
|
|
}
|
|
async function getProviderConfigById(id) {
|
|
return prisma.emailProviderConfig.findUnique({
|
|
where: { id },
|
|
});
|
|
}
|
|
async function getDefaultProviderConfig() {
|
|
return prisma.emailProviderConfig.findFirst({
|
|
where: { isActive: true, isDefault: true },
|
|
});
|
|
}
|
|
async function getActiveProviderConfig() {
|
|
// Erst Default-Provider versuchen, dann irgendeinen aktiven
|
|
const defaultProvider = await getDefaultProviderConfig();
|
|
if (defaultProvider)
|
|
return defaultProvider;
|
|
return prisma.emailProviderConfig.findFirst({
|
|
where: { isActive: true },
|
|
});
|
|
}
|
|
async function createProviderConfig(data) {
|
|
// Falls isDefault=true, alle anderen auf false setzen
|
|
if (data.isDefault) {
|
|
await prisma.emailProviderConfig.updateMany({
|
|
where: { isDefault: true },
|
|
data: { isDefault: false },
|
|
});
|
|
}
|
|
// Passwort verschlüsseln falls vorhanden
|
|
const { encrypt } = await import('../../utils/encryption.js');
|
|
const passwordEncrypted = data.password ? encrypt(data.password) : null;
|
|
return prisma.emailProviderConfig.create({
|
|
data: {
|
|
name: data.name,
|
|
type: data.type,
|
|
apiUrl: data.apiUrl,
|
|
apiKey: data.apiKey || null,
|
|
username: data.username || null,
|
|
passwordEncrypted,
|
|
domain: data.domain,
|
|
defaultForwardEmail: data.defaultForwardEmail || null,
|
|
imapEncryption: data.imapEncryption ?? 'SSL',
|
|
smtpEncryption: data.smtpEncryption ?? 'SSL',
|
|
allowSelfSignedCerts: data.allowSelfSignedCerts ?? false,
|
|
isActive: data.isActive ?? true,
|
|
isDefault: data.isDefault ?? false,
|
|
},
|
|
});
|
|
}
|
|
async function updateProviderConfig(id, data) {
|
|
// Falls isDefault=true, alle anderen auf false setzen
|
|
if (data.isDefault) {
|
|
await prisma.emailProviderConfig.updateMany({
|
|
where: { isDefault: true, id: { not: id } },
|
|
data: { isDefault: false },
|
|
});
|
|
}
|
|
const updateData = {};
|
|
if (data.name !== undefined)
|
|
updateData.name = data.name;
|
|
if (data.type !== undefined)
|
|
updateData.type = data.type;
|
|
if (data.apiUrl !== undefined)
|
|
updateData.apiUrl = data.apiUrl;
|
|
if (data.apiKey !== undefined)
|
|
updateData.apiKey = data.apiKey || null;
|
|
if (data.username !== undefined)
|
|
updateData.username = data.username || null;
|
|
if (data.domain !== undefined)
|
|
updateData.domain = data.domain;
|
|
if (data.defaultForwardEmail !== undefined)
|
|
updateData.defaultForwardEmail = data.defaultForwardEmail || null;
|
|
if (data.imapEncryption !== undefined)
|
|
updateData.imapEncryption = data.imapEncryption;
|
|
if (data.smtpEncryption !== undefined)
|
|
updateData.smtpEncryption = data.smtpEncryption;
|
|
if (data.allowSelfSignedCerts !== undefined)
|
|
updateData.allowSelfSignedCerts = data.allowSelfSignedCerts;
|
|
if (data.isActive !== undefined)
|
|
updateData.isActive = data.isActive;
|
|
if (data.isDefault !== undefined)
|
|
updateData.isDefault = data.isDefault;
|
|
// Passwort-Logik:
|
|
// - Wenn neues Passwort übergeben → verschlüsseln und speichern
|
|
// - Wenn Benutzername gelöscht wird → Passwort auch löschen (gehören zusammen)
|
|
if (data.password) {
|
|
const { encrypt } = await import('../../utils/encryption.js');
|
|
updateData.passwordEncrypted = encrypt(data.password);
|
|
}
|
|
else if (data.username !== undefined && !data.username) {
|
|
// Benutzername wird gelöscht → Passwort auch löschen
|
|
updateData.passwordEncrypted = null;
|
|
}
|
|
return prisma.emailProviderConfig.update({
|
|
where: { id },
|
|
data: updateData,
|
|
});
|
|
}
|
|
async function deleteProviderConfig(id) {
|
|
return prisma.emailProviderConfig.delete({
|
|
where: { id },
|
|
});
|
|
}
|
|
// ==================== EMAIL OPERATIONS ====================
|
|
// Provider-Instanz aus DB-Config erstellen
|
|
async function getProviderInstance() {
|
|
const dbConfig = await getActiveProviderConfig();
|
|
if (!dbConfig) {
|
|
throw new Error('Kein aktiver Email-Provider konfiguriert');
|
|
}
|
|
// Passwort entschlüsseln
|
|
let password;
|
|
if (dbConfig.passwordEncrypted) {
|
|
try {
|
|
password = (0, encryption_js_1.decrypt)(dbConfig.passwordEncrypted);
|
|
}
|
|
catch {
|
|
console.error('Konnte Passwort nicht entschlüsseln');
|
|
}
|
|
}
|
|
const config = {
|
|
id: dbConfig.id,
|
|
name: dbConfig.name,
|
|
type: dbConfig.type,
|
|
apiUrl: dbConfig.apiUrl,
|
|
apiKey: dbConfig.apiKey || undefined,
|
|
username: dbConfig.username || undefined,
|
|
password,
|
|
domain: dbConfig.domain,
|
|
defaultForwardEmail: dbConfig.defaultForwardEmail || undefined,
|
|
imapServer: dbConfig.imapServer || undefined,
|
|
imapPort: dbConfig.imapPort || undefined,
|
|
smtpServer: dbConfig.smtpServer || undefined,
|
|
smtpPort: dbConfig.smtpPort || undefined,
|
|
imapEncryption: dbConfig.imapEncryption,
|
|
smtpEncryption: dbConfig.smtpEncryption,
|
|
allowSelfSignedCerts: dbConfig.allowSelfSignedCerts,
|
|
isActive: dbConfig.isActive,
|
|
isDefault: dbConfig.isDefault,
|
|
};
|
|
return createProvider(config);
|
|
}
|
|
// Prüfen ob eine E-Mail existiert
|
|
async function checkEmailExists(localPart) {
|
|
try {
|
|
const provider = await getProviderInstance();
|
|
return provider.emailExists(localPart);
|
|
}
|
|
catch (error) {
|
|
console.error('checkEmailExists error:', error);
|
|
return { exists: false };
|
|
}
|
|
}
|
|
// E-Mail erstellen mit Weiterleitungen
|
|
async function provisionEmail(localPart, customerEmail) {
|
|
try {
|
|
const provider = await getProviderInstance();
|
|
const config = await getActiveProviderConfig();
|
|
// Weiterleitungsziele zusammenstellen
|
|
const forwardTargets = [customerEmail];
|
|
// Unsere eigene Weiterleitungsadresse hinzufügen falls konfiguriert
|
|
if (config?.defaultForwardEmail) {
|
|
forwardTargets.push(config.defaultForwardEmail);
|
|
}
|
|
// Prüfen ob existiert
|
|
const exists = await provider.emailExists(localPart);
|
|
if (exists.exists) {
|
|
return {
|
|
success: true,
|
|
message: `E-Mail ${exists.email} existiert bereits`,
|
|
};
|
|
}
|
|
// Erstellen
|
|
const result = await provider.createEmail({
|
|
localPart,
|
|
forwardTargets,
|
|
});
|
|
return result;
|
|
}
|
|
catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
|
return {
|
|
success: false,
|
|
error: errorMessage,
|
|
};
|
|
}
|
|
}
|
|
// E-Mail mit echter Mailbox erstellen (IMAP/SMTP-Zugang)
|
|
async function provisionEmailWithMailbox(localPart, customerEmail, password) {
|
|
try {
|
|
const provider = await getProviderInstance();
|
|
const config = await getActiveProviderConfig();
|
|
// Weiterleitungsziele zusammenstellen
|
|
const forwardTargets = [customerEmail];
|
|
// Unsere eigene Weiterleitungsadresse hinzufügen falls konfiguriert
|
|
if (config?.defaultForwardEmail) {
|
|
forwardTargets.push(config.defaultForwardEmail);
|
|
}
|
|
// Prüfen ob existiert
|
|
const exists = await provider.emailExists(localPart);
|
|
if (exists.exists) {
|
|
return {
|
|
success: true,
|
|
message: `E-Mail ${exists.email} existiert bereits`,
|
|
email: exists.email,
|
|
};
|
|
}
|
|
// Mit Mailbox erstellen
|
|
const result = await provider.createEmailWithMailbox({
|
|
localPart,
|
|
forwardTargets,
|
|
password,
|
|
});
|
|
return result;
|
|
}
|
|
catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
|
return {
|
|
success: false,
|
|
error: errorMessage,
|
|
};
|
|
}
|
|
}
|
|
// Mailbox für existierende E-Mail-Weiterleitung aktivieren
|
|
async function enableMailboxForExistingEmail(localPart, password) {
|
|
try {
|
|
const provider = await getProviderInstance();
|
|
const result = await provider.enableMailboxForExisting({
|
|
localPart,
|
|
password,
|
|
});
|
|
return result;
|
|
}
|
|
catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
|
return {
|
|
success: false,
|
|
error: errorMessage,
|
|
};
|
|
}
|
|
}
|
|
// Mailbox-Passwort beim Provider aktualisieren
|
|
async function updateMailboxPassword(localPart, password) {
|
|
try {
|
|
const provider = await getProviderInstance();
|
|
const result = await provider.updateMailboxPassword({
|
|
localPart,
|
|
password,
|
|
});
|
|
return result;
|
|
}
|
|
catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
|
return {
|
|
success: false,
|
|
error: errorMessage,
|
|
};
|
|
}
|
|
}
|
|
async function getImapSmtpSettings() {
|
|
const config = await getActiveProviderConfig();
|
|
if (!config)
|
|
return null;
|
|
// Default-Server: Hostname aus der apiUrl extrahieren (z.B. rs001871.fastrootserver.de aus https://rs001871.fastrootserver.de:8443)
|
|
// Der Plesk-Server ist gleichzeitig der Mail-Server
|
|
let defaultServer;
|
|
try {
|
|
const url = new URL(config.apiUrl);
|
|
defaultServer = url.hostname;
|
|
}
|
|
catch {
|
|
// Fallback falls apiUrl ungültig
|
|
defaultServer = `mail.${config.domain}`;
|
|
}
|
|
// Verschlüsselungs-Einstellungen
|
|
const imapEncryption = (config.imapEncryption ?? 'SSL');
|
|
const smtpEncryption = (config.smtpEncryption ?? 'SSL');
|
|
// Ports basierend auf Verschlüsselung berechnen:
|
|
// SSL: IMAP 993, SMTP 465
|
|
// STARTTLS: IMAP 143, SMTP 587
|
|
// NONE: IMAP 143, SMTP 25
|
|
//
|
|
// Standard-Ports werden IMMER basierend auf Verschlüsselung berechnet.
|
|
// Nur benutzerdefinierte Ports (nicht 993/143/465/587/25) werden aus der DB übernommen.
|
|
const getImapPort = (enc, storedPort) => {
|
|
const standardPorts = [993, 143];
|
|
// Wenn ein nicht-standard Port gespeichert ist, diesen verwenden
|
|
if (storedPort && !standardPorts.includes(storedPort)) {
|
|
return storedPort;
|
|
}
|
|
// Sonst basierend auf Verschlüsselung
|
|
return enc === 'SSL' ? 993 : 143;
|
|
};
|
|
const getSmtpPort = (enc, storedPort) => {
|
|
const standardPorts = [465, 587, 25];
|
|
// Wenn ein nicht-standard Port gespeichert ist, diesen verwenden
|
|
if (storedPort && !standardPorts.includes(storedPort)) {
|
|
return storedPort;
|
|
}
|
|
// Sonst basierend auf Verschlüsselung
|
|
if (enc === 'SSL')
|
|
return 465;
|
|
if (enc === 'STARTTLS')
|
|
return 587;
|
|
return 25; // NONE
|
|
};
|
|
return {
|
|
imapServer: config.imapServer || defaultServer,
|
|
imapPort: getImapPort(imapEncryption, config.imapPort),
|
|
imapEncryption,
|
|
smtpServer: config.smtpServer || defaultServer,
|
|
smtpPort: getSmtpPort(smtpEncryption, config.smtpPort),
|
|
smtpEncryption,
|
|
allowSelfSignedCerts: config.allowSelfSignedCerts ?? false,
|
|
domain: config.domain,
|
|
};
|
|
}
|
|
// E-Mail löschen
|
|
async function deprovisionEmail(localPart) {
|
|
try {
|
|
const provider = await getProviderInstance();
|
|
return provider.deleteEmail(localPart);
|
|
}
|
|
catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
|
return {
|
|
success: false,
|
|
error: errorMessage,
|
|
};
|
|
}
|
|
}
|
|
// E-Mail umbenennen
|
|
async function renameProvisionedEmail(oldLocalPart, newLocalPart) {
|
|
try {
|
|
const provider = await getProviderInstance();
|
|
return provider.renameEmail({ oldLocalPart, newLocalPart });
|
|
}
|
|
catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
|
return {
|
|
success: false,
|
|
error: errorMessage,
|
|
};
|
|
}
|
|
}
|
|
// Domain aus aktivem Provider holen
|
|
async function getProviderDomain() {
|
|
const config = await getActiveProviderConfig();
|
|
return config?.domain || null;
|
|
}
|
|
// Provider-Instanz aus übergebener Config erstellen (für Tests mit ungespeicherten Daten)
|
|
function createProviderFromFormData(data) {
|
|
const config = {
|
|
id: 0,
|
|
name: 'Test',
|
|
type: data.type,
|
|
apiUrl: data.apiUrl,
|
|
apiKey: data.apiKey,
|
|
username: data.username,
|
|
password: data.password,
|
|
domain: data.domain,
|
|
isActive: true,
|
|
isDefault: false,
|
|
};
|
|
return createProvider(config);
|
|
}
|
|
// Provider-Instanz aus DB-Config per ID erstellen
|
|
async function getProviderInstanceById(id) {
|
|
const dbConfig = await getProviderConfigById(id);
|
|
if (!dbConfig) {
|
|
throw new Error('Email-Provider nicht gefunden');
|
|
}
|
|
// Passwort entschlüsseln
|
|
let password;
|
|
if (dbConfig.passwordEncrypted) {
|
|
try {
|
|
password = (0, encryption_js_1.decrypt)(dbConfig.passwordEncrypted);
|
|
}
|
|
catch {
|
|
console.error('Konnte Passwort nicht entschlüsseln');
|
|
}
|
|
}
|
|
const config = {
|
|
id: dbConfig.id,
|
|
name: dbConfig.name,
|
|
type: dbConfig.type,
|
|
apiUrl: dbConfig.apiUrl,
|
|
apiKey: dbConfig.apiKey || undefined,
|
|
username: dbConfig.username || undefined,
|
|
password,
|
|
domain: dbConfig.domain,
|
|
defaultForwardEmail: dbConfig.defaultForwardEmail || undefined,
|
|
imapServer: dbConfig.imapServer || undefined,
|
|
imapPort: dbConfig.imapPort || undefined,
|
|
smtpServer: dbConfig.smtpServer || undefined,
|
|
smtpPort: dbConfig.smtpPort || undefined,
|
|
imapEncryption: dbConfig.imapEncryption,
|
|
smtpEncryption: dbConfig.smtpEncryption,
|
|
allowSelfSignedCerts: dbConfig.allowSelfSignedCerts,
|
|
isActive: dbConfig.isActive,
|
|
isDefault: dbConfig.isDefault,
|
|
};
|
|
return createProvider(config);
|
|
}
|
|
// Provider-Verbindung testen (mit ID, Formulardaten oder Default-Provider)
|
|
async function testProviderConnection(options) {
|
|
try {
|
|
let provider;
|
|
if (options?.testData) {
|
|
// Mit übergebenen Daten testen (z.B. aus Modal beim Neuanlegen)
|
|
provider = createProviderFromFormData(options.testData);
|
|
}
|
|
else if (options?.id) {
|
|
// Gespeicherten Provider per ID testen
|
|
provider = await getProviderInstanceById(options.id);
|
|
}
|
|
else {
|
|
// Default-Provider testen
|
|
provider = await getProviderInstance();
|
|
}
|
|
// Expliziter Verbindungstest (wirft Fehler bei Auth-Problemen)
|
|
await provider.testConnection();
|
|
return {
|
|
success: true,
|
|
message: 'Verbindung zum Email-Provider erfolgreich',
|
|
};
|
|
}
|
|
catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
|
return {
|
|
success: false,
|
|
error: errorMessage,
|
|
};
|
|
}
|
|
}
|
|
//# sourceMappingURL=emailProviderService.js.map
|