Files
mpm/apps/platform-backend/src/audit/audit.service.ts
2026-10-08 21:13:57 +02:00

72 lines
2.2 KiB
TypeScript

import { Injectable, Logger } from '@nestjs/common';
import { DatabaseService } from '../database/database.service';
/** Definierte Audit-Aktionen der Plattform. */
export const AUDIT_ACTIONS = {
LOGIN_SUCCESS: 'LOGIN_SUCCESS',
LOGIN_FAILED: 'LOGIN_FAILED',
LOGIN_LOCKED: 'LOGIN_FAILED_LOCKED',
LOGOUT: 'LOGOUT',
USER_CREATED: 'USER_CREATED',
USER_UPDATED: 'USER_UPDATED',
USER_ENABLED: 'USER_ENABLED',
USER_DISABLED: 'USER_DISABLED',
USER_DELETED: 'USER_DELETED',
USER_PASSWORD_RESET: 'USER_PASSWORD_RESET',
USER_PASSWORD_CHANGED: 'USER_PASSWORD_CHANGED',
MODULE_INSTALLED: 'MODULE_INSTALLED',
MODULE_UPDATED: 'MODULE_UPDATED',
MODULE_REMOVED: 'MODULE_REMOVED',
MODULE_STARTED: 'MODULE_STARTED',
MODULE_STOPPED: 'MODULE_STOPPED',
MODULE_RESTARTED: 'MODULE_RESTARTED',
MODULE_CONFIG_UPDATED: 'MODULE_CONFIG_UPDATED',
MODULE_ENABLED: 'MODULE_ENABLED',
MODULE_DISABLED: 'MODULE_DISABLED',
PERMISSION_GRANTED: 'PERMISSION_GRANTED',
PERMISSION_REVOKED: 'PERMISSION_REVOKED',
SETTINGS_CHANGED: 'SETTINGS_CHANGED',
} as const;
export type AuditAction = (typeof AUDIT_ACTIONS)[keyof typeof AUDIT_ACTIONS];
/**
* Zentrales Audit-Logging: Sicherheitsrelevante Ereignisse werden
* nachvollziehbar aufgezeichnet. Es werden niemals Passwörter,
* Tokens oder personenbezogene Daten geloggt.
*/
@Injectable()
export class AuditService {
private readonly logger = new Logger('Audit');
constructor(private readonly database: DatabaseService) {}
async record(input: {
userId: string | null;
username: string;
action: AuditAction;
details?: Record<string, unknown>;
ipAddress?: string | null;
}): Promise<void> {
try {
await this.database.query(
`INSERT INTO audit_logs (user_id, username, action, details, ip_address)
VALUES ($1, $2, $3, $4::jsonb, $5)`,
[
input.userId,
input.username,
input.action,
JSON.stringify(input.details ?? {}),
input.ipAddress ?? null,
],
);
} catch (error) {
// Audit-Fehler dürfen den eigentlichen Request niemals blockieren.
this.logger.error(
`Audit-Log fehlgeschlagen (${input.action})`,
error instanceof Error ? error.stack : String(error),
);
}
}
}