"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AuditInterceptor = exports.SKIP_AUDIT_KEY = exports.AUDIT_ENTITY_KEY = exports.AUDIT_ACTION_KEY = void 0; exports.AuditActionDecorator = AuditActionDecorator; exports.AuditEntity = AuditEntity; exports.SkipAudit = SkipAudit; const common_1 = require("@nestjs/common"); const rxjs_1 = require("rxjs"); const core_1 = require("@nestjs/core"); const audit_service_1 = require("../services/audit.service"); const audit_log_entity_1 = require("../entities/audit-log.entity"); exports.AUDIT_ACTION_KEY = 'audit_action'; exports.AUDIT_ENTITY_KEY = 'audit_entity'; exports.SKIP_AUDIT_KEY = 'skip_audit'; function AuditActionDecorator(action) { return (target, propertyKey, descriptor) => { Reflect.defineMetadata(exports.AUDIT_ACTION_KEY, action, descriptor.value); return descriptor; }; } function AuditEntity(entityType) { return (target, propertyKey, descriptor) => { Reflect.defineMetadata(exports.AUDIT_ENTITY_KEY, entityType, descriptor.value); return descriptor; }; } function SkipAudit() { return (target, propertyKey, descriptor) => { Reflect.defineMetadata(exports.SKIP_AUDIT_KEY, true, descriptor.value); return descriptor; }; } let AuditInterceptor = class AuditInterceptor { constructor(auditService, reflector) { this.auditService = auditService; this.reflector = reflector; } intercept(context, next) { const request = context.switchToHttp().getRequest(); const handler = context.getHandler(); const startTime = Date.now(); const skipAudit = this.reflector.get(exports.SKIP_AUDIT_KEY, handler); if (skipAudit) { return next.handle(); } const auditAction = this.reflector.get(exports.AUDIT_ACTION_KEY, handler); const entityType = this.reflector.get(exports.AUDIT_ENTITY_KEY, handler); const action = auditAction || this.inferActionFromMethod(request.method); if (!action) { return next.handle(); } return next.handle().pipe((0, rxjs_1.tap)({ next: async (response) => { const duration = Date.now() - startTime; await this.logAudit(request, action, entityType, response, 200, duration); }, error: async (error) => { const duration = Date.now() - startTime; const statusCode = error.status || 500; await this.logAudit(request, action, entityType, null, statusCode, duration); }, })); } inferActionFromMethod(method) { switch (method.toUpperCase()) { case 'POST': return audit_log_entity_1.AuditAction.CREATE; case 'PUT': case 'PATCH': return audit_log_entity_1.AuditAction.UPDATE; case 'DELETE': return audit_log_entity_1.AuditAction.DELETE; case 'GET': return null; default: return null; } } async logAudit(request, action, entityType, response, statusCode, duration) { try { const tenantId = request.user?.tenantId || request.headers['x-tenant-id']; if (!tenantId) { return; } const params = { tenant_id: tenantId, user_id: request.user?.sub || request.user?.id, action, entity_type: entityType || this.inferEntityFromPath(request.path), entity_id: request.params?.id, old_values: request.body?._oldValues, new_values: this.sanitizeBody(request.body), ip_address: this.getClientIp(request), user_agent: request.headers['user-agent'], endpoint: request.path, http_method: request.method, response_status: statusCode, duration_ms: duration, metadata: { query: request.query, response_id: response?.id, }, }; await this.auditService.createAuditLog(params); } catch (error) { console.error('Failed to create audit log:', error); } } inferEntityFromPath(path) { const segments = path.split('/').filter(Boolean); const apiIndex = segments.findIndex((s) => s === 'api'); if (apiIndex !== -1 && segments.length > apiIndex + 2) { return segments[apiIndex + 2]; } return segments[segments.length - 1] || 'unknown'; } sanitizeBody(body) { if (!body) return undefined; const sanitized = { ...body }; const sensitiveFields = ['password', 'token', 'secret', 'creditCard', 'cvv', '_oldValues']; for (const field of sensitiveFields) { if (field in sanitized) { sanitized[field] = '[REDACTED]'; } } return sanitized; } getClientIp(request) { return (request.headers['x-forwarded-for']?.split(',')[0]?.trim() || request.headers['x-real-ip'] || request.connection?.remoteAddress || request.ip || 'unknown'); } }; exports.AuditInterceptor = AuditInterceptor; exports.AuditInterceptor = AuditInterceptor = __decorate([ (0, common_1.Injectable)(), __metadata("design:paramtypes", [audit_service_1.AuditService, core_1.Reflector]) ], AuditInterceptor); //# sourceMappingURL=audit.interceptor.js.map