@noony-serverless/core 0.1.5 → 0.2.0
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/core/core.d.ts +16 -48
- package/build/core/core.js +2 -61
- package/build/core/handler.d.ts +37 -16
- package/build/core/handler.js +131 -42
- package/build/core/index.d.ts +0 -1
- package/build/core/index.js +0 -1
- package/build/middlewares/ConsolidatedValidationMiddleware.d.ts +126 -0
- package/build/middlewares/ConsolidatedValidationMiddleware.js +330 -0
- package/build/middlewares/ProcessingMiddleware.d.ts +138 -0
- package/build/middlewares/ProcessingMiddleware.js +425 -0
- package/build/middlewares/SecurityMiddleware.d.ts +157 -0
- package/build/middlewares/SecurityMiddleware.js +307 -0
- package/build/middlewares/bodyValidationMiddleware.d.ts +12 -10
- package/build/middlewares/bodyValidationMiddleware.js +10 -8
- package/build/middlewares/guards/RouteGuards.d.ts +239 -4
- package/build/middlewares/guards/RouteGuards.js +301 -8
- package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.d.ts +271 -0
- package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.js +301 -0
- package/build/middlewares/guards/config/GuardConfiguration.d.ts +50 -0
- package/build/middlewares/guards/config/GuardConfiguration.js +59 -0
- package/build/middlewares/guards/guards/FastAuthGuard.d.ts +5 -5
- package/build/middlewares/guards/guards/PermissionGuardFactory.d.ts +5 -13
- package/build/middlewares/guards/guards/PermissionGuardFactory.js +4 -4
- package/build/middlewares/guards/index.d.ts +43 -1
- package/build/middlewares/guards/index.js +46 -1
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.js +1 -1
- package/build/middlewares/guards/resolvers/PermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/PlainPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/WildcardPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/services/FastUserContextService.d.ts +20 -33
- package/build/middlewares/guards/services/FastUserContextService.js +17 -4
- package/build/middlewares/httpAttributesMiddleware.js +1 -1
- package/build/middlewares/index.d.ts +3 -1
- package/build/middlewares/index.js +6 -1
- package/build/middlewares/rateLimitingMiddleware.d.ts +492 -4
- package/build/middlewares/rateLimitingMiddleware.js +514 -6
- package/package.json +11 -9
- package/build/core/containerPool.d.ts +0 -44
- package/build/core/containerPool.js +0 -103
- package/build/middlewares/validationMiddleware.d.ts +0 -154
- package/build/middlewares/validationMiddleware.js +0 -185
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
* return { valid: false, error: error.message };
|
|
44
44
|
* }
|
|
45
45
|
* },
|
|
46
|
-
* extractUserId: (decoded:
|
|
47
|
-
* isTokenExpired: (decoded:
|
|
46
|
+
* extractUserId: (decoded: unknown) => (decoded as any).sub,
|
|
47
|
+
* isTokenExpired: (decoded: unknown) => (decoded as any).exp < Date.now() / 1000
|
|
48
48
|
* };
|
|
49
49
|
*
|
|
50
50
|
* // Configure guard system
|
|
@@ -168,6 +168,50 @@ const ConservativeCacheInvalidation_1 = require("./cache/ConservativeCacheInvali
|
|
|
168
168
|
const FastAuthGuard_1 = require("./guards/FastAuthGuard");
|
|
169
169
|
const PermissionGuardFactory_1 = require("./guards/PermissionGuardFactory");
|
|
170
170
|
const PermissionRegistry_1 = require("./registry/PermissionRegistry");
|
|
171
|
+
const CustomTokenVerificationPortAdapter_1 = require("./adapters/CustomTokenVerificationPortAdapter");
|
|
172
|
+
/**
|
|
173
|
+
* Helper function to check if a token validator is a CustomTokenVerificationPort
|
|
174
|
+
*/
|
|
175
|
+
function isCustomTokenVerificationPort(validator) {
|
|
176
|
+
return (typeof validator === 'object' &&
|
|
177
|
+
'verifyToken' in validator &&
|
|
178
|
+
!('validateToken' in validator));
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Convert any token validator to the TokenValidator interface expected by RouteGuards.
|
|
182
|
+
* Automatically wraps CustomTokenVerificationPort implementations with an adapter.
|
|
183
|
+
*/
|
|
184
|
+
function normalizeTokenValidator(validator) {
|
|
185
|
+
if (isCustomTokenVerificationPort(validator)) {
|
|
186
|
+
// For CustomTokenVerificationPort, we create a generic adapter
|
|
187
|
+
// We use a basic configuration that tries to extract common fields
|
|
188
|
+
return new CustomTokenVerificationPortAdapter_1.CustomTokenVerificationPortAdapter(validator, {
|
|
189
|
+
userIdExtractor: (user) => {
|
|
190
|
+
// Try to extract user ID from common field names
|
|
191
|
+
if (user && typeof user === 'object') {
|
|
192
|
+
const userObj = user;
|
|
193
|
+
return String(userObj.sub ||
|
|
194
|
+
userObj.id ||
|
|
195
|
+
userObj.userId ||
|
|
196
|
+
userObj.user_id ||
|
|
197
|
+
'unknown');
|
|
198
|
+
}
|
|
199
|
+
return 'unknown';
|
|
200
|
+
},
|
|
201
|
+
expirationExtractor: (user) => {
|
|
202
|
+
// Try to extract expiration from common field names
|
|
203
|
+
if (user && typeof user === 'object') {
|
|
204
|
+
const userObj = user;
|
|
205
|
+
const exp = userObj.exp || userObj.expiresAt || userObj.expires_at;
|
|
206
|
+
return typeof exp === 'number' ? exp : undefined;
|
|
207
|
+
}
|
|
208
|
+
return undefined;
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
// Already a TokenValidator, return as-is
|
|
213
|
+
return validator;
|
|
214
|
+
}
|
|
171
215
|
/**
|
|
172
216
|
* Route Guards Facade Implementation
|
|
173
217
|
*
|
|
@@ -211,9 +255,58 @@ let RouteGuards = class RouteGuards {
|
|
|
211
255
|
*
|
|
212
256
|
* @param profile - Environment profile with guard configurations
|
|
213
257
|
* @param permissionSource - User permission data source
|
|
214
|
-
* @param tokenValidator -
|
|
258
|
+
* @param tokenValidator - Token validation service (supports both TokenValidator and CustomTokenVerificationPort)
|
|
215
259
|
* @param authConfig - Authentication guard configuration
|
|
216
260
|
* @returns Promise resolving when configuration is complete
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* Using with CustomTokenVerificationPort from AuthenticationMiddleware:
|
|
264
|
+
* ```typescript
|
|
265
|
+
* import { CustomTokenVerificationPort } from '@/middlewares/authenticationMiddleware';
|
|
266
|
+
* import { RouteGuards, GuardSetup } from '@/middlewares/guards';
|
|
267
|
+
*
|
|
268
|
+
* // Same token verifier used across the framework
|
|
269
|
+
* const tokenVerifier: CustomTokenVerificationPort<User> = {
|
|
270
|
+
* async verifyToken(token: string): Promise<User> {
|
|
271
|
+
* const payload = jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload;
|
|
272
|
+
* return {
|
|
273
|
+
* id: payload.sub,
|
|
274
|
+
* email: payload.email,
|
|
275
|
+
* roles: payload.roles || [],
|
|
276
|
+
* sub: payload.sub,
|
|
277
|
+
* exp: payload.exp
|
|
278
|
+
* };
|
|
279
|
+
* }
|
|
280
|
+
* };
|
|
281
|
+
*
|
|
282
|
+
* // Configure RouteGuards with the same verifier
|
|
283
|
+
* await RouteGuards.configure(
|
|
284
|
+
* GuardSetup.production(),
|
|
285
|
+
* userPermissionSource,
|
|
286
|
+
* tokenVerifier, // Automatically wrapped with adapter
|
|
287
|
+
* authConfig
|
|
288
|
+
* );
|
|
289
|
+
* ```
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* Traditional usage with TokenValidator (backward compatible):
|
|
293
|
+
* ```typescript
|
|
294
|
+
* const tokenValidator: TokenValidator = {
|
|
295
|
+
* async validateToken(token: string) {
|
|
296
|
+
* // Your existing validation logic
|
|
297
|
+
* return { valid: true, decoded: userPayload };
|
|
298
|
+
* },
|
|
299
|
+
* extractUserId: (decoded) => decoded.sub,
|
|
300
|
+
* isTokenExpired: (decoded) => decoded.exp < Date.now() / 1000
|
|
301
|
+
* };
|
|
302
|
+
*
|
|
303
|
+
* await RouteGuards.configure(
|
|
304
|
+
* GuardSetup.production(),
|
|
305
|
+
* userPermissionSource,
|
|
306
|
+
* tokenValidator, // Works as before
|
|
307
|
+
* authConfig
|
|
308
|
+
* );
|
|
309
|
+
* ```
|
|
217
310
|
*/
|
|
218
311
|
static async configure(profile, permissionSource, tokenValidator, authConfig) {
|
|
219
312
|
if (RouteGuards_1.isConfigured) {
|
|
@@ -223,20 +316,30 @@ let RouteGuards = class RouteGuards {
|
|
|
223
316
|
try {
|
|
224
317
|
// Create guard configuration
|
|
225
318
|
const config = GuardConfiguration_1.GuardConfiguration.fromEnvironmentProfile(profile);
|
|
226
|
-
//
|
|
319
|
+
// Get effective cache type considering environment variable override
|
|
320
|
+
// Environment variable NOONY_GUARD_CACHE_ENABLE takes precedence for security
|
|
321
|
+
const effectiveCacheType = GuardConfiguration_1.GuardConfiguration.getEffectiveCacheType(profile.cacheType);
|
|
322
|
+
// Select cache adapter based on effective cache type
|
|
227
323
|
let cache;
|
|
228
|
-
if (
|
|
324
|
+
if (effectiveCacheType === 'memory') {
|
|
229
325
|
cache = new MemoryCacheAdapter_1.MemoryCacheAdapter({
|
|
230
326
|
maxSize: config.cache.maxEntries || 1000,
|
|
231
327
|
defaultTTL: config.cache.defaultTtlMs || 15 * 60 * 1000,
|
|
232
328
|
name: 'guard-memory-cache',
|
|
233
329
|
});
|
|
234
330
|
}
|
|
235
|
-
else if (
|
|
331
|
+
else if (effectiveCacheType === 'none') {
|
|
236
332
|
cache = new NoopCacheAdapter_1.NoopCacheAdapter();
|
|
333
|
+
// Log cache status for debugging
|
|
334
|
+
if (!GuardConfiguration_1.GuardConfiguration.isCachingEnabled()) {
|
|
335
|
+
console.log(`🚫 Guard caching disabled by environment variable NOONY_GUARD_CACHE_ENABLE`);
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
console.log(`🚫 Guard caching disabled by configuration (cacheType: 'none')`);
|
|
339
|
+
}
|
|
237
340
|
}
|
|
238
341
|
else {
|
|
239
|
-
// Default to memory cache
|
|
342
|
+
// Default to memory cache (redis support would go here)
|
|
240
343
|
cache = new MemoryCacheAdapter_1.MemoryCacheAdapter({
|
|
241
344
|
maxSize: 1000,
|
|
242
345
|
defaultTTL: 15 * 60 * 1000,
|
|
@@ -249,8 +352,10 @@ let RouteGuards = class RouteGuards {
|
|
|
249
352
|
const userContextService = new FastUserContextService_1.FastUserContextService(cache, config, permissionSource, permissionRegistry);
|
|
250
353
|
// Create cache invalidation service
|
|
251
354
|
const cacheInvalidation = new ConservativeCacheInvalidation_1.ConservativeCacheInvalidation(cache);
|
|
355
|
+
// Normalize token validator to ensure compatibility
|
|
356
|
+
const normalizedTokenValidator = normalizeTokenValidator(tokenValidator);
|
|
252
357
|
// Create authentication guard
|
|
253
|
-
const authGuard = new FastAuthGuard_1.FastAuthGuard(cache, config, authConfig, userContextService, cacheInvalidation,
|
|
358
|
+
const authGuard = new FastAuthGuard_1.FastAuthGuard(cache, config, authConfig, userContextService, cacheInvalidation, normalizedTokenValidator);
|
|
254
359
|
// Create permission guard factory
|
|
255
360
|
const guardFactory = new PermissionGuardFactory_1.PermissionGuardFactory(userContextService, config, cache);
|
|
256
361
|
// Register services with TypeDI container
|
|
@@ -269,6 +374,8 @@ let RouteGuards = class RouteGuards {
|
|
|
269
374
|
console.log('✅ RouteGuards configured successfully', {
|
|
270
375
|
environment: profile.environment,
|
|
271
376
|
cacheType: profile.cacheType,
|
|
377
|
+
effectiveCacheType: effectiveCacheType,
|
|
378
|
+
cachingEnabled: GuardConfiguration_1.GuardConfiguration.isCachingEnabled(),
|
|
272
379
|
permissionStrategy: config.security.permissionResolutionStrategy,
|
|
273
380
|
timestamp: new Date().toISOString(),
|
|
274
381
|
});
|
|
@@ -437,6 +544,192 @@ let RouteGuards = class RouteGuards {
|
|
|
437
544
|
const instance = RouteGuards_1.getInstance();
|
|
438
545
|
return instance.performHealthCheck();
|
|
439
546
|
}
|
|
547
|
+
/**
|
|
548
|
+
* Factory method: Configure RouteGuards with CustomTokenVerificationPort for JWT tokens.
|
|
549
|
+
* Provides a streamlined setup for JWT-based authentication with common field extraction.
|
|
550
|
+
*
|
|
551
|
+
* @example
|
|
552
|
+
* Quick JWT setup with CustomTokenVerificationPort:
|
|
553
|
+
* ```typescript
|
|
554
|
+
* import { CustomTokenVerificationPort } from '@/middlewares/authenticationMiddleware';
|
|
555
|
+
*
|
|
556
|
+
* interface JWTUser {
|
|
557
|
+
* sub: string;
|
|
558
|
+
* email: string;
|
|
559
|
+
* roles: string[];
|
|
560
|
+
* exp: number;
|
|
561
|
+
* }
|
|
562
|
+
*
|
|
563
|
+
* const jwtVerifier: CustomTokenVerificationPort<JWTUser> = {
|
|
564
|
+
* async verifyToken(token: string): Promise<JWTUser> {
|
|
565
|
+
* const payload = jwt.verify(token, process.env.JWT_SECRET!) as any;
|
|
566
|
+
* return {
|
|
567
|
+
* sub: payload.sub,
|
|
568
|
+
* email: payload.email,
|
|
569
|
+
* roles: payload.roles || [],
|
|
570
|
+
* exp: payload.exp
|
|
571
|
+
* };
|
|
572
|
+
* }
|
|
573
|
+
* };
|
|
574
|
+
*
|
|
575
|
+
* // One-line setup for JWT authentication
|
|
576
|
+
* await RouteGuards.configureWithJWT(
|
|
577
|
+
* GuardSetup.production(),
|
|
578
|
+
* userPermissionSource,
|
|
579
|
+
* jwtVerifier,
|
|
580
|
+
* {
|
|
581
|
+
* tokenHeader: 'authorization',
|
|
582
|
+
* tokenPrefix: 'Bearer ',
|
|
583
|
+
* requireEmailVerification: true
|
|
584
|
+
* }
|
|
585
|
+
* );
|
|
586
|
+
* ```
|
|
587
|
+
*/
|
|
588
|
+
static async configureWithJWT(profile, permissionSource, jwtVerifier, authConfig) {
|
|
589
|
+
// Create a properly typed adapter for JWT tokens
|
|
590
|
+
const tokenValidator = CustomTokenVerificationPortAdapter_1.TokenVerificationAdapterFactory.forJWT(jwtVerifier);
|
|
591
|
+
await RouteGuards_1.configure(profile, permissionSource, tokenValidator, authConfig);
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Factory method: Configure RouteGuards with CustomTokenVerificationPort for API keys.
|
|
595
|
+
* Provides setup for API key-based authentication with flexible field mapping.
|
|
596
|
+
*
|
|
597
|
+
* @example
|
|
598
|
+
* API key authentication setup:
|
|
599
|
+
* ```typescript
|
|
600
|
+
* interface APIKeyUser {
|
|
601
|
+
* keyId: string;
|
|
602
|
+
* permissions: string[];
|
|
603
|
+
* organization: string;
|
|
604
|
+
* expiresAt?: number;
|
|
605
|
+
* isActive: boolean;
|
|
606
|
+
* }
|
|
607
|
+
*
|
|
608
|
+
* const apiKeyVerifier: CustomTokenVerificationPort<APIKeyUser> = {
|
|
609
|
+
* async verifyToken(token: string): Promise<APIKeyUser> {
|
|
610
|
+
* const keyData = await validateAPIKeyInDatabase(token);
|
|
611
|
+
* if (!keyData || !keyData.isActive) {
|
|
612
|
+
* throw new Error('Invalid or inactive API key');
|
|
613
|
+
* }
|
|
614
|
+
* return keyData;
|
|
615
|
+
* }
|
|
616
|
+
* };
|
|
617
|
+
*
|
|
618
|
+
* await RouteGuards.configureWithAPIKey(
|
|
619
|
+
* GuardSetup.production(),
|
|
620
|
+
* userPermissionSource,
|
|
621
|
+
* apiKeyVerifier,
|
|
622
|
+
* {
|
|
623
|
+
* tokenHeader: 'x-api-key',
|
|
624
|
+
* tokenPrefix: '',
|
|
625
|
+
* allowInactiveUsers: false
|
|
626
|
+
* },
|
|
627
|
+
* 'keyId',
|
|
628
|
+
* 'expiresAt'
|
|
629
|
+
* );
|
|
630
|
+
* ```
|
|
631
|
+
*/
|
|
632
|
+
static async configureWithAPIKey(profile, permissionSource, apiKeyVerifier, authConfig, userIdField, expirationField) {
|
|
633
|
+
// Create a properly configured adapter for API keys
|
|
634
|
+
const tokenValidator = CustomTokenVerificationPortAdapter_1.TokenVerificationAdapterFactory.forAPIKey(apiKeyVerifier, userIdField, expirationField);
|
|
635
|
+
await RouteGuards_1.configure(profile, permissionSource, tokenValidator, authConfig);
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Factory method: Configure RouteGuards with CustomTokenVerificationPort for OAuth tokens.
|
|
639
|
+
* Provides setup for OAuth-based authentication with scope validation.
|
|
640
|
+
*
|
|
641
|
+
* @example
|
|
642
|
+
* OAuth token authentication with scope requirements:
|
|
643
|
+
* ```typescript
|
|
644
|
+
* interface OAuthUser {
|
|
645
|
+
* sub: string;
|
|
646
|
+
* email: string;
|
|
647
|
+
* scope: string[];
|
|
648
|
+
* exp: number;
|
|
649
|
+
* client_id: string;
|
|
650
|
+
* }
|
|
651
|
+
*
|
|
652
|
+
* const oauthVerifier: CustomTokenVerificationPort<OAuthUser> = {
|
|
653
|
+
* async verifyToken(token: string): Promise<OAuthUser> {
|
|
654
|
+
* const response = await fetch(`${OAUTH_INTROSPECT_URL}`, {
|
|
655
|
+
* method: 'POST',
|
|
656
|
+
* headers: { 'Authorization': `Bearer ${token}` },
|
|
657
|
+
* body: new URLSearchParams({ token })
|
|
658
|
+
* });
|
|
659
|
+
*
|
|
660
|
+
* const tokenInfo = await response.json();
|
|
661
|
+
* if (!tokenInfo.active) {
|
|
662
|
+
* throw new Error('Token is not active');
|
|
663
|
+
* }
|
|
664
|
+
*
|
|
665
|
+
* return tokenInfo as OAuthUser;
|
|
666
|
+
* }
|
|
667
|
+
* };
|
|
668
|
+
*
|
|
669
|
+
* await RouteGuards.configureWithOAuth(
|
|
670
|
+
* GuardSetup.production(),
|
|
671
|
+
* userPermissionSource,
|
|
672
|
+
* oauthVerifier,
|
|
673
|
+
* {
|
|
674
|
+
* tokenHeader: 'authorization',
|
|
675
|
+
* tokenPrefix: 'Bearer ',
|
|
676
|
+
* requireEmailVerification: false
|
|
677
|
+
* },
|
|
678
|
+
* ['read:profile', 'write:data'] // Required OAuth scopes
|
|
679
|
+
* );
|
|
680
|
+
* ```
|
|
681
|
+
*/
|
|
682
|
+
static async configureWithOAuth(profile, permissionSource, oauthVerifier, authConfig, requiredScopes) {
|
|
683
|
+
// Create a properly configured adapter for OAuth tokens
|
|
684
|
+
const tokenValidator = CustomTokenVerificationPortAdapter_1.TokenVerificationAdapterFactory.forOAuth(oauthVerifier, requiredScopes);
|
|
685
|
+
await RouteGuards_1.configure(profile, permissionSource, tokenValidator, authConfig);
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Factory method: Configure RouteGuards with a custom CustomTokenVerificationPort adapter.
|
|
689
|
+
* Provides maximum flexibility for custom token validation scenarios.
|
|
690
|
+
*
|
|
691
|
+
* @example
|
|
692
|
+
* Custom token validation with business-specific logic:
|
|
693
|
+
* ```typescript
|
|
694
|
+
* interface CustomUser {
|
|
695
|
+
* userId: string;
|
|
696
|
+
* tenantId: string;
|
|
697
|
+
* roles: string[];
|
|
698
|
+
* sessionExpiry: number;
|
|
699
|
+
* isVerified: boolean;
|
|
700
|
+
* }
|
|
701
|
+
*
|
|
702
|
+
* const customVerifier: CustomTokenVerificationPort<CustomUser> = {
|
|
703
|
+
* async verifyToken(token: string): Promise<CustomUser> {
|
|
704
|
+
* // Your custom verification logic
|
|
705
|
+
* return await verifyCustomToken(token);
|
|
706
|
+
* }
|
|
707
|
+
* };
|
|
708
|
+
*
|
|
709
|
+
* await RouteGuards.configureWithCustom(
|
|
710
|
+
* GuardSetup.production(),
|
|
711
|
+
* userPermissionSource,
|
|
712
|
+
* customVerifier,
|
|
713
|
+
* {
|
|
714
|
+
* tokenHeader: 'x-auth-token',
|
|
715
|
+
* tokenPrefix: 'Custom ',
|
|
716
|
+
* customValidation: async (token, user) => {
|
|
717
|
+
* return user.isVerified && user.tenantId === 'valid-tenant';
|
|
718
|
+
* }
|
|
719
|
+
* },
|
|
720
|
+
* {
|
|
721
|
+
* userIdExtractor: (user) => user.userId,
|
|
722
|
+
* expirationExtractor: (user) => user.sessionExpiry,
|
|
723
|
+
* additionalValidation: (user) => user.isVerified
|
|
724
|
+
* }
|
|
725
|
+
* );
|
|
726
|
+
* ```
|
|
727
|
+
*/
|
|
728
|
+
static async configureWithCustom(profile, permissionSource, customVerifier, authConfig, adapterConfig) {
|
|
729
|
+
// Create a custom configured adapter
|
|
730
|
+
const tokenValidator = CustomTokenVerificationPortAdapter_1.TokenVerificationAdapterFactory.custom(customVerifier, adapterConfig);
|
|
731
|
+
await RouteGuards_1.configure(profile, permissionSource, tokenValidator, authConfig);
|
|
732
|
+
}
|
|
440
733
|
// Private implementation methods
|
|
441
734
|
createPlainPermissionGuard(permissions, options) {
|
|
442
735
|
this.trackGuardCreation();
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CustomTokenVerificationPort Adapter
|
|
3
|
+
*
|
|
4
|
+
* Bridges the CustomTokenVerificationPort interface from AuthenticationMiddleware
|
|
5
|
+
* to the RouteGuards TokenValidator interface, enabling code reuse and unified
|
|
6
|
+
* token validation across the entire Noony Framework.
|
|
7
|
+
*
|
|
8
|
+
* Key Features:
|
|
9
|
+
* - Seamless integration between authentication systems
|
|
10
|
+
* - Maintains type safety through generics
|
|
11
|
+
* - Supports any token validation implementation (JWT, OAuth, API keys, etc.)
|
|
12
|
+
* - Preserves all existing RouteGuards functionality
|
|
13
|
+
* - Zero-overhead abstraction with full performance
|
|
14
|
+
*
|
|
15
|
+
* Benefits:
|
|
16
|
+
* - One authentication interface to implement and maintain
|
|
17
|
+
* - Consistent patterns across AuthenticationMiddleware and RouteGuards
|
|
18
|
+
* - Backward compatibility with existing RouteGuards implementations
|
|
19
|
+
* - Simplified setup for authentication workflows
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* Bridge a JWT verification port to RouteGuards:
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import { CustomTokenVerificationPort } from '@/middlewares/authenticationMiddleware';
|
|
25
|
+
* import { CustomTokenVerificationPortAdapter } from '@/middlewares/guards/adapters';
|
|
26
|
+
*
|
|
27
|
+
* // Define your user type
|
|
28
|
+
* interface User {
|
|
29
|
+
* id: string;
|
|
30
|
+
* email: string;
|
|
31
|
+
* roles: string[];
|
|
32
|
+
* sub: string; // JWT subject
|
|
33
|
+
* exp: number; // JWT expiration
|
|
34
|
+
* iat: number; // Issued at
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* // Implement token verification once
|
|
38
|
+
* const jwtVerifier: CustomTokenVerificationPort<User> = {
|
|
39
|
+
* async verifyToken(token: string): Promise<User> {
|
|
40
|
+
* const payload = jwt.verify(token, process.env.JWT_SECRET!) as any;
|
|
41
|
+
* return {
|
|
42
|
+
* id: payload.sub,
|
|
43
|
+
* email: payload.email,
|
|
44
|
+
* roles: payload.roles || [],
|
|
45
|
+
* sub: payload.sub,
|
|
46
|
+
* exp: payload.exp,
|
|
47
|
+
* iat: payload.iat
|
|
48
|
+
* };
|
|
49
|
+
* }
|
|
50
|
+
* };
|
|
51
|
+
*
|
|
52
|
+
* // Create adapter for RouteGuards
|
|
53
|
+
* const tokenValidator = new CustomTokenVerificationPortAdapter(
|
|
54
|
+
* jwtVerifier,
|
|
55
|
+
* {
|
|
56
|
+
* userIdExtractor: (user: User) => user.id,
|
|
57
|
+
* expirationExtractor: (user: User) => user.exp
|
|
58
|
+
* }
|
|
59
|
+
* );
|
|
60
|
+
*
|
|
61
|
+
* // Use with RouteGuards
|
|
62
|
+
* await RouteGuards.configure(
|
|
63
|
+
* GuardSetup.production(),
|
|
64
|
+
* userPermissionSource,
|
|
65
|
+
* tokenValidator, // Works seamlessly!
|
|
66
|
+
* authConfig
|
|
67
|
+
* );
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* API key verification with custom user structure:
|
|
72
|
+
* ```typescript
|
|
73
|
+
* interface APIKeyUser {
|
|
74
|
+
* keyId: string;
|
|
75
|
+
* permissions: string[];
|
|
76
|
+
* organization: string;
|
|
77
|
+
* expiresAt: number;
|
|
78
|
+
* isActive: boolean;
|
|
79
|
+
* }
|
|
80
|
+
*
|
|
81
|
+
* const apiKeyVerifier: CustomTokenVerificationPort<APIKeyUser> = {
|
|
82
|
+
* async verifyToken(token: string): Promise<APIKeyUser> {
|
|
83
|
+
* const keyData = await validateAPIKey(token);
|
|
84
|
+
* if (!keyData || !keyData.isActive) {
|
|
85
|
+
* throw new Error('Invalid or inactive API key');
|
|
86
|
+
* }
|
|
87
|
+
* return keyData;
|
|
88
|
+
* }
|
|
89
|
+
* };
|
|
90
|
+
*
|
|
91
|
+
* // Adapter with custom extractors
|
|
92
|
+
* const apiTokenValidator = new CustomTokenVerificationPortAdapter(
|
|
93
|
+
* apiKeyVerifier,
|
|
94
|
+
* {
|
|
95
|
+
* userIdExtractor: (user: APIKeyUser) => user.keyId,
|
|
96
|
+
* expirationExtractor: (user: APIKeyUser) => user.expiresAt,
|
|
97
|
+
* additionalValidation: (user: APIKeyUser) => user.isActive
|
|
98
|
+
* }
|
|
99
|
+
* );
|
|
100
|
+
*
|
|
101
|
+
* // Seamlessly works with RouteGuards
|
|
102
|
+
* await RouteGuards.configure(
|
|
103
|
+
* GuardSetup.production(),
|
|
104
|
+
* userPermissionSource,
|
|
105
|
+
* apiTokenValidator,
|
|
106
|
+
* authConfig
|
|
107
|
+
* );
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* OAuth token verification:
|
|
112
|
+
* ```typescript
|
|
113
|
+
* interface OAuthUser {
|
|
114
|
+
* sub: string; // OAuth subject
|
|
115
|
+
* email: string;
|
|
116
|
+
* scope: string[]; // OAuth scopes
|
|
117
|
+
* exp: number;
|
|
118
|
+
* client_id: string;
|
|
119
|
+
* }
|
|
120
|
+
*
|
|
121
|
+
* const oauthVerifier: CustomTokenVerificationPort<OAuthUser> = {
|
|
122
|
+
* async verifyToken(token: string): Promise<OAuthUser> {
|
|
123
|
+
* // Validate with OAuth provider
|
|
124
|
+
* const response = await fetch(`${OAUTH_INTROSPECT_URL}`, {
|
|
125
|
+
* method: 'POST',
|
|
126
|
+
* headers: { 'Authorization': `Bearer ${token}` }
|
|
127
|
+
* });
|
|
128
|
+
*
|
|
129
|
+
* const tokenInfo = await response.json();
|
|
130
|
+
* if (!tokenInfo.active) {
|
|
131
|
+
* throw new Error('Token is not active');
|
|
132
|
+
* }
|
|
133
|
+
*
|
|
134
|
+
* return tokenInfo as OAuthUser;
|
|
135
|
+
* }
|
|
136
|
+
* };
|
|
137
|
+
*
|
|
138
|
+
* const oauthTokenValidator = new CustomTokenVerificationPortAdapter(
|
|
139
|
+
* oauthVerifier,
|
|
140
|
+
* {
|
|
141
|
+
* userIdExtractor: (user: OAuthUser) => user.sub,
|
|
142
|
+
* expirationExtractor: (user: OAuthUser) => user.exp
|
|
143
|
+
* }
|
|
144
|
+
* );
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* @author Noony Framework Team
|
|
148
|
+
* @version 1.0.0
|
|
149
|
+
*/
|
|
150
|
+
import { CustomTokenVerificationPort } from '../../authenticationMiddleware';
|
|
151
|
+
import { TokenValidator } from '../guards/FastAuthGuard';
|
|
152
|
+
/**
|
|
153
|
+
* Configuration options for the CustomTokenVerificationPort adapter.
|
|
154
|
+
* Provides flexible configuration for extracting required data from
|
|
155
|
+
* different user object structures.
|
|
156
|
+
*/
|
|
157
|
+
export interface AdapterConfig<T> {
|
|
158
|
+
/**
|
|
159
|
+
* Extract user ID from the verified user object.
|
|
160
|
+
* This ID will be used for permission lookups and caching.
|
|
161
|
+
*/
|
|
162
|
+
userIdExtractor: (user: T) => string;
|
|
163
|
+
/**
|
|
164
|
+
* Extract token expiration timestamp from the user object.
|
|
165
|
+
* Should return Unix timestamp (seconds since epoch).
|
|
166
|
+
*
|
|
167
|
+
* @param user - Verified user object
|
|
168
|
+
* @returns Unix timestamp or undefined if no expiration
|
|
169
|
+
*/
|
|
170
|
+
expirationExtractor?: (user: T) => number | undefined;
|
|
171
|
+
/**
|
|
172
|
+
* Optional additional validation after token verification.
|
|
173
|
+
* Allows custom business logic validation on the verified user.
|
|
174
|
+
*
|
|
175
|
+
* @param user - Verified user object
|
|
176
|
+
* @returns true if user passes additional validation
|
|
177
|
+
*/
|
|
178
|
+
additionalValidation?: (user: T) => boolean | Promise<boolean>;
|
|
179
|
+
/**
|
|
180
|
+
* Custom error message for token validation failures.
|
|
181
|
+
* If not provided, uses the original error from the verification port.
|
|
182
|
+
*/
|
|
183
|
+
errorMessage?: string;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Adapter class that bridges CustomTokenVerificationPort to TokenValidator.
|
|
187
|
+
* Enables seamless integration between AuthenticationMiddleware and RouteGuards
|
|
188
|
+
* while maintaining full type safety and performance.
|
|
189
|
+
*
|
|
190
|
+
* @template T - The user type returned by the CustomTokenVerificationPort
|
|
191
|
+
*/
|
|
192
|
+
export declare class CustomTokenVerificationPortAdapter<T> implements TokenValidator {
|
|
193
|
+
private readonly verificationPort;
|
|
194
|
+
private readonly config;
|
|
195
|
+
constructor(verificationPort: CustomTokenVerificationPort<T>, config: AdapterConfig<T>);
|
|
196
|
+
/**
|
|
197
|
+
* Validate and decode token using the wrapped CustomTokenVerificationPort.
|
|
198
|
+
*
|
|
199
|
+
* @param token - JWT token string to validate
|
|
200
|
+
* @returns Validation result with decoded user data
|
|
201
|
+
*/
|
|
202
|
+
validateToken(token: string): Promise<{
|
|
203
|
+
valid: boolean;
|
|
204
|
+
decoded?: T;
|
|
205
|
+
error?: string;
|
|
206
|
+
}>;
|
|
207
|
+
/**
|
|
208
|
+
* Extract user ID from the decoded token/user data.
|
|
209
|
+
* Uses the configured userIdExtractor function.
|
|
210
|
+
*
|
|
211
|
+
* @param decoded - Decoded user data from validateToken
|
|
212
|
+
* @returns User ID string
|
|
213
|
+
*/
|
|
214
|
+
extractUserId(decoded: T): string;
|
|
215
|
+
/**
|
|
216
|
+
* Check if the token is expired based on the decoded data.
|
|
217
|
+
* Uses the configured expirationExtractor if available.
|
|
218
|
+
*
|
|
219
|
+
* @param decoded - Decoded user data from validateToken
|
|
220
|
+
* @returns true if token is expired, false otherwise
|
|
221
|
+
*/
|
|
222
|
+
isTokenExpired(decoded: T): boolean;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Helper factory functions for common token verification scenarios.
|
|
226
|
+
* Provides pre-configured adapters for standard authentication patterns.
|
|
227
|
+
*/
|
|
228
|
+
export declare class TokenVerificationAdapterFactory {
|
|
229
|
+
/**
|
|
230
|
+
* Create adapter for standard JWT tokens with common claims.
|
|
231
|
+
* Assumes the user object has 'sub' for user ID and 'exp' for expiration.
|
|
232
|
+
*
|
|
233
|
+
* @param verificationPort - JWT token verification port
|
|
234
|
+
* @returns Configured adapter for JWT tokens
|
|
235
|
+
*/
|
|
236
|
+
static forJWT<T extends {
|
|
237
|
+
sub: string;
|
|
238
|
+
exp?: number;
|
|
239
|
+
}>(verificationPort: CustomTokenVerificationPort<T>): CustomTokenVerificationPortAdapter<T>;
|
|
240
|
+
/**
|
|
241
|
+
* Create adapter for API key tokens with custom ID and expiration fields.
|
|
242
|
+
*
|
|
243
|
+
* @param verificationPort - API key verification port
|
|
244
|
+
* @param userIdField - Field name for user/key ID (e.g., 'keyId', 'apiKeyId')
|
|
245
|
+
* @param expirationField - Optional field name for expiration (e.g., 'expiresAt', 'exp')
|
|
246
|
+
* @returns Configured adapter for API key tokens
|
|
247
|
+
*/
|
|
248
|
+
static forAPIKey<T extends Record<string, unknown>>(verificationPort: CustomTokenVerificationPort<T>, userIdField: keyof T, expirationField?: keyof T): CustomTokenVerificationPortAdapter<T>;
|
|
249
|
+
/**
|
|
250
|
+
* Create adapter for OAuth tokens with standard OAuth claims.
|
|
251
|
+
*
|
|
252
|
+
* @param verificationPort - OAuth token verification port
|
|
253
|
+
* @param additionalScopes - Optional required OAuth scopes
|
|
254
|
+
* @returns Configured adapter for OAuth tokens
|
|
255
|
+
*/
|
|
256
|
+
static forOAuth<T extends {
|
|
257
|
+
sub: string;
|
|
258
|
+
exp?: number;
|
|
259
|
+
scope?: string[];
|
|
260
|
+
}>(verificationPort: CustomTokenVerificationPort<T>, additionalScopes?: string[]): CustomTokenVerificationPortAdapter<T>;
|
|
261
|
+
/**
|
|
262
|
+
* Create adapter with custom configuration.
|
|
263
|
+
* Use this for non-standard token structures or complex validation logic.
|
|
264
|
+
*
|
|
265
|
+
* @param verificationPort - Token verification port
|
|
266
|
+
* @param config - Custom adapter configuration
|
|
267
|
+
* @returns Configured adapter with custom settings
|
|
268
|
+
*/
|
|
269
|
+
static custom<T>(verificationPort: CustomTokenVerificationPort<T>, config: AdapterConfig<T>): CustomTokenVerificationPortAdapter<T>;
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=CustomTokenVerificationPortAdapter.d.ts.map
|