@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,460 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Fast Authentication Guard
|
|
4
|
+
*
|
|
5
|
+
* High-performance authentication guard with multi-layer caching for serverless
|
|
6
|
+
* environments. Provides sub-millisecond cached authentication checks while
|
|
7
|
+
* maintaining security through conservative cache invalidation strategies.
|
|
8
|
+
*
|
|
9
|
+
* Key Features:
|
|
10
|
+
* - Multi-layer caching (L1 memory + L2 distributed)
|
|
11
|
+
* - JWT token validation with caching
|
|
12
|
+
* - User context loading and caching
|
|
13
|
+
* - Permission pre-loading for faster authorization
|
|
14
|
+
* - Security-first approach with automatic cache invalidation
|
|
15
|
+
* - Comprehensive audit logging and metrics
|
|
16
|
+
*
|
|
17
|
+
* Performance Characteristics:
|
|
18
|
+
* - Cached authentication: ~0.1ms (sub-millisecond)
|
|
19
|
+
* - Cold authentication: ~2-5ms (including token validation)
|
|
20
|
+
* - Memory usage: Low (LRU cache with configurable limits)
|
|
21
|
+
* - Network usage: Minimal (cached responses)
|
|
22
|
+
*
|
|
23
|
+
* Security Features:
|
|
24
|
+
* - Token signature validation
|
|
25
|
+
* - Token expiration checks
|
|
26
|
+
* - User status validation (active/suspended/deleted)
|
|
27
|
+
* - Automatic cache invalidation on security events
|
|
28
|
+
* - Rate limiting integration
|
|
29
|
+
* - Audit trail for all authentication events
|
|
30
|
+
*
|
|
31
|
+
* @author Noony Framework Team
|
|
32
|
+
* @version 1.0.0
|
|
33
|
+
*/
|
|
34
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
35
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
36
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
37
|
+
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;
|
|
38
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
39
|
+
};
|
|
40
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
41
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
42
|
+
};
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.FastAuthGuard = void 0;
|
|
45
|
+
const typedi_1 = require("typedi");
|
|
46
|
+
const errors_1 = require("../../../core/errors");
|
|
47
|
+
const CacheAdapter_1 = require("../cache/CacheAdapter");
|
|
48
|
+
const GuardConfiguration_1 = require("../config/GuardConfiguration");
|
|
49
|
+
const FastUserContextService_1 = require("../services/FastUserContextService");
|
|
50
|
+
const ConservativeCacheInvalidation_1 = require("../cache/ConservativeCacheInvalidation");
|
|
51
|
+
/**
|
|
52
|
+
* Fast Authentication Guard Implementation
|
|
53
|
+
*/
|
|
54
|
+
let FastAuthGuard = class FastAuthGuard {
|
|
55
|
+
cache;
|
|
56
|
+
config;
|
|
57
|
+
authConfig;
|
|
58
|
+
userContextService;
|
|
59
|
+
cacheInvalidation;
|
|
60
|
+
tokenValidator;
|
|
61
|
+
// Performance tracking
|
|
62
|
+
authAttempts = 0;
|
|
63
|
+
cacheHits = 0;
|
|
64
|
+
cacheMisses = 0;
|
|
65
|
+
authFailures = 0;
|
|
66
|
+
totalResolutionTimeUs = 0;
|
|
67
|
+
// Security tracking
|
|
68
|
+
suspiciousAttempts = 0;
|
|
69
|
+
blockedTokens = new Set();
|
|
70
|
+
lastSecurityEvent = 0;
|
|
71
|
+
constructor(cache, config, authConfig, userContextService, cacheInvalidation, tokenValidator) {
|
|
72
|
+
this.cache = cache;
|
|
73
|
+
this.config = config;
|
|
74
|
+
this.authConfig = authConfig;
|
|
75
|
+
this.userContextService = userContextService;
|
|
76
|
+
this.cacheInvalidation = cacheInvalidation;
|
|
77
|
+
this.tokenValidator = tokenValidator;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Execute authentication check
|
|
81
|
+
*
|
|
82
|
+
* This is the main middleware execution method that handles the complete
|
|
83
|
+
* authentication flow with caching and security validations.
|
|
84
|
+
*/
|
|
85
|
+
async before(context) {
|
|
86
|
+
const startTime = process.hrtime.bigint();
|
|
87
|
+
this.authAttempts++;
|
|
88
|
+
try {
|
|
89
|
+
// Extract token from request
|
|
90
|
+
const token = this.extractToken(context);
|
|
91
|
+
if (!token) {
|
|
92
|
+
throw new errors_1.AuthenticationError('Authentication token required');
|
|
93
|
+
}
|
|
94
|
+
// Check if token is blocked
|
|
95
|
+
if (this.blockedTokens.has(token)) {
|
|
96
|
+
this.recordSecurityEvent('blocked_token_used', context);
|
|
97
|
+
throw new errors_1.AuthenticationError('Token has been revoked');
|
|
98
|
+
}
|
|
99
|
+
// Authenticate user
|
|
100
|
+
const authResult = await this.authenticateUser(token);
|
|
101
|
+
if (!authResult.success || !authResult.user) {
|
|
102
|
+
this.authFailures++;
|
|
103
|
+
throw new errors_1.AuthenticationError(authResult.reason || 'Authentication failed');
|
|
104
|
+
}
|
|
105
|
+
// Store authentication result in context
|
|
106
|
+
context.businessData.set('authResult', authResult);
|
|
107
|
+
context.businessData.set('user', authResult.user);
|
|
108
|
+
context.businessData.set('userId', authResult.user.userId);
|
|
109
|
+
// Update performance metrics
|
|
110
|
+
const endTime = process.hrtime.bigint();
|
|
111
|
+
const resolutionTimeUs = Number(endTime - startTime) / 1000;
|
|
112
|
+
this.totalResolutionTimeUs += resolutionTimeUs;
|
|
113
|
+
// Log successful authentication
|
|
114
|
+
this.logAuthenticationEvent('success', {
|
|
115
|
+
userId: authResult.user.userId,
|
|
116
|
+
cached: authResult.cached,
|
|
117
|
+
resolutionTimeUs,
|
|
118
|
+
requestId: context.requestId,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
// Update failure metrics
|
|
123
|
+
this.authFailures++;
|
|
124
|
+
// Log authentication failure
|
|
125
|
+
this.logAuthenticationEvent('failure', {
|
|
126
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
127
|
+
requestId: context.requestId,
|
|
128
|
+
suspicious: this.isSuspiciousRequest(context),
|
|
129
|
+
});
|
|
130
|
+
// Handle suspicious activity
|
|
131
|
+
if (this.isSuspiciousRequest(context)) {
|
|
132
|
+
this.handleSuspiciousActivity(context);
|
|
133
|
+
}
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
const endTime = process.hrtime.bigint();
|
|
138
|
+
const resolutionTimeUs = Number(endTime - startTime) / 1000;
|
|
139
|
+
this.totalResolutionTimeUs += resolutionTimeUs;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Authenticate user with multi-layer caching
|
|
144
|
+
*
|
|
145
|
+
* Implements the core authentication logic with intelligent caching
|
|
146
|
+
* to minimize database calls and token validation overhead.
|
|
147
|
+
*
|
|
148
|
+
* @param token - JWT token string
|
|
149
|
+
* @returns Authentication result with user context
|
|
150
|
+
*/
|
|
151
|
+
async authenticateUser(token) {
|
|
152
|
+
const startTime = process.hrtime.bigint();
|
|
153
|
+
try {
|
|
154
|
+
// Check authentication cache first
|
|
155
|
+
const cacheKey = CacheAdapter_1.CacheKeyBuilder.authToken(token);
|
|
156
|
+
const cachedAuth = await this.cache.get(cacheKey);
|
|
157
|
+
if (cachedAuth && this.isCachedAuthValid(cachedAuth)) {
|
|
158
|
+
this.cacheHits++;
|
|
159
|
+
return {
|
|
160
|
+
...cachedAuth,
|
|
161
|
+
cached: true,
|
|
162
|
+
resolutionTimeUs: Number(process.hrtime.bigint() - startTime) / 1000,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
this.cacheMisses++;
|
|
166
|
+
// Validate token signature and structure
|
|
167
|
+
const tokenValidation = await this.tokenValidator.validateToken(token);
|
|
168
|
+
if (!tokenValidation.valid || !tokenValidation.decoded) {
|
|
169
|
+
return {
|
|
170
|
+
success: false,
|
|
171
|
+
cached: false,
|
|
172
|
+
resolutionTimeUs: Number(process.hrtime.bigint() - startTime) / 1000,
|
|
173
|
+
reason: tokenValidation.error || 'Invalid token',
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
// Check token expiration
|
|
177
|
+
if (this.tokenValidator.isTokenExpired(tokenValidation.decoded)) {
|
|
178
|
+
return {
|
|
179
|
+
success: false,
|
|
180
|
+
cached: false,
|
|
181
|
+
resolutionTimeUs: Number(process.hrtime.bigint() - startTime) / 1000,
|
|
182
|
+
reason: 'Token expired',
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
// Extract user ID and load user context
|
|
186
|
+
const userId = this.tokenValidator.extractUserId(tokenValidation.decoded);
|
|
187
|
+
const userContext = await this.userContextService.getUserContext(userId);
|
|
188
|
+
if (!userContext) {
|
|
189
|
+
return {
|
|
190
|
+
success: false,
|
|
191
|
+
cached: false,
|
|
192
|
+
resolutionTimeUs: Number(process.hrtime.bigint() - startTime) / 1000,
|
|
193
|
+
reason: 'User not found',
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
// Validate user status and permissions
|
|
197
|
+
if (!this.isUserAllowed(userContext)) {
|
|
198
|
+
return {
|
|
199
|
+
success: false,
|
|
200
|
+
cached: false,
|
|
201
|
+
resolutionTimeUs: Number(process.hrtime.bigint() - startTime) / 1000,
|
|
202
|
+
reason: 'User account is not active',
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
// Run custom validation if configured
|
|
206
|
+
if (this.authConfig.customValidation) {
|
|
207
|
+
const customValid = await this.authConfig.customValidation(tokenValidation.decoded, userContext);
|
|
208
|
+
if (!customValid) {
|
|
209
|
+
return {
|
|
210
|
+
success: false,
|
|
211
|
+
cached: false,
|
|
212
|
+
resolutionTimeUs: Number(process.hrtime.bigint() - startTime) / 1000,
|
|
213
|
+
reason: 'Custom validation failed',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Build successful authentication result
|
|
218
|
+
const authResult = {
|
|
219
|
+
success: true,
|
|
220
|
+
user: userContext,
|
|
221
|
+
token: {
|
|
222
|
+
decoded: tokenValidation.decoded,
|
|
223
|
+
raw: token,
|
|
224
|
+
expiresAt: new Date(tokenValidation.decoded.exp * 1000).toISOString(),
|
|
225
|
+
issuer: tokenValidation.decoded.iss,
|
|
226
|
+
},
|
|
227
|
+
cached: false,
|
|
228
|
+
resolutionTimeUs: Number(process.hrtime.bigint() - startTime) / 1000,
|
|
229
|
+
};
|
|
230
|
+
// Cache the successful authentication
|
|
231
|
+
await this.cacheAuthResult(token, authResult);
|
|
232
|
+
return authResult;
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
return {
|
|
236
|
+
success: false,
|
|
237
|
+
cached: false,
|
|
238
|
+
resolutionTimeUs: Number(process.hrtime.bigint() - startTime) / 1000,
|
|
239
|
+
reason: error instanceof Error ? error.message : 'Authentication error',
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Invalidate authentication cache for user
|
|
245
|
+
*
|
|
246
|
+
* Called when user permissions change or security events occur.
|
|
247
|
+
* Uses conservative invalidation to ensure security.
|
|
248
|
+
*
|
|
249
|
+
* @param userId - User ID to invalidate
|
|
250
|
+
* @param reason - Reason for invalidation
|
|
251
|
+
*/
|
|
252
|
+
async invalidateUserAuth(userId, reason) {
|
|
253
|
+
// Use conservative cache invalidation
|
|
254
|
+
await this.cacheInvalidation.invalidateUserPermissions(userId, reason);
|
|
255
|
+
// Also clear direct auth caches
|
|
256
|
+
await this.cache.deletePattern(`auth:token:*:${userId}`);
|
|
257
|
+
console.log('🔄 User authentication cache invalidated', {
|
|
258
|
+
userId,
|
|
259
|
+
reason,
|
|
260
|
+
timestamp: new Date().toISOString(),
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Block token for security reasons
|
|
265
|
+
*
|
|
266
|
+
* Immediately blocks a token from being used and clears its cache.
|
|
267
|
+
*
|
|
268
|
+
* @param token - Token to block
|
|
269
|
+
* @param reason - Reason for blocking
|
|
270
|
+
*/
|
|
271
|
+
async blockToken(token, reason) {
|
|
272
|
+
// Add to blocked tokens
|
|
273
|
+
this.blockedTokens.add(token);
|
|
274
|
+
// Clear token cache
|
|
275
|
+
const cacheKey = CacheAdapter_1.CacheKeyBuilder.authToken(token);
|
|
276
|
+
await this.cache.delete(cacheKey);
|
|
277
|
+
// Record security event
|
|
278
|
+
this.recordSecurityEvent('token_blocked', null, { token, reason });
|
|
279
|
+
console.warn('🚫 Token blocked for security', {
|
|
280
|
+
tokenHash: this.hashToken(token),
|
|
281
|
+
reason,
|
|
282
|
+
timestamp: new Date().toISOString(),
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Get authentication statistics
|
|
287
|
+
*/
|
|
288
|
+
getStats() {
|
|
289
|
+
const totalCacheRequests = this.cacheHits + this.cacheMisses;
|
|
290
|
+
return {
|
|
291
|
+
authAttempts: this.authAttempts,
|
|
292
|
+
authFailures: this.authFailures,
|
|
293
|
+
successRate: this.authAttempts > 0
|
|
294
|
+
? ((this.authAttempts - this.authFailures) / this.authAttempts) * 100
|
|
295
|
+
: 100,
|
|
296
|
+
cacheHitRate: totalCacheRequests > 0
|
|
297
|
+
? (this.cacheHits / totalCacheRequests) * 100
|
|
298
|
+
: 0,
|
|
299
|
+
cacheHits: this.cacheHits,
|
|
300
|
+
cacheMisses: this.cacheMisses,
|
|
301
|
+
averageResolutionTimeUs: this.authAttempts > 0
|
|
302
|
+
? this.totalResolutionTimeUs / this.authAttempts
|
|
303
|
+
: 0,
|
|
304
|
+
totalResolutionTimeUs: this.totalResolutionTimeUs,
|
|
305
|
+
suspiciousAttempts: this.suspiciousAttempts,
|
|
306
|
+
blockedTokens: this.blockedTokens.size,
|
|
307
|
+
lastSecurityEvent: this.lastSecurityEvent,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Reset statistics
|
|
312
|
+
*/
|
|
313
|
+
resetStats() {
|
|
314
|
+
this.authAttempts = 0;
|
|
315
|
+
this.cacheHits = 0;
|
|
316
|
+
this.cacheMisses = 0;
|
|
317
|
+
this.authFailures = 0;
|
|
318
|
+
this.totalResolutionTimeUs = 0;
|
|
319
|
+
this.suspiciousAttempts = 0;
|
|
320
|
+
this.lastSecurityEvent = 0;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Extract token from request context
|
|
324
|
+
*/
|
|
325
|
+
extractToken(context) {
|
|
326
|
+
const authHeader = context.req.headers[this.authConfig.tokenHeader.toLowerCase()];
|
|
327
|
+
if (!authHeader || typeof authHeader !== 'string') {
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
// Check for token prefix
|
|
331
|
+
if (this.authConfig.tokenPrefix) {
|
|
332
|
+
if (!authHeader.startsWith(this.authConfig.tokenPrefix)) {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
return authHeader.substring(this.authConfig.tokenPrefix.length).trim();
|
|
336
|
+
}
|
|
337
|
+
return authHeader.trim();
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Check if cached authentication is still valid
|
|
341
|
+
*/
|
|
342
|
+
isCachedAuthValid(cachedAuth) {
|
|
343
|
+
if (!cachedAuth.success || !cachedAuth.token) {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
// Check token expiration
|
|
347
|
+
const expiresAt = new Date(cachedAuth.token.expiresAt);
|
|
348
|
+
if (expiresAt <= new Date()) {
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
// Check if cache entry is too old
|
|
352
|
+
const cacheAge = Date.now() - cachedAuth.resolutionTimeUs / 1000;
|
|
353
|
+
const maxCacheAge = this.config.cache.authTokenTtlMs || 5 * 60 * 1000;
|
|
354
|
+
return cacheAge < maxCacheAge;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Check if user is allowed to authenticate
|
|
358
|
+
*/
|
|
359
|
+
isUserAllowed(user) {
|
|
360
|
+
// Check if user is active
|
|
361
|
+
if (!this.authConfig.allowInactiveUsers) {
|
|
362
|
+
// Assume user context has status field
|
|
363
|
+
const userStatus = user.metadata?.status;
|
|
364
|
+
if (userStatus && userStatus !== 'active') {
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// Check email verification if required
|
|
369
|
+
if (this.authConfig.requireEmailVerification) {
|
|
370
|
+
const emailVerified = user.metadata?.emailVerified;
|
|
371
|
+
if (!emailVerified) {
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return true;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Cache authentication result
|
|
379
|
+
*/
|
|
380
|
+
async cacheAuthResult(token, authResult) {
|
|
381
|
+
const cacheKey = CacheAdapter_1.CacheKeyBuilder.authToken(token);
|
|
382
|
+
const ttlMs = this.config.cache.authTokenTtlMs || 5 * 60 * 1000; // 5 minutes default
|
|
383
|
+
// Don't cache the raw token in the result
|
|
384
|
+
const cacheData = {
|
|
385
|
+
...authResult,
|
|
386
|
+
token: {
|
|
387
|
+
...authResult.token,
|
|
388
|
+
raw: undefined, // Remove raw token from cache for security
|
|
389
|
+
},
|
|
390
|
+
};
|
|
391
|
+
await this.cache.set(cacheKey, cacheData, ttlMs);
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Check if request appears suspicious
|
|
395
|
+
*/
|
|
396
|
+
isSuspiciousRequest(context) {
|
|
397
|
+
// Implement suspicious activity detection logic
|
|
398
|
+
// This is a simplified version - in production, you'd implement more sophisticated detection
|
|
399
|
+
const userAgent = context.req.headers['user-agent'];
|
|
400
|
+
// Flag requests without user agent
|
|
401
|
+
if (!userAgent) {
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
// Flag requests from known suspicious patterns
|
|
405
|
+
if (userAgent.includes('bot') && !userAgent.includes('Googlebot')) {
|
|
406
|
+
return true;
|
|
407
|
+
}
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Handle suspicious activity
|
|
412
|
+
*/
|
|
413
|
+
handleSuspiciousActivity(context) {
|
|
414
|
+
this.suspiciousAttempts++;
|
|
415
|
+
// Record security event
|
|
416
|
+
this.recordSecurityEvent('suspicious_activity', context);
|
|
417
|
+
// In production, you might:
|
|
418
|
+
// - Rate limit the IP
|
|
419
|
+
// - Alert security team
|
|
420
|
+
// - Block certain patterns
|
|
421
|
+
// - Require additional verification
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Record security event
|
|
425
|
+
*/
|
|
426
|
+
recordSecurityEvent(eventType, context, additionalData) {
|
|
427
|
+
this.lastSecurityEvent = Date.now();
|
|
428
|
+
console.warn('🔒 Security event recorded', {
|
|
429
|
+
eventType,
|
|
430
|
+
requestId: context?.requestId,
|
|
431
|
+
timestamp: new Date().toISOString(),
|
|
432
|
+
...additionalData,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Hash token for secure logging
|
|
437
|
+
*/
|
|
438
|
+
hashToken(token) {
|
|
439
|
+
// Simple hash for logging (in production, use proper crypto)
|
|
440
|
+
return token.substring(0, 8) + '...' + token.substring(token.length - 8);
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Log authentication event
|
|
444
|
+
*/
|
|
445
|
+
logAuthenticationEvent(eventType, data) {
|
|
446
|
+
const logLevel = eventType === 'success' ? 'info' : 'warn';
|
|
447
|
+
const emoji = eventType === 'success' ? '✅' : '❌';
|
|
448
|
+
console[logLevel](`${emoji} Authentication ${eventType}`, {
|
|
449
|
+
...data,
|
|
450
|
+
timestamp: new Date().toISOString(),
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
exports.FastAuthGuard = FastAuthGuard;
|
|
455
|
+
exports.FastAuthGuard = FastAuthGuard = __decorate([
|
|
456
|
+
(0, typedi_1.Service)(),
|
|
457
|
+
__metadata("design:paramtypes", [Object, GuardConfiguration_1.GuardConfiguration, Object, FastUserContextService_1.FastUserContextService,
|
|
458
|
+
ConservativeCacheInvalidation_1.ConservativeCacheInvalidation, Object])
|
|
459
|
+
], FastAuthGuard);
|
|
460
|
+
//# sourceMappingURL=FastAuthGuard.js.map
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission Guard Factory
|
|
3
|
+
*
|
|
4
|
+
* Factory for creating optimized permission guards tailored to specific endpoint requirements.
|
|
5
|
+
* This factory generates specialized guards that use the most appropriate permission resolution
|
|
6
|
+
* strategy based on the permission requirements, maximizing performance while maintaining security.
|
|
7
|
+
*
|
|
8
|
+
* Key Features:
|
|
9
|
+
* - Automatic resolver selection based on requirement patterns
|
|
10
|
+
* - Optimized guard generation for specific permission types
|
|
11
|
+
* - Caching strategy optimization per guard type
|
|
12
|
+
* - Performance monitoring and metrics collection
|
|
13
|
+
* - Configuration-driven guard customization
|
|
14
|
+
* - Built-in error handling and logging
|
|
15
|
+
*
|
|
16
|
+
* Guard Types:
|
|
17
|
+
* - PlainPermissionGuard: For simple permission lists (fastest)
|
|
18
|
+
* - WildcardPermissionGuard: For hierarchical wildcard patterns
|
|
19
|
+
* - ExpressionPermissionGuard: For complex boolean expressions
|
|
20
|
+
* - CompositePermissionGuard: For mixed permission requirements
|
|
21
|
+
*
|
|
22
|
+
* Performance Optimization:
|
|
23
|
+
* - Pre-compiled permission validators
|
|
24
|
+
* - Strategy-specific caching configurations
|
|
25
|
+
* - Minimal overhead per request
|
|
26
|
+
* - Smart cache key generation
|
|
27
|
+
*
|
|
28
|
+
* @author Noony Framework Team
|
|
29
|
+
* @version 1.0.0
|
|
30
|
+
*/
|
|
31
|
+
import { Context } from '../../../core/core';
|
|
32
|
+
import { BaseMiddleware } from '../../../core/handler';
|
|
33
|
+
import { CacheAdapter } from '../cache/CacheAdapter';
|
|
34
|
+
import { GuardConfiguration } from '../config/GuardConfiguration';
|
|
35
|
+
import { FastUserContextService, UserContext } from '../services/FastUserContextService';
|
|
36
|
+
import { PermissionResolverType, PermissionCheckResult, PermissionExpression } from '../resolvers/PermissionResolver';
|
|
37
|
+
/**
|
|
38
|
+
* Guard configuration for specific permission requirements
|
|
39
|
+
*/
|
|
40
|
+
export interface GuardConfig {
|
|
41
|
+
requireAuth: boolean;
|
|
42
|
+
permissions: any;
|
|
43
|
+
resolverType?: PermissionResolverType;
|
|
44
|
+
cacheResults: boolean;
|
|
45
|
+
auditTrail: boolean;
|
|
46
|
+
errorMessage?: string;
|
|
47
|
+
allowPartialMatch?: boolean;
|
|
48
|
+
requireAllPermissions?: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Permission guard result
|
|
52
|
+
*/
|
|
53
|
+
export interface PermissionGuardResult {
|
|
54
|
+
allowed: boolean;
|
|
55
|
+
user?: UserContext;
|
|
56
|
+
checkResult: PermissionCheckResult;
|
|
57
|
+
guardType: string;
|
|
58
|
+
processingTimeUs: number;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Abstract base class for all permission guards
|
|
62
|
+
*/
|
|
63
|
+
declare abstract class BasePermissionGuard implements BaseMiddleware {
|
|
64
|
+
protected readonly config: GuardConfig;
|
|
65
|
+
protected readonly userContextService: FastUserContextService;
|
|
66
|
+
protected readonly guardConfig: GuardConfiguration;
|
|
67
|
+
protected readonly cache: CacheAdapter;
|
|
68
|
+
protected checkCount: number;
|
|
69
|
+
protected successCount: number;
|
|
70
|
+
protected failureCount: number;
|
|
71
|
+
protected totalProcessingTimeUs: number;
|
|
72
|
+
constructor(config: GuardConfig, userContextService: FastUserContextService, guardConfig: GuardConfiguration, cache: CacheAdapter);
|
|
73
|
+
before(context: Context): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Abstract method for permission checking - implemented by subclasses
|
|
76
|
+
*/
|
|
77
|
+
abstract checkPermissions(context: Context): Promise<PermissionGuardResult>;
|
|
78
|
+
/**
|
|
79
|
+
* Get performance statistics
|
|
80
|
+
*/
|
|
81
|
+
getStats(): {
|
|
82
|
+
guardType: string;
|
|
83
|
+
checkCount: number;
|
|
84
|
+
successCount: number;
|
|
85
|
+
failureCount: number;
|
|
86
|
+
successRate: number;
|
|
87
|
+
averageProcessingTimeUs: number;
|
|
88
|
+
totalProcessingTimeUs: number;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Reset statistics
|
|
92
|
+
*/
|
|
93
|
+
resetStats(): void;
|
|
94
|
+
/**
|
|
95
|
+
* Get guard type name
|
|
96
|
+
*/
|
|
97
|
+
abstract getGuardType(): string;
|
|
98
|
+
/**
|
|
99
|
+
* Log authorization event
|
|
100
|
+
*/
|
|
101
|
+
private logAuthorizationEvent;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Permission Guard Factory Implementation
|
|
105
|
+
*/
|
|
106
|
+
export declare class PermissionGuardFactory {
|
|
107
|
+
private readonly userContextService;
|
|
108
|
+
private readonly guardConfig;
|
|
109
|
+
private readonly cache;
|
|
110
|
+
private readonly guardCache;
|
|
111
|
+
constructor(userContextService: FastUserContextService, guardConfig: GuardConfiguration, cache: CacheAdapter);
|
|
112
|
+
/**
|
|
113
|
+
* Create a plain permission guard for simple permission lists
|
|
114
|
+
*
|
|
115
|
+
* @param permissions - Array of required permissions
|
|
116
|
+
* @param config - Optional guard configuration
|
|
117
|
+
* @returns Plain permission guard instance
|
|
118
|
+
*/
|
|
119
|
+
createPlainGuard(permissions: string[], config?: Partial<GuardConfig>): BasePermissionGuard;
|
|
120
|
+
/**
|
|
121
|
+
* Create a wildcard permission guard for hierarchical patterns
|
|
122
|
+
*
|
|
123
|
+
* @param wildcardPatterns - Array of wildcard patterns
|
|
124
|
+
* @param config - Optional guard configuration
|
|
125
|
+
* @returns Wildcard permission guard instance
|
|
126
|
+
*/
|
|
127
|
+
createWildcardGuard(wildcardPatterns: string[], config?: Partial<GuardConfig>): BasePermissionGuard;
|
|
128
|
+
/**
|
|
129
|
+
* Create an expression permission guard for complex boolean logic
|
|
130
|
+
*
|
|
131
|
+
* @param expression - Permission expression
|
|
132
|
+
* @param config - Optional guard configuration
|
|
133
|
+
* @returns Expression permission guard instance
|
|
134
|
+
*/
|
|
135
|
+
createExpressionGuard(expression: PermissionExpression, config?: Partial<GuardConfig>): BasePermissionGuard;
|
|
136
|
+
/**
|
|
137
|
+
* Create a composite guard for mixed permission requirements
|
|
138
|
+
*
|
|
139
|
+
* @param requirements - Array of sub-requirements with different resolver types
|
|
140
|
+
* @param config - Optional guard configuration
|
|
141
|
+
* @returns Composite permission guard instance
|
|
142
|
+
*/
|
|
143
|
+
createCompositeGuard(requirements: Array<{
|
|
144
|
+
permissions: any;
|
|
145
|
+
resolverType: PermissionResolverType;
|
|
146
|
+
required: boolean;
|
|
147
|
+
}>, config?: Partial<GuardConfig>): BasePermissionGuard;
|
|
148
|
+
/**
|
|
149
|
+
* Create guard with automatic resolver selection
|
|
150
|
+
*
|
|
151
|
+
* Analyzes the permission requirements and automatically selects
|
|
152
|
+
* the most appropriate resolver type for optimal performance.
|
|
153
|
+
*
|
|
154
|
+
* @param permissions - Permission requirements of any type
|
|
155
|
+
* @param config - Optional guard configuration
|
|
156
|
+
* @returns Optimally configured permission guard
|
|
157
|
+
*/
|
|
158
|
+
createAutoGuard(permissions: any, config?: Partial<GuardConfig>): BasePermissionGuard;
|
|
159
|
+
/**
|
|
160
|
+
* Get factory statistics
|
|
161
|
+
*/
|
|
162
|
+
getStats(): {
|
|
163
|
+
totalGuards: number;
|
|
164
|
+
guardsByType: Record<string, number>;
|
|
165
|
+
individualGuardStats: {
|
|
166
|
+
guardType: string;
|
|
167
|
+
checkCount: number;
|
|
168
|
+
successCount: number;
|
|
169
|
+
failureCount: number;
|
|
170
|
+
successRate: number;
|
|
171
|
+
averageProcessingTimeUs: number;
|
|
172
|
+
totalProcessingTimeUs: number;
|
|
173
|
+
}[];
|
|
174
|
+
aggregatedStats: any;
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Clear guard cache
|
|
178
|
+
*/
|
|
179
|
+
clearCache(): void;
|
|
180
|
+
/**
|
|
181
|
+
* Select optimal resolver based on permission requirements
|
|
182
|
+
*/
|
|
183
|
+
private selectOptimalResolver;
|
|
184
|
+
/**
|
|
185
|
+
* Generate cache key for guard instance reuse
|
|
186
|
+
*/
|
|
187
|
+
private generateCacheKey;
|
|
188
|
+
/**
|
|
189
|
+
* Simple hash function for cache keys
|
|
190
|
+
*/
|
|
191
|
+
private simpleHash;
|
|
192
|
+
/**
|
|
193
|
+
* Get guard counts by type
|
|
194
|
+
*/
|
|
195
|
+
private getGuardCountsByType;
|
|
196
|
+
/**
|
|
197
|
+
* Aggregate statistics from all guards
|
|
198
|
+
*/
|
|
199
|
+
private aggregateGuardStats;
|
|
200
|
+
}
|
|
201
|
+
export {};
|
|
202
|
+
//# sourceMappingURL=PermissionGuardFactory.d.ts.map
|