Datenschutz vollmacht fixed, two time counter added
This commit is contained in:
+239
-16
@@ -24,6 +24,9 @@ const RESOURCE_MAPPING: Record<string, { type: string; extractId?: (req: AuthReq
|
||||
'/api/contract-durations': { type: 'ContractDuration', extractId: (req) => req.params.id },
|
||||
'/api/settings': { type: 'AppSetting', extractId: (req) => req.params.key },
|
||||
'/api/email-providers': { type: 'EmailProviderConfig', extractId: (req) => req.params.id },
|
||||
'/api/meters': { type: 'Meter', extractId: (req) => req.params.id || req.params.meterId },
|
||||
'/api/upload': { type: 'Upload' },
|
||||
'/api/email-logs': { type: 'EmailLog' },
|
||||
'/api/auth': { type: 'Authentication' },
|
||||
'/api/audit-logs': { type: 'AuditLog', extractId: (req) => req.params.id },
|
||||
'/api/gdpr': { type: 'GDPR' },
|
||||
@@ -116,6 +119,240 @@ function getClientIp(req: AuthRequest): string {
|
||||
return req.socket.remoteAddress || 'unknown';
|
||||
}
|
||||
|
||||
// Menschenlesbare Bezeichnungen für Resource-Typen
|
||||
const RESOURCE_TYPE_LABELS: Record<string, string> = {
|
||||
Customer: 'Kunde',
|
||||
Contract: 'Vertrag',
|
||||
BankCard: 'Bankverbindung',
|
||||
IdentityDocument: 'Ausweis',
|
||||
Address: 'Adresse',
|
||||
Meter: 'Zähler',
|
||||
MeterReading: 'Zählerstand',
|
||||
User: 'Benutzer',
|
||||
Provider: 'Anbieter',
|
||||
Tariff: 'Tarif',
|
||||
SalesPlatform: 'Vertriebsplattform',
|
||||
ContractCategory: 'Vertragskategorie',
|
||||
CancellationPeriod: 'Kündigungsfrist',
|
||||
ContractDuration: 'Vertragslaufzeit',
|
||||
EmailProviderConfig: 'E-Mail-Provider',
|
||||
AppSetting: 'Einstellung',
|
||||
CustomerConsent: 'Einwilligung',
|
||||
ContractTask: 'Aufgabe',
|
||||
ContractHistoryEntry: 'Vertragshistorie',
|
||||
GDPR: 'Datenschutz',
|
||||
Authentication: 'Anmeldung',
|
||||
AuditLog: 'Audit-Protokoll',
|
||||
StressfreiEmail: 'Stressfrei-E-Mail',
|
||||
CachedEmail: 'E-Mail',
|
||||
};
|
||||
|
||||
const ACTION_LABELS: Record<string, string> = {
|
||||
CREATE: 'erstellt',
|
||||
READ: 'aufgerufen',
|
||||
UPDATE: 'aktualisiert',
|
||||
DELETE: 'gelöscht',
|
||||
EXPORT: 'exportiert',
|
||||
ANONYMIZE: 'anonymisiert',
|
||||
LOGIN: 'angemeldet',
|
||||
LOGOUT: 'abgemeldet',
|
||||
LOGIN_FAILED: 'Anmeldung fehlgeschlagen',
|
||||
};
|
||||
|
||||
/**
|
||||
* Erzeugt ein menschenlesbares Label für den Audit-Log-Eintrag
|
||||
*/
|
||||
function generateHumanLabel(
|
||||
action: AuditAction,
|
||||
resourceType: string,
|
||||
req: AuthRequest,
|
||||
responseBody: unknown
|
||||
): string {
|
||||
const typeName = RESOURCE_TYPE_LABELS[resourceType] || resourceType;
|
||||
const actionName = ACTION_LABELS[action] || action;
|
||||
|
||||
// Identifikator aus Response oder Request extrahieren
|
||||
let identifier = '';
|
||||
if (responseBody && typeof responseBody === 'object' && 'data' in responseBody) {
|
||||
const data = (responseBody as { data: Record<string, unknown> }).data;
|
||||
if (data) {
|
||||
identifier =
|
||||
(data.contractNumber as string) ||
|
||||
(data.customerNumber as string) ||
|
||||
(data.meterNumber as string) ||
|
||||
(data.name as string) ||
|
||||
(data.email as string) ||
|
||||
(data.firstName && data.lastName ? `${data.firstName} ${data.lastName}` : '') ||
|
||||
'';
|
||||
}
|
||||
}
|
||||
|
||||
// Spezial-Labels für bestimmte Endpunkte
|
||||
const path = req.path;
|
||||
|
||||
// Auth
|
||||
if (path.includes('/auth/login') || path.includes('/auth/customer-login')) {
|
||||
const email = req.body?.email || '';
|
||||
return action === 'LOGIN'
|
||||
? `Benutzer ${email} hat sich angemeldet`
|
||||
: `Anmeldung fehlgeschlagen für ${email}`;
|
||||
}
|
||||
if (path.includes('/auth/logout')) return 'Benutzer hat sich abgemeldet';
|
||||
|
||||
// Kunden-Operationen
|
||||
if (resourceType === 'Customer') {
|
||||
if (action === 'CREATE') return `Kunde ${identifier} angelegt`;
|
||||
if (action === 'UPDATE') return `Kundendaten ${identifier} aktualisiert`;
|
||||
if (action === 'DELETE') return `Kunde ${identifier} gelöscht`;
|
||||
if (action === 'READ' && req.params.id) return `Kundendaten ${identifier} aufgerufen`;
|
||||
if (action === 'READ') return 'Kundenliste aufgerufen';
|
||||
}
|
||||
|
||||
// Verträge
|
||||
if (resourceType === 'Contract') {
|
||||
if (path.includes('/cockpit')) return 'Vertrags-Cockpit aufgerufen';
|
||||
if (path.includes('/follow-up')) return `Folgevertrag für ${identifier} erstellt`;
|
||||
if (path.includes('/snooze')) return `Vertrag ${identifier} zurückgestellt`;
|
||||
if (path.includes('/password')) return `Passwort für Vertrag ${identifier} abgerufen`;
|
||||
if (path.includes('/sip-credentials')) return 'SIP-Zugangsdaten abgerufen';
|
||||
if (path.includes('/internet-credentials')) return `Internet-Zugangsdaten für Vertrag ${identifier} abgerufen`;
|
||||
if (path.includes('/successor-meter')) return `Folgezähler zu Vertrag ${identifier} hinzugefügt`;
|
||||
if (action === 'CREATE') return `Vertrag ${identifier} angelegt`;
|
||||
if (action === 'UPDATE') return `Vertrag ${identifier} aktualisiert`;
|
||||
if (action === 'DELETE') return `Vertrag ${identifier} gelöscht`;
|
||||
if (action === 'READ' && req.params.id) return `Vertrag ${identifier} aufgerufen`;
|
||||
if (action === 'READ') return 'Vertragsliste aufgerufen';
|
||||
}
|
||||
|
||||
// Bankverbindungen
|
||||
if (resourceType === 'BankCard') {
|
||||
if (action === 'CREATE') return `Bankverbindung hinzugefügt`;
|
||||
if (action === 'UPDATE') return `Bankverbindung aktualisiert`;
|
||||
if (action === 'DELETE') return `Bankverbindung gelöscht`;
|
||||
}
|
||||
|
||||
// Ausweise
|
||||
if (resourceType === 'IdentityDocument') {
|
||||
if (action === 'CREATE') return `Ausweis ${identifier} hinzugefügt`;
|
||||
if (action === 'UPDATE') return `Ausweis ${identifier} aktualisiert`;
|
||||
if (action === 'DELETE') return `Ausweis gelöscht`;
|
||||
}
|
||||
|
||||
// Adressen
|
||||
if (resourceType === 'Address') {
|
||||
if (action === 'CREATE') return `Adresse hinzugefügt`;
|
||||
if (action === 'UPDATE') return `Adresse aktualisiert`;
|
||||
if (action === 'DELETE') return `Adresse gelöscht`;
|
||||
}
|
||||
|
||||
// Zähler
|
||||
if (resourceType === 'Meter') {
|
||||
if (action === 'CREATE') return `Zähler ${identifier} angelegt`;
|
||||
if (action === 'UPDATE') return `Zähler ${identifier} aktualisiert`;
|
||||
if (action === 'DELETE') return `Zähler gelöscht`;
|
||||
}
|
||||
|
||||
// Einwilligungen
|
||||
if (resourceType === 'CustomerConsent') {
|
||||
const consentType = req.params.consentType || '';
|
||||
const consentLabels: Record<string, string> = {
|
||||
DATA_PROCESSING: 'Datenverarbeitung',
|
||||
MARKETING_EMAIL: 'E-Mail-Marketing',
|
||||
MARKETING_PHONE: 'Telefonmarketing',
|
||||
DATA_SHARING_PARTNER: 'Datenweitergabe',
|
||||
};
|
||||
const consentName = consentLabels[consentType] || consentType;
|
||||
if (action === 'UPDATE') {
|
||||
const status = req.body?.status;
|
||||
return status === 'GRANTED'
|
||||
? `Einwilligung "${consentName}" erteilt`
|
||||
: `Einwilligung "${consentName}" widerrufen`;
|
||||
}
|
||||
if (action === 'READ') return 'Einwilligungen abgerufen';
|
||||
}
|
||||
|
||||
// Benutzer
|
||||
if (resourceType === 'User') {
|
||||
if (action === 'CREATE') return `Benutzer ${identifier} angelegt`;
|
||||
if (action === 'UPDATE') return `Benutzer ${identifier} aktualisiert`;
|
||||
if (action === 'DELETE') return `Benutzer ${identifier} gelöscht`;
|
||||
if (action === 'READ' && req.params.id) return `Benutzerdaten ${identifier} aufgerufen`;
|
||||
if (action === 'READ') return 'Benutzerliste aufgerufen';
|
||||
}
|
||||
|
||||
// Aufgaben
|
||||
if (resourceType === 'ContractTask') {
|
||||
if (path.includes('/complete')) return `Aufgabe als erledigt markiert`;
|
||||
if (action === 'CREATE') return `Aufgabe erstellt`;
|
||||
if (action === 'UPDATE') return `Aufgabe aktualisiert`;
|
||||
if (action === 'DELETE') return `Aufgabe gelöscht`;
|
||||
}
|
||||
|
||||
// E-Mail-Provider
|
||||
if (resourceType === 'EmailProviderConfig') {
|
||||
if (path.includes('/test-connection')) return `E-Mail-Provider Verbindungstest`;
|
||||
if (path.includes('/provision')) return `E-Mail-Adresse provisioniert`;
|
||||
if (action === 'CREATE') return `E-Mail-Provider ${identifier} angelegt`;
|
||||
if (action === 'UPDATE') return `E-Mail-Provider ${identifier} aktualisiert`;
|
||||
if (action === 'DELETE') return `E-Mail-Provider ${identifier} gelöscht`;
|
||||
}
|
||||
|
||||
// GDPR
|
||||
if (resourceType === 'GDPR') {
|
||||
if (path.includes('/dashboard')) return 'DSGVO-Dashboard aufgerufen';
|
||||
if (path.includes('/export')) return 'Kundendaten exportiert (DSGVO Art. 15)';
|
||||
if (path.includes('/privacy-policy')) {
|
||||
return action === 'UPDATE' ? 'Datenschutzerklärung aktualisiert' : 'Datenschutzerklärung aufgerufen';
|
||||
}
|
||||
if (path.includes('/authorization-template')) {
|
||||
return action === 'UPDATE' ? 'Vollmacht-Vorlage aktualisiert' : 'Vollmacht-Vorlage aufgerufen';
|
||||
}
|
||||
if (path.includes('/send-consent-link')) return 'Datenschutz-Link versendet';
|
||||
if (path.includes('/authorizations') && path.includes('/send')) return 'Vollmacht-Anfrage versendet';
|
||||
if (path.includes('/authorizations') && path.includes('/grant')) return 'Vollmacht erteilt';
|
||||
if (path.includes('/authorizations') && path.includes('/withdraw')) return 'Vollmacht widerrufen';
|
||||
if (path.includes('/authorizations') && path.includes('/upload')) return 'Vollmacht-PDF hochgeladen';
|
||||
if (path.includes('/authorizations') && path.includes('/document') && action === 'DELETE') return 'Vollmacht-PDF gelöscht';
|
||||
if (path.includes('/my-privacy')) return 'Eigene Datenschutzseite aufgerufen';
|
||||
if (path.includes('/my-consent-status')) return 'Eigener Einwilligungsstatus geprüft';
|
||||
if (path.includes('/my-authorizations')) return 'Eigene Vollmachten aufgerufen';
|
||||
if (path.includes('/deletions')) {
|
||||
if (action === 'CREATE') return 'Löschanfrage erstellt';
|
||||
if (path.includes('/process')) return 'Löschanfrage bearbeitet';
|
||||
return 'Löschanfragen aufgerufen';
|
||||
}
|
||||
if (path.includes('/consent-status')) return 'Einwilligungsstatus geprüft';
|
||||
if (path.includes('/consents/overview')) return 'Einwilligungsübersicht aufgerufen';
|
||||
}
|
||||
|
||||
// Einstellungen
|
||||
if (resourceType === 'AppSetting') {
|
||||
if (action === 'UPDATE') return `Einstellung "${req.params.key || ''}" geändert`;
|
||||
if (action === 'READ') return 'Einstellungen aufgerufen';
|
||||
}
|
||||
|
||||
// Zähler-Readings
|
||||
if (path.includes('/readings')) {
|
||||
if (path.includes('/report')) return 'Zählerstand vom Kunden gemeldet';
|
||||
if (path.includes('/transfer')) return 'Zählerstand als übertragen markiert';
|
||||
if (action === 'CREATE') return 'Zählerstand erfasst';
|
||||
if (action === 'UPDATE') return 'Zählerstand aktualisiert';
|
||||
if (action === 'DELETE') return 'Zählerstand gelöscht';
|
||||
}
|
||||
|
||||
// Upload-Operationen
|
||||
if (path.includes('/upload') || path.includes('/privacy-policy')) {
|
||||
if (path.includes('/privacy-policy') && action === 'DELETE') return 'Datenschutzerklärung-PDF gelöscht';
|
||||
if (path.includes('/privacy-policy')) return 'Datenschutzerklärung-PDF hochgeladen';
|
||||
}
|
||||
|
||||
// Standard-Fallback
|
||||
if (identifier) {
|
||||
return `${typeName} ${identifier} ${actionName}`;
|
||||
}
|
||||
return `${typeName} ${actionName}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Audit Middleware - loggt alle API-Aufrufe asynchron
|
||||
*/
|
||||
@@ -162,22 +399,8 @@ export function auditMiddleware(req: AuthRequest, res: Response, next: NextFunct
|
||||
// Audit-Kontext abrufen (enthält Before/After-Werte von Prisma Middleware)
|
||||
const auditContext = getAuditContext();
|
||||
|
||||
// Label für bessere Lesbarkeit generieren
|
||||
let resourceLabel: string | undefined;
|
||||
if (responseBody && typeof responseBody === 'object' && 'data' in responseBody) {
|
||||
const data = (responseBody as { data: Record<string, unknown> }).data;
|
||||
if (data) {
|
||||
// Versuche verschiedene Label-Felder
|
||||
resourceLabel =
|
||||
(data.contractNumber as string) ||
|
||||
(data.customerNumber as string) ||
|
||||
(data.name as string) ||
|
||||
(data.email as string) ||
|
||||
(data.firstName && data.lastName
|
||||
? `${data.firstName} ${data.lastName}`
|
||||
: undefined);
|
||||
}
|
||||
}
|
||||
// Menschenlesbares Label generieren
|
||||
const resourceLabel = generateHumanLabel(action, mapping.type, req, responseBody);
|
||||
|
||||
await createAuditLog({
|
||||
userId: req.user?.userId,
|
||||
|
||||
Reference in New Issue
Block a user