ecrs-auth-core 1.0.64 → 1.0.66

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,9 +1,10 @@
1
+ import { Request } from 'express';
1
2
  import { AuthService } from './auth.service';
2
3
  import { LoginDto } from './dtos/login.dto';
3
4
  export declare class AuthController {
4
5
  private readonly authService;
5
6
  constructor(authService: AuthService);
6
- login(body: LoginDto): Promise<{
7
+ login(request: Request, body: LoginDto): Promise<{
7
8
  status: boolean;
8
9
  message: string;
9
10
  data: {
@@ -21,8 +22,31 @@ export declare class AuthController {
21
22
  employeeId: number;
22
23
  parentId: number;
23
24
  referenceId: number;
25
+ branchId: any;
26
+ dispatchCenterId: any;
27
+ departmentId: any;
28
+ designationId: any;
29
+ profile_photo_url: string;
24
30
  };
25
31
  };
26
32
  access_token: string;
27
33
  }>;
34
+ /**
35
+ * Extract additional client data from request and user-agent
36
+ */
37
+ private extractClientData;
38
+ /**
39
+ * Parse user-agent string to extract browser, OS, and device type
40
+ */
41
+ private parseUserAgent;
42
+ /**
43
+ * Extract client IP from request
44
+ * Priority:
45
+ * 1. X-Forwarded-For header (proxy)
46
+ * 2. X-Real-IP header (nginx)
47
+ * 3. CF-Connecting-IP (Cloudflare)
48
+ * 4. request.ip (Express native)
49
+ * 5. socket.remoteAddress (direct connection)
50
+ */
51
+ private getClientIp;
28
52
  }
@@ -22,10 +22,19 @@ let AuthController = class AuthController {
22
22
  constructor(authService) {
23
23
  this.authService = authService;
24
24
  }
25
- async login(body) {
26
- const user = await this.authService.validateUser(body.email, body.password);
25
+ async login(request, body) {
26
+ // Get client IP from socket/request
27
+ const clientIp = this.getClientIp(request);
28
+ const userAgent = request.get('user-agent') || 'Unknown';
29
+ // Extract additional client data
30
+ const additionalData = this.extractClientData(request, userAgent);
31
+ console.log(`📍 Login attempt from IP: ${clientIp}, User-Agent: ${userAgent}`);
32
+ // Validate user with IP restriction check
33
+ const user = await this.authService.validateUser(body.email, body.password, clientIp);
27
34
  if (!user) {
28
- throw new common_1.UnauthorizedException('Login failed: email or password not matched');
35
+ // Save failed login attempt
36
+ await this.authService.saveLastLogin({ email: body.email }, clientIp, 'failed', 'Invalid credentials or IP not allowed', additionalData).catch(() => { }); // Ignore errors
37
+ throw new common_1.UnauthorizedException('Login failed: email or password not matched or IP not allowed');
29
38
  }
30
39
  const requestedModuleId = Number(body.moduleId);
31
40
  if (!Number.isFinite(requestedModuleId)) {
@@ -39,7 +48,104 @@ let AuthController = class AuthController {
39
48
  if (!Array.isArray(perms.modules) || !perms.modules.includes(requestedModuleId)) {
40
49
  throw new common_1.UnauthorizedException('You are not authorized to access this module');
41
50
  }
42
- return this.authService.login(user, requestedModuleId);
51
+ const loginResponse = await this.authService.login(user, requestedModuleId);
52
+ // Save successful login details with additional client data
53
+ await this.authService.saveLastLogin(user, clientIp, 'success', undefined, {
54
+ ...additionalData,
55
+ moduleId: requestedModuleId,
56
+ }).catch(() => { }); // Ignore errors - don't block login
57
+ return loginResponse;
58
+ }
59
+ /**
60
+ * Extract additional client data from request and user-agent
61
+ */
62
+ extractClientData(request, userAgent) {
63
+ const { browser, os, deviceType } = this.parseUserAgent(userAgent);
64
+ const ipAddressName = request.get('x-forwarded-host') || request.get('host') || 'Unknown';
65
+ const location = request.get('cf-ipcountry') || 'Unknown'; // Cloudflare header
66
+ return {
67
+ browser,
68
+ deviceType,
69
+ operatingSystem: os,
70
+ userAgent,
71
+ location,
72
+ ipAddressName,
73
+ };
74
+ }
75
+ /**
76
+ * Parse user-agent string to extract browser, OS, and device type
77
+ */
78
+ parseUserAgent(userAgent) {
79
+ const ua = userAgent.toLowerCase();
80
+ // Detect browser
81
+ let browser = 'Unknown';
82
+ if (ua.includes('chrome'))
83
+ browser = 'Chrome';
84
+ else if (ua.includes('firefox'))
85
+ browser = 'Firefox';
86
+ else if (ua.includes('safari'))
87
+ browser = 'Safari';
88
+ else if (ua.includes('edg/'))
89
+ browser = 'Edge';
90
+ else if (ua.includes('opera') || ua.includes('opr/'))
91
+ browser = 'Opera';
92
+ else if (ua.includes('trident'))
93
+ browser = 'Internet Explorer';
94
+ // Detect OS
95
+ let os = 'Unknown';
96
+ if (ua.includes('windows'))
97
+ os = 'Windows';
98
+ else if (ua.includes('mac'))
99
+ os = 'macOS';
100
+ else if (ua.includes('linux'))
101
+ os = 'Linux';
102
+ else if (ua.includes('iphone') || ua.includes('ipad'))
103
+ os = 'iOS';
104
+ else if (ua.includes('android'))
105
+ os = 'Android';
106
+ // Detect device type
107
+ let deviceType = 'Desktop';
108
+ if (ua.includes('mobile') || ua.includes('android') || ua.includes('iphone'))
109
+ deviceType = 'Mobile';
110
+ else if (ua.includes('tablet') || ua.includes('ipad'))
111
+ deviceType = 'Tablet';
112
+ return { browser, os, deviceType };
113
+ }
114
+ /**
115
+ * Extract client IP from request
116
+ * Priority:
117
+ * 1. X-Forwarded-For header (proxy)
118
+ * 2. X-Real-IP header (nginx)
119
+ * 3. CF-Connecting-IP (Cloudflare)
120
+ * 4. request.ip (Express native)
121
+ * 5. socket.remoteAddress (direct connection)
122
+ */
123
+ getClientIp(request) {
124
+ // Check X-Forwarded-For header (most common with proxies)
125
+ const xForwardedFor = request.headers['x-forwarded-for'];
126
+ if (xForwardedFor) {
127
+ const ips = Array.isArray(xForwardedFor)
128
+ ? xForwardedFor
129
+ : xForwardedFor.split(',');
130
+ return ips[0].trim();
131
+ }
132
+ // Check X-Real-IP header (nginx)
133
+ const xRealIp = request.headers['x-real-ip'];
134
+ if (xRealIp) {
135
+ return Array.isArray(xRealIp) ? xRealIp[0] : xRealIp;
136
+ }
137
+ // Check CF-Connecting-IP (Cloudflare)
138
+ const cfIp = request.headers['cf-connecting-ip'];
139
+ if (cfIp) {
140
+ return Array.isArray(cfIp) ? cfIp[0] : cfIp;
141
+ }
142
+ // Use Express native request.ip (handles proxies if trust proxy is set)
143
+ if (request.ip) {
144
+ return request.ip;
145
+ }
146
+ // Fallback to socket remote address
147
+ const socketIp = (request.socket.remoteAddress || '').replace(/^.*:/, '');
148
+ return socketIp || 'unknown';
43
149
  }
44
150
  };
45
151
  exports.AuthController = AuthController;
@@ -84,10 +190,11 @@ __decorate([
84
190
  }
85
191
  }
86
192
  }),
87
- (0, swagger_1.ApiUnauthorizedResponse)({ description: 'Invalid credentials' }),
88
- __param(0, (0, common_1.Body)()),
193
+ (0, swagger_1.ApiUnauthorizedResponse)({ description: 'Invalid credentials or IP not allowed' }),
194
+ __param(0, (0, common_1.Req)()),
195
+ __param(1, (0, common_1.Body)()),
89
196
  __metadata("design:type", Function),
90
- __metadata("design:paramtypes", [login_dto_1.LoginDto]),
197
+ __metadata("design:paramtypes", [Object, login_dto_1.LoginDto]),
91
198
  __metadata("design:returntype", Promise)
92
199
  ], AuthController.prototype, "login", null);
