complete new audit system
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
import prisma from '../lib/prisma.js';
|
||||
|
||||
// Default settings
|
||||
const DEFAULT_SETTINGS: Record<string, string> = {
|
||||
|
||||
@@ -3,6 +3,42 @@ import crypto from 'crypto';
|
||||
import { encrypt, decrypt } from '../utils/encryption.js';
|
||||
import prisma from '../lib/prisma.js';
|
||||
|
||||
/**
|
||||
* Vereinfachte Audit-Log-Funktion für gezielte Änderungsprotokolle.
|
||||
* Wird direkt in Controllern aufgerufen mit aussagekräftigen Details.
|
||||
*/
|
||||
export async function logChange(opts: {
|
||||
req: any; // Express Request (für userId, email, IP)
|
||||
action: AuditAction;
|
||||
resourceType: string;
|
||||
resourceId?: string;
|
||||
label: string; // Menschenlesbares Label z.B. "Vollmacht für Stefan Hacker widerrufen"
|
||||
details?: Record<string, unknown>; // Zusätzliche Details z.B. { vorher: 'erteilt', nachher: 'widerrufen' }
|
||||
customerId?: number;
|
||||
}) {
|
||||
try {
|
||||
const user = opts.req?.user;
|
||||
await createAuditLog({
|
||||
userId: user?.userId,
|
||||
userEmail: user?.email || 'system',
|
||||
userRole: user?.isCustomerPortal ? 'Kundenportal' : 'Mitarbeiter',
|
||||
customerId: user?.customerId,
|
||||
isCustomerPortal: user?.isCustomerPortal,
|
||||
action: opts.action,
|
||||
resourceType: opts.resourceType,
|
||||
resourceId: opts.resourceId,
|
||||
resourceLabel: opts.label,
|
||||
endpoint: opts.req?.path || '',
|
||||
httpMethod: opts.req?.method || '',
|
||||
ipAddress: opts.req?.socket?.remoteAddress || opts.req?.headers?.['x-forwarded-for'] || 'unknown',
|
||||
dataSubjectId: opts.customerId,
|
||||
changesAfter: opts.details,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[logChange] Fehler:', error);
|
||||
}
|
||||
}
|
||||
|
||||
export interface CreateAuditLogData {
|
||||
userId?: number;
|
||||
userEmail: string;
|
||||
@@ -101,16 +137,11 @@ function determineSensitivity(resourceType: string): AuditSensitivity {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft ob Änderungen verschlüsselt werden sollen
|
||||
* Prüft ob Änderungen verschlüsselt werden sollen.
|
||||
* Deaktiviert - sensible Felder werden bereits von der Prisma-Middleware als [REDACTED] gefiltert.
|
||||
*/
|
||||
function shouldEncryptChanges(resourceType: string): boolean {
|
||||
const encryptedTypes = [
|
||||
'BankCard',
|
||||
'IdentityDocument',
|
||||
'User',
|
||||
'Customer', // Enthält Portal-Passwörter
|
||||
];
|
||||
return encryptedTypes.includes(resourceType);
|
||||
function shouldEncryptChanges(_resourceType: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -381,6 +412,49 @@ export async function verifyIntegrity(fromId?: number, toId?: number): Promise<{
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash-Kette komplett neu berechnen (Reparatur)
|
||||
*/
|
||||
export async function rehashAll(): Promise<{ rehashedCount: number }> {
|
||||
const logs = await prisma.auditLog.findMany({
|
||||
orderBy: { id: 'asc' },
|
||||
select: {
|
||||
id: true,
|
||||
userEmail: true,
|
||||
action: true,
|
||||
resourceType: true,
|
||||
resourceId: true,
|
||||
endpoint: true,
|
||||
createdAt: true,
|
||||
},
|
||||
});
|
||||
|
||||
let previousHash: string | null = null;
|
||||
let count = 0;
|
||||
|
||||
for (const log of logs) {
|
||||
const hash = generateHash({
|
||||
userEmail: log.userEmail,
|
||||
action: log.action,
|
||||
resourceType: log.resourceType,
|
||||
resourceId: log.resourceId,
|
||||
endpoint: log.endpoint,
|
||||
createdAt: log.createdAt,
|
||||
previousHash,
|
||||
});
|
||||
|
||||
await prisma.auditLog.update({
|
||||
where: { id: log.id },
|
||||
data: { hash, previousHash },
|
||||
});
|
||||
|
||||
previousHash = hash;
|
||||
count++;
|
||||
}
|
||||
|
||||
return { rehashedCount: count };
|
||||
}
|
||||
|
||||
/**
|
||||
* Exportiert Audit-Logs als JSON oder CSV
|
||||
*/
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import prisma from '../lib/prisma.js';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { JwtPayload } from '../types/index.js';
|
||||
import { encrypt, decrypt } from '../utils/encryption.js';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// Mitarbeiter-Login
|
||||
export async function login(email: string, password: string) {
|
||||
const user = await prisma.user.findUnique({
|
||||
|
||||
@@ -4,15 +4,13 @@
|
||||
* Ermöglicht Backup und Restore der Datenbank und Uploads über die Web-Oberfläche.
|
||||
*/
|
||||
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import prisma from '../lib/prisma.js';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import archiver from 'archiver';
|
||||
import AdmZip from 'adm-zip';
|
||||
import bcrypt from 'bcryptjs';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// Verzeichnisse
|
||||
const BACKUPS_DIR = path.join(__dirname, '../../prisma/backups');
|
||||
const UPLOADS_DIR = path.join(process.cwd(), 'uploads');
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
// ==================== CACHED EMAIL SERVICE ====================
|
||||
// Service für E-Mail-Caching und Vertragszuordnung
|
||||
|
||||
import { PrismaClient, CachedEmail, Prisma, EmailFolder } from '@prisma/client';
|
||||
import { CachedEmail, Prisma, EmailFolder } from '@prisma/client';
|
||||
import prisma from '../lib/prisma.js';
|
||||
import { decrypt } from '../utils/encryption.js';
|
||||
import { fetchEmails, ImapCredentials, FetchedEmail, moveToTrash, restoreFromTrash, permanentDelete } from './imapService.js';
|
||||
import { getImapSmtpSettings } from './emailProvider/emailProviderService.js';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// ==================== TYPES ====================
|
||||
|
||||
export interface CachedEmailWithRelations extends CachedEmail {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
import prisma from '../lib/prisma.js';
|
||||
|
||||
export async function getAllCancellationPeriods(includeInactive = false) {
|
||||
const where = includeInactive ? {} : { isActive: true };
|
||||
|
||||
@@ -253,8 +253,8 @@ export const CONSENT_TYPE_LABELS: Record<ConsentType, { label: string; descripti
|
||||
description: 'Grundlegende Verarbeitung personenbezogener Daten zur Vertragserfüllung',
|
||||
},
|
||||
MARKETING_EMAIL: {
|
||||
label: 'E-Mail-Marketing',
|
||||
description: 'Zusendung von Werbung und Angeboten per E-Mail',
|
||||
label: 'Elektronisches Marketing',
|
||||
description: 'Zusendung von Werbung und Angeboten über elektronische Kommunikationswege (E-Mail, Messenger etc.)',
|
||||
},
|
||||
MARKETING_PHONE: {
|
||||
label: 'Telefonmarketing',
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
import prisma from '../lib/prisma.js';
|
||||
|
||||
export async function getAllContractDurations(includeInactive = false) {
|
||||
const where = includeInactive ? {} : { isActive: true };
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { PrismaClient, ContractType, ContractStatus } from '@prisma/client';
|
||||
import { ContractType, ContractStatus } from '@prisma/client';
|
||||
import prisma from '../lib/prisma.js';
|
||||
import { generateContractNumber, paginate, buildPaginationResponse } from '../utils/helpers.js';
|
||||
import { encrypt, decrypt } from '../utils/encryption.js';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export interface ContractFilters {
|
||||
customerId?: number;
|
||||
customerIds?: number[]; // Für Kundenportal: eigene ID + vertretene Kunden
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
import prisma from '../lib/prisma.js';
|
||||
|
||||
export async function getAllContractCategories(includeInactive = false) {
|
||||
return prisma.contractCategory.findMany({
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { PrismaClient, ContractStatus
|
||||
} from '@prisma/client';
|
||||
import { ContractStatus } from '@prisma/client';
|
||||
import prisma from '../lib/prisma.js';
|
||||
import * as appSettingService from './appSetting.service.js';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// Typen für das Cockpit
|
||||
export type UrgencyLevel = 'critical' | 'warning' | 'ok' | 'none';
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
import prisma from '../lib/prisma.js';
|
||||
|
||||
export interface CreateHistoryEntryData {
|
||||
title: string;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { PrismaClient, ContractTaskStatus } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
import { ContractTaskStatus } from '@prisma/client';
|
||||
import prisma from '../lib/prisma.js';
|
||||
|
||||
export interface ContractTaskFilters {
|
||||
contractId: number;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { PrismaClient, CustomerType, ContractStatus } from '@prisma/client';
|
||||
import { CustomerType, ContractStatus } from '@prisma/client';
|
||||
import prisma from '../lib/prisma.js';
|
||||
import { generateCustomerNumber, paginate, buildPaginationResponse } from '../utils/helpers.js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// Helper zum Löschen von Dateien
|
||||
function deleteFileIfExists(filePath: string | null) {
|
||||
if (!filePath) return;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// ==================== EMAIL PROVIDER SERVICE ====================
|
||||
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import prisma from '../../lib/prisma.js';
|
||||
import { decrypt } from '../../utils/encryption.js';
|
||||
import {
|
||||
IEmailProvider,
|
||||
@@ -12,8 +12,6 @@ import {
|
||||
} from './types.js';
|
||||
import { PleskEmailProvider } from './pleskProvider.js';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// Factory-Funktion um den richtigen Provider zu erstellen
|
||||
function createProvider(config: EmailProviderConfig): IEmailProvider {
|
||||
switch (config.type) {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { PrismaClient, InvoiceType } from '@prisma/client';
|
||||
import { InvoiceType } from '@prisma/client';
|
||||
import prisma from '../lib/prisma.js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export interface CreateInvoiceData {
|
||||
invoiceDate: Date;
|
||||
invoiceType: InvoiceType;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
import prisma from '../lib/prisma.js';
|
||||
|
||||
export async function getAllPlatforms(includeInactive = false) {
|
||||
const where = includeInactive ? {} : { isActive: true };
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
import prisma from '../lib/prisma.js';
|
||||
|
||||
export async function getAllProviders(includeInactive = false) {
|
||||
const where = includeInactive ? {} : { isActive: true };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import prisma from '../lib/prisma.js';
|
||||
import { encrypt, decrypt } from '../utils/encryption.js';
|
||||
import {
|
||||
provisionEmail,
|
||||
@@ -10,8 +10,6 @@ import {
|
||||
} from './emailProvider/emailProviderService.js';
|
||||
import { generateSecurePassword } from '../utils/passwordGenerator.js';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export async function getEmailsByCustomerId(customerId: number, includeInactive = false) {
|
||||
const where: Record<string, unknown> = { customerId };
|
||||
if (!includeInactive) {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
import prisma from '../lib/prisma.js';
|
||||
|
||||
export async function getTariffsByProvider(providerId: number, includeInactive = false) {
|
||||
const where: { providerId: number; isActive?: boolean } = { providerId };
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import prisma from '../lib/prisma.js';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import { paginate, buildPaginationResponse } from '../utils/helpers.js';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export interface UserFilters {
|
||||
search?: string;
|
||||
isActive?: boolean;
|
||||
|
||||
Reference in New Issue
Block a user