first commit
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
import { EmailExistsResult, EmailOperationResult } from './types.js';
|
||||
export declare function getAllProviderConfigs(): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
}[]>;
|
||||
export declare function getProviderConfigById(id: number): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
} | null>;
|
||||
export declare function getDefaultProviderConfig(): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
} | null>;
|
||||
export declare function getActiveProviderConfig(): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
} | null>;
|
||||
export interface CreateProviderConfigData {
|
||||
name: string;
|
||||
type: 'PLESK' | 'CPANEL' | 'DIRECTADMIN';
|
||||
apiUrl: string;
|
||||
apiKey?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
domain: string;
|
||||
defaultForwardEmail?: string;
|
||||
isActive?: boolean;
|
||||
isDefault?: boolean;
|
||||
}
|
||||
export declare function createProviderConfig(data: CreateProviderConfigData): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
}>;
|
||||
export declare function updateProviderConfig(id: number, data: Partial<CreateProviderConfigData>): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
}>;
|
||||
export declare function deleteProviderConfig(id: number): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
}>;
|
||||
export declare function checkEmailExists(localPart: string): Promise<EmailExistsResult>;
|
||||
export declare function provisionEmail(localPart: string, customerEmail: string): Promise<EmailOperationResult>;
|
||||
export declare function deprovisionEmail(localPart: string): Promise<EmailOperationResult>;
|
||||
export declare function renameProvisionedEmail(oldLocalPart: string, newLocalPart: string): Promise<EmailOperationResult>;
|
||||
export declare function getProviderDomain(): Promise<string | null>;
|
||||
export declare function testProviderConnection(options?: {
|
||||
id?: number;
|
||||
testData?: {
|
||||
type: 'PLESK' | 'CPANEL' | 'DIRECTADMIN';
|
||||
apiUrl: string;
|
||||
apiKey?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
domain: string;
|
||||
};
|
||||
}): Promise<EmailOperationResult>;
|
||||
//# sourceMappingURL=emailProviderService.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"emailProviderService.d.ts","sourceRoot":"","sources":["../../../src/services/emailProvider/emailProviderService.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,iBAAiB,EACjB,oBAAoB,EAErB,MAAM,YAAY,CAAC;AAuBpB,wBAAsB,qBAAqB;;;;;;;;;;;;;;KAI1C;AAED,wBAAsB,qBAAqB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;UAIrD;AAED,wBAAsB,wBAAwB;;;;;;;;;;;;;;UAI7C;AAED,wBAAsB,uBAAuB;;;;;;;;;;;;;;UAQ5C;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,aAAa,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,wBAAwB;;;;;;;;;;;;;;GA2BxE;AAED,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,CAAC,wBAAwB,CAAC;;;;;;;;;;;;;;GAsCxC;AAED,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;GAIpD;AAwCD,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAQpF;AAGD,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,oBAAoB,CAAC,CAoC/B;AAGD,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAWvF;AAGD,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,oBAAoB,CAAC,CAW/B;AAGD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGhE;AA8DD,wBAAsB,sBAAsB,CAAC,OAAO,CAAC,EAAE;IACrD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,aAAa,CAAC;QACzC,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA6BhC"}
|
||||
@@ -0,0 +1,323 @@
|
||||
"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.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,
|
||||
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.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,
|
||||
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 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,
|
||||
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
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
export * from './types.js';
|
||||
export * from './emailProviderService.js';
|
||||
export { PleskEmailProvider } from './pleskProvider.js';
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/emailProvider/index.ts"],"names":[],"mappings":"AAEA,cAAc,YAAY,CAAC;AAC3B,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
// ==================== EMAIL PROVIDER EXPORTS ====================
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.PleskEmailProvider = void 0;
|
||||
__exportStar(require("./types.js"), exports);
|
||||
__exportStar(require("./emailProviderService.js"), exports);
|
||||
var pleskProvider_js_1 = require("./pleskProvider.js");
|
||||
Object.defineProperty(exports, "PleskEmailProvider", { enumerable: true, get: function () { return pleskProvider_js_1.PleskEmailProvider; } });
|
||||
//# sourceMappingURL=index.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/emailProvider/index.ts"],"names":[],"mappings":";AAAA,mEAAmE;;;;;;;;;;;;;;;;;AAEnE,6CAA2B;AAC3B,4DAA0C;AAC1C,uDAAwD;AAA/C,sHAAA,kBAAkB,OAAA"}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { IEmailProvider, EmailProviderConfig, EmailExistsResult, EmailOperationResult, CreateEmailParams, RenameEmailParams } from './types.js';
|
||||
export declare class PleskEmailProvider implements IEmailProvider {
|
||||
readonly type = "PLESK";
|
||||
private config;
|
||||
constructor(config: EmailProviderConfig);
|
||||
private get baseUrl();
|
||||
private request;
|
||||
testConnection(): Promise<void>;
|
||||
emailExists(localPart: string): Promise<EmailExistsResult>;
|
||||
createEmail(params: CreateEmailParams): Promise<EmailOperationResult>;
|
||||
deleteEmail(localPart: string): Promise<EmailOperationResult>;
|
||||
renameEmail(params: RenameEmailParams): Promise<EmailOperationResult>;
|
||||
updateForwardTargets(localPart: string, targets: string[]): Promise<EmailOperationResult>;
|
||||
}
|
||||
//# sourceMappingURL=pleskProvider.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"pleskProvider.d.ts","sourceRoot":"","sources":["../../../src/services/emailProvider/pleskProvider.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAiBpB,qBAAa,kBAAmB,YAAW,cAAc;IACvD,QAAQ,CAAC,IAAI,WAAW;IACxB,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,EAAE,mBAAmB;IAKvC,OAAO,KAAK,OAAO,GAGlB;YAGa,OAAO;IAsFf,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB/B,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA8C1D,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAuCrE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAgC7D,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IA2CrE,oBAAoB,CACxB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,oBAAoB,CAAC;CAmCjC"}
|
||||
@@ -0,0 +1,297 @@
|
||||
"use strict";
|
||||
// ==================== PLESK EMAIL PROVIDER ====================
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.PleskEmailProvider = void 0;
|
||||
const undici_1 = require("undici");
|
||||
// Undici-Agent der selbstsignierte Zertifikate akzeptiert
|
||||
// Mit Timeouts und Connection-Limits um Probleme zu vermeiden
|
||||
const httpsAgent = new undici_1.Agent({
|
||||
connect: {
|
||||
rejectUnauthorized: false,
|
||||
timeout: 10000, // 10 Sekunden Connect-Timeout
|
||||
},
|
||||
bodyTimeout: 30000, // 30 Sekunden für Response-Body
|
||||
headersTimeout: 30000, // 30 Sekunden für Headers
|
||||
keepAliveTimeout: 1000, // Connections nach 1 Sekunde schließen
|
||||
keepAliveMaxTimeout: 5000, // Maximal 5 Sekunden Keep-Alive
|
||||
connections: 1, // Nur eine Connection gleichzeitig pro Host
|
||||
pipelining: 1, // Kein Pipelining
|
||||
});
|
||||
class PleskEmailProvider {
|
||||
type = 'PLESK';
|
||||
config;
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
}
|
||||
// Basis-URL für API-Requests
|
||||
get baseUrl() {
|
||||
// Entferne trailing slash falls vorhanden
|
||||
return this.config.apiUrl.replace(/\/$/, '');
|
||||
}
|
||||
// HTTP-Request an Plesk API senden
|
||||
async request(method, endpoint, data) {
|
||||
const url = `${this.baseUrl}${endpoint}`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
};
|
||||
// Authentifizierung: API-Key hat Priorität, sonst Basic Auth
|
||||
if (this.config.apiKey) {
|
||||
// Nur API-Key verwenden (ohne Basic Auth)
|
||||
headers['X-API-Key'] = this.config.apiKey;
|
||||
}
|
||||
else if (this.config.username && this.config.password) {
|
||||
// Basic Auth nur wenn kein API-Key
|
||||
const authHeader = Buffer.from(`${this.config.username}:${this.config.password}`).toString('base64');
|
||||
headers['Authorization'] = `Basic ${authHeader}`;
|
||||
}
|
||||
else {
|
||||
// Keine Authentifizierung vorhanden
|
||||
throw new Error('Keine Zugangsdaten angegeben - bitte API-Key oder Benutzername/Passwort eingeben');
|
||||
}
|
||||
const options = {
|
||||
method,
|
||||
headers,
|
||||
dispatcher: httpsAgent,
|
||||
};
|
||||
if (data && (method === 'POST' || method === 'PUT')) {
|
||||
options.body = JSON.stringify(data);
|
||||
}
|
||||
try {
|
||||
const response = await (0, undici_1.fetch)(url, options);
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`Plesk API Fehler: ${response.status} - ${errorText}`);
|
||||
}
|
||||
// Leere Response bei DELETE
|
||||
if (response.status === 204) {
|
||||
return {};
|
||||
}
|
||||
return await response.json();
|
||||
}
|
||||
catch (error) {
|
||||
// Verbesserte Fehlermeldungen für häufige Probleme
|
||||
if (error instanceof Error) {
|
||||
const msg = error.message.toLowerCase();
|
||||
// Netzwerkfehler
|
||||
if (msg.includes('econnrefused')) {
|
||||
throw new Error(`Server nicht erreichbar unter ${this.baseUrl} - Ist der Server gestartet?`);
|
||||
}
|
||||
if (msg.includes('enotfound') || msg.includes('getaddrinfo')) {
|
||||
throw new Error(`Server-Adresse nicht gefunden: ${this.baseUrl} - Bitte URL prüfen`);
|
||||
}
|
||||
if (msg.includes('etimedout') || msg.includes('timeout')) {
|
||||
throw new Error(`Zeitüberschreitung bei Verbindung zu ${this.baseUrl}`);
|
||||
}
|
||||
if (msg.includes('econnreset')) {
|
||||
throw new Error(`Verbindung wurde vom Server abgebrochen`);
|
||||
}
|
||||
// SSL/TLS Fehler
|
||||
if (msg.includes('cert') || msg.includes('ssl') || msg.includes('tls') || msg.includes('unable_to_verify')) {
|
||||
throw new Error(`SSL-Zertifikatsfehler - Selbstsigniertes Zertifikat wird nicht akzeptiert`);
|
||||
}
|
||||
// fetch failed ist meist ein Netzwerk/SSL Problem
|
||||
if (msg.includes('fetch failed')) {
|
||||
throw new Error(`Verbindung fehlgeschlagen zu ${this.baseUrl} - Bitte prüfen: Server erreichbar? HTTPS-Port korrekt?`);
|
||||
}
|
||||
}
|
||||
console.error('Plesk API Request failed:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async testConnection() {
|
||||
// Versuche Server-Info abzurufen - wirft Fehler bei Auth-Problemen
|
||||
try {
|
||||
await this.request('GET', '/api/v2/server');
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof Error) {
|
||||
// Verbesserte Fehlermeldung
|
||||
if (error.message.includes('401')) {
|
||||
throw new Error('Authentifizierung fehlgeschlagen - Benutzername/Passwort oder API-Key prüfen');
|
||||
}
|
||||
if (error.message.includes('403')) {
|
||||
throw new Error('Zugriff verweigert - Berechtigungen prüfen');
|
||||
}
|
||||
// Andere Fehler wurden schon in request() übersetzt
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async emailExists(localPart) {
|
||||
const email = `${localPart}@${this.config.domain}`;
|
||||
try {
|
||||
// Plesk CLI API: Mail-Info abfragen
|
||||
const result = await this.request('POST', '/api/v2/cli/mail/call', { params: ['--info', email] });
|
||||
// Debug: Response-Struktur loggen
|
||||
console.log('Plesk emailExists response:', JSON.stringify(result, null, 2));
|
||||
// Plesk gibt code=0 bei Erfolg, code!=0 bei Fehler
|
||||
// stderr enthält Fehlermeldung wenn Mail nicht existiert
|
||||
const hasError = result.code !== 0 ||
|
||||
result.stderr?.toLowerCase().includes('not found') ||
|
||||
result.stderr?.toLowerCase().includes('does not exist') ||
|
||||
result.stderr?.toLowerCase().includes('unable to find') ||
|
||||
result.stderr?.toLowerCase().includes('no such');
|
||||
if (hasError) {
|
||||
return { exists: false };
|
||||
}
|
||||
// stdout sollte die Mail-Infos enthalten
|
||||
const exists = result.stdout?.toLowerCase().includes(localPart.toLowerCase());
|
||||
return {
|
||||
exists,
|
||||
email: exists ? email : undefined,
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
// HTTP-Fehler oder Netzwerkfehler
|
||||
if (error instanceof Error) {
|
||||
const msg = error.message.toLowerCase();
|
||||
// "not found" = Mail gibt es nicht
|
||||
if (msg.includes('not found') || msg.includes('does not exist') || msg.includes('unable to find')) {
|
||||
return { exists: false };
|
||||
}
|
||||
}
|
||||
console.error('Plesk emailExists error:', error);
|
||||
return { exists: false };
|
||||
}
|
||||
}
|
||||
async createEmail(params) {
|
||||
const { localPart, forwardTargets } = params;
|
||||
const email = `${localPart}@${this.config.domain}`;
|
||||
try {
|
||||
// Prüfen ob schon existiert
|
||||
const exists = await this.emailExists(localPart);
|
||||
if (exists.exists) {
|
||||
return {
|
||||
success: false,
|
||||
error: `E-Mail ${email} existiert bereits`,
|
||||
};
|
||||
}
|
||||
// Plesk CLI API: Mail-Account mit Weiterleitung erstellen
|
||||
// Verwendet den CLI-Wrapper unter /api/v2/cli/mail/call
|
||||
await this.request('POST', '/api/v2/cli/mail/call', {
|
||||
params: [
|
||||
'--create', email,
|
||||
'-forwarding', 'true',
|
||||
'-forwarding-addresses', forwardTargets.join(','),
|
||||
'-mailbox', 'false',
|
||||
],
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: `E-Mail ${email} erfolgreich erstellt mit Weiterleitung an: ${forwardTargets.join(', ')}`,
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
||||
console.error('Plesk createEmail error:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: `Fehler beim Erstellen der E-Mail: ${errorMessage}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
async deleteEmail(localPart) {
|
||||
const email = `${localPart}@${this.config.domain}`;
|
||||
try {
|
||||
// Prüfen ob Mail existiert
|
||||
const exists = await this.emailExists(localPart);
|
||||
if (!exists.exists) {
|
||||
return {
|
||||
success: false,
|
||||
error: `E-Mail ${email} nicht gefunden`,
|
||||
};
|
||||
}
|
||||
// Plesk CLI API: Mail-Account löschen
|
||||
await this.request('POST', '/api/v2/cli/mail/call', {
|
||||
params: ['--remove', email],
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: `E-Mail ${email} erfolgreich gelöscht`,
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
||||
console.error('Plesk deleteEmail error:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: `Fehler beim Löschen der E-Mail: ${errorMessage}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
async renameEmail(params) {
|
||||
const { oldLocalPart, newLocalPart } = params;
|
||||
const oldEmail = `${oldLocalPart}@${this.config.domain}`;
|
||||
const newEmail = `${newLocalPart}@${this.config.domain}`;
|
||||
try {
|
||||
// Prüfen ob alte Mail existiert
|
||||
const oldExists = await this.emailExists(oldLocalPart);
|
||||
if (!oldExists.exists) {
|
||||
return {
|
||||
success: false,
|
||||
error: `E-Mail ${oldEmail} nicht gefunden`,
|
||||
};
|
||||
}
|
||||
// Prüfen ob neue Adresse schon existiert
|
||||
const newExists = await this.emailExists(newLocalPart);
|
||||
if (newExists.exists) {
|
||||
return {
|
||||
success: false,
|
||||
error: `E-Mail ${newEmail} existiert bereits`,
|
||||
};
|
||||
}
|
||||
// Plesk CLI API: Mail-Account umbenennen
|
||||
await this.request('POST', '/api/v2/cli/mail/call', {
|
||||
params: ['--rename', oldEmail, '-new-name', newLocalPart],
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: `E-Mail erfolgreich umbenannt von ${oldEmail} zu ${newEmail}`,
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
||||
console.error('Plesk renameEmail error:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: `Fehler beim Umbenennen der E-Mail: ${errorMessage}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
async updateForwardTargets(localPart, targets) {
|
||||
const email = `${localPart}@${this.config.domain}`;
|
||||
try {
|
||||
// Prüfen ob Mail existiert
|
||||
const exists = await this.emailExists(localPart);
|
||||
if (!exists.exists) {
|
||||
return {
|
||||
success: false,
|
||||
error: `E-Mail ${email} nicht gefunden`,
|
||||
};
|
||||
}
|
||||
// Plesk CLI API: Weiterleitungsziele aktualisieren
|
||||
await this.request('POST', '/api/v2/cli/mail/call', {
|
||||
params: [
|
||||
'--update', email,
|
||||
'-forwarding', 'true',
|
||||
'-forwarding-addresses', targets.join(','),
|
||||
],
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: `Weiterleitungen für ${email} aktualisiert: ${targets.join(', ')}`,
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
||||
console.error('Plesk updateForwardTargets error:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: `Fehler beim Aktualisieren der Weiterleitungen: ${errorMessage}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.PleskEmailProvider = PleskEmailProvider;
|
||||
//# sourceMappingURL=pleskProvider.js.map
|
||||
File diff suppressed because one or more lines are too long
+43
@@ -0,0 +1,43 @@
|
||||
export interface EmailForwardTarget {
|
||||
email: string;
|
||||
}
|
||||
export interface CreateEmailParams {
|
||||
localPart: string;
|
||||
forwardTargets: string[];
|
||||
}
|
||||
export interface RenameEmailParams {
|
||||
oldLocalPart: string;
|
||||
newLocalPart: string;
|
||||
}
|
||||
export interface EmailExistsResult {
|
||||
exists: boolean;
|
||||
email?: string;
|
||||
}
|
||||
export interface EmailOperationResult {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}
|
||||
export interface IEmailProvider {
|
||||
readonly type: string;
|
||||
testConnection(): Promise<void>;
|
||||
emailExists(localPart: string): Promise<EmailExistsResult>;
|
||||
createEmail(params: CreateEmailParams): Promise<EmailOperationResult>;
|
||||
deleteEmail(localPart: string): Promise<EmailOperationResult>;
|
||||
renameEmail(params: RenameEmailParams): Promise<EmailOperationResult>;
|
||||
updateForwardTargets(localPart: string, targets: string[]): Promise<EmailOperationResult>;
|
||||
}
|
||||
export interface EmailProviderConfig {
|
||||
id: number;
|
||||
name: string;
|
||||
type: 'PLESK' | 'CPANEL' | 'DIRECTADMIN';
|
||||
apiUrl: string;
|
||||
apiKey?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
domain: string;
|
||||
defaultForwardEmail?: string;
|
||||
isActive: boolean;
|
||||
isDefault: boolean;
|
||||
}
|
||||
//# sourceMappingURL=types.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/emailProvider/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAGD,MAAM,WAAW,cAAc;IAE7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAGtB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAGhC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAG3D,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAGtE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAG9D,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAGtE,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC3F;AAGD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,aAAa,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB"}
|
||||
@@ -0,0 +1,4 @@
|
||||
"use strict";
|
||||
// ==================== EMAIL PROVIDER TYPES ====================
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
//# sourceMappingURL=types.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/services/emailProvider/types.ts"],"names":[],"mappings":";AAAA,iEAAiE"}
|
||||
Reference in New Issue
Block a user