@noony-serverless/core 0.1.0 → 0.1.5
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/build/middlewares/authenticationMiddleware.d.ts +379 -0
- package/build/middlewares/authenticationMiddleware.js +216 -0
- package/build/middlewares/bodyParserMiddleware.d.ts +99 -0
- package/build/middlewares/bodyParserMiddleware.js +99 -0
- package/build/middlewares/bodyValidationMiddleware.d.ts +68 -4
- package/build/middlewares/bodyValidationMiddleware.js +64 -0
- package/build/middlewares/dependencyInjectionMiddleware.d.ts +238 -0
- package/build/middlewares/dependencyInjectionMiddleware.js +238 -0
- package/build/middlewares/errorHandlerMiddleware.d.ts +94 -0
- package/build/middlewares/errorHandlerMiddleware.js +105 -0
- package/build/middlewares/guards/RouteGuards.d.ts +475 -0
- package/build/middlewares/guards/RouteGuards.js +604 -0
- package/build/middlewares/guards/cache/CacheAdapter.d.ts +473 -0
- package/build/middlewares/guards/cache/CacheAdapter.js +205 -0
- package/build/middlewares/guards/cache/ConservativeCacheInvalidation.d.ts +191 -0
- package/build/middlewares/guards/cache/ConservativeCacheInvalidation.js +510 -0
- package/build/middlewares/guards/cache/MemoryCacheAdapter.d.ts +228 -0
- package/build/middlewares/guards/cache/MemoryCacheAdapter.js +403 -0
- package/build/middlewares/guards/cache/NoopCacheAdapter.d.ts +95 -0
- package/build/middlewares/guards/cache/NoopCacheAdapter.js +131 -0
- package/build/middlewares/guards/config/GuardConfiguration.d.ts +612 -0
- package/build/middlewares/guards/config/GuardConfiguration.js +334 -0
- package/build/middlewares/guards/guards/FastAuthGuard.d.ts +201 -0
- package/build/middlewares/guards/guards/FastAuthGuard.js +460 -0
- package/build/middlewares/guards/guards/PermissionGuardFactory.d.ts +202 -0
- package/build/middlewares/guards/guards/PermissionGuardFactory.js +563 -0
- package/build/middlewares/guards/index.d.ts +67 -0
- package/build/middlewares/guards/index.js +192 -0
- package/build/middlewares/guards/registry/PermissionRegistry.d.ts +188 -0
- package/build/middlewares/guards/registry/PermissionRegistry.js +425 -0
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.d.ts +129 -0
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.js +451 -0
- package/build/middlewares/guards/resolvers/PermissionResolver.d.ts +155 -0
- package/build/middlewares/guards/resolvers/PermissionResolver.js +176 -0
- package/build/middlewares/guards/resolvers/PlainPermissionResolver.d.ts +101 -0
- package/build/middlewares/guards/resolvers/PlainPermissionResolver.js +248 -0
- package/build/middlewares/guards/resolvers/WildcardPermissionResolver.d.ts +146 -0
- package/build/middlewares/guards/resolvers/WildcardPermissionResolver.js +377 -0
- package/build/middlewares/guards/services/FastUserContextService.d.ts +216 -0
- package/build/middlewares/guards/services/FastUserContextService.js +435 -0
- package/build/middlewares/headerVariablesMiddleware.d.ts +118 -0
- package/build/middlewares/headerVariablesMiddleware.js +118 -0
- package/build/middlewares/httpAttributesMiddleware.d.ts +235 -0
- package/build/middlewares/httpAttributesMiddleware.js +235 -0
- package/build/middlewares/index.d.ts +1 -0
- package/build/middlewares/index.js +1 -0
- package/build/middlewares/queryParametersMiddleware.d.ts +105 -0
- package/build/middlewares/queryParametersMiddleware.js +105 -0
- package/build/middlewares/rateLimitingMiddleware.d.ts +109 -5
- package/build/middlewares/rateLimitingMiddleware.js +109 -5
- package/build/middlewares/responseWrapperMiddleware.d.ts +170 -1
- package/build/middlewares/responseWrapperMiddleware.js +170 -1
- package/build/middlewares/securityAuditMiddleware.js +5 -5
- package/build/middlewares/validationMiddleware.d.ts +145 -0
- package/build/middlewares/validationMiddleware.js +145 -0
- package/package.json +2 -2
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conservative Cache Invalidation Service
|
|
3
|
+
*
|
|
4
|
+
* Implements a security-first approach to cache invalidation for permission systems.
|
|
5
|
+
* When in doubt about data freshness or permission changes, this service errs on the
|
|
6
|
+
* side of security by clearing broader cache segments rather than risking stale data.
|
|
7
|
+
*
|
|
8
|
+
* Security Principles:
|
|
9
|
+
* - Invalidate broadly rather than narrowly when permissions change
|
|
10
|
+
* - Clear dependent caches proactively to prevent inconsistencies
|
|
11
|
+
* - Use time-based invalidation as backup for missed updates
|
|
12
|
+
* - Log all invalidation events for audit trails
|
|
13
|
+
* - Provide rollback capabilities for accidental cache clears
|
|
14
|
+
*
|
|
15
|
+
* Use Cases:
|
|
16
|
+
* - User permission changes (role assignments, direct permissions)
|
|
17
|
+
* - System-wide permission updates (new permissions, policy changes)
|
|
18
|
+
* - Security incidents requiring immediate cache clearing
|
|
19
|
+
* - Scheduled maintenance and cache refresh operations
|
|
20
|
+
* - Development and testing environment resets
|
|
21
|
+
*
|
|
22
|
+
* @author Noony Framework Team
|
|
23
|
+
* @version 1.0.0
|
|
24
|
+
*/
|
|
25
|
+
import { CacheAdapter } from './CacheAdapter';
|
|
26
|
+
/**
|
|
27
|
+
* Cache invalidation event for audit logging
|
|
28
|
+
*/
|
|
29
|
+
export interface CacheInvalidationEvent {
|
|
30
|
+
eventId: string;
|
|
31
|
+
type: InvalidationType;
|
|
32
|
+
scope: InvalidationScope;
|
|
33
|
+
patterns: string[];
|
|
34
|
+
affectedKeys?: string[];
|
|
35
|
+
reason: string;
|
|
36
|
+
userId?: string;
|
|
37
|
+
timestamp: string;
|
|
38
|
+
restorable: boolean;
|
|
39
|
+
performance: {
|
|
40
|
+
keysCleared: number;
|
|
41
|
+
executionTimeMs: number;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Types of cache invalidation operations
|
|
46
|
+
*/
|
|
47
|
+
export declare enum InvalidationType {
|
|
48
|
+
USER_PERMISSION_CHANGE = "user_permission_change",
|
|
49
|
+
ROLE_ASSIGNMENT_CHANGE = "role_assignment_change",
|
|
50
|
+
SYSTEM_PERMISSION_UPDATE = "system_permission_update",
|
|
51
|
+
SECURITY_INCIDENT = "security_incident",
|
|
52
|
+
SCHEDULED_REFRESH = "scheduled_refresh",
|
|
53
|
+
MANUAL_CLEAR = "manual_clear",
|
|
54
|
+
DEVELOPMENT_RESET = "development_reset"
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Scope of cache invalidation
|
|
58
|
+
*/
|
|
59
|
+
export declare enum InvalidationScope {
|
|
60
|
+
SINGLE_USER = "single_user",
|
|
61
|
+
MULTIPLE_USERS = "multiple_users",
|
|
62
|
+
ROLE_BASED = "role_based",
|
|
63
|
+
SYSTEM_WIDE = "system_wide",
|
|
64
|
+
PERMISSION_SPECIFIC = "permission_specific"
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Conservative Cache Invalidation Implementation
|
|
68
|
+
*/
|
|
69
|
+
export declare class ConservativeCacheInvalidation {
|
|
70
|
+
private readonly cache;
|
|
71
|
+
private readonly auditLog;
|
|
72
|
+
private readonly backups;
|
|
73
|
+
private readonly maxAuditLogSize;
|
|
74
|
+
private readonly maxBackupAge;
|
|
75
|
+
private invalidationCount;
|
|
76
|
+
private totalKeysCleared;
|
|
77
|
+
private totalExecutionTimeMs;
|
|
78
|
+
constructor(cache: CacheAdapter);
|
|
79
|
+
/**
|
|
80
|
+
* Invalidate cache for specific user permission changes
|
|
81
|
+
*
|
|
82
|
+
* Conservative approach: Clears all permission-related caches for the user
|
|
83
|
+
* and any cached data that might depend on their permissions.
|
|
84
|
+
*
|
|
85
|
+
* @param userId - User whose permissions changed
|
|
86
|
+
* @param reason - Reason for invalidation
|
|
87
|
+
* @param createBackup - Whether to create restoration backup
|
|
88
|
+
* @returns Invalidation event details
|
|
89
|
+
*/
|
|
90
|
+
invalidateUserPermissions(userId: string, reason: string, createBackup?: boolean): Promise<CacheInvalidationEvent>;
|
|
91
|
+
/**
|
|
92
|
+
* Invalidate cache for role-based permission changes
|
|
93
|
+
*
|
|
94
|
+
* Conservative approach: Clears caches for all users with the affected roles
|
|
95
|
+
* plus any system-level permission caches that might be affected.
|
|
96
|
+
*
|
|
97
|
+
* @param roles - Roles whose permissions changed
|
|
98
|
+
* @param reason - Reason for invalidation
|
|
99
|
+
* @param createBackup - Whether to create restoration backup
|
|
100
|
+
* @returns Invalidation event details
|
|
101
|
+
*/
|
|
102
|
+
invalidateRolePermissions(roles: string[], reason: string, createBackup?: boolean): Promise<CacheInvalidationEvent>;
|
|
103
|
+
/**
|
|
104
|
+
* System-wide cache invalidation
|
|
105
|
+
*
|
|
106
|
+
* Nuclear option: Clears all permission-related caches across the system.
|
|
107
|
+
* Used for major system updates, security incidents, or when unsure about
|
|
108
|
+
* the scope of changes.
|
|
109
|
+
*
|
|
110
|
+
* @param reason - Reason for system-wide invalidation
|
|
111
|
+
* @param createBackup - Whether to create restoration backup
|
|
112
|
+
* @returns Invalidation event details
|
|
113
|
+
*/
|
|
114
|
+
invalidateSystemWide(reason: string, createBackup?: boolean): Promise<CacheInvalidationEvent>;
|
|
115
|
+
/**
|
|
116
|
+
* Emergency security invalidation
|
|
117
|
+
*
|
|
118
|
+
* Immediate cache clearing for security incidents.
|
|
119
|
+
* Bypasses backup creation for speed and clears everything.
|
|
120
|
+
*
|
|
121
|
+
* @param reason - Security incident description
|
|
122
|
+
* @returns Invalidation event details
|
|
123
|
+
*/
|
|
124
|
+
emergencySecurityInvalidation(reason: string): Promise<CacheInvalidationEvent>;
|
|
125
|
+
/**
|
|
126
|
+
* Restore cache from backup
|
|
127
|
+
*
|
|
128
|
+
* Attempts to restore previously backed up cache data.
|
|
129
|
+
* Use with caution - only restore if you're certain the data is safe.
|
|
130
|
+
*
|
|
131
|
+
* @param backupId - ID of the backup to restore
|
|
132
|
+
* @returns Restoration success status
|
|
133
|
+
*/
|
|
134
|
+
restoreFromBackup(backupId: string): Promise<boolean>;
|
|
135
|
+
/**
|
|
136
|
+
* Get invalidation audit log
|
|
137
|
+
*/
|
|
138
|
+
getAuditLog(): CacheInvalidationEvent[];
|
|
139
|
+
/**
|
|
140
|
+
* Get available backups
|
|
141
|
+
*/
|
|
142
|
+
getAvailableBackups(): Array<{
|
|
143
|
+
backupId: string;
|
|
144
|
+
timestamp: string;
|
|
145
|
+
scope: InvalidationScope;
|
|
146
|
+
totalEntries: number;
|
|
147
|
+
sizeBytes: number;
|
|
148
|
+
ageHours: number;
|
|
149
|
+
}>;
|
|
150
|
+
/**
|
|
151
|
+
* Get invalidation statistics
|
|
152
|
+
*/
|
|
153
|
+
getStats(): {
|
|
154
|
+
invalidationCount: number;
|
|
155
|
+
totalKeysCleared: number;
|
|
156
|
+
averageExecutionTimeMs: number;
|
|
157
|
+
totalExecutionTimeMs: number;
|
|
158
|
+
auditLogSize: number;
|
|
159
|
+
backupsAvailable: number;
|
|
160
|
+
oldestBackupAge: number;
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Clear patterns from cache
|
|
164
|
+
*/
|
|
165
|
+
private clearCachesByPatterns;
|
|
166
|
+
/**
|
|
167
|
+
* Create backup of cache data
|
|
168
|
+
*/
|
|
169
|
+
private createBackup;
|
|
170
|
+
/**
|
|
171
|
+
* Record audit event
|
|
172
|
+
*/
|
|
173
|
+
private recordAuditEvent;
|
|
174
|
+
/**
|
|
175
|
+
* Update performance metrics
|
|
176
|
+
*/
|
|
177
|
+
private updatePerformanceMetrics;
|
|
178
|
+
/**
|
|
179
|
+
* Generate unique event ID
|
|
180
|
+
*/
|
|
181
|
+
private generateEventId;
|
|
182
|
+
/**
|
|
183
|
+
* Clean up old backups
|
|
184
|
+
*/
|
|
185
|
+
private cleanupOldBackups;
|
|
186
|
+
/**
|
|
187
|
+
* Get age of oldest backup in hours
|
|
188
|
+
*/
|
|
189
|
+
private getOldestBackupAge;
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=ConservativeCacheInvalidation.d.ts.map
|
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Conservative Cache Invalidation Service
|
|
4
|
+
*
|
|
5
|
+
* Implements a security-first approach to cache invalidation for permission systems.
|
|
6
|
+
* When in doubt about data freshness or permission changes, this service errs on the
|
|
7
|
+
* side of security by clearing broader cache segments rather than risking stale data.
|
|
8
|
+
*
|
|
9
|
+
* Security Principles:
|
|
10
|
+
* - Invalidate broadly rather than narrowly when permissions change
|
|
11
|
+
* - Clear dependent caches proactively to prevent inconsistencies
|
|
12
|
+
* - Use time-based invalidation as backup for missed updates
|
|
13
|
+
* - Log all invalidation events for audit trails
|
|
14
|
+
* - Provide rollback capabilities for accidental cache clears
|
|
15
|
+
*
|
|
16
|
+
* Use Cases:
|
|
17
|
+
* - User permission changes (role assignments, direct permissions)
|
|
18
|
+
* - System-wide permission updates (new permissions, policy changes)
|
|
19
|
+
* - Security incidents requiring immediate cache clearing
|
|
20
|
+
* - Scheduled maintenance and cache refresh operations
|
|
21
|
+
* - Development and testing environment resets
|
|
22
|
+
*
|
|
23
|
+
* @author Noony Framework Team
|
|
24
|
+
* @version 1.0.0
|
|
25
|
+
*/
|
|
26
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
27
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
28
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
29
|
+
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;
|
|
30
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
31
|
+
};
|
|
32
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
33
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
34
|
+
};
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ConservativeCacheInvalidation = exports.InvalidationScope = exports.InvalidationType = void 0;
|
|
37
|
+
const typedi_1 = require("typedi");
|
|
38
|
+
const CacheAdapter_1 = require("./CacheAdapter");
|
|
39
|
+
/**
|
|
40
|
+
* Types of cache invalidation operations
|
|
41
|
+
*/
|
|
42
|
+
var InvalidationType;
|
|
43
|
+
(function (InvalidationType) {
|
|
44
|
+
InvalidationType["USER_PERMISSION_CHANGE"] = "user_permission_change";
|
|
45
|
+
InvalidationType["ROLE_ASSIGNMENT_CHANGE"] = "role_assignment_change";
|
|
46
|
+
InvalidationType["SYSTEM_PERMISSION_UPDATE"] = "system_permission_update";
|
|
47
|
+
InvalidationType["SECURITY_INCIDENT"] = "security_incident";
|
|
48
|
+
InvalidationType["SCHEDULED_REFRESH"] = "scheduled_refresh";
|
|
49
|
+
InvalidationType["MANUAL_CLEAR"] = "manual_clear";
|
|
50
|
+
InvalidationType["DEVELOPMENT_RESET"] = "development_reset";
|
|
51
|
+
})(InvalidationType || (exports.InvalidationType = InvalidationType = {}));
|
|
52
|
+
/**
|
|
53
|
+
* Scope of cache invalidation
|
|
54
|
+
*/
|
|
55
|
+
var InvalidationScope;
|
|
56
|
+
(function (InvalidationScope) {
|
|
57
|
+
InvalidationScope["SINGLE_USER"] = "single_user";
|
|
58
|
+
InvalidationScope["MULTIPLE_USERS"] = "multiple_users";
|
|
59
|
+
InvalidationScope["ROLE_BASED"] = "role_based";
|
|
60
|
+
InvalidationScope["SYSTEM_WIDE"] = "system_wide";
|
|
61
|
+
InvalidationScope["PERMISSION_SPECIFIC"] = "permission_specific";
|
|
62
|
+
})(InvalidationScope || (exports.InvalidationScope = InvalidationScope = {}));
|
|
63
|
+
/**
|
|
64
|
+
* Conservative Cache Invalidation Implementation
|
|
65
|
+
*/
|
|
66
|
+
let ConservativeCacheInvalidation = class ConservativeCacheInvalidation {
|
|
67
|
+
cache;
|
|
68
|
+
auditLog = [];
|
|
69
|
+
backups = new Map();
|
|
70
|
+
maxAuditLogSize = 1000;
|
|
71
|
+
maxBackupAge = 24 * 60 * 60 * 1000; // 24 hours
|
|
72
|
+
// Performance tracking
|
|
73
|
+
invalidationCount = 0;
|
|
74
|
+
totalKeysCleared = 0;
|
|
75
|
+
totalExecutionTimeMs = 0;
|
|
76
|
+
constructor(cache) {
|
|
77
|
+
this.cache = cache;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Invalidate cache for specific user permission changes
|
|
81
|
+
*
|
|
82
|
+
* Conservative approach: Clears all permission-related caches for the user
|
|
83
|
+
* and any cached data that might depend on their permissions.
|
|
84
|
+
*
|
|
85
|
+
* @param userId - User whose permissions changed
|
|
86
|
+
* @param reason - Reason for invalidation
|
|
87
|
+
* @param createBackup - Whether to create restoration backup
|
|
88
|
+
* @returns Invalidation event details
|
|
89
|
+
*/
|
|
90
|
+
async invalidateUserPermissions(userId, reason, createBackup = false) {
|
|
91
|
+
const startTime = Date.now();
|
|
92
|
+
const eventId = this.generateEventId();
|
|
93
|
+
try {
|
|
94
|
+
// Define patterns to clear for this user
|
|
95
|
+
const patterns = [
|
|
96
|
+
CacheAdapter_1.CacheKeyBuilder.userContext(userId),
|
|
97
|
+
`perm:*:${userId}:*`, // Plain permission checks
|
|
98
|
+
`wild:*:${userId}:*`, // Wildcard permission checks
|
|
99
|
+
`expr:*:${userId}:*`, // Expression permission checks
|
|
100
|
+
`auth:${userId}:*`, // Authentication caches
|
|
101
|
+
];
|
|
102
|
+
// Create backup if requested
|
|
103
|
+
if (createBackup) {
|
|
104
|
+
await this.createBackup(`user_${userId}_${eventId}`, InvalidationScope.SINGLE_USER, patterns, `User permission change: ${reason}`);
|
|
105
|
+
}
|
|
106
|
+
// Clear caches
|
|
107
|
+
const keysCleared = await this.clearCachesByPatterns(patterns);
|
|
108
|
+
// Create audit event
|
|
109
|
+
const event = {
|
|
110
|
+
eventId,
|
|
111
|
+
type: InvalidationType.USER_PERMISSION_CHANGE,
|
|
112
|
+
scope: InvalidationScope.SINGLE_USER,
|
|
113
|
+
patterns,
|
|
114
|
+
reason,
|
|
115
|
+
userId,
|
|
116
|
+
timestamp: new Date().toISOString(),
|
|
117
|
+
restorable: createBackup,
|
|
118
|
+
performance: {
|
|
119
|
+
keysCleared,
|
|
120
|
+
executionTimeMs: Date.now() - startTime,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
await this.recordAuditEvent(event);
|
|
124
|
+
this.updatePerformanceMetrics(keysCleared, Date.now() - startTime);
|
|
125
|
+
console.log('🧹 Conservative cache invalidation completed', {
|
|
126
|
+
type: 'user_permission_change',
|
|
127
|
+
userId,
|
|
128
|
+
keysCleared,
|
|
129
|
+
duration: Date.now() - startTime,
|
|
130
|
+
reason,
|
|
131
|
+
});
|
|
132
|
+
return event;
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
console.error('❌ Cache invalidation failed', {
|
|
136
|
+
userId,
|
|
137
|
+
reason,
|
|
138
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
139
|
+
duration: Date.now() - startTime,
|
|
140
|
+
});
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Invalidate cache for role-based permission changes
|
|
146
|
+
*
|
|
147
|
+
* Conservative approach: Clears caches for all users with the affected roles
|
|
148
|
+
* plus any system-level permission caches that might be affected.
|
|
149
|
+
*
|
|
150
|
+
* @param roles - Roles whose permissions changed
|
|
151
|
+
* @param reason - Reason for invalidation
|
|
152
|
+
* @param createBackup - Whether to create restoration backup
|
|
153
|
+
* @returns Invalidation event details
|
|
154
|
+
*/
|
|
155
|
+
async invalidateRolePermissions(roles, reason, createBackup = false) {
|
|
156
|
+
const startTime = Date.now();
|
|
157
|
+
const eventId = this.generateEventId();
|
|
158
|
+
try {
|
|
159
|
+
// Conservative approach: Clear all user contexts and permission caches
|
|
160
|
+
// Since we don't know which users have these roles, clear everything
|
|
161
|
+
const patterns = [
|
|
162
|
+
'user:context:*', // All user contexts
|
|
163
|
+
'perm:*', // All permission checks
|
|
164
|
+
'wild:*', // All wildcard checks
|
|
165
|
+
'expr:*', // All expression checks
|
|
166
|
+
'auth:*', // All authentication caches
|
|
167
|
+
'role:permissions:*', // Role permission mappings
|
|
168
|
+
];
|
|
169
|
+
// Create backup if requested
|
|
170
|
+
if (createBackup) {
|
|
171
|
+
await this.createBackup(`roles_${roles.join('_')}_${eventId}`, InvalidationScope.ROLE_BASED, patterns, `Role permission change: ${reason}`);
|
|
172
|
+
}
|
|
173
|
+
// Clear caches
|
|
174
|
+
const keysCleared = await this.clearCachesByPatterns(patterns);
|
|
175
|
+
// Create audit event
|
|
176
|
+
const event = {
|
|
177
|
+
eventId,
|
|
178
|
+
type: InvalidationType.ROLE_ASSIGNMENT_CHANGE,
|
|
179
|
+
scope: InvalidationScope.ROLE_BASED,
|
|
180
|
+
patterns,
|
|
181
|
+
reason: `Roles affected: ${roles.join(', ')} - ${reason}`,
|
|
182
|
+
timestamp: new Date().toISOString(),
|
|
183
|
+
restorable: createBackup,
|
|
184
|
+
performance: {
|
|
185
|
+
keysCleared,
|
|
186
|
+
executionTimeMs: Date.now() - startTime,
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
await this.recordAuditEvent(event);
|
|
190
|
+
this.updatePerformanceMetrics(keysCleared, Date.now() - startTime);
|
|
191
|
+
console.log('🧹 Conservative role cache invalidation completed', {
|
|
192
|
+
type: 'role_permission_change',
|
|
193
|
+
roles,
|
|
194
|
+
keysCleared,
|
|
195
|
+
duration: Date.now() - startTime,
|
|
196
|
+
reason,
|
|
197
|
+
});
|
|
198
|
+
return event;
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
console.error('❌ Role cache invalidation failed', {
|
|
202
|
+
roles,
|
|
203
|
+
reason,
|
|
204
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
205
|
+
duration: Date.now() - startTime,
|
|
206
|
+
});
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* System-wide cache invalidation
|
|
212
|
+
*
|
|
213
|
+
* Nuclear option: Clears all permission-related caches across the system.
|
|
214
|
+
* Used for major system updates, security incidents, or when unsure about
|
|
215
|
+
* the scope of changes.
|
|
216
|
+
*
|
|
217
|
+
* @param reason - Reason for system-wide invalidation
|
|
218
|
+
* @param createBackup - Whether to create restoration backup
|
|
219
|
+
* @returns Invalidation event details
|
|
220
|
+
*/
|
|
221
|
+
async invalidateSystemWide(reason, createBackup = false) {
|
|
222
|
+
const startTime = Date.now();
|
|
223
|
+
const eventId = this.generateEventId();
|
|
224
|
+
try {
|
|
225
|
+
// Nuclear option: clear everything
|
|
226
|
+
const patterns = ['*'];
|
|
227
|
+
// Create backup if requested (warning: this could be large)
|
|
228
|
+
if (createBackup) {
|
|
229
|
+
await this.createBackup(`system_wide_${eventId}`, InvalidationScope.SYSTEM_WIDE, patterns, `System-wide invalidation: ${reason}`);
|
|
230
|
+
}
|
|
231
|
+
// Flush entire cache
|
|
232
|
+
await this.cache.flush();
|
|
233
|
+
const keysCleared = -1; // Unknown count for flush operation
|
|
234
|
+
// Create audit event
|
|
235
|
+
const event = {
|
|
236
|
+
eventId,
|
|
237
|
+
type: InvalidationType.SYSTEM_PERMISSION_UPDATE,
|
|
238
|
+
scope: InvalidationScope.SYSTEM_WIDE,
|
|
239
|
+
patterns,
|
|
240
|
+
reason,
|
|
241
|
+
timestamp: new Date().toISOString(),
|
|
242
|
+
restorable: createBackup,
|
|
243
|
+
performance: {
|
|
244
|
+
keysCleared,
|
|
245
|
+
executionTimeMs: Date.now() - startTime,
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
await this.recordAuditEvent(event);
|
|
249
|
+
this.updatePerformanceMetrics(1000, Date.now() - startTime); // Estimate for stats
|
|
250
|
+
console.log('💥 System-wide cache invalidation completed', {
|
|
251
|
+
type: 'system_wide',
|
|
252
|
+
duration: Date.now() - startTime,
|
|
253
|
+
reason,
|
|
254
|
+
warning: 'All caches cleared',
|
|
255
|
+
});
|
|
256
|
+
return event;
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
console.error('❌ System-wide cache invalidation failed', {
|
|
260
|
+
reason,
|
|
261
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
262
|
+
duration: Date.now() - startTime,
|
|
263
|
+
});
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Emergency security invalidation
|
|
269
|
+
*
|
|
270
|
+
* Immediate cache clearing for security incidents.
|
|
271
|
+
* Bypasses backup creation for speed and clears everything.
|
|
272
|
+
*
|
|
273
|
+
* @param reason - Security incident description
|
|
274
|
+
* @returns Invalidation event details
|
|
275
|
+
*/
|
|
276
|
+
async emergencySecurityInvalidation(reason) {
|
|
277
|
+
const startTime = Date.now();
|
|
278
|
+
const eventId = this.generateEventId();
|
|
279
|
+
try {
|
|
280
|
+
// Emergency flush - no backup, clear everything immediately
|
|
281
|
+
await this.cache.flush();
|
|
282
|
+
// Create audit event
|
|
283
|
+
const event = {
|
|
284
|
+
eventId,
|
|
285
|
+
type: InvalidationType.SECURITY_INCIDENT,
|
|
286
|
+
scope: InvalidationScope.SYSTEM_WIDE,
|
|
287
|
+
patterns: ['*'],
|
|
288
|
+
reason: `SECURITY INCIDENT: ${reason}`,
|
|
289
|
+
timestamp: new Date().toISOString(),
|
|
290
|
+
restorable: false,
|
|
291
|
+
performance: {
|
|
292
|
+
keysCleared: -1,
|
|
293
|
+
executionTimeMs: Date.now() - startTime,
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
await this.recordAuditEvent(event);
|
|
297
|
+
this.updatePerformanceMetrics(1000, Date.now() - startTime);
|
|
298
|
+
console.error('🚨 EMERGENCY: Security cache invalidation completed', {
|
|
299
|
+
type: 'security_incident',
|
|
300
|
+
duration: Date.now() - startTime,
|
|
301
|
+
reason,
|
|
302
|
+
warning: 'ALL CACHES CLEARED FOR SECURITY',
|
|
303
|
+
});
|
|
304
|
+
return event;
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
console.error('❌ CRITICAL: Emergency cache invalidation failed', {
|
|
308
|
+
reason,
|
|
309
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
310
|
+
duration: Date.now() - startTime,
|
|
311
|
+
});
|
|
312
|
+
throw error;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Restore cache from backup
|
|
317
|
+
*
|
|
318
|
+
* Attempts to restore previously backed up cache data.
|
|
319
|
+
* Use with caution - only restore if you're certain the data is safe.
|
|
320
|
+
*
|
|
321
|
+
* @param backupId - ID of the backup to restore
|
|
322
|
+
* @returns Restoration success status
|
|
323
|
+
*/
|
|
324
|
+
async restoreFromBackup(backupId) {
|
|
325
|
+
const backup = this.backups.get(backupId);
|
|
326
|
+
if (!backup) {
|
|
327
|
+
console.error('❌ Backup not found', { backupId });
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
// Check backup age
|
|
331
|
+
const backupAge = Date.now() - new Date(backup.timestamp).getTime();
|
|
332
|
+
if (backupAge > this.maxBackupAge) {
|
|
333
|
+
console.warn('⚠️ Backup is old, restoration may not be safe', {
|
|
334
|
+
backupId,
|
|
335
|
+
ageHours: backupAge / (1000 * 60 * 60),
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
try {
|
|
339
|
+
let restoredCount = 0;
|
|
340
|
+
// Restore each cache entry
|
|
341
|
+
for (const [key, value] of backup.data) {
|
|
342
|
+
await this.cache.set(key, value);
|
|
343
|
+
restoredCount++;
|
|
344
|
+
}
|
|
345
|
+
console.log('✅ Cache restored from backup', {
|
|
346
|
+
backupId,
|
|
347
|
+
restoredEntries: restoredCount,
|
|
348
|
+
originalSize: backup.metadata.totalEntries,
|
|
349
|
+
});
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
catch (error) {
|
|
353
|
+
console.error('❌ Cache restoration failed', {
|
|
354
|
+
backupId,
|
|
355
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
356
|
+
});
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Get invalidation audit log
|
|
362
|
+
*/
|
|
363
|
+
getAuditLog() {
|
|
364
|
+
return [...this.auditLog];
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Get available backups
|
|
368
|
+
*/
|
|
369
|
+
getAvailableBackups() {
|
|
370
|
+
return Array.from(this.backups.values()).map((backup) => ({
|
|
371
|
+
backupId: backup.backupId,
|
|
372
|
+
timestamp: backup.timestamp,
|
|
373
|
+
scope: backup.scope,
|
|
374
|
+
totalEntries: backup.metadata.totalEntries,
|
|
375
|
+
sizeBytes: backup.metadata.sizeBytes,
|
|
376
|
+
ageHours: (Date.now() - new Date(backup.timestamp).getTime()) / (1000 * 60 * 60),
|
|
377
|
+
}));
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Get invalidation statistics
|
|
381
|
+
*/
|
|
382
|
+
getStats() {
|
|
383
|
+
return {
|
|
384
|
+
invalidationCount: this.invalidationCount,
|
|
385
|
+
totalKeysCleared: this.totalKeysCleared,
|
|
386
|
+
averageExecutionTimeMs: this.invalidationCount > 0
|
|
387
|
+
? this.totalExecutionTimeMs / this.invalidationCount
|
|
388
|
+
: 0,
|
|
389
|
+
totalExecutionTimeMs: this.totalExecutionTimeMs,
|
|
390
|
+
auditLogSize: this.auditLog.length,
|
|
391
|
+
backupsAvailable: this.backups.size,
|
|
392
|
+
oldestBackupAge: this.getOldestBackupAge(),
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Clear patterns from cache
|
|
397
|
+
*/
|
|
398
|
+
async clearCachesByPatterns(patterns) {
|
|
399
|
+
let totalKeysCleared = 0;
|
|
400
|
+
for (const pattern of patterns) {
|
|
401
|
+
try {
|
|
402
|
+
if (pattern === '*') {
|
|
403
|
+
// Special case: flush all
|
|
404
|
+
await this.cache.flush();
|
|
405
|
+
return -1; // Unknown count
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
// Pattern-based deletion
|
|
409
|
+
await this.cache.deletePattern(pattern);
|
|
410
|
+
totalKeysCleared += 10; // Estimate since we don't have exact counts
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
console.warn('⚠️ Pattern deletion failed', {
|
|
415
|
+
pattern,
|
|
416
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return totalKeysCleared;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Create backup of cache data
|
|
424
|
+
*/
|
|
425
|
+
async createBackup(backupId, scope, patterns, reason) {
|
|
426
|
+
// Note: This is a simplified backup implementation
|
|
427
|
+
// In production, you'd implement pattern-based cache reading
|
|
428
|
+
const backup = {
|
|
429
|
+
backupId,
|
|
430
|
+
timestamp: new Date().toISOString(),
|
|
431
|
+
scope,
|
|
432
|
+
data: new Map(), // Would contain actual cached data
|
|
433
|
+
metadata: {
|
|
434
|
+
totalEntries: 0,
|
|
435
|
+
sizeBytes: 0,
|
|
436
|
+
createdBy: 'ConservativeCacheInvalidation',
|
|
437
|
+
reason,
|
|
438
|
+
},
|
|
439
|
+
};
|
|
440
|
+
this.backups.set(backupId, backup);
|
|
441
|
+
// Clean up old backups
|
|
442
|
+
this.cleanupOldBackups();
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Record audit event
|
|
446
|
+
*/
|
|
447
|
+
async recordAuditEvent(event) {
|
|
448
|
+
this.auditLog.push(event);
|
|
449
|
+
// Keep audit log size manageable
|
|
450
|
+
if (this.auditLog.length > this.maxAuditLogSize) {
|
|
451
|
+
this.auditLog.shift();
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Update performance metrics
|
|
456
|
+
*/
|
|
457
|
+
updatePerformanceMetrics(keysCleared, executionTimeMs) {
|
|
458
|
+
this.invalidationCount++;
|
|
459
|
+
this.totalKeysCleared += Math.max(0, keysCleared);
|
|
460
|
+
this.totalExecutionTimeMs += executionTimeMs;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Generate unique event ID
|
|
464
|
+
*/
|
|
465
|
+
generateEventId() {
|
|
466
|
+
return `inv_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Clean up old backups
|
|
470
|
+
*/
|
|
471
|
+
cleanupOldBackups() {
|
|
472
|
+
const now = Date.now();
|
|
473
|
+
const keysToDelete = [];
|
|
474
|
+
for (const [backupId, backup] of this.backups) {
|
|
475
|
+
const age = now - new Date(backup.timestamp).getTime();
|
|
476
|
+
if (age > this.maxBackupAge) {
|
|
477
|
+
keysToDelete.push(backupId);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
keysToDelete.forEach((key) => {
|
|
481
|
+
this.backups.delete(key);
|
|
482
|
+
});
|
|
483
|
+
if (keysToDelete.length > 0) {
|
|
484
|
+
console.log('🗑️ Cleaned up old cache backups', {
|
|
485
|
+
removedBackups: keysToDelete.length,
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Get age of oldest backup in hours
|
|
491
|
+
*/
|
|
492
|
+
getOldestBackupAge() {
|
|
493
|
+
if (this.backups.size === 0)
|
|
494
|
+
return 0;
|
|
495
|
+
let oldest = Date.now();
|
|
496
|
+
for (const backup of this.backups.values()) {
|
|
497
|
+
const backupTime = new Date(backup.timestamp).getTime();
|
|
498
|
+
if (backupTime < oldest) {
|
|
499
|
+
oldest = backupTime;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return (Date.now() - oldest) / (1000 * 60 * 60);
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
exports.ConservativeCacheInvalidation = ConservativeCacheInvalidation;
|
|
506
|
+
exports.ConservativeCacheInvalidation = ConservativeCacheInvalidation = __decorate([
|
|
507
|
+
(0, typedi_1.Service)(),
|
|
508
|
+
__metadata("design:paramtypes", [Object])
|
|
509
|
+
], ConservativeCacheInvalidation);
|
|
510
|
+
//# sourceMappingURL=ConservativeCacheInvalidation.js.map
|