93
200
  exports.AuthController = AuthController = __decorate([
@@ -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);
@@ -25,10 +25,40 @@ export declare class AuthService {
25
25
  private readonly featureAccessRepo;
26
26
  private readonly moduleAccessRepo;
27
27
  private readonly screenPermissionRepo;
28
+ private readonly ipRestrictionsRepo;
29
+ private readonly userLastLoginRepo;
30
+ private readonly employeeWorkProfileRepo;
31
+ private uploadPhotoDir;
28
32
  constructor(jwtService: JwtService, options: AuthCoreOptions);
29
- validateUser(email: string, password: string): Promise<User | null>;
33
+ validateUser(email: string, password: string, clientIp?: string): Promise<User | null>;
34
+ /**
35
+ * Validate IP restriction for a user
36
+ *
37
+ * Logic:
38
+ * 1. Check if user has any IP restrictions (is_active = 1)
39
+ * 2. If NO restrictions exist → Allow login (return true)
40
+ * 3. If restrictions exist → Check if requestIp matches any allowed IP
41
+ * 4. If match found → Allow login (return true)
42
+ * 5. If NO match → Deny login (return false)
43
+ */
44
+ private normalizeIp;
45
+ private validateIpRestriction;
30
46
  hasModuleAccess(userId: number, moduleId: number): Promise<boolean>;
31
47
  getPermissions(userId: number): Promise<PermissionsTree>;
48
+ /**
49
+ * Save user last login details
50
+ * Updates the tbl_user_last_login table with latest login info
51
+ */
52
+ saveLastLogin(user: User, clientIp: string, loginStatus?: 'success' | 'failed' | 'blocked', failureReason?: string, additionalData?: {
53
+ browser?: string;
54
+ deviceType?: string;
55
+ operatingSystem?: string;
56
+ userAgent?: string;
57
+ location?: string;
58
+ moduleId?: number;
59
+ ipAddressName?: string;
60
+ metadata?: Record<string, any>;
61
+ }): Promise<void>;
32
62
  login(user: User, selectedModuleId?: number): Promise<{
33
63
  status: boolean;
34
64
  message: string;
@@ -47,10 +77,20 @@ export declare class AuthService {
47
77
  employeeId: number;
48
78
  parentId: number;
49
79
  referenceId: number;
80
+ branchId: any;
81
+ dispatchCenterId: any;
82
+ departmentId: any;
83
+ designationId: any;
84
+ profile_photo_url: string;
50
85
  };
51
86
  };
52
87
  access_token: string;
53
88
  }>;
89
+ /**
90
+ * Extract clean IPv4 address from request
91
+ * Handles various formats: IPv6-mapped, plain IPv4, descriptive text
92
+ */
93
+ extractUserIpv4(clientIp: string | undefined): string;
54
94
  findUserById(id: number): Promise<User | null>;
55
95
  private loadPermissions;
56
96
  }