@tomei/sso 0.61.0 → 0.61.1
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/dist/__tests__/unit/components/group-privilege/group-privilege.test.d.ts +1 -0
- package/dist/__tests__/unit/components/group-privilege/group-privilege.test.js +71 -0
- package/dist/__tests__/unit/components/group-privilege/group-privilege.test.js.map +1 -0
- package/dist/__tests__/unit/components/login-user/login-user.spec.d.ts +0 -0
- package/dist/__tests__/unit/components/login-user/login-user.spec.js +6 -0
- package/dist/__tests__/unit/components/login-user/login-user.spec.js.map +1 -0
- package/dist/src/components/login-history/login-history.d.ts +23 -0
- package/dist/src/components/login-history/login-history.js +88 -0
- package/dist/src/components/login-history/login-history.js.map +1 -0
- package/dist/src/components/login-user/user.js +3 -2
- package/dist/src/components/login-user/user.js.map +1 -1
- package/dist/src/interfaces/login-history-search-attr.interface.d.ts +8 -0
- package/dist/src/interfaces/login-history-search-attr.interface.js +3 -0
- package/dist/src/interfaces/login-history-search-attr.interface.js.map +1 -0
- package/dist/src/interfaces/login-history.interface.d.ts +11 -0
- package/dist/src/interfaces/login-history.interface.js +3 -0
- package/dist/src/interfaces/login-history.interface.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/components/api-key/api-key.repository.ts +15 -15
- package/src/components/api-key/api-key.ts +448 -448
- package/src/components/api-key/index.ts +4 -4
- package/src/components/building/building.repository.ts +27 -27
- package/src/components/building/index.ts +2 -2
- package/src/components/group/group.repository.ts +26 -26
- package/src/components/group/group.ts +2284 -2284
- package/src/components/group/index.ts +3 -3
- package/src/components/group-object-privilege/group-object-privilege.repository.ts +25 -25
- package/src/components/group-object-privilege/group-object-privilege.ts +278 -278
- package/src/components/group-object-privilege/index.ts +2 -2
- package/src/components/group-privilege/group-privilege.repository.ts +29 -29
- package/src/components/group-privilege/group-privilege.ts +84 -84
- package/src/components/group-privilege/index.ts +2 -2
- package/src/components/group-reporting-user/group-reporting-user.repository.ts +23 -23
- package/src/components/group-reporting-user/group-reporting-user.ts +506 -506
- package/src/components/group-reporting-user/index.ts +3 -3
- package/src/components/group-system-access/group-system-access.repository.ts +43 -43
- package/src/components/group-system-access/group-system-access.ts +90 -90
- package/src/components/group-system-access/index.ts +2 -2
- package/src/components/index.ts +20 -20
- package/src/components/login-user/index.ts +5 -5
- package/src/components/login-user/interfaces/check-user-info-duplicated.interface.ts +7 -7
- package/src/components/login-user/interfaces/index.ts +1 -1
- package/src/components/login-user/interfaces/system-access.interface.ts +13 -13
- package/src/components/login-user/interfaces/user-info.interface.ts +34 -34
- package/src/components/login-user/login-user.ts +362 -362
- package/src/components/login-user/user.repository.ts +11 -11
- package/src/components/login-user/user.ts +3 -2
- package/src/components/password-hash/index.ts +2 -2
- package/src/components/password-hash/interfaces/index.ts +1 -1
- package/src/components/password-hash/interfaces/password-hash-service.interface.ts +4 -4
- package/src/components/password-hash/password-hash.service.ts +14 -14
- package/src/components/staff/index.ts +2 -2
- package/src/components/staff/staff.repository.ts +27 -27
- package/src/components/system/index.ts +3 -3
- package/src/components/system/system.repository.ts +11 -11
- package/src/components/system/system.ts +456 -456
- package/src/components/system-privilege/index.ts +4 -4
- package/src/components/system-privilege/system-privilege.repository.ts +18 -18
- package/src/components/system-privilege/system-privilege.ts +541 -541
- package/src/components/user-group/index.ts +2 -2
- package/src/components/user-group/user-group.repository.ts +19 -19
- package/src/components/user-group/user-group.ts +764 -764
- package/src/components/user-object-privilege/index.ts +2 -2
- package/src/components/user-object-privilege/user-object-privilege.repository.ts +11 -11
- package/src/components/user-object-privilege/user-object-privilege.ts +79 -79
- package/src/components/user-password-history/index.ts +2 -2
- package/src/components/user-password-history/user-password-history.repository.ts +39 -39
- package/src/components/user-password-history/user-password-history.ts +187 -187
- package/src/components/user-privilege/index.ts +2 -2
- package/src/components/user-privilege/user-privilege.repository.ts +25 -25
- package/src/components/user-privilege/user-privilege.ts +662 -662
- package/src/components/user-reporting-hierarchy/index.ts +2 -2
- package/src/components/user-reporting-hierarchy/user-reporting-hierarchy.repository.ts +30 -30
- package/src/components/user-reporting-hierarchy/user-reporting-hierarchy.ts +505 -505
- package/src/components/user-system-access/index.ts +2 -2
- package/src/components/user-system-access/user-system-access.repository.ts +41 -41
- package/src/database.ts +15 -15
- package/src/enum/api-key.enum.ts +5 -5
- package/src/enum/building-type.enum.ts +6 -6
- package/src/enum/group-type.enum.ts +8 -8
- package/src/enum/index.ts +6 -6
- package/src/enum/login-status.enum.ts +4 -4
- package/src/enum/object-status.enum.ts +4 -4
- package/src/enum/user-status.enum.ts +7 -7
- package/src/enum/yn.enum.ts +4 -4
- package/src/index.ts +8 -8
- package/src/interfaces/api-key-attr.interface.ts +16 -16
- package/src/interfaces/group-object-privilege.interface.ts +14 -14
- package/src/interfaces/group-privilege.interface.ts +10 -10
- package/src/interfaces/group-reporting-user.interface.ts +11 -11
- package/src/interfaces/group-search-attr.interface.ts +9 -9
- package/src/interfaces/group-system-access.interface.ts +10 -10
- package/src/interfaces/group.interface.ts +17 -17
- package/src/interfaces/index.ts +13 -13
- package/src/interfaces/system-login.interface.ts +6 -6
- package/src/interfaces/system-privilege-search.interface.ts +5 -5
- package/src/interfaces/system-privilege.interface.ts +11 -11
- package/src/interfaces/system-search-attr.interface.ts +5 -5
- package/src/interfaces/system.interface.ts +15 -15
- package/src/interfaces/user-group.interface.ts +12 -12
- package/src/interfaces/user-object-privilege.interface.ts +14 -14
- package/src/interfaces/user-password-history.interface.ts +6 -6
- package/src/interfaces/user-privilege.interface.ts +10 -10
- package/src/interfaces/user-reporting-hierarchy.interface.ts +11 -11
- package/src/interfaces/user-session.interface.ts +5 -5
- package/src/interfaces/user-system-access.interface.ts +10 -10
- package/src/models/api-key-entity.ts +101 -101
- package/src/models/building.entity.ts +103 -103
- package/src/models/group-object-privilege.entity.ts +91 -91
- package/src/models/group-privilege.entity.ts +78 -78
- package/src/models/group-reporting-user.entity.ts +95 -95
- package/src/models/group-system-access.entity.ts +81 -81
- package/src/models/group.entity.ts +127 -127
- package/src/models/staff.entity.ts +91 -91
- package/src/models/system-privilege.entity.ts +90 -90
- package/src/models/system.entity.ts +113 -113
- package/src/models/user-group.entity.ts +91 -91
- package/src/models/user-object-privilege.entity.ts +90 -90
- package/src/models/user-password-history.ts +51 -51
- package/src/models/user-privilege.entity.ts +78 -78
- package/src/models/user-reporting-hierarchy.entity.ts +102 -102
- package/src/models/user-system-access.entity.ts +87 -87
- package/src/models/user.entity.ts +193 -193
- package/src/redis-client/__mocks__/jest-initial-setup.ts +2 -2
- package/src/redis-client/__mocks__/redis-mock.ts +28 -28
- package/src/redis-client/index.ts +1 -1
- package/src/redis-client/redis.service.ts +75 -75
- package/src/session/index.ts +2 -2
- package/src/session/interfaces/index.ts +1 -1
- package/src/session/interfaces/session-service.interface.ts +26 -26
- package/src/session/session.service.ts +96 -96
- package/src/types/auth-context.ts +10 -10
- package/src/types/index.ts +1 -1
@@ -1,362 +1,362 @@
|
|
1
|
-
import { ILoginUser } from '@tomei/general';
|
2
|
-
import { User } from './user';
|
3
|
-
import { ISystemLogin } from '../../../src/interfaces/system-login.interface';
|
4
|
-
import GroupModel from '../../models/group.entity';
|
5
|
-
import { ISessionService } from '../../session/interfaces/session-service.interface';
|
6
|
-
import { RedisService } from '../../redis-client/redis.service';
|
7
|
-
import { UserRepository } from './user.repository';
|
8
|
-
import { IUserAttr, IUserInfo } from './interfaces/user-info.interface';
|
9
|
-
import Staff from '../../models/staff.entity';
|
10
|
-
import UserModel from '../../models/user.entity';
|
11
|
-
import { createHash, randomBytes, randomUUID } from 'crypto';
|
12
|
-
import { UserGroupRepository } from '../user-group/user-group.repository';
|
13
|
-
import GroupSystemAccessModel from '../../models/group-system-access.entity';
|
14
|
-
import SystemModel from '../../models/system.entity';
|
15
|
-
import { ApplicationConfig } from '@tomei/config';
|
16
|
-
|
17
|
-
export class LoginUser extends User implements ILoginUser {
|
18
|
-
session = {
|
19
|
-
Id: null,
|
20
|
-
};
|
21
|
-
|
22
|
-
static async init(
|
23
|
-
sessionService: ISessionService,
|
24
|
-
userId?: number,
|
25
|
-
dbTransaction = null,
|
26
|
-
): Promise<LoginUser> {
|
27
|
-
User._RedisService = await RedisService.init();
|
28
|
-
if (userId) {
|
29
|
-
if (dbTransaction) {
|
30
|
-
User._Repository = new UserRepository();
|
31
|
-
}
|
32
|
-
const user = await User._Repository.findOne({
|
33
|
-
where: {
|
34
|
-
UserId: userId,
|
35
|
-
},
|
36
|
-
include: [
|
37
|
-
{
|
38
|
-
model: Staff,
|
39
|
-
},
|
40
|
-
],
|
41
|
-
transaction: dbTransaction,
|
42
|
-
});
|
43
|
-
|
44
|
-
if (!user) {
|
45
|
-
throw new Error('Invalid credentials.');
|
46
|
-
}
|
47
|
-
|
48
|
-
if (user) {
|
49
|
-
const userAttr: IUserAttr = {
|
50
|
-
UserId: user.UserId,
|
51
|
-
UserName: user.UserName,
|
52
|
-
FullName: user?.FullName || null,
|
53
|
-
IDNo: user?.IdNo || null,
|
54
|
-
IDType: user?.IdType || null,
|
55
|
-
ContactNo: user?.ContactNo || null,
|
56
|
-
Email: user.Email,
|
57
|
-
Password: user.Password,
|
58
|
-
Status: user.Status,
|
59
|
-
DefaultPasswordChangedYN: user.DefaultPasswordChangedYN,
|
60
|
-
FirstLoginAt: user.FirstLoginAt,
|
61
|
-
LastLoginAt: user.LastLoginAt,
|
62
|
-
MFAEnabled: user.MFAEnabled,
|
63
|
-
MFAConfig: user.MFAConfig,
|
64
|
-
RecoveryEmail: user.RecoveryEmail,
|
65
|
-
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
|
66
|
-
LastFailedLoginAt: user.LastFailedLoginAt,
|
67
|
-
LastPasswordChangedAt: user.LastPasswordChangedAt,
|
68
|
-
NeedToChangePasswordYN: user.NeedToChangePasswordYN,
|
69
|
-
PasscodeHash: user.PasscodeHash,
|
70
|
-
PasscodeUpdatedAt: user.PasscodeUpdatedAt,
|
71
|
-
CreatedById: user.CreatedById,
|
72
|
-
CreatedAt: user.CreatedAt,
|
73
|
-
UpdatedById: user.UpdatedById,
|
74
|
-
UpdatedAt: user.UpdatedAt,
|
75
|
-
staffs: user?.Staff,
|
76
|
-
};
|
77
|
-
|
78
|
-
return new LoginUser(sessionService, dbTransaction, userAttr);
|
79
|
-
} else {
|
80
|
-
throw new Error('User not found');
|
81
|
-
}
|
82
|
-
}
|
83
|
-
return new LoginUser(sessionService, dbTransaction);
|
84
|
-
}
|
85
|
-
|
86
|
-
async checkPrivileges(
|
87
|
-
systemCode: string,
|
88
|
-
privilegeName: string,
|
89
|
-
): Promise<boolean> {
|
90
|
-
try {
|
91
|
-
if (!this.ObjectId) {
|
92
|
-
throw new Error('ObjectId(UserId) is not set');
|
93
|
-
}
|
94
|
-
|
95
|
-
const sessionName =
|
96
|
-
ApplicationConfig.getComponentConfigValue('sessionName');
|
97
|
-
if (!sessionName) {
|
98
|
-
throw new Error('Session name is not set');
|
99
|
-
}
|
100
|
-
|
101
|
-
const userSession = await this._SessionService.retrieveUserSession(
|
102
|
-
this.ObjectId,
|
103
|
-
sessionName,
|
104
|
-
);
|
105
|
-
|
106
|
-
const systemLogin = userSession.systemLogins.find(
|
107
|
-
(system) => system.code === systemCode,
|
108
|
-
);
|
109
|
-
|
110
|
-
if (!systemLogin) {
|
111
|
-
return false;
|
112
|
-
}
|
113
|
-
|
114
|
-
const privileges = systemLogin.privileges;
|
115
|
-
const hasPrivilege = privileges.includes(privilegeName);
|
116
|
-
return hasPrivilege;
|
117
|
-
} catch (error) {
|
118
|
-
throw error;
|
119
|
-
}
|
120
|
-
}
|
121
|
-
|
122
|
-
async checkSession(
|
123
|
-
systemCode: string,
|
124
|
-
sessionId: string,
|
125
|
-
userId: string,
|
126
|
-
): Promise<ISystemLogin> {
|
127
|
-
try {
|
128
|
-
const sessionName =
|
129
|
-
ApplicationConfig.getComponentConfigValue('sessionName');
|
130
|
-
if (!sessionName) {
|
131
|
-
throw new Error('Session name is not set');
|
132
|
-
}
|
133
|
-
const userSession = await this._SessionService.retrieveUserSession(
|
134
|
-
userId,
|
135
|
-
sessionName,
|
136
|
-
);
|
137
|
-
|
138
|
-
if (userSession.systemLogins.length === 0) {
|
139
|
-
throw new Error('Session expired.');
|
140
|
-
}
|
141
|
-
|
142
|
-
const systemLogin = userSession.systemLogins.find(
|
143
|
-
(sl) => sl.code === systemCode,
|
144
|
-
);
|
145
|
-
|
146
|
-
if (!systemLogin) {
|
147
|
-
throw new Error('Session expired.');
|
148
|
-
}
|
149
|
-
|
150
|
-
if (systemLogin.sessionId !== sessionId) {
|
151
|
-
throw new Error('Session expired.');
|
152
|
-
}
|
153
|
-
|
154
|
-
await this._SessionService.refreshDuration(userId, sessionName);
|
155
|
-
|
156
|
-
return systemLogin;
|
157
|
-
} catch (error) {
|
158
|
-
throw error;
|
159
|
-
}
|
160
|
-
}
|
161
|
-
|
162
|
-
async logout(systemCode: string) {
|
163
|
-
try {
|
164
|
-
if (!this.ObjectId) {
|
165
|
-
throw new Error('ObjectId(UserId) is not set');
|
166
|
-
}
|
167
|
-
|
168
|
-
const sessionName =
|
169
|
-
ApplicationConfig.getComponentConfigValue('sessionName');
|
170
|
-
if (!sessionName) {
|
171
|
-
throw new Error('Session name is not set');
|
172
|
-
}
|
173
|
-
|
174
|
-
const userSession = await this._SessionService.retrieveUserSession(
|
175
|
-
this.ObjectId,
|
176
|
-
sessionName,
|
177
|
-
);
|
178
|
-
const index = userSession.systemLogins.findIndex(
|
179
|
-
(system) => system.code === systemCode,
|
180
|
-
);
|
181
|
-
userSession.systemLogins.splice(index, 1);
|
182
|
-
this._SessionService.setUserSession(
|
183
|
-
this.ObjectId,
|
184
|
-
userSession,
|
185
|
-
sessionName,
|
186
|
-
);
|
187
|
-
} catch (error) {
|
188
|
-
throw error;
|
189
|
-
}
|
190
|
-
}
|
191
|
-
|
192
|
-
async getProfile(dbTransaction: any) {
|
193
|
-
const user = await User._Repository.findOne({
|
194
|
-
where: {
|
195
|
-
UserId: this.UserId,
|
196
|
-
Status: 'Active',
|
197
|
-
},
|
198
|
-
include: [
|
199
|
-
{
|
200
|
-
model: Staff,
|
201
|
-
},
|
202
|
-
],
|
203
|
-
transaction: dbTransaction,
|
204
|
-
});
|
205
|
-
return user;
|
206
|
-
}
|
207
|
-
|
208
|
-
public static async getGroups(loginUser: User, dbTransaction: any) {
|
209
|
-
// This method will retrieve all user groups.
|
210
|
-
|
211
|
-
// Part 2: Retrieve User Groups & Returns
|
212
|
-
const userGroups = await User._UserGroupRepo.findAll({
|
213
|
-
where: {
|
214
|
-
UserId: loginUser.ObjectId,
|
215
|
-
Status: 'Active',
|
216
|
-
},
|
217
|
-
include: [{ model: UserModel, as: 'User' }, { model: GroupModel }],
|
218
|
-
transaction: dbTransaction,
|
219
|
-
});
|
220
|
-
|
221
|
-
return userGroups;
|
222
|
-
}
|
223
|
-
|
224
|
-
public static async getSystems(loginUser: User, dbTransaction: any) {
|
225
|
-
// This method will retrieve all system records which user has accessed to.
|
226
|
-
|
227
|
-
// Part 2: Retrieve System Access
|
228
|
-
const groups = await this.getGroups(loginUser, dbTransaction);
|
229
|
-
const systemAccess = await User.combineSystemAccess(
|
230
|
-
loginUser,
|
231
|
-
dbTransaction,
|
232
|
-
groups,
|
233
|
-
);
|
234
|
-
const output = [];
|
235
|
-
if (systemAccess) {
|
236
|
-
for (let i = 0; i < systemAccess.length; i++) {
|
237
|
-
const system = await User._SystemRepository.findOne({
|
238
|
-
where: {
|
239
|
-
SystemCode: systemAccess[i].SystemCode,
|
240
|
-
Status: 'Active',
|
241
|
-
},
|
242
|
-
});
|
243
|
-
output.push({
|
244
|
-
UserSystemAccessId: systemAccess[i].UserSystemAccessId,
|
245
|
-
UserId: systemAccess[i].UserId,
|
246
|
-
SystemCode: systemAccess[i].SystemCode,
|
247
|
-
Status: systemAccess[i].Status,
|
248
|
-
CreatedById: systemAccess[i].CreatedById,
|
249
|
-
UpdatedById: systemAccess[i].UpdatedById,
|
250
|
-
CreatedAt: systemAccess[i].CreatedAt,
|
251
|
-
UpdatedAt: systemAccess[i].UpdatedAt,
|
252
|
-
inheritedBy: ['OWN'],
|
253
|
-
System: system,
|
254
|
-
});
|
255
|
-
}
|
256
|
-
}
|
257
|
-
|
258
|
-
let userGroupRepository = new UserGroupRepository();
|
259
|
-
const userGroups = await userGroupRepository.findAll({
|
260
|
-
where: {
|
261
|
-
UserId: loginUser.UserId,
|
262
|
-
Status: 'Active',
|
263
|
-
},
|
264
|
-
include: [
|
265
|
-
{
|
266
|
-
model: GroupModel,
|
267
|
-
required: true,
|
268
|
-
where: {
|
269
|
-
Status: 'Active',
|
270
|
-
},
|
271
|
-
include: [
|
272
|
-
{
|
273
|
-
model: GroupSystemAccessModel,
|
274
|
-
where: {
|
275
|
-
Status: 'Active',
|
276
|
-
},
|
277
|
-
include: [
|
278
|
-
{
|
279
|
-
model: SystemModel,
|
280
|
-
},
|
281
|
-
],
|
282
|
-
},
|
283
|
-
],
|
284
|
-
},
|
285
|
-
],
|
286
|
-
transaction: dbTransaction,
|
287
|
-
});
|
288
|
-
|
289
|
-
if (userGroups) {
|
290
|
-
for (let i = 0; i < userGroups.length; i++) {
|
291
|
-
let systemAccessList = userGroups[i].Group.GroupSystemAccesses;
|
292
|
-
for (let j = 0; j < systemAccessList.length; j++) {
|
293
|
-
let systemDetails = systemAccessList[j];
|
294
|
-
let isFound = output.findIndex(
|
295
|
-
(e) => e.SystemCode === systemDetails.SystemCode,
|
296
|
-
);
|
297
|
-
if (isFound > -1) {
|
298
|
-
output[isFound].inheritedBy.push(userGroups[i].GroupCode);
|
299
|
-
} else {
|
300
|
-
output.push({
|
301
|
-
UserSystemAccessId: systemDetails.GroupSystemAccessId,
|
302
|
-
UserId: systemDetails.GroupSystemAccessId,
|
303
|
-
SystemCode: systemDetails.SystemCode,
|
304
|
-
Status: systemDetails.Status,
|
305
|
-
CreatedById: systemDetails.CreatedById,
|
306
|
-
UpdatedById: systemDetails.UpdatedById,
|
307
|
-
CreatedAt: systemDetails.CreatedAt,
|
308
|
-
UpdatedAt: systemDetails.UpdatedAt,
|
309
|
-
inheritedBy: [userGroups[i].GroupCode],
|
310
|
-
System: systemDetails.System,
|
311
|
-
});
|
312
|
-
}
|
313
|
-
}
|
314
|
-
}
|
315
|
-
}
|
316
|
-
|
317
|
-
// Part 3: Map Result to System Object
|
318
|
-
return output;
|
319
|
-
}
|
320
|
-
|
321
|
-
async setSession(systemCode: string, sessionId: string, dbTransaction: any) {
|
322
|
-
// fetch user session if exists
|
323
|
-
const sessionName =
|
324
|
-
ApplicationConfig.getComponentConfigValue('sessionName');
|
325
|
-
|
326
|
-
if (!sessionName) {
|
327
|
-
throw new Error('Session name is not set in the configuration');
|
328
|
-
}
|
329
|
-
|
330
|
-
const userSession = await this._SessionService.retrieveUserSession(
|
331
|
-
this.ObjectId,
|
332
|
-
sessionName,
|
333
|
-
);
|
334
|
-
const systemLogin = userSession.systemLogins.find(
|
335
|
-
(system) => system.code === systemCode,
|
336
|
-
);
|
337
|
-
|
338
|
-
if (systemLogin) {
|
339
|
-
const privileges = await this.getPrivileges(systemCode, dbTransaction);
|
340
|
-
systemLogin.sessionId = sessionId;
|
341
|
-
systemLogin.privileges = privileges;
|
342
|
-
userSession.systemLogins.map((system) =>
|
343
|
-
system.code === systemCode ? systemLogin : system,
|
344
|
-
);
|
345
|
-
} else {
|
346
|
-
// if not, add new system login into the userSession
|
347
|
-
const newLogin = {
|
348
|
-
id: systemCode,
|
349
|
-
code: systemCode,
|
350
|
-
sessionId: sessionId,
|
351
|
-
privileges: await this.getPrivileges(systemCode, dbTransaction),
|
352
|
-
};
|
353
|
-
userSession.systemLogins.push(newLogin);
|
354
|
-
}
|
355
|
-
// then update userSession inside the redis storage with 1 day duration of time-to-live
|
356
|
-
this._SessionService.setUserSession(
|
357
|
-
this.ObjectId,
|
358
|
-
userSession,
|
359
|
-
sessionName,
|
360
|
-
);
|
361
|
-
}
|
362
|
-
}
|
1
|
+
import { ILoginUser } from '@tomei/general';
|
2
|
+
import { User } from './user';
|
3
|
+
import { ISystemLogin } from '../../../src/interfaces/system-login.interface';
|
4
|
+
import GroupModel from '../../models/group.entity';
|
5
|
+
import { ISessionService } from '../../session/interfaces/session-service.interface';
|
6
|
+
import { RedisService } from '../../redis-client/redis.service';
|
7
|
+
import { UserRepository } from './user.repository';
|
8
|
+
import { IUserAttr, IUserInfo } from './interfaces/user-info.interface';
|
9
|
+
import Staff from '../../models/staff.entity';
|
10
|
+
import UserModel from '../../models/user.entity';
|
11
|
+
import { createHash, randomBytes, randomUUID } from 'crypto';
|
12
|
+
import { UserGroupRepository } from '../user-group/user-group.repository';
|
13
|
+
import GroupSystemAccessModel from '../../models/group-system-access.entity';
|
14
|
+
import SystemModel from '../../models/system.entity';
|
15
|
+
import { ApplicationConfig } from '@tomei/config';
|
16
|
+
|
17
|
+
export class LoginUser extends User implements ILoginUser {
|
18
|
+
session = {
|
19
|
+
Id: null,
|
20
|
+
};
|
21
|
+
|
22
|
+
static async init(
|
23
|
+
sessionService: ISessionService,
|
24
|
+
userId?: number,
|
25
|
+
dbTransaction = null,
|
26
|
+
): Promise<LoginUser> {
|
27
|
+
User._RedisService = await RedisService.init();
|
28
|
+
if (userId) {
|
29
|
+
if (dbTransaction) {
|
30
|
+
User._Repository = new UserRepository();
|
31
|
+
}
|
32
|
+
const user = await User._Repository.findOne({
|
33
|
+
where: {
|
34
|
+
UserId: userId,
|
35
|
+
},
|
36
|
+
include: [
|
37
|
+
{
|
38
|
+
model: Staff,
|
39
|
+
},
|
40
|
+
],
|
41
|
+
transaction: dbTransaction,
|
42
|
+
});
|
43
|
+
|
44
|
+
if (!user) {
|
45
|
+
throw new Error('Invalid credentials.');
|
46
|
+
}
|
47
|
+
|
48
|
+
if (user) {
|
49
|
+
const userAttr: IUserAttr = {
|
50
|
+
UserId: user.UserId,
|
51
|
+
UserName: user.UserName,
|
52
|
+
FullName: user?.FullName || null,
|
53
|
+
IDNo: user?.IdNo || null,
|
54
|
+
IDType: user?.IdType || null,
|
55
|
+
ContactNo: user?.ContactNo || null,
|
56
|
+
Email: user.Email,
|
57
|
+
Password: user.Password,
|
58
|
+
Status: user.Status,
|
59
|
+
DefaultPasswordChangedYN: user.DefaultPasswordChangedYN,
|
60
|
+
FirstLoginAt: user.FirstLoginAt,
|
61
|
+
LastLoginAt: user.LastLoginAt,
|
62
|
+
MFAEnabled: user.MFAEnabled,
|
63
|
+
MFAConfig: user.MFAConfig,
|
64
|
+
RecoveryEmail: user.RecoveryEmail,
|
65
|
+
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
|
66
|
+
LastFailedLoginAt: user.LastFailedLoginAt,
|
67
|
+
LastPasswordChangedAt: user.LastPasswordChangedAt,
|
68
|
+
NeedToChangePasswordYN: user.NeedToChangePasswordYN,
|
69
|
+
PasscodeHash: user.PasscodeHash,
|
70
|
+
PasscodeUpdatedAt: user.PasscodeUpdatedAt,
|
71
|
+
CreatedById: user.CreatedById,
|
72
|
+
CreatedAt: user.CreatedAt,
|
73
|
+
UpdatedById: user.UpdatedById,
|
74
|
+
UpdatedAt: user.UpdatedAt,
|
75
|
+
staffs: user?.Staff,
|
76
|
+
};
|
77
|
+
|
78
|
+
return new LoginUser(sessionService, dbTransaction, userAttr);
|
79
|
+
} else {
|
80
|
+
throw new Error('User not found');
|
81
|
+
}
|
82
|
+
}
|
83
|
+
return new LoginUser(sessionService, dbTransaction);
|
84
|
+
}
|
85
|
+
|
86
|
+
async checkPrivileges(
|
87
|
+
systemCode: string,
|
88
|
+
privilegeName: string,
|
89
|
+
): Promise<boolean> {
|
90
|
+
try {
|
91
|
+
if (!this.ObjectId) {
|
92
|
+
throw new Error('ObjectId(UserId) is not set');
|
93
|
+
}
|
94
|
+
|
95
|
+
const sessionName =
|
96
|
+
ApplicationConfig.getComponentConfigValue('sessionName');
|
97
|
+
if (!sessionName) {
|
98
|
+
throw new Error('Session name is not set');
|
99
|
+
}
|
100
|
+
|
101
|
+
const userSession = await this._SessionService.retrieveUserSession(
|
102
|
+
this.ObjectId,
|
103
|
+
sessionName,
|
104
|
+
);
|
105
|
+
|
106
|
+
const systemLogin = userSession.systemLogins.find(
|
107
|
+
(system) => system.code === systemCode,
|
108
|
+
);
|
109
|
+
|
110
|
+
if (!systemLogin) {
|
111
|
+
return false;
|
112
|
+
}
|
113
|
+
|
114
|
+
const privileges = systemLogin.privileges;
|
115
|
+
const hasPrivilege = privileges.includes(privilegeName);
|
116
|
+
return hasPrivilege;
|
117
|
+
} catch (error) {
|
118
|
+
throw error;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
async checkSession(
|
123
|
+
systemCode: string,
|
124
|
+
sessionId: string,
|
125
|
+
userId: string,
|
126
|
+
): Promise<ISystemLogin> {
|
127
|
+
try {
|
128
|
+
const sessionName =
|
129
|
+
ApplicationConfig.getComponentConfigValue('sessionName');
|
130
|
+
if (!sessionName) {
|
131
|
+
throw new Error('Session name is not set');
|
132
|
+
}
|
133
|
+
const userSession = await this._SessionService.retrieveUserSession(
|
134
|
+
userId,
|
135
|
+
sessionName,
|
136
|
+
);
|
137
|
+
|
138
|
+
if (userSession.systemLogins.length === 0) {
|
139
|
+
throw new Error('Session expired.');
|
140
|
+
}
|
141
|
+
|
142
|
+
const systemLogin = userSession.systemLogins.find(
|
143
|
+
(sl) => sl.code === systemCode,
|
144
|
+
);
|
145
|
+
|
146
|
+
if (!systemLogin) {
|
147
|
+
throw new Error('Session expired.');
|
148
|
+
}
|
149
|
+
|
150
|
+
if (systemLogin.sessionId !== sessionId) {
|
151
|
+
throw new Error('Session expired.');
|
152
|
+
}
|
153
|
+
|
154
|
+
await this._SessionService.refreshDuration(userId, sessionName);
|
155
|
+
|
156
|
+
return systemLogin;
|
157
|
+
} catch (error) {
|
158
|
+
throw error;
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
async logout(systemCode: string) {
|
163
|
+
try {
|
164
|
+
if (!this.ObjectId) {
|
165
|
+
throw new Error('ObjectId(UserId) is not set');
|
166
|
+
}
|
167
|
+
|
168
|
+
const sessionName =
|
169
|
+
ApplicationConfig.getComponentConfigValue('sessionName');
|
170
|
+
if (!sessionName) {
|
171
|
+
throw new Error('Session name is not set');
|
172
|
+
}
|
173
|
+
|
174
|
+
const userSession = await this._SessionService.retrieveUserSession(
|
175
|
+
this.ObjectId,
|
176
|
+
sessionName,
|
177
|
+
);
|
178
|
+
const index = userSession.systemLogins.findIndex(
|
179
|
+
(system) => system.code === systemCode,
|
180
|
+
);
|
181
|
+
userSession.systemLogins.splice(index, 1);
|
182
|
+
this._SessionService.setUserSession(
|
183
|
+
this.ObjectId,
|
184
|
+
userSession,
|
185
|
+
sessionName,
|
186
|
+
);
|
187
|
+
} catch (error) {
|
188
|
+
throw error;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
|
192
|
+
async getProfile(dbTransaction: any) {
|
193
|
+
const user = await User._Repository.findOne({
|
194
|
+
where: {
|
195
|
+
UserId: this.UserId,
|
196
|
+
Status: 'Active',
|
197
|
+
},
|
198
|
+
include: [
|
199
|
+
{
|
200
|
+
model: Staff,
|
201
|
+
},
|
202
|
+
],
|
203
|
+
transaction: dbTransaction,
|
204
|
+
});
|
205
|
+
return user;
|
206
|
+
}
|
207
|
+
|
208
|
+
public static async getGroups(loginUser: User, dbTransaction: any) {
|
209
|
+
// This method will retrieve all user groups.
|
210
|
+
|
211
|
+
// Part 2: Retrieve User Groups & Returns
|
212
|
+
const userGroups = await User._UserGroupRepo.findAll({
|
213
|
+
where: {
|
214
|
+
UserId: loginUser.ObjectId,
|
215
|
+
Status: 'Active',
|
216
|
+
},
|
217
|
+
include: [{ model: UserModel, as: 'User' }, { model: GroupModel }],
|
218
|
+
transaction: dbTransaction,
|
219
|
+
});
|
220
|
+
|
221
|
+
return userGroups;
|
222
|
+
}
|
223
|
+
|
224
|
+
public static async getSystems(loginUser: User, dbTransaction: any) {
|
225
|
+
// This method will retrieve all system records which user has accessed to.
|
226
|
+
|
227
|
+
// Part 2: Retrieve System Access
|
228
|
+
const groups = await this.getGroups(loginUser, dbTransaction);
|
229
|
+
const systemAccess = await User.combineSystemAccess(
|
230
|
+
loginUser,
|
231
|
+
dbTransaction,
|
232
|
+
groups,
|
233
|
+
);
|
234
|
+
const output = [];
|
235
|
+
if (systemAccess) {
|
236
|
+
for (let i = 0; i < systemAccess.length; i++) {
|
237
|
+
const system = await User._SystemRepository.findOne({
|
238
|
+
where: {
|
239
|
+
SystemCode: systemAccess[i].SystemCode,
|
240
|
+
Status: 'Active',
|
241
|
+
},
|
242
|
+
});
|
243
|
+
output.push({
|
244
|
+
UserSystemAccessId: systemAccess[i].UserSystemAccessId,
|
245
|
+
UserId: systemAccess[i].UserId,
|
246
|
+
SystemCode: systemAccess[i].SystemCode,
|
247
|
+
Status: systemAccess[i].Status,
|
248
|
+
CreatedById: systemAccess[i].CreatedById,
|
249
|
+
UpdatedById: systemAccess[i].UpdatedById,
|
250
|
+
CreatedAt: systemAccess[i].CreatedAt,
|
251
|
+
UpdatedAt: systemAccess[i].UpdatedAt,
|
252
|
+
inheritedBy: ['OWN'],
|
253
|
+
System: system,
|
254
|
+
});
|
255
|
+
}
|
256
|
+
}
|
257
|
+
|
258
|
+
let userGroupRepository = new UserGroupRepository();
|
259
|
+
const userGroups = await userGroupRepository.findAll({
|
260
|
+
where: {
|
261
|
+
UserId: loginUser.UserId,
|
262
|
+
Status: 'Active',
|
263
|
+
},
|
264
|
+
include: [
|
265
|
+
{
|
266
|
+
model: GroupModel,
|
267
|
+
required: true,
|
268
|
+
where: {
|
269
|
+
Status: 'Active',
|
270
|
+
},
|
271
|
+
include: [
|
272
|
+
{
|
273
|
+
model: GroupSystemAccessModel,
|
274
|
+
where: {
|
275
|
+
Status: 'Active',
|
276
|
+
},
|
277
|
+
include: [
|
278
|
+
{
|
279
|
+
model: SystemModel,
|
280
|
+
},
|
281
|
+
],
|
282
|
+
},
|
283
|
+
],
|
284
|
+
},
|
285
|
+
],
|
286
|
+
transaction: dbTransaction,
|
287
|
+
});
|
288
|
+
|
289
|
+
if (userGroups) {
|
290
|
+
for (let i = 0; i < userGroups.length; i++) {
|
291
|
+
let systemAccessList = userGroups[i].Group.GroupSystemAccesses;
|
292
|
+
for (let j = 0; j < systemAccessList.length; j++) {
|
293
|
+
let systemDetails = systemAccessList[j];
|
294
|
+
let isFound = output.findIndex(
|
295
|
+
(e) => e.SystemCode === systemDetails.SystemCode,
|
296
|
+
);
|
297
|
+
if (isFound > -1) {
|
298
|
+
output[isFound].inheritedBy.push(userGroups[i].GroupCode);
|
299
|
+
} else {
|
300
|
+
output.push({
|
301
|
+
UserSystemAccessId: systemDetails.GroupSystemAccessId,
|
302
|
+
UserId: systemDetails.GroupSystemAccessId,
|
303
|
+
SystemCode: systemDetails.SystemCode,
|
304
|
+
Status: systemDetails.Status,
|
305
|
+
CreatedById: systemDetails.CreatedById,
|
306
|
+
UpdatedById: systemDetails.UpdatedById,
|
307
|
+
CreatedAt: systemDetails.CreatedAt,
|
308
|
+
UpdatedAt: systemDetails.UpdatedAt,
|
309
|
+
inheritedBy: [userGroups[i].GroupCode],
|
310
|
+
System: systemDetails.System,
|
311
|
+
});
|
312
|
+
}
|
313
|
+
}
|
314
|
+
}
|
315
|
+
}
|
316
|
+
|
317
|
+
// Part 3: Map Result to System Object
|
318
|
+
return output;
|
319
|
+
}
|
320
|
+
|
321
|
+
async setSession(systemCode: string, sessionId: string, dbTransaction: any) {
|
322
|
+
// fetch user session if exists
|
323
|
+
const sessionName =
|
324
|
+
ApplicationConfig.getComponentConfigValue('sessionName');
|
325
|
+
|
326
|
+
if (!sessionName) {
|
327
|
+
throw new Error('Session name is not set in the configuration');
|
328
|
+
}
|
329
|
+
|
330
|
+
const userSession = await this._SessionService.retrieveUserSession(
|
331
|
+
this.ObjectId,
|
332
|
+
sessionName,
|
333
|
+
);
|
334
|
+
const systemLogin = userSession.systemLogins.find(
|
335
|
+
(system) => system.code === systemCode,
|
336
|
+
);
|
337
|
+
|
338
|
+
if (systemLogin) {
|
339
|
+
const privileges = await this.getPrivileges(systemCode, dbTransaction);
|
340
|
+
systemLogin.sessionId = sessionId;
|
341
|
+
systemLogin.privileges = privileges;
|
342
|
+
userSession.systemLogins.map((system) =>
|
343
|
+
system.code === systemCode ? systemLogin : system,
|
344
|
+
);
|
345
|
+
} else {
|
346
|
+
// if not, add new system login into the userSession
|
347
|
+
const newLogin = {
|
348
|
+
id: systemCode,
|
349
|
+
code: systemCode,
|
350
|
+
sessionId: sessionId,
|
351
|
+
privileges: await this.getPrivileges(systemCode, dbTransaction),
|
352
|
+
};
|
353
|
+
userSession.systemLogins.push(newLogin);
|
354
|
+
}
|
355
|
+
// then update userSession inside the redis storage with 1 day duration of time-to-live
|
356
|
+
this._SessionService.setUserSession(
|
357
|
+
this.ObjectId,
|
358
|
+
userSession,
|
359
|
+
sessionName,
|
360
|
+
);
|
361
|
+
}
|
362
|
+
}
|