diff --git a/src/common/interceptors/audit.interceptor.spec.ts b/src/common/interceptors/audit.interceptor.spec.ts index 5f4aa39c..17f762df 100644 --- a/src/common/interceptors/audit.interceptor.spec.ts +++ b/src/common/interceptors/audit.interceptor.spec.ts @@ -137,10 +137,10 @@ describe('AuditInterceptor', () => { it('should handle forwarded IP from x-forwarded-for header', async () => { const ctx = buildMockContext(); - const req = (ctx.switchToHttp() as ReturnType) - .getRequest() as ReturnType extends { getRequest(): infer R } ? R : never; - (req as unknown as { headers: Record }).headers['x-forwarded-for'] = - '10.0.0.1, 10.0.0.2'; + const req = (ctx.switchToHttp() as ReturnType)[ + 'getRequest' + ]() as Record & { headers: Record }; + req.headers['x-forwarded-for'] = '10.0.0.1, 10.0.0.2'; const next = buildCallHandler(); await interceptor.intercept(ctx, next).toPromise(); diff --git a/src/common/interceptors/audit.interceptor.ts b/src/common/interceptors/audit.interceptor.ts index f6cb234f..a8c5622d 100644 --- a/src/common/interceptors/audit.interceptor.ts +++ b/src/common/interceptors/audit.interceptor.ts @@ -40,6 +40,7 @@ const EXCLUDED_META_KEYS = new Set(['password', 'token', 'authorization', 'x-api * * Routes decorated with @SkipAudit() are excluded. */ + @Injectable() export class AuditInterceptor implements NestInterceptor { private readonly logger = new Logger(AuditInterceptor.name); @@ -82,38 +83,14 @@ export class AuditInterceptor implements NestInterceptor { const startTime = Date.now(); - return next.handle().pipe( - tap({ - next: () => { - const durationMs = Date.now() - startTime; - this.persistAuditLog({ - organizationId, - userId, - agentId, - action: customAction, - method, - url: originalUrl, - statusCode: res.statusCode, - ipAddress, - userAgent, - requestId, - body: sanitizedBody, - params: sanitizedParams, - query: sanitizedQuery, - durationMs, - }).catch((err) => { - this.logger.error( - `Failed to persist audit log for ${method} ${originalUrl}: ${(err as Error).message}`, - ); - }); - }, - error: () => { + const recordLog = () => { const durationMs = Date.now() - startTime; + const action = customAction ?? `${method} ${originalUrl}`; this.persistAuditLog({ organizationId, userId, agentId, - action: customAction, + action, method, url: originalUrl, statusCode: res.statusCode, @@ -129,7 +106,12 @@ export class AuditInterceptor implements NestInterceptor { `Failed to persist audit log for ${method} ${originalUrl}: ${(err as Error).message}`, ); }); - }, + }; + + return next.handle().pipe( + tap({ + next: () => recordLog(), + error: () => recordLog(), }), ); } @@ -169,7 +151,7 @@ export class AuditInterceptor implements NestInterceptor { organizationId: string | null; userId: string | null; agentId: string | null; - action: string | undefined; + action: string; method: string; url: string; statusCode: number; @@ -188,7 +170,7 @@ export class AuditInterceptor implements NestInterceptor { await this.auditService.record({ organizationId: data.organizationId, userId: data.userId, - action: data.action ?? `${data.method} ${data.url}`, + action: data.action, entity: 'http', entityId: null, newValue: {