first commit
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user