64 lines
1.8 KiB
TypeScript
64 lines
1.8 KiB
TypeScript
import {
|
|
Injectable,
|
|
NestInterceptor,
|
|
ExecutionContext,
|
|
CallHandler,
|
|
Logger,
|
|
} from '@nestjs/common';
|
|
import { Observable } from 'rxjs';
|
|
import { tap } from 'rxjs/operators';
|
|
|
|
@Injectable()
|
|
export class AuditLogInterceptor implements NestInterceptor {
|
|
private readonly logger = new Logger(AuditLogInterceptor.name);
|
|
|
|
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
const request = context.switchToHttp().getRequest();
|
|
const { method, url, body } = request;
|
|
const sourceService = request.sourceService || 'unknown';
|
|
const sourceIp = request.sourceIp || 'unknown';
|
|
|
|
const startTime = Date.now();
|
|
|
|
// Log sensitive fields redacted
|
|
const sanitizedBody = this.sanitizeBody(body);
|
|
|
|
this.logger.log(
|
|
`[${sourceService}] ${method} ${url} - Request from ${sourceIp}`,
|
|
);
|
|
this.logger.debug(`Request body: ${JSON.stringify(sanitizedBody)}`);
|
|
|
|
return next.handle().pipe(
|
|
tap({
|
|
next: (response) => {
|
|
const duration = Date.now() - startTime;
|
|
this.logger.log(
|
|
`[${sourceService}] ${method} ${url} - Response ${duration}ms - Success`,
|
|
);
|
|
},
|
|
error: (error) => {
|
|
const duration = Date.now() - startTime;
|
|
this.logger.error(
|
|
`[${sourceService}] ${method} ${url} - Response ${duration}ms - Error: ${error.message}`,
|
|
);
|
|
},
|
|
}),
|
|
);
|
|
}
|
|
|
|
private sanitizeBody(body: any): any {
|
|
if (!body) return body;
|
|
|
|
const sanitized = { ...body };
|
|
const sensitiveFields = ['encryptedShareData', 'recoveryToken', 'password', 'secret'];
|
|
|
|
for (const field of sensitiveFields) {
|
|
if (sanitized[field]) {
|
|
sanitized[field] = '[REDACTED]';
|
|
}
|
|
}
|
|
|
|
return sanitized;
|
|
}
|
|
}
|