ecrs-auth-core 1.0.62 → 1.0.64

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.
@@ -1,152 +1,152 @@
1
- "use strict";
2
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
- 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;
6
- return c > 3 && r && Object.defineProperty(target, key, r), r;
7
- };
8
- var AuthCoreModule_1;
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.AuthCoreModule = exports.AUTH_CORE_OPTIONS = void 0;
11
- const common_1 = require("@nestjs/common");
12
- const jwt_1 = require("@nestjs/jwt");
13
- const auth_service_1 = require("./auth.service");
14
- const auth_controller_1 = require("./auth.controller");
15
- const jwt_strategy_1 = require("./jwt/jwt.strategy");
16
- const jwt_guard_1 = require("./jwt/jwt.guard");
17
- const module_guard_1 = require("./guards/module.guard");
18
- const roles_guard_1 = require("./guards/roles.guard");
19
- const feature_guard_1 = require("./guards/feature.guard");
20
- const route_guard_1 = require("./guards/route.guard");
21
- const permission_guard_1 = require("./guards/permission.guard");
22
- const api_key_guard_1 = require("./guards/api-key.guard");
23
- exports.AUTH_CORE_OPTIONS = 'AUTH_CORE_OPTIONS';
24
- // @Global()
25
- // @Module({})
26
- // export class AuthCoreModule {
27
- // static registerAsync(options: {
28
- // inject: any[];
29
- // useFactory: (...args: any[]) => Promise<AuthCoreOptions>;
30
- // }): DynamicModule {
31
- // const asyncProvider = {
32
- // provide: AUTH_CORE_OPTIONS,
33
- // inject: options.inject,
34
- // useFactory: options.useFactory,
35
- // };
36
- // return {
37
- // module: AuthCoreModule,
38
- // imports: [
39
- // JwtModule.registerAsync({
40
- // inject: options.inject,
41
- // useFactory: async (...args: any[]) => {
42
- // const config = await options.useFactory(...args);
43
- // console.log("🔐 JWT Secret from AUTH_CORE_OPTIONS:", config.jwtSecret);
44
- // console.log("⏳ JWT Expiry:", config.jwtExpiresIn);
45
- // return {
46
- // secret: config.jwtSecret,
47
- // signOptions: { expiresIn: config.jwtExpiresIn },
48
- // };
49
- // },
50
- // }),
51
- // ],
52
- // providers: [
53
- // asyncProvider,
54
- // {
55
- // provide: 'MODULE_CONFIG',
56
- // useFactory: (options: AuthCoreOptions) => options.moduleConfig || {},
57
- // inject: [AUTH_CORE_OPTIONS],
58
- // },
59
- // AuthService,
60
- // JwtStrategy,
61
- // JwtAuthGuard,
62
- // ModuleGuard,
63
- // RolesGuard,
64
- // FeatureGuard,
65
- // RouteGuard,
66
- // PermissionGuard,
67
- // ],
68
- // controllers: [AuthController],
69
- // exports: [
70
- // AuthService,
71
- // JwtStrategy,
72
- // JwtAuthGuard,
73
- // ModuleGuard,
74
- // RolesGuard,
75
- // FeatureGuard,
76
- // RouteGuard,
77
- // PermissionGuard,
78
- // JwtModule,
79
- // ],
80
- // };
81
- // }
82
- // }
83
- let AuthCoreModule = AuthCoreModule_1 = class AuthCoreModule {
84
- static registerAsync(options) {
85
- const asyncProvider = {
86
- provide: exports.AUTH_CORE_OPTIONS,
87
- inject: options.inject,
88
- useFactory: options.useFactory,
89
- };
90
- return {
91
- module: AuthCoreModule_1,
92
- imports: [
93
- jwt_1.JwtModule.registerAsync({
94
- inject: options.inject,
95
- useFactory: async (...args) => {
96
- const config = await options.useFactory(...args);
97
- console.log('🔐 JWT Secret from AUTH_CORE_OPTIONS:', config.jwtSecret);
98
- console.log('⏳ JWT Expiry:', config.jwtExpiresIn);
99
- return {
100
- secret: config.jwtSecret,
101
- signOptions: { expiresIn: config.jwtExpiresIn },
102
- };
103
- },
104
- }),
105
- ],
106
- providers: [
107
- asyncProvider,
108
- {
109
- provide: 'MODULE_CONFIG',
110
- useFactory: (opts) => opts.moduleConfig || {},
111
- inject: [exports.AUTH_CORE_OPTIONS],
112
- },
113
- {
114
- provide: 'API_KEY_REPOSITORY',
115
- useFactory: (opts) => opts.repositories?.apiKeyRepo || null,
116
- inject: [exports.AUTH_CORE_OPTIONS],
117
- },
118
- auth_service_1.AuthService,
119
- jwt_strategy_1.JwtStrategy,
120
- jwt_guard_1.JwtAuthGuard,
121
- module_guard_1.ModuleGuard,
122
- roles_guard_1.RolesGuard,
123
- feature_guard_1.FeatureGuard,
124
- route_guard_1.RouteGuard,
125
- permission_guard_1.PermissionGuard,
126
- api_key_guard_1.ApiKeyGuard,
127
- ],
128
- controllers: [auth_controller_1.AuthController],
129
- exports: [
130
- // ⬇️ export these so Superadmin can resolve guard deps
131
- exports.AUTH_CORE_OPTIONS,
132
- 'MODULE_CONFIG',
133
- 'API_KEY_REPOSITORY',
134
- jwt_1.JwtModule,
135
- auth_service_1.AuthService,
136
- jwt_strategy_1.JwtStrategy,
137
- jwt_guard_1.JwtAuthGuard,
138
- module_guard_1.ModuleGuard,
139
- roles_guard_1.RolesGuard,
140
- feature_guard_1.FeatureGuard,
141
- route_guard_1.RouteGuard,
142
- permission_guard_1.PermissionGuard,
143
- api_key_guard_1.ApiKeyGuard,
144
- ],
145
- };
146
- }
147
- };
148
- exports.AuthCoreModule = AuthCoreModule;
149
- exports.AuthCoreModule = AuthCoreModule = AuthCoreModule_1 = __decorate([
150
- (0, common_1.Global)(),
151
- (0, common_1.Module)({})
152
- ], AuthCoreModule);
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var AuthCoreModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.AuthCoreModule = exports.AUTH_CORE_OPTIONS = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const jwt_1 = require("@nestjs/jwt");
13
+ const auth_service_1 = require("./auth.service");
14
+ const auth_controller_1 = require("./auth.controller");
15
+ const jwt_strategy_1 = require("./jwt/jwt.strategy");
16
+ const jwt_guard_1 = require("./jwt/jwt.guard");
17
+ const module_guard_1 = require("./guards/module.guard");
18
+ const roles_guard_1 = require("./guards/roles.guard");
19
+ const feature_guard_1 = require("./guards/feature.guard");
20
+ const route_guard_1 = require("./guards/route.guard");
21
+ const permission_guard_1 = require("./guards/permission.guard");
22
+ const api_key_guard_1 = require("./guards/api-key.guard");
23
+ exports.AUTH_CORE_OPTIONS = 'AUTH_CORE_OPTIONS';
24
+ // @Global()
25
+ // @Module({})
26
+ // export class AuthCoreModule {
27
+ // static registerAsync(options: {
28
+ // inject: any[];
29
+ // useFactory: (...args: any[]) => Promise<AuthCoreOptions>;
30
+ // }): DynamicModule {
31
+ // const asyncProvider = {
32
+ // provide: AUTH_CORE_OPTIONS,
33
+ // inject: options.inject,
34
+ // useFactory: options.useFactory,
35
+ // };
36
+ // return {
37
+ // module: AuthCoreModule,
38
+ // imports: [
39
+ // JwtModule.registerAsync({
40
+ // inject: options.inject,
41
+ // useFactory: async (...args: any[]) => {
42
+ // const config = await options.useFactory(...args);
43
+ // console.log("🔐 JWT Secret from AUTH_CORE_OPTIONS:", config.jwtSecret);
44
+ // console.log("⏳ JWT Expiry:", config.jwtExpiresIn);
45
+ // return {
46
+ // secret: config.jwtSecret,
47
+ // signOptions: { expiresIn: config.jwtExpiresIn },
48
+ // };
49
+ // },
50
+ // }),
51
+ // ],
52
+ // providers: [
53
+ // asyncProvider,
54
+ // {
55
+ // provide: 'MODULE_CONFIG',
56
+ // useFactory: (options: AuthCoreOptions) => options.moduleConfig || {},
57
+ // inject: [AUTH_CORE_OPTIONS],
58
+ // },
59
+ // AuthService,
60
+ // JwtStrategy,
61
+ // JwtAuthGuard,
62
+ // ModuleGuard,
63
+ // RolesGuard,
64
+ // FeatureGuard,
65
+ // RouteGuard,
66
+ // PermissionGuard,
67
+ // ],
68
+ // controllers: [AuthController],
69
+ // exports: [
70
+ // AuthService,
71
+ // JwtStrategy,
72
+ // JwtAuthGuard,
73
+ // ModuleGuard,
74
+ // RolesGuard,
75
+ // FeatureGuard,
76
+ // RouteGuard,
77
+ // PermissionGuard,
78
+ // JwtModule,
79
+ // ],
80
+ // };
81
+ // }
82
+ // }
83
+ let AuthCoreModule = AuthCoreModule_1 = class AuthCoreModule {
84
+ static registerAsync(options) {
85
+ const asyncProvider = {
86
+ provide: exports.AUTH_CORE_OPTIONS,
87
+ inject: options.inject,
88
+ useFactory: options.useFactory,
89
+ };
90
+ return {
91
+ module: AuthCoreModule_1,
92
+ imports: [
93
+ jwt_1.JwtModule.registerAsync({
94
+ inject: options.inject,
95
+ useFactory: async (...args) => {
96
+ const config = await options.useFactory(...args);
97
+ console.log('🔐 JWT Secret from AUTH_CORE_OPTIONS:', config.jwtSecret);
98
+ console.log('⏳ JWT Expiry:', config.jwtExpiresIn);
99
+ return {
100
+ secret: config.jwtSecret,
101
+ signOptions: { expiresIn: config.jwtExpiresIn },
102
+ };
103
+ },
104
+ }),
105
+ ],
106
+ providers: [
107
+ asyncProvider,
108
+ {
109
+ provide: 'MODULE_CONFIG',
110
+ useFactory: (opts) => opts.moduleConfig || {},
111
+ inject: [exports.AUTH_CORE_OPTIONS],
112
+ },
113
+ {
114
+ provide: 'API_KEY_REPOSITORY',
115
+ useFactory: (opts) => opts.repositories?.apiKeyRepo || null,
116
+ inject: [exports.AUTH_CORE_OPTIONS],
117
+ },
118
+ auth_service_1.AuthService,
119
+ jwt_strategy_1.JwtStrategy,
120
+ jwt_guard_1.JwtAuthGuard,
121
+ module_guard_1.ModuleGuard,
122
+ roles_guard_1.RolesGuard,
123
+ feature_guard_1.FeatureGuard,
124
+ route_guard_1.RouteGuard,
125
+ permission_guard_1.PermissionGuard,
126
+ api_key_guard_1.ApiKeyGuard,
127
+ ],
128
+ controllers: [auth_controller_1.AuthController],
129
+ exports: [
130
+ // ⬇️ export these so Superadmin can resolve guard deps
131
+ exports.AUTH_CORE_OPTIONS,
132
+ 'MODULE_CONFIG',
133
+ 'API_KEY_REPOSITORY',
134
+ jwt_1.JwtModule,
135
+ auth_service_1.AuthService,
136
+ jwt_strategy_1.JwtStrategy,
137
+ jwt_guard_1.JwtAuthGuard,
138
+ module_guard_1.ModuleGuard,
139
+ roles_guard_1.RolesGuard,
140
+ feature_guard_1.FeatureGuard,
141
+ route_guard_1.RouteGuard,
142
+ permission_guard_1.PermissionGuard,
143
+ api_key_guard_1.ApiKeyGuard,
144
+ ],
145
+ };
146
+ }
147
+ };
148
+ exports.AuthCoreModule = AuthCoreModule;
149
+ exports.AuthCoreModule = AuthCoreModule = AuthCoreModule_1 = __decorate([
150
+ (0, common_1.Global)(),
151
+ (0, common_1.Module)({})
152
+ ], AuthCoreModule);
@@ -1,15 +1,15 @@
1
- import { CanActivate, ExecutionContext } from '@nestjs/common';
2
- import { Reflector } from '@nestjs/core';
3
- import { Repository } from 'typeorm';
4
- import { ApiKeyEntity } from '../entities/api-key.entity';
5
- export declare class ApiKeyGuard implements CanActivate {
6
- private readonly reflector;
7
- private apiKeyRepo;
8
- private rateLimitMap;
9
- constructor(reflector: Reflector, apiKeyRepository?: Repository<ApiKeyEntity>);
10
- canActivate(context: ExecutionContext): Promise<boolean>;
11
- private extractApiKey;
12
- private validateApiKey;
13
- private getClientIp;
14
- private checkRateLimit;
15
- }
1
+ import { CanActivate, ExecutionContext } from '@nestjs/common';
2
+ import { Reflector } from '@nestjs/core';
3
+ import { Repository } from 'typeorm';
4
+ import { ApiKeyEntity } from '../entities/api-key.entity';
5
+ export declare class ApiKeyGuard implements CanActivate {
6
+ private readonly reflector;
7
+ private apiKeyRepo;
8
+ private rateLimitMap;
9
+ constructor(reflector: Reflector, apiKeyRepository?: Repository<ApiKeyEntity>);
10
+ canActivate(context: ExecutionContext): Promise<boolean>;
11
+ private extractApiKey;
12
+ private validateApiKey;
13
+ private getClientIp;
14
+ private checkRateLimit;
15
+ }
@@ -1,182 +1,182 @@
1
- "use strict";
2
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
- 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;
6
- return c > 3 && r && Object.defineProperty(target, key, r), r;
7
- };
8
- var __metadata = (this && this.__metadata) || function (k, v) {
9
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
- };
11
- var __param = (this && this.__param) || function (paramIndex, decorator) {
12
- return function (target, key) { decorator(target, key, paramIndex); }
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.ApiKeyGuard = void 0;
16
- const common_1 = require("@nestjs/common");
17
- const core_1 = require("@nestjs/core");
18
- const typeorm_1 = require("typeorm");
19
- let ApiKeyGuard = class ApiKeyGuard {
20
- constructor(reflector, apiKeyRepository) {
21
- this.reflector = reflector;
22
- this.rateLimitMap = new Map();
23
- if (apiKeyRepository) {
24
- this.apiKeyRepo = apiKeyRepository;
25
- }
26
- }
27
- async canActivate(context) {
28
- const options = this.reflector.get('api_key_options', context.getHandler());
29
- // If no @ApiKey decorator is present, skip this guard
30
- if (!options) {
31
- return true;
32
- }
33
- const request = context.switchToHttp().getRequest();
34
- const apiKey = this.extractApiKey(request);
35
- if (!apiKey) {
36
- throw new common_1.UnauthorizedException('API key is missing');
37
- }
38
- // Validate API key
39
- const validation = await this.validateApiKey(apiKey, request, options);
40
- if (!validation.valid) {
41
- throw new common_1.UnauthorizedException(validation.message || 'Invalid API key');
42
- }
43
- // Attach API key info to request for downstream use
44
- request.apiKey = validation.apiKey;
45
- request.apiKeyClient = {
46
- id: validation.apiKey?.id,
47
- clientName: validation.apiKey?.clientName,
48
- scope: validation.apiKey?.scope,
49
- };
50
- return true;
51
- }
52
- extractApiKey(request) {
53
- // Check 'X-API-Key' header
54
- const headerKey = request.headers['x-api-key'];
55
- if (headerKey) {
56
- return headerKey;
57
- }
58
- // Check 'api_key' query parameter
59
- if (request.query?.api_key) {
60
- return request.query.api_key;
61
- }
62
- // Check Authorization header (format: 'ApiKey <key>')
63
- const authHeader = request.headers.authorization;
64
- if (authHeader && authHeader.startsWith('ApiKey ')) {
65
- return authHeader.substring(7);
66
- }
67
- return null;
68
- }
69
- async validateApiKey(apiKey, request, options) {
70
- if (!this.apiKeyRepo) {
71
- return { valid: false, message: 'API key validation not configured' };
72
- }
73
- const record = await this.apiKeyRepo.findOne({
74
- where: { key: apiKey, isActive: true },
75
- });
76
- if (!record) {
77
- return { valid: false, message: 'API key not found or inactive' };
78
- }
79
- // Check scope
80
- const requiredScope = options.scope || 'common';
81
- if (record.scope !== 'common' && record.scope !== requiredScope) {
82
- return {
83
- valid: false,
84
- message: `API key scope '${record.scope}' does not match required scope '${requiredScope}'`,
85
- };
86
- }
87
- // Check IP whitelist
88
- if (record.allowedIps) {
89
- const clientIp = this.getClientIp(request);
90
- const allowedIps = record.allowedIps.split(',').map((ip) => ip.trim());
91
- if (!allowedIps.includes(clientIp)) {
92
- return {
93
- valid: false,
94
- message: `Client IP '${clientIp}' is not whitelisted`,
95
- };
96
- }
97
- }
98
- // Check endpoint restriction
99
- if (record.allowedEndpoints) {
100
- const requestEndpoint = `${request.method} ${request.path}`;
101
- const allowedEndpoints = record.allowedEndpoints
102
- .split(',')
103
- .map((ep) => ep.trim());
104
- const isAllowed = allowedEndpoints.some((ep) => {
105
- // Support wildcard matching (e.g., 'GET /spot/*')
106
- if (ep.includes('*')) {
107
- const pattern = ep.replace(/\*/g, '.*');
108
- return new RegExp(`^${pattern}$`).test(requestEndpoint);
109
- }
110
- return ep === requestEndpoint;
111
- });
112
- if (!isAllowed) {
113
- return {
114
- valid: false,
115
- message: `Endpoint '${requestEndpoint}' is not allowed for this API key`,
116
- };
117
- }
118
- }
119
- // Check rate limit
120
- if (record.rateLimit) {
121
- const isRateLimited = this.checkRateLimit(apiKey, record.rateLimit);
122
- if (isRateLimited) {
123
- return {
124
- valid: false,
125
- message: `Rate limit exceeded (${record.rateLimit} requests per minute)`,
126
- };
127
- }
128
- }
129
- // Update last used timestamp
130
- if (this.apiKeyRepo) {
131
- await this.apiKeyRepo.update(record.id, {
132
- lastUsedAt: Date.now(),
133
- });
134
- }
135
- return { valid: true, apiKey: record };
136
- }
137
- getClientIp(request) {
138
- // Support common proxy headers
139
- const xForwardedFor = request.headers['x-forwarded-for'];
140
- if (xForwardedFor) {
141
- return xForwardedFor.split(',')[0].trim();
142
- }
143
- const xRealIp = request.headers['x-real-ip'];
144
- if (xRealIp) {
145
- return xRealIp;
146
- }
147
- return request.ip || request.connection.remoteAddress || 'unknown';
148
- }
149
- checkRateLimit(apiKey, rateLimit) {
150
- const now = Date.now();
151
- const limitData = this.rateLimitMap.get(apiKey);
152
- if (!limitData) {
153
- // First request, initialize
154
- this.rateLimitMap.set(apiKey, {
155
- count: 1,
156
- resetTime: now + 60000, // 1 minute
157
- });
158
- return false;
159
- }
160
- if (now > limitData.resetTime) {
161
- // Reset window expired
162
- this.rateLimitMap.set(apiKey, {
163
- count: 1,
164
- resetTime: now + 60000,
165
- });
166
- return false;
167
- }
168
- // Still within window
169
- if (limitData.count >= rateLimit) {
170
- return true;
171
- }
172
- limitData.count++;
173
- return false;
174
- }
175
- };
176
- exports.ApiKeyGuard = ApiKeyGuard;
177
- exports.ApiKeyGuard = ApiKeyGuard = __decorate([
178
- (0, common_1.Injectable)(),
179
- __param(1, (0, common_1.Inject)('API_KEY_REPOSITORY')),
180
- __metadata("design:paramtypes", [core_1.Reflector,
181
- typeorm_1.Repository])
182
- ], ApiKeyGuard);
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ApiKeyGuard = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const core_1 = require("@nestjs/core");
18
+ const typeorm_1 = require("typeorm");
19
+ let ApiKeyGuard = class ApiKeyGuard {
20
+ constructor(reflector, apiKeyRepository) {
21
+ this.reflector = reflector;
22
+ this.rateLimitMap = new Map();
23
+ if (apiKeyRepository) {
24
+ this.apiKeyRepo = apiKeyRepository;
25
+ }
26
+ }
27
+ async canActivate(context) {
28
+ const options = this.reflector.get('api_key_options', context.getHandler());
29
+ // If no @ApiKey decorator is present, skip this guard
30
+ if (!options) {
31
+ return true;
32
+ }
33
+ const request = context.switchToHttp().getRequest();
34
+ const apiKey = this.extractApiKey(request);
35
+ if (!apiKey) {
36
+ throw new common_1.UnauthorizedException('API key is missing');
37
+ }
38
+ // Validate API key
39
+ const validation = await this.validateApiKey(apiKey, request, options);
40
+ if (!validation.valid) {
41
+ throw new common_1.UnauthorizedException(validation.message || 'Invalid API key');
42
+ }
43
+ // Attach API key info to request for downstream use
44
+ request.apiKey = validation.apiKey;
45
+ request.apiKeyClient = {
46
+ id: validation.apiKey?.id,
47
+ clientName: validation.apiKey?.clientName,
48
+ scope: validation.apiKey?.scope,
49
+ };
50
+ return true;
51
+ }
52
+ extractApiKey(request) {
53
+ // Check 'X-API-Key' header
54
+ const headerKey = request.headers['x-api-key'];
55
+ if (headerKey) {
56
+ return headerKey;
57
+ }
58
+ // Check 'api_key' query parameter
59
+ if (request.query?.api_key) {
60
+ return request.query.api_key;
61
+ }
62
+ // Check Authorization header (format: 'ApiKey <key>')
63
+ const authHeader = request.headers.authorization;
64
+ if (authHeader && authHeader.startsWith('ApiKey ')) {
65
+ return authHeader.substring(7);
66
+ }
67
+ return null;
68
+ }
69
+ async validateApiKey(apiKey, request, options) {
70
+ if (!this.apiKeyRepo) {
71
+ return { valid: false, message: 'API key validation not configured' };
72
+ }
73
+ const record = await this.apiKeyRepo.findOne({
74
+ where: { key: apiKey, isActive: true },
75
+ });
76
+ if (!record) {
77
+ return { valid: false, message: 'API key not found or inactive' };
78
+ }
79
+ // Check scope
80
+ const requiredScope = options.scope || 'common';
81
+ if (record.scope !== 'common' && record.scope !== requiredScope) {
82
+ return {
83
+ valid: false,
84
+ message: `API key scope '${record.scope}' does not match required scope '${requiredScope}'`,
85
+ };
86
+ }
87
+ // Check IP whitelist
88
+ if (record.allowedIps) {
89
+ const clientIp = this.getClientIp(request);
90
+ const allowedIps = record.allowedIps.split(',').map((ip) => ip.trim());
91
+ if (!allowedIps.includes(clientIp)) {
92
+ return {
93
+ valid: false,
94
+ message: `Client IP '${clientIp}' is not whitelisted`,
95
+ };
96
+ }
97
+ }
98
+ // Check endpoint restriction
99
+ if (record.allowedEndpoints) {
100
+ const requestEndpoint = `${request.method} ${request.path}`;
101
+ const allowedEndpoints = record.allowedEndpoints
102
+ .split(',')
103
+ .map((ep) => ep.trim());
104
+ const isAllowed = allowedEndpoints.some((ep) => {
105
+ // Support wildcard matching (e.g., 'GET /spot/*')
106
+ if (ep.includes('*')) {
107
+ const pattern = ep.replace(/\*/g, '.*');
108
+ return new RegExp(`^${pattern}$`).test(requestEndpoint);
109
+ }
110
+ return ep === requestEndpoint;
111
+ });
112
+ if (!isAllowed) {
113
+ return {
114
+ valid: false,
115
+ message: `Endpoint '${requestEndpoint}' is not allowed for this API key`,
116
+ };
117
+ }
118
+ }
119
+ // Check rate limit
120
+ if (record.rateLimit) {
121
+ const isRateLimited = this.checkRateLimit(apiKey, record.rateLimit);
122
+ if (isRateLimited) {
123
+ return {
124
+ valid: false,
125
+ message: `Rate limit exceeded (${record.rateLimit} requests per minute)`,
126
+ };
127
+ }
128
+ }
129
+ // Update last used timestamp
130
+ if (this.apiKeyRepo) {
131
+ await this.apiKeyRepo.update(record.id, {
132
+ lastUsedAt: Date.now(),
133
+ });
134
+ }
135
+ return { valid: true, apiKey: record };
136
+ }
137
+ getClientIp(request) {
138
+ // Support common proxy headers
139
+ const xForwardedFor = request.headers['x-forwarded-for'];
140
+ if (xForwardedFor) {
141
+ return xForwardedFor.split(',')[0].trim();
142
+ }
143
+ const xRealIp = request.headers['x-real-ip'];
144
+ if (xRealIp) {
145
+ return xRealIp;
146
+ }
147
+ return request.ip || request.connection.remoteAddress || 'unknown';
148
+ }
149
+ checkRateLimit(apiKey, rateLimit) {
150
+ const now = Date.now();
151
+ const limitData = this.rateLimitMap.get(apiKey);
152
+ if (!limitData) {
153
+ // First request, initialize
154
+ this.rateLimitMap.set(apiKey, {
155
+ count: 1,
156
+ resetTime: now + 60000, // 1 minute
157
+ });
158
+ return false;
159
+ }
160
+ if (now > limitData.resetTime) {
161
+ // Reset window expired
162
+ this.rateLimitMap.set(apiKey, {
163
+ count: 1,
164
+ resetTime: now + 60000,
165
+ });
166
+ return false;
167
+ }
168
+ // Still within window
169
+ if (limitData.count >= rateLimit) {
170
+ return true;
171
+ }
172
+ limitData.count++;
173
+ return false;
174
+ }
175
+ };
176
+ exports.ApiKeyGuard = ApiKeyGuard;
177
+ exports.ApiKeyGuard = ApiKeyGuard = __decorate([
178
+ (0, common_1.Injectable)(),
179
+ __param(1, (0, common_1.Inject)('API_KEY_REPOSITORY')),
180
+ __metadata("design:paramtypes", [core_1.Reflector,
181
+ typeorm_1.Repository])
182
+ ], ApiKeyGuard);
package/dist/index.d.ts CHANGED
@@ -1,28 +1,28 @@
1
- export * from './auth.module';
2
- export * from './auth.service';
3
- export * from './dtos/login.dto';
4
- export * from './dtos/login-response.dto';
5
- export * from './decorators/current-user.decorator';
6
- export * from './decorators/feature.decorator';
7
- export * from './decorators/has-permission.decorator';
8
- export * from './decorators/roles.decorator';
9
- export * from './decorators/route-permission.decorator';
10
- export * from './decorators/api-key.decorator';
11
- export * from './guards/module.guard';
12
- export * from './guards/roles.guard';
13
- export * from './guards/feature.guard';
14
- export * from './guards/route.guard';
15
- export * from './guards/permission.guard';
16
- export * from './guards/api-key.guard';
17
- export * from './jwt/jwt.guard';
18
- export * from './jwt/jwt.strategy';
19
- export * from './interfaces/auth-core-options.interface';
20
- export * from './entities/user.entity';
21
- export * from './entities/role.entity';
22
- export * from './entities/module.entity';
23
- export * from './entities/feature.entity';
24
- export * from './entities/module-route.entity';
25
- export * from './entities/user-feature-access.entity';
26
- export * from './entities/user-module-access.entity';
27
- export * from './entities/module-screen-permission.entity';
28
- export * from './entities/api-key.entity';
1
+ export * from './auth.module';
2
+ export * from './auth.service';
3
+ export * from './dtos/login.dto';
4
+ export * from './dtos/login-response.dto';
5
+ export * from './decorators/current-user.decorator';
6
+ export * from './decorators/feature.decorator';
7
+ export * from './decorators/has-permission.decorator';
8
+ export * from './decorators/roles.decorator';
9
+ export * from './decorators/route-permission.decorator';
10
+ export * from './decorators/api-key.decorator';
11
+ export * from './guards/module.guard';
12
+ export * from './guards/roles.guard';
13
+ export * from './guards/feature.guard';
14
+ export * from './guards/route.guard';
15
+ export * from './guards/permission.guard';
16
+ export * from './guards/api-key.guard';
17
+ export * from './jwt/jwt.guard';
18
+ export * from './jwt/jwt.strategy';
19
+ export * from './interfaces/auth-core-options.interface';
20
+ export * from './entities/user.entity';
21
+ export * from './entities/role.entity';
22
+ export * from './entities/module.entity';
23
+ export * from './entities/feature.entity';
24
+ export * from './entities/module-route.entity';
25
+ export * from './entities/user-feature-access.entity';
26
+ export * from './entities/user-module-access.entity';
27
+ export * from './entities/module-screen-permission.entity';
28
+ export * from './entities/api-key.entity';
package/dist/index.js CHANGED
@@ -1,51 +1,51 @@
1
- "use strict";
2
- // src/index.ts
3
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
- if (k2 === undefined) k2 = k;
5
- var desc = Object.getOwnPropertyDescriptor(m, k);
6
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
- desc = { enumerable: true, get: function() { return m[k]; } };
8
- }
9
- Object.defineProperty(o, k2, desc);
10
- }) : (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- o[k2] = m[k];
13
- }));
14
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
16
- };
17
- Object.defineProperty(exports, "__esModule", { value: true });
18
- __exportStar(require("./auth.module"), exports);
19
- __exportStar(require("./auth.service"), exports);
20
- // DTOs
21
- __exportStar(require("./dtos/login.dto"), exports);
22
- __exportStar(require("./dtos/login-response.dto"), exports);
23
- // Decorators
24
- __exportStar(require("./decorators/current-user.decorator"), exports);
25
- __exportStar(require("./decorators/feature.decorator"), exports);
26
- __exportStar(require("./decorators/has-permission.decorator"), exports);
27
- __exportStar(require("./decorators/roles.decorator"), exports);
28
- __exportStar(require("./decorators/route-permission.decorator"), exports);
29
- __exportStar(require("./decorators/api-key.decorator"), exports);
30
- // Guards
31
- __exportStar(require("./guards/module.guard"), exports);
32
- __exportStar(require("./guards/roles.guard"), exports);
33
- __exportStar(require("./guards/feature.guard"), exports);
34
- __exportStar(require("./guards/route.guard"), exports);
35
- __exportStar(require("./guards/permission.guard"), exports);
36
- __exportStar(require("./guards/api-key.guard"), exports);
37
- // JWT
38
- __exportStar(require("./jwt/jwt.guard"), exports);
39
- __exportStar(require("./jwt/jwt.strategy"), exports);
40
- // Interfaces
41
- __exportStar(require("./interfaces/auth-core-options.interface"), exports);
42
- // ✅ Entities
43
- __exportStar(require("./entities/user.entity"), exports);
44
- __exportStar(require("./entities/role.entity"), exports);
45
- __exportStar(require("./entities/module.entity"), exports);
46
- __exportStar(require("./entities/feature.entity"), exports);
47
- __exportStar(require("./entities/module-route.entity"), exports);
48
- __exportStar(require("./entities/user-feature-access.entity"), exports);
49
- __exportStar(require("./entities/user-module-access.entity"), exports);
50
- __exportStar(require("./entities/module-screen-permission.entity"), exports);
51
- __exportStar(require("./entities/api-key.entity"), exports);
1
+ "use strict";
2
+ // src/index.ts
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ __exportStar(require("./auth.module"), exports);
19
+ __exportStar(require("./auth.service"), exports);
20
+ // DTOs
21
+ __exportStar(require("./dtos/login.dto"), exports);
22
+ __exportStar(require("./dtos/login-response.dto"), exports);
23
+ // Decorators
24
+ __exportStar(require("./decorators/current-user.decorator"), exports);
25
+ __exportStar(require("./decorators/feature.decorator"), exports);
26
+ __exportStar(require("./decorators/has-permission.decorator"), exports);
27
+ __exportStar(require("./decorators/roles.decorator"), exports);
28
+ __exportStar(require("./decorators/route-permission.decorator"), exports);
29
+ __exportStar(require("./decorators/api-key.decorator"), exports);
30
+ // Guards
31
+ __exportStar(require("./guards/module.guard"), exports);
32
+ __exportStar(require("./guards/roles.guard"), exports);
33
+ __exportStar(require("./guards/feature.guard"), exports);
34
+ __exportStar(require("./guards/route.guard"), exports);
35
+ __exportStar(require("./guards/permission.guard"), exports);
36
+ __exportStar(require("./guards/api-key.guard"), exports);
37
+ // JWT
38
+ __exportStar(require("./jwt/jwt.guard"), exports);
39
+ __exportStar(require("./jwt/jwt.strategy"), exports);
40
+ // Interfaces
41
+ __exportStar(require("./interfaces/auth-core-options.interface"), exports);
42
+ // ✅ Entities
43
+ __exportStar(require("./entities/user.entity"), exports);
44
+ __exportStar(require("./entities/role.entity"), exports);
45
+ __exportStar(require("./entities/module.entity"), exports);
46
+ __exportStar(require("./entities/feature.entity"), exports);
47
+ __exportStar(require("./entities/module-route.entity"), exports);
48
+ __exportStar(require("./entities/user-feature-access.entity"), exports);
49
+ __exportStar(require("./entities/user-module-access.entity"), exports);
50
+ __exportStar(require("./entities/module-screen-permission.entity"), exports);
51
+ __exportStar(require("./entities/api-key.entity"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ecrs-auth-core",
3
- "version": "1.0.62",
3
+ "version": "1.0.64",
4
4
  "description": "Centralized authentication and authorization module for ECRS apps",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",