@pawells/nestjs-shared 1.0.0-dev.4c8c698
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +802 -0
- package/build/LICENSE +21 -0
- package/build/README.md +802 -0
- package/build/common/common.module.d.ts +49 -0
- package/build/common/common.module.d.ts.map +1 -0
- package/build/common/common.module.js +178 -0
- package/build/common/common.module.js.map +1 -0
- package/build/common/constants/histogram-buckets.constants.d.ts +12 -0
- package/build/common/constants/histogram-buckets.constants.d.ts.map +1 -0
- package/build/common/constants/histogram-buckets.constants.js +51 -0
- package/build/common/constants/histogram-buckets.constants.js.map +1 -0
- package/build/common/constants/http-status.constants.d.ts +27 -0
- package/build/common/constants/http-status.constants.d.ts.map +1 -0
- package/build/common/constants/http-status.constants.js +27 -0
- package/build/common/constants/http-status.constants.js.map +1 -0
- package/build/common/constants/timeout.constants.d.ts +29 -0
- package/build/common/constants/timeout.constants.d.ts.map +1 -0
- package/build/common/constants/timeout.constants.js +45 -0
- package/build/common/constants/timeout.constants.js.map +1 -0
- package/build/common/controllers/metrics.controller.d.ts +23 -0
- package/build/common/controllers/metrics.controller.d.ts.map +1 -0
- package/build/common/controllers/metrics.controller.js +66 -0
- package/build/common/controllers/metrics.controller.js.map +1 -0
- package/build/common/decorators/common-decorators.d.ts +90 -0
- package/build/common/decorators/common-decorators.d.ts.map +1 -0
- package/build/common/decorators/common-decorators.js +101 -0
- package/build/common/decorators/common-decorators.js.map +1 -0
- package/build/common/decorators/decorator-factory.d.ts +108 -0
- package/build/common/decorators/decorator-factory.d.ts.map +1 -0
- package/build/common/decorators/decorator-factory.js +104 -0
- package/build/common/decorators/decorator-factory.js.map +1 -0
- package/build/common/decorators/guard.decorators.d.ts +48 -0
- package/build/common/decorators/guard.decorators.d.ts.map +1 -0
- package/build/common/decorators/guard.decorators.js +49 -0
- package/build/common/decorators/guard.decorators.js.map +1 -0
- package/build/common/decorators/index.d.ts +10 -0
- package/build/common/decorators/index.d.ts.map +1 -0
- package/build/common/decorators/index.js +11 -0
- package/build/common/decorators/index.js.map +1 -0
- package/build/common/decorators/instrument.decorator.d.ts +128 -0
- package/build/common/decorators/instrument.decorator.d.ts.map +1 -0
- package/build/common/decorators/instrument.decorator.js +165 -0
- package/build/common/decorators/instrument.decorator.js.map +1 -0
- package/build/common/decorators/metric.decorators.d.ts +42 -0
- package/build/common/decorators/metric.decorators.d.ts.map +1 -0
- package/build/common/decorators/metric.decorators.js +85 -0
- package/build/common/decorators/metric.decorators.js.map +1 -0
- package/build/common/decorators/request-property.decorator.d.ts +65 -0
- package/build/common/decorators/request-property.decorator.d.ts.map +1 -0
- package/build/common/decorators/request-property.decorator.js +102 -0
- package/build/common/decorators/request-property.decorator.js.map +1 -0
- package/build/common/errors/base-application-error.d.ts +98 -0
- package/build/common/errors/base-application-error.d.ts.map +1 -0
- package/build/common/errors/base-application-error.js +133 -0
- package/build/common/errors/base-application-error.js.map +1 -0
- package/build/common/errors/error-factory.d.ts +93 -0
- package/build/common/errors/error-factory.d.ts.map +1 -0
- package/build/common/errors/error-factory.js +105 -0
- package/build/common/errors/error-factory.js.map +1 -0
- package/build/common/errors/index.d.ts +13 -0
- package/build/common/errors/index.d.ts.map +1 -0
- package/build/common/errors/index.js +15 -0
- package/build/common/errors/index.js.map +1 -0
- package/build/common/factories/index.d.ts +5 -0
- package/build/common/factories/index.d.ts.map +1 -0
- package/build/common/factories/index.js +3 -0
- package/build/common/factories/index.js.map +1 -0
- package/build/common/factories/module-factory.d.ts +178 -0
- package/build/common/factories/module-factory.d.ts.map +1 -0
- package/build/common/factories/module-factory.js +253 -0
- package/build/common/factories/module-factory.js.map +1 -0
- package/build/common/factories/rate-limit-config.factory.d.ts +79 -0
- package/build/common/factories/rate-limit-config.factory.d.ts.map +1 -0
- package/build/common/factories/rate-limit-config.factory.js +115 -0
- package/build/common/factories/rate-limit-config.factory.js.map +1 -0
- package/build/common/factories/security-bootstrap.factory.d.ts +77 -0
- package/build/common/factories/security-bootstrap.factory.d.ts.map +1 -0
- package/build/common/factories/security-bootstrap.factory.js +222 -0
- package/build/common/factories/security-bootstrap.factory.js.map +1 -0
- package/build/common/filters/global-exception.filter.d.ts +78 -0
- package/build/common/filters/global-exception.filter.d.ts.map +1 -0
- package/build/common/filters/global-exception.filter.js +192 -0
- package/build/common/filters/global-exception.filter.js.map +1 -0
- package/build/common/filters/http-exception.filter.d.ts +37 -0
- package/build/common/filters/http-exception.filter.d.ts.map +1 -0
- package/build/common/filters/http-exception.filter.js +91 -0
- package/build/common/filters/http-exception.filter.js.map +1 -0
- package/build/common/guards/csrf.guard.d.ts +53 -0
- package/build/common/guards/csrf.guard.d.ts.map +1 -0
- package/build/common/guards/csrf.guard.js +109 -0
- package/build/common/guards/csrf.guard.js.map +1 -0
- package/build/common/guards/metrics.guard.d.ts +42 -0
- package/build/common/guards/metrics.guard.d.ts.map +1 -0
- package/build/common/guards/metrics.guard.js +124 -0
- package/build/common/guards/metrics.guard.js.map +1 -0
- package/build/common/index.d.ts +43 -0
- package/build/common/index.d.ts.map +1 -0
- package/build/common/index.js +50 -0
- package/build/common/index.js.map +1 -0
- package/build/common/interceptors/http-client.interceptor.d.ts +11 -0
- package/build/common/interceptors/http-client.interceptor.d.ts.map +1 -0
- package/build/common/interceptors/http-client.interceptor.js +69 -0
- package/build/common/interceptors/http-client.interceptor.js.map +1 -0
- package/build/common/interceptors/http-instrumentation.interceptor.d.ts +64 -0
- package/build/common/interceptors/http-instrumentation.interceptor.d.ts.map +1 -0
- package/build/common/interceptors/http-instrumentation.interceptor.js +148 -0
- package/build/common/interceptors/http-instrumentation.interceptor.js.map +1 -0
- package/build/common/interceptors/http-metrics.interceptor.d.ts +46 -0
- package/build/common/interceptors/http-metrics.interceptor.d.ts.map +1 -0
- package/build/common/interceptors/http-metrics.interceptor.js +120 -0
- package/build/common/interceptors/http-metrics.interceptor.js.map +1 -0
- package/build/common/interceptors/logging.interceptor.d.ts +22 -0
- package/build/common/interceptors/logging.interceptor.d.ts.map +1 -0
- package/build/common/interceptors/logging.interceptor.js +67 -0
- package/build/common/interceptors/logging.interceptor.js.map +1 -0
- package/build/common/interfaces/cache-provider.interface.d.ts +54 -0
- package/build/common/interfaces/cache-provider.interface.d.ts.map +1 -0
- package/build/common/interfaces/cache-provider.interface.js +6 -0
- package/build/common/interfaces/cache-provider.interface.js.map +1 -0
- package/build/common/interfaces/index.d.ts +7 -0
- package/build/common/interfaces/index.d.ts.map +1 -0
- package/build/common/interfaces/index.js +3 -0
- package/build/common/interfaces/index.js.map +1 -0
- package/build/common/interfaces/log-context.interface.d.ts +77 -0
- package/build/common/interfaces/log-context.interface.d.ts.map +1 -0
- package/build/common/interfaces/log-context.interface.js +2 -0
- package/build/common/interfaces/log-context.interface.js.map +1 -0
- package/build/common/interfaces/log-entry.interface.d.ts +26 -0
- package/build/common/interfaces/log-entry.interface.d.ts.map +1 -0
- package/build/common/interfaces/log-entry.interface.js +33 -0
- package/build/common/interfaces/log-entry.interface.js.map +1 -0
- package/build/common/interfaces/logger.interface.d.ts +62 -0
- package/build/common/interfaces/logger.interface.d.ts.map +1 -0
- package/build/common/interfaces/logger.interface.js +2 -0
- package/build/common/interfaces/logger.interface.js.map +1 -0
- package/build/common/interfaces/metrics-exporter.interface.d.ts +275 -0
- package/build/common/interfaces/metrics-exporter.interface.d.ts.map +1 -0
- package/build/common/interfaces/metrics-exporter.interface.js +8 -0
- package/build/common/interfaces/metrics-exporter.interface.js.map +1 -0
- package/build/common/metrics/base-metrics-collector.d.ts +81 -0
- package/build/common/metrics/base-metrics-collector.d.ts.map +1 -0
- package/build/common/metrics/base-metrics-collector.js +88 -0
- package/build/common/metrics/base-metrics-collector.js.map +1 -0
- package/build/common/metrics/index.d.ts +2 -0
- package/build/common/metrics/index.d.ts.map +1 -0
- package/build/common/metrics/index.js +2 -0
- package/build/common/metrics/index.js.map +1 -0
- package/build/common/metrics.module.d.ts +50 -0
- package/build/common/metrics.module.d.ts.map +1 -0
- package/build/common/metrics.module.js +77 -0
- package/build/common/metrics.module.js.map +1 -0
- package/build/common/modules/throttler.module.d.ts +69 -0
- package/build/common/modules/throttler.module.d.ts.map +1 -0
- package/build/common/modules/throttler.module.js +117 -0
- package/build/common/modules/throttler.module.js.map +1 -0
- package/build/common/pipes/base-validation.pipe.d.ts +67 -0
- package/build/common/pipes/base-validation.pipe.d.ts.map +1 -0
- package/build/common/pipes/base-validation.pipe.js +95 -0
- package/build/common/pipes/base-validation.pipe.js.map +1 -0
- package/build/common/pipes/validation.pipe.d.ts +32 -0
- package/build/common/pipes/validation.pipe.d.ts.map +1 -0
- package/build/common/pipes/validation.pipe.js +60 -0
- package/build/common/pipes/validation.pipe.js.map +1 -0
- package/build/common/registry/instrumentation-registry.d.ts +227 -0
- package/build/common/registry/instrumentation-registry.d.ts.map +1 -0
- package/build/common/registry/instrumentation-registry.js +414 -0
- package/build/common/registry/instrumentation-registry.js.map +1 -0
- package/build/common/services/audit-logger.service.d.ts +91 -0
- package/build/common/services/audit-logger.service.d.ts.map +1 -0
- package/build/common/services/audit-logger.service.js +180 -0
- package/build/common/services/audit-logger.service.js.map +1 -0
- package/build/common/services/csrf.service.d.ts +202 -0
- package/build/common/services/csrf.service.d.ts.map +1 -0
- package/build/common/services/csrf.service.js +478 -0
- package/build/common/services/csrf.service.js.map +1 -0
- package/build/common/services/error-categorizer.service.d.ts +82 -0
- package/build/common/services/error-categorizer.service.d.ts.map +1 -0
- package/build/common/services/error-categorizer.service.js +339 -0
- package/build/common/services/error-categorizer.service.js.map +1 -0
- package/build/common/services/error-sanitizer.service.d.ts +146 -0
- package/build/common/services/error-sanitizer.service.d.ts.map +1 -0
- package/build/common/services/error-sanitizer.service.js +287 -0
- package/build/common/services/error-sanitizer.service.js.map +1 -0
- package/build/common/services/health-check.service.d.ts +86 -0
- package/build/common/services/health-check.service.d.ts.map +1 -0
- package/build/common/services/health-check.service.js +132 -0
- package/build/common/services/health-check.service.js.map +1 -0
- package/build/common/services/http-client.service.d.ts +113 -0
- package/build/common/services/http-client.service.d.ts.map +1 -0
- package/build/common/services/http-client.service.js +294 -0
- package/build/common/services/http-client.service.js.map +1 -0
- package/build/common/services/logger.service.d.ts +189 -0
- package/build/common/services/logger.service.d.ts.map +1 -0
- package/build/common/services/logger.service.js +423 -0
- package/build/common/services/logger.service.js.map +1 -0
- package/build/common/services/metrics-registry.service.d.ts +98 -0
- package/build/common/services/metrics-registry.service.d.ts.map +1 -0
- package/build/common/services/metrics-registry.service.js +262 -0
- package/build/common/services/metrics-registry.service.js.map +1 -0
- package/build/common/services/nest-logger-adapter.service.d.ts +62 -0
- package/build/common/services/nest-logger-adapter.service.d.ts.map +1 -0
- package/build/common/services/nest-logger-adapter.service.js +120 -0
- package/build/common/services/nest-logger-adapter.service.js.map +1 -0
- package/build/common/utils/error.utils.d.ts +16 -0
- package/build/common/utils/error.utils.d.ts.map +1 -0
- package/build/common/utils/error.utils.js +26 -0
- package/build/common/utils/error.utils.js.map +1 -0
- package/build/common/utils/lazy-getter.types.d.ts +190 -0
- package/build/common/utils/lazy-getter.types.d.ts.map +1 -0
- package/build/common/utils/lazy-getter.types.js +114 -0
- package/build/common/utils/lazy-getter.types.js.map +1 -0
- package/build/common/utils/module.utils.d.ts +33 -0
- package/build/common/utils/module.utils.d.ts.map +1 -0
- package/build/common/utils/module.utils.js +48 -0
- package/build/common/utils/module.utils.js.map +1 -0
- package/build/common/utils/sanitization.utils.d.ts +69 -0
- package/build/common/utils/sanitization.utils.d.ts.map +1 -0
- package/build/common/utils/sanitization.utils.js +141 -0
- package/build/common/utils/sanitization.utils.js.map +1 -0
- package/build/config/config.module.d.ts +30 -0
- package/build/config/config.module.d.ts.map +1 -0
- package/build/config/config.module.js +49 -0
- package/build/config/config.module.js.map +1 -0
- package/build/config/config.service.d.ts +74 -0
- package/build/config/config.service.d.ts.map +1 -0
- package/build/config/config.service.js +145 -0
- package/build/config/config.service.js.map +1 -0
- package/build/config/config.types.d.ts +143 -0
- package/build/config/config.types.d.ts.map +1 -0
- package/build/config/config.types.js +2 -0
- package/build/config/config.types.js.map +1 -0
- package/build/config/decorators/config.decorators.d.ts +43 -0
- package/build/config/decorators/config.decorators.d.ts.map +1 -0
- package/build/config/decorators/config.decorators.js +68 -0
- package/build/config/decorators/config.decorators.js.map +1 -0
- package/build/config/decorators/index.d.ts +2 -0
- package/build/config/decorators/index.d.ts.map +1 -0
- package/build/config/decorators/index.js +2 -0
- package/build/config/decorators/index.js.map +1 -0
- package/build/config/index.d.ts +7 -0
- package/build/config/index.d.ts.map +1 -0
- package/build/config/index.js +9 -0
- package/build/config/index.js.map +1 -0
- package/build/config/validation.utils.d.ts +136 -0
- package/build/config/validation.utils.d.ts.map +1 -0
- package/build/config/validation.utils.js +263 -0
- package/build/config/validation.utils.js.map +1 -0
- package/build/errors/index.d.ts +9 -0
- package/build/errors/index.d.ts.map +1 -0
- package/build/errors/index.js +12 -0
- package/build/errors/index.js.map +1 -0
- package/build/guards/custom-throttle.guard.d.ts +28 -0
- package/build/guards/custom-throttle.guard.d.ts.map +1 -0
- package/build/guards/custom-throttle.guard.js +52 -0
- package/build/guards/custom-throttle.guard.js.map +1 -0
- package/build/guards/index.d.ts +2 -0
- package/build/guards/index.d.ts.map +1 -0
- package/build/guards/index.js +2 -0
- package/build/guards/index.js.map +1 -0
- package/build/index.d.ts +53 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +61 -0
- package/build/index.js.map +1 -0
- package/build/logging/index.d.ts +7 -0
- package/build/logging/index.d.ts.map +1 -0
- package/build/logging/index.js +7 -0
- package/build/logging/index.js.map +1 -0
- package/build/metrics/index.d.ts +6 -0
- package/build/metrics/index.d.ts.map +1 -0
- package/build/metrics/index.js +11 -0
- package/build/metrics/index.js.map +1 -0
- package/build/package.json +72 -0
- package/build/security/index.d.ts +8 -0
- package/build/security/index.d.ts.map +1 -0
- package/build/security/index.js +11 -0
- package/build/security/index.js.map +1 -0
- package/build/test-setup.d.ts +2 -0
- package/build/test-setup.d.ts.map +1 -0
- package/build/test-setup.js +40 -0
- package/build/test-setup.js.map +1 -0
- package/build/validation/index.d.ts +6 -0
- package/build/validation/index.d.ts.map +1 -0
- package/build/validation/index.js +8 -0
- package/build/validation/index.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ModuleRef } from '@nestjs/core';
|
|
2
|
+
import { LazyModuleRefService } from '../utils/lazy-getter.types.js';
|
|
3
|
+
import { AppLogger } from './logger.service.js';
|
|
4
|
+
/**
|
|
5
|
+
* Audit log entry for security events.
|
|
6
|
+
*/
|
|
7
|
+
export interface AuditLogEntry {
|
|
8
|
+
timestamp: Date;
|
|
9
|
+
userId?: string;
|
|
10
|
+
action: string;
|
|
11
|
+
resource: string;
|
|
12
|
+
result: 'success' | 'failure';
|
|
13
|
+
details?: Record<string, any>;
|
|
14
|
+
ipAddress?: string;
|
|
15
|
+
userAgent?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Audit Logger Service.
|
|
19
|
+
* Specialized logging for security-related events: authentication, authorization, token operations,
|
|
20
|
+
* CSRF violations, rate limiting, and configuration changes.
|
|
21
|
+
*
|
|
22
|
+
* All audit events are logged at INFO level (or WARN for failures) with structured JSON data
|
|
23
|
+
* for easy parsing by log aggregation systems (Loki, Splunk, etc.).
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* - Automatically redacts sensitive fields (passwords, tokens) via AppLogger
|
|
27
|
+
* - All events include ISO timestamps and structured event data
|
|
28
|
+
* - Integrates with log aggregation for compliance and forensics
|
|
29
|
+
* - Available globally via CommonModule
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* // Log authentication attempt
|
|
34
|
+
* auditLogger.logAuthenticationAttempt('user@example.com', true, '192.168.1.1');
|
|
35
|
+
*
|
|
36
|
+
* // Log CSRF violation
|
|
37
|
+
* auditLogger.logCsrfViolation('192.168.1.1', '/api/users');
|
|
38
|
+
*
|
|
39
|
+
* // Log custom security event
|
|
40
|
+
* auditLogger.logSecurityEvent({
|
|
41
|
+
* userId: 'user-123',
|
|
42
|
+
* action: 'delete_user',
|
|
43
|
+
* resource: 'users/456',
|
|
44
|
+
* result: 'failure',
|
|
45
|
+
* ipAddress: '192.168.1.1'
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare class AuditLoggerService implements LazyModuleRefService {
|
|
50
|
+
private _contextualLogger;
|
|
51
|
+
readonly Module: ModuleRef;
|
|
52
|
+
constructor(module: ModuleRef);
|
|
53
|
+
get Logger(): AppLogger;
|
|
54
|
+
/**
|
|
55
|
+
* Log authentication attempt
|
|
56
|
+
*/
|
|
57
|
+
logAuthenticationAttempt(email: string, success: boolean, ipAddress?: string, reason?: string): void;
|
|
58
|
+
/**
|
|
59
|
+
* Log authorization failure
|
|
60
|
+
*/
|
|
61
|
+
logAuthorizationFailure(userId: string, resource: string, action: string, ipAddress?: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* Log token generation
|
|
64
|
+
*/
|
|
65
|
+
logTokenGeneration(userId: string, tokenType: 'access' | 'refresh'): void;
|
|
66
|
+
/**
|
|
67
|
+
* Log token revocation
|
|
68
|
+
*/
|
|
69
|
+
logTokenRevocation(userId: string, reason: string): void;
|
|
70
|
+
/**
|
|
71
|
+
* Log rate limit violation
|
|
72
|
+
*/
|
|
73
|
+
logRateLimitViolation(endpoint: string, ipAddress: string, limit: number): void;
|
|
74
|
+
/**
|
|
75
|
+
* Log CSRF violation
|
|
76
|
+
*/
|
|
77
|
+
logCsrfViolation(ipAddress: string, endpoint: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* Log security configuration change
|
|
80
|
+
*/
|
|
81
|
+
logConfigurationChange(userId: string, config: string, oldValue: any, newValue: any): void;
|
|
82
|
+
/**
|
|
83
|
+
* Log data access
|
|
84
|
+
*/
|
|
85
|
+
logDataAccess(userId: string, resource: string, action: string): void;
|
|
86
|
+
/**
|
|
87
|
+
* Log security event
|
|
88
|
+
*/
|
|
89
|
+
logSecurityEvent(entry: AuditLogEntry): void;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=audit-logger.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-logger.service.d.ts","sourceRoot":"","sources":["../../../src/common/services/audit-logger.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBACa,kBAAmB,YAAW,oBAAoB;IAC9D,OAAO,CAAC,iBAAiB,CAAwB;IAEjD,SAAgB,MAAM,EAAE,SAAS,CAAC;gBAEtB,MAAM,EAAE,SAAS;IAI7B,IAAW,MAAM,IAAI,SAAS,CAM7B;IAED;;OAEG;IACI,wBAAwB,CAC9B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,GACb,IAAI;IAeP;;OAEG;IACI,uBAAuB,CAC7B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,GAChB,IAAI;IAeP;;OAEG;IACI,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI;IAahF;;OAEG;IACI,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAa/D;;OAEG;IACI,qBAAqB,CAC3B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACX,IAAI;IAcP;;OAEG;IACI,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAalE;;OAEG;IACI,sBAAsB,CAC5B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,GAAG,EACb,QAAQ,EAAE,GAAG,GACX,IAAI;IAeP;;OAEG;IACI,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAc5E;;OAEG;IACI,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;CAUnD"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var AuditLoggerService_1;
|
|
11
|
+
import { Injectable } from '@nestjs/common';
|
|
12
|
+
import { ModuleRef } from '@nestjs/core';
|
|
13
|
+
import { AppLogger } from './logger.service.js';
|
|
14
|
+
import { escapeNewlines } from '../utils/sanitization.utils.js';
|
|
15
|
+
/**
|
|
16
|
+
* Audit Logger Service.
|
|
17
|
+
* Specialized logging for security-related events: authentication, authorization, token operations,
|
|
18
|
+
* CSRF violations, rate limiting, and configuration changes.
|
|
19
|
+
*
|
|
20
|
+
* All audit events are logged at INFO level (or WARN for failures) with structured JSON data
|
|
21
|
+
* for easy parsing by log aggregation systems (Loki, Splunk, etc.).
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* - Automatically redacts sensitive fields (passwords, tokens) via AppLogger
|
|
25
|
+
* - All events include ISO timestamps and structured event data
|
|
26
|
+
* - Integrates with log aggregation for compliance and forensics
|
|
27
|
+
* - Available globally via CommonModule
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* // Log authentication attempt
|
|
32
|
+
* auditLogger.logAuthenticationAttempt('user@example.com', true, '192.168.1.1');
|
|
33
|
+
*
|
|
34
|
+
* // Log CSRF violation
|
|
35
|
+
* auditLogger.logCsrfViolation('192.168.1.1', '/api/users');
|
|
36
|
+
*
|
|
37
|
+
* // Log custom security event
|
|
38
|
+
* auditLogger.logSecurityEvent({
|
|
39
|
+
* userId: 'user-123',
|
|
40
|
+
* action: 'delete_user',
|
|
41
|
+
* resource: 'users/456',
|
|
42
|
+
* result: 'failure',
|
|
43
|
+
* ipAddress: '192.168.1.1'
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
let AuditLoggerService = AuditLoggerService_1 = class AuditLoggerService {
|
|
48
|
+
_contextualLogger;
|
|
49
|
+
Module;
|
|
50
|
+
constructor(module) {
|
|
51
|
+
this.Module = module;
|
|
52
|
+
}
|
|
53
|
+
get Logger() {
|
|
54
|
+
if (!this._contextualLogger) {
|
|
55
|
+
const baseLogger = this.Module.get(AppLogger);
|
|
56
|
+
this._contextualLogger = baseLogger.createContextualLogger(AuditLoggerService_1.name);
|
|
57
|
+
}
|
|
58
|
+
return this._contextualLogger;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Log authentication attempt
|
|
62
|
+
*/
|
|
63
|
+
logAuthenticationAttempt(email, success, ipAddress, reason) {
|
|
64
|
+
const auditData = {
|
|
65
|
+
event: 'authentication',
|
|
66
|
+
email,
|
|
67
|
+
success,
|
|
68
|
+
ipAddress,
|
|
69
|
+
reason,
|
|
70
|
+
timestamp: new Date().toISOString(),
|
|
71
|
+
};
|
|
72
|
+
this.Logger.info(`Authentication ${success ? 'SUCCESS' : 'FAILURE'}: ${escapeNewlines(email)}${reason ? ` - ${escapeNewlines(reason)}` : ''} | ${JSON.stringify(auditData)}`, 'AuditLogger');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Log authorization failure
|
|
76
|
+
*/
|
|
77
|
+
logAuthorizationFailure(userId, resource, action, ipAddress) {
|
|
78
|
+
const auditData = {
|
|
79
|
+
event: 'authorization_failure',
|
|
80
|
+
userId,
|
|
81
|
+
resource,
|
|
82
|
+
action,
|
|
83
|
+
ipAddress,
|
|
84
|
+
timestamp: new Date().toISOString(),
|
|
85
|
+
};
|
|
86
|
+
this.Logger.warn(`Authorization FAILURE: User ${escapeNewlines(userId)} attempted ${escapeNewlines(action)} on ${escapeNewlines(resource)} | ${JSON.stringify(auditData)}`, 'AuditLogger');
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Log token generation
|
|
90
|
+
*/
|
|
91
|
+
logTokenGeneration(userId, tokenType) {
|
|
92
|
+
const auditData = {
|
|
93
|
+
event: 'token_generation',
|
|
94
|
+
userId,
|
|
95
|
+
tokenType,
|
|
96
|
+
timestamp: new Date().toISOString(),
|
|
97
|
+
};
|
|
98
|
+
this.Logger.info(`Token GENERATED: ${tokenType} token for user ${escapeNewlines(userId)} | ${JSON.stringify(auditData)}`, 'AuditLogger');
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Log token revocation
|
|
102
|
+
*/
|
|
103
|
+
logTokenRevocation(userId, reason) {
|
|
104
|
+
const auditData = {
|
|
105
|
+
event: 'token_revocation',
|
|
106
|
+
userId,
|
|
107
|
+
reason,
|
|
108
|
+
timestamp: new Date().toISOString(),
|
|
109
|
+
};
|
|
110
|
+
this.Logger.info(`Token REVOCATION: User ${escapeNewlines(userId)} - ${escapeNewlines(reason)} | ${JSON.stringify(auditData)}`, 'AuditLogger');
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Log rate limit violation
|
|
114
|
+
*/
|
|
115
|
+
logRateLimitViolation(endpoint, ipAddress, limit) {
|
|
116
|
+
const auditData = {
|
|
117
|
+
event: 'rate_limit_violation',
|
|
118
|
+
endpoint,
|
|
119
|
+
ipAddress,
|
|
120
|
+
limit,
|
|
121
|
+
timestamp: new Date().toISOString(),
|
|
122
|
+
};
|
|
123
|
+
this.Logger.warn(`Rate LIMIT VIOLATION: ${escapeNewlines(endpoint)} from ${escapeNewlines(ipAddress)} (limit: ${limit}/min) | ${JSON.stringify(auditData)}`, 'AuditLogger');
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Log CSRF violation
|
|
127
|
+
*/
|
|
128
|
+
logCsrfViolation(ipAddress, endpoint) {
|
|
129
|
+
const auditData = {
|
|
130
|
+
event: 'csrf_violation',
|
|
131
|
+
ipAddress,
|
|
132
|
+
endpoint,
|
|
133
|
+
timestamp: new Date().toISOString(),
|
|
134
|
+
};
|
|
135
|
+
this.Logger.warn(`CSRF VIOLATION: ${escapeNewlines(endpoint)} from ${escapeNewlines(ipAddress)} | ${JSON.stringify(auditData)}`, 'AuditLogger');
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Log security configuration change
|
|
139
|
+
*/
|
|
140
|
+
logConfigurationChange(userId, config, oldValue, newValue) {
|
|
141
|
+
const auditData = {
|
|
142
|
+
event: 'config_change',
|
|
143
|
+
userId,
|
|
144
|
+
config,
|
|
145
|
+
oldValue,
|
|
146
|
+
newValue,
|
|
147
|
+
timestamp: new Date().toISOString(),
|
|
148
|
+
};
|
|
149
|
+
this.Logger.info(`Configuration CHANGE: ${escapeNewlines(config)} modified by ${escapeNewlines(userId)} | ${JSON.stringify(auditData)}`, 'AuditLogger');
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Log data access
|
|
153
|
+
*/
|
|
154
|
+
logDataAccess(userId, resource, action) {
|
|
155
|
+
const auditData = {
|
|
156
|
+
event: 'data_access',
|
|
157
|
+
userId,
|
|
158
|
+
resource,
|
|
159
|
+
action,
|
|
160
|
+
timestamp: new Date().toISOString(),
|
|
161
|
+
};
|
|
162
|
+
this.Logger.info(`Data ACCESS: User ${escapeNewlines(userId)} ${escapeNewlines(action)} ${escapeNewlines(resource)} | ${JSON.stringify(auditData)}`, 'AuditLogger');
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Log security event
|
|
166
|
+
*/
|
|
167
|
+
logSecurityEvent(entry) {
|
|
168
|
+
const auditData = {
|
|
169
|
+
...entry,
|
|
170
|
+
timestamp: new Date().toISOString(),
|
|
171
|
+
};
|
|
172
|
+
this.Logger.info(`Security EVENT: ${escapeNewlines(entry.action)} on ${escapeNewlines(entry.resource)} - ${entry.result} | ${JSON.stringify(auditData)}`, 'AuditLogger');
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
AuditLoggerService = AuditLoggerService_1 = __decorate([
|
|
176
|
+
Injectable(),
|
|
177
|
+
__metadata("design:paramtypes", [ModuleRef])
|
|
178
|
+
], AuditLoggerService);
|
|
179
|
+
export { AuditLoggerService };
|
|
180
|
+
//# sourceMappingURL=audit-logger.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-logger.service.js","sourceRoot":"","sources":["../../../src/common/services/audit-logger.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|
2
|
+
import { ConfigService } from '@nestjs/config';
|
|
3
|
+
import { Request, Response, NextFunction } from 'express';
|
|
4
|
+
/**
|
|
5
|
+
* Configuration options for CSRF protection.
|
|
6
|
+
*/
|
|
7
|
+
export interface CSRFServiceOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Whether to trust X-Forwarded-For header for client IP detection.
|
|
10
|
+
* Set to true when running behind a reverse proxy (nginx, Apache, load balancer, etc.)
|
|
11
|
+
* to correctly identify the real client IP for rate limiting.
|
|
12
|
+
*
|
|
13
|
+
* Security note: Only enable if your reverse proxy is trusted and properly configured
|
|
14
|
+
* to set X-Forwarded-For. Enabling this on an untrusted proxy allows IP spoofing attacks.
|
|
15
|
+
*
|
|
16
|
+
* Default: false (use direct socket IP)
|
|
17
|
+
*/
|
|
18
|
+
trustProxy?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* CSRF Service.
|
|
22
|
+
* Provides CSRF token generation and validation using the Double Submit Cookie pattern.
|
|
23
|
+
* Uses cryptographic signing and per-session/IP binding for secure token verification.
|
|
24
|
+
*
|
|
25
|
+
* Features:
|
|
26
|
+
* - Double-CSRF token pattern (cookie + request header/body)
|
|
27
|
+
* - Per-IP rate limiting: 10 tokens per 60 seconds
|
|
28
|
+
* - Session binding (when available) or IP-based fallback
|
|
29
|
+
* - Automatic pruning of stale timestamps
|
|
30
|
+
* - Capacity monitoring with safety margin (80% threshold)
|
|
31
|
+
* - SSL-only, HTTPOnly cookies in production
|
|
32
|
+
*
|
|
33
|
+
* Configuration requirements:
|
|
34
|
+
* - CSRF_SECRET: Min 32 characters, cryptographically random, high entropy
|
|
35
|
+
* - Express app with cookie parser middleware
|
|
36
|
+
* - Optional: trustProxy for reverse proxy environments
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* - In-memory rate limiting supports ~10,000 concurrent IPs per instance
|
|
40
|
+
* - For distributed deployments, use Redis-backed SharedThrottlerModule instead
|
|
41
|
+
* - Token generation timeout: 30 seconds (queue timeout)
|
|
42
|
+
* - Token timestamp pruning interval: 10 seconds
|
|
43
|
+
* - IP map capacity threshold: 80% (8,000 IPs) before pruning
|
|
44
|
+
* - Returns 503 Service Unavailable if at capacity after pruning
|
|
45
|
+
* - Returns 429 Too Many Requests if rate limit exceeded
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* // Generate token for form
|
|
50
|
+
* const token = await csrfService.generateToken(req, res);
|
|
51
|
+
* res.render('form', { csrfToken: token });
|
|
52
|
+
*
|
|
53
|
+
* // Validate incoming request (done automatically by CSRFGuard)
|
|
54
|
+
* const isValid = csrfService.validateToken(req);
|
|
55
|
+
*
|
|
56
|
+
* // Refresh token after sensitive operation (login, password change)
|
|
57
|
+
* const newToken = await csrfService.refreshToken(req, res);
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare class CSRFService implements OnModuleInit, OnModuleDestroy {
|
|
61
|
+
private readonly configService?;
|
|
62
|
+
private static readonly MIN_SECRET_LENGTH;
|
|
63
|
+
private static readonly MIN_CHARACTER_SET_DIVERSITY;
|
|
64
|
+
private static readonly ANONYMOUS_TOKEN_RANDOMNESS_BYTES;
|
|
65
|
+
private static readonly RATE_LIMIT_WINDOW_MS;
|
|
66
|
+
private static readonly RATE_LIMIT_COUNT;
|
|
67
|
+
/**
|
|
68
|
+
* Maximum number of unique IP addresses tracked for rate limiting.
|
|
69
|
+
* This in-memory strategy supports ~10,000 concurrent IPs per instance.
|
|
70
|
+
*
|
|
71
|
+
* **Scaling guidance**: For deployments exceeding 10,000 concurrent unique IPs,
|
|
72
|
+
* migrate to a Redis-backed rate limiting solution via SharedThrottlerModule:
|
|
73
|
+
* - Configure SharedThrottlerModule with Redis backend
|
|
74
|
+
* - Adjust limits and TTL for your traffic pattern
|
|
75
|
+
*
|
|
76
|
+
* **Memory management**: When the tracked IPs map reaches 80% capacity
|
|
77
|
+
* (8,000 IPs), the pruning logic removes stale entries (>60s old).
|
|
78
|
+
* If after pruning the map remains >= 10,000 IPs, token generation is
|
|
79
|
+
* rejected with HTTP 503 to prevent unbounded memory growth.
|
|
80
|
+
* The 80% threshold provides a safety margin before hard limits are hit.
|
|
81
|
+
*
|
|
82
|
+
* @see SharedThrottlerModule for Redis-backed distributed rate limiting
|
|
83
|
+
*/
|
|
84
|
+
private static readonly MAX_TRACKED_IPS;
|
|
85
|
+
private static readonly TIMESTAMP_PRUNING_INTERVAL_MS;
|
|
86
|
+
private static readonly IP_LOCK_TIMEOUT_MS;
|
|
87
|
+
private static readonly CAPACITY_THRESHOLD_PERCENT;
|
|
88
|
+
private csrfProtection;
|
|
89
|
+
private readonly logger;
|
|
90
|
+
private readonly tokenGenTimestamps;
|
|
91
|
+
private readonly ipLocks;
|
|
92
|
+
private readonly trustProxy;
|
|
93
|
+
private capacityThresholdCrossedCount;
|
|
94
|
+
private pruneIntervalHandle;
|
|
95
|
+
private _isPruning;
|
|
96
|
+
constructor(configService?: ConfigService | undefined, options?: CSRFServiceOptions);
|
|
97
|
+
/**
|
|
98
|
+
* NestJS lifecycle hook: validate required CSRF_SECRET environment variable
|
|
99
|
+
* at application bootstrap time
|
|
100
|
+
*/
|
|
101
|
+
onModuleInit(): void;
|
|
102
|
+
/**
|
|
103
|
+
* NestJS lifecycle hook: clear the pruning interval on module destroy
|
|
104
|
+
*/
|
|
105
|
+
onModuleDestroy(): void;
|
|
106
|
+
/**
|
|
107
|
+
* Validate trust proxy configuration to detect mismatches early
|
|
108
|
+
* Checks if X-Forwarded-For header support is configured correctly in both directions:
|
|
109
|
+
* - If trustProxy=false but X-Forwarded-For is present: may miss real client IP
|
|
110
|
+
* - If trustProxy=true but X-Forwarded-For is absent: proxy may not be configured correctly
|
|
111
|
+
*/
|
|
112
|
+
private validateTrustProxyConfiguration;
|
|
113
|
+
/**
|
|
114
|
+
* Calculate Shannon entropy of a string to measure randomness.
|
|
115
|
+
* Higher entropy indicates better randomness quality.
|
|
116
|
+
*
|
|
117
|
+
* The minimum threshold of 4.0 bits/char is chosen because:
|
|
118
|
+
* - A uniformly random string from a 16-character alphabet (hex: 0-9a-f) has log2(16) = 4.0 bits/char
|
|
119
|
+
* - This ensures the CSRF_SECRET has sufficient entropy for cryptographic purposes
|
|
120
|
+
* - Values below 4.0 bits/char indicate the secret uses a limited character set or has patterns
|
|
121
|
+
*
|
|
122
|
+
* @param str - Input string to analyze
|
|
123
|
+
* @returns Entropy in bits per character
|
|
124
|
+
*/
|
|
125
|
+
private calculateEntropy;
|
|
126
|
+
/**
|
|
127
|
+
* Check if the secret contains obviously weak patterns
|
|
128
|
+
*/
|
|
129
|
+
private isWeakSecret;
|
|
130
|
+
/**
|
|
131
|
+
* Get session identifier for CSRF token binding
|
|
132
|
+
* Prefers session ID if available, falls back to IP address
|
|
133
|
+
* @param req - Express request object
|
|
134
|
+
* @returns Session identifier
|
|
135
|
+
*/
|
|
136
|
+
private getSessionIdentifier;
|
|
137
|
+
/**
|
|
138
|
+
* Extract client IP address from request, respecting trustProxy setting
|
|
139
|
+
*
|
|
140
|
+
* **Note on Express vs Fastify**: This implementation uses `req.ip` (Express-specific).
|
|
141
|
+
* For Fastify deployments, ensure the `trustProxy` option is properly configured:
|
|
142
|
+
* - In Fastify, use `app.register(require('@fastify/proxy'), { ...config })`
|
|
143
|
+
* - Or set the Fastify instance option: `fastify({ trustProxy: true })`
|
|
144
|
+
* - Without correct Fastify configuration, IP detection will fail
|
|
145
|
+
*
|
|
146
|
+
* @param req - Express request object
|
|
147
|
+
* @returns Client IP address or null if unavailable
|
|
148
|
+
*/
|
|
149
|
+
private extractClientIp;
|
|
150
|
+
/**
|
|
151
|
+
* Prune old token generation timestamps to prevent unbounded map growth
|
|
152
|
+
* Removes entries older than 60 seconds and cleans up idle IPs from both
|
|
153
|
+
* tokenGenTimestamps and ipLocks to prevent memory accumulation.
|
|
154
|
+
*/
|
|
155
|
+
private pruneTokenTimestamps;
|
|
156
|
+
/**
|
|
157
|
+
* Generate CSRF token with per-IP rate limiting
|
|
158
|
+
* Limits to 10 token generations per IP per 60 seconds
|
|
159
|
+
* Uses per-IP locking to serialize concurrent requests from the same IP,
|
|
160
|
+
* preventing race conditions in rate limit checks.
|
|
161
|
+
* @param req - Express request object
|
|
162
|
+
* @param res - Express response object
|
|
163
|
+
* @returns CSRF token
|
|
164
|
+
* @throws Error if CSRF_SECRET was not initialized in onModuleInit
|
|
165
|
+
* @throws {HttpException} 429 - When rate limit exceeded for this IP
|
|
166
|
+
* @throws {HttpException} 503 - When service is at capacity
|
|
167
|
+
*/
|
|
168
|
+
generateToken(req: Request, res: Response): Promise<string>;
|
|
169
|
+
/**
|
|
170
|
+
* Perform rate-limited token generation for a single IP.
|
|
171
|
+
* This method is called within an IP-serialized lock to ensure atomicity.
|
|
172
|
+
* @param req - Express request object
|
|
173
|
+
* @param res - Express response object
|
|
174
|
+
* @returns CSRF token
|
|
175
|
+
* @throws HttpException with 429 status if rate limit exceeded
|
|
176
|
+
*/
|
|
177
|
+
private performRateLimitedTokenGeneration;
|
|
178
|
+
/**
|
|
179
|
+
* Validate CSRF token
|
|
180
|
+
* @param req - Express request object
|
|
181
|
+
* @returns true if token is valid, false otherwise
|
|
182
|
+
* @throws Error if CSRF_SECRET was not initialized in onModuleInit
|
|
183
|
+
*/
|
|
184
|
+
validateToken(req: Request): boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Refresh CSRF token by invalidating the current one and generating a new one
|
|
187
|
+
* Use this after sensitive operations like login, password change, or privilege escalation
|
|
188
|
+
* to ensure the user has a fresh token that cannot be replayed from before the operation
|
|
189
|
+
* @param req - Express request object
|
|
190
|
+
* @param res - Express response object
|
|
191
|
+
* @returns New CSRF token
|
|
192
|
+
* @throws Error if CSRF_SECRET was not initialized in onModuleInit
|
|
193
|
+
*/
|
|
194
|
+
refreshToken(req: Request, res: Response): Promise<string>;
|
|
195
|
+
/**
|
|
196
|
+
* Get CSRF middleware
|
|
197
|
+
* @returns CSRF protection middleware
|
|
198
|
+
* @throws Error if CSRF_SECRET was not initialized in onModuleInit
|
|
199
|
+
*/
|
|
200
|
+
getMiddleware(): (req: Request, res: Response, next: NextFunction) => void;
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=csrf.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csrf.service.d.ts","sourceRoot":"","sources":["../../../src/common/services/csrf.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,YAAY,EAAE,eAAe,EAAuD,MAAM,gBAAgB,CAAC;AAChI,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBACa,WAAY,YAAW,YAAY,EAAE,eAAe;IAgD5B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IA7CnE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAM;IAE/C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,2BAA2B,CAAK;IAExD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gCAAgC,CAAK;IAE7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAU;IAEtD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAM;IAC9C;;;;;;;;;;;;;;;;OAgBG;IAEH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAS;IAEhD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,6BAA6B,CAAa;IAElE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAU;IAEpD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,0BAA0B,CAAO;IAEzD,OAAO,CAAC,cAAc,CAAkC;IACxD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA+B;IAClE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IACrC,OAAO,CAAC,6BAA6B,CAAK;IAC1C,OAAO,CAAC,mBAAmB,CAA6C;IACxE,OAAO,CAAC,UAAU,CAAS;gBAG0B,aAAa,CAAC,EAAE,aAAa,YAAA,EACrE,OAAO,CAAC,EAAE,kBAAkB;IAOzC;;;OAGG;IACI,YAAY,IAAI,IAAI;IA2D3B;;OAEG;IACI,eAAe,IAAI,IAAI;IAU9B;;;;;OAKG;IACH,OAAO,CAAC,+BAA+B;IAyBvC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;OAEG;IACH,OAAO,CAAC,YAAY;IAsBpB;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAiB5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,eAAe;IA4BvB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAgB5B;;;;;;;;;;;OAWG;IACU,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IA6CxE;;;;;;;OAOG;IACH,OAAO,CAAC,iCAAiC;IAiEzC;;;;;OAKG;IACI,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO;IAa3C;;;;;;;;OAQG;IAEI,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAWjE;;;;OAIG;IACI,aAAa,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI;CAOjF"}
|