@tomei/sso 0.65.0 → 0.65.1-test.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.
Files changed (33) hide show
  1. package/.gitlab-ci.yml +234 -13
  2. package/.husky/commit-msg +0 -0
  3. package/.husky/pre-commit +0 -0
  4. package/__tests__/unit/components/api-key/api-key.spec.ts +201 -0
  5. package/__tests__/unit/components/group/group.spec.ts +6 -0
  6. package/__tests__/unit/components/group-reporting-user/group-reporting-user.spec.ts +9 -1
  7. package/__tests__/unit/components/login-user/login.spec.ts +1199 -5
  8. package/__tests__/unit/components/system/system.spec.ts +1 -0
  9. package/__tests__/unit/components/user-password-history/user-password-history.spec.ts +165 -0
  10. package/__tests__/unit/components/user-reporting-hierarchy/user-reporting-hierarchy.spec.ts +233 -0
  11. package/coverage/cobertura-coverage.xml +6837 -0
  12. package/coverage/test-report.xml +161 -0
  13. package/dist/__tests__/unit/components/api-key/api-key.spec.d.ts +1 -0
  14. package/dist/__tests__/unit/components/api-key/api-key.spec.js +158 -0
  15. package/dist/__tests__/unit/components/api-key/api-key.spec.js.map +1 -0
  16. package/dist/__tests__/unit/components/group/group.spec.js +4 -0
  17. package/dist/__tests__/unit/components/group/group.spec.js.map +1 -1
  18. package/dist/__tests__/unit/components/group-reporting-user/group-reporting-user.spec.js +9 -1
  19. package/dist/__tests__/unit/components/group-reporting-user/group-reporting-user.spec.js.map +1 -1
  20. package/dist/__tests__/unit/components/login-user/login.spec.js +703 -0
  21. package/dist/__tests__/unit/components/login-user/login.spec.js.map +1 -1
  22. package/dist/__tests__/unit/components/system/system.spec.js +1 -0
  23. package/dist/__tests__/unit/components/system/system.spec.js.map +1 -1
  24. package/dist/__tests__/unit/components/user-password-history/user-password-history.spec.d.ts +1 -0
  25. package/dist/__tests__/unit/components/user-password-history/user-password-history.spec.js +138 -0
  26. package/dist/__tests__/unit/components/user-password-history/user-password-history.spec.js.map +1 -0
  27. package/dist/__tests__/unit/components/user-reporting-hierarchy/user-reporting-hierarchy.spec.d.ts +1 -0
  28. package/dist/__tests__/unit/components/user-reporting-hierarchy/user-reporting-hierarchy.spec.js +182 -0
  29. package/dist/__tests__/unit/components/user-reporting-hierarchy/user-reporting-hierarchy.spec.js.map +1 -0
  30. package/dist/tsconfig.tsbuildinfo +1 -1
  31. package/jest.config.js +2 -0
  32. package/migrations/20250805085707-add-bulk-approval-code-to-sso-user.js +29 -0
  33. package/package.json +2 -2
@@ -1,3 +1,706 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ const session_service_1 = require("../../../../src/session/session.service");
13
+ const login_user_1 = require("../../../../src/components/login-user/login-user");
14
+ const config_1 = require("@tomei/config");
15
+ const user_repository_1 = require("../../../../src/components/login-user/user.repository");
16
+ const general_1 = require("@tomei/general");
17
+ const user_status_enum_1 = require("../../../../src/enum/user-status.enum");
18
+ const system_privilege_entity_1 = require("../../../../src/models/system-privilege.entity");
19
+ const group_system_access_repository_1 = require("../../../../src/components/group-system-access/group-system-access.repository");
20
+ const group_repository_1 = require("../../../../src/components/group/group.repository");
21
+ const mockUserData = {
22
+ UserId: 1,
23
+ FullName: 'John Doe',
24
+ Email: 'john.doe@example.com',
25
+ Password: 'password',
26
+ Status: 'Active',
27
+ DefaultPasswordChangedYN: 'N',
28
+ FirstLoginAt: new Date(),
29
+ LastLoginAt: new Date(),
30
+ MFAEnabled: 1,
31
+ MFAConfig: 'config',
32
+ RecoveryEmail: 'john.doe@example.com',
33
+ FailedLoginAttemptCount: 0,
34
+ LastFailedLoginAt: null,
35
+ LastPasswordChangedAt: new Date(),
36
+ NeedToChangePasswordYN: 'N',
37
+ CreatedById: 1,
38
+ CreatedAt: new Date(),
39
+ UpdatedById: 1,
40
+ UpdatedAt: new Date(),
41
+ Staff: {
42
+ FullName: 'John Doe',
43
+ IdNo: '1234567890',
44
+ Mobile: '1234567890',
45
+ },
46
+ };
47
+ const mockSessionService = {
48
+ setUserSession: jest.fn(),
49
+ retrieveUserSession: jest.fn(),
50
+ refreshDuration: jest.fn(),
51
+ };
52
+ describe('LoginUser', () => {
53
+ beforeAll(() => {
54
+ process.env.REDIS_HOST = 'localhost';
55
+ process.env.REDIS_PORT = '6379';
56
+ });
57
+ afterAll(() => {
58
+ jest.restoreAllMocks();
59
+ });
60
+ describe('init', () => {
61
+ let sessionService;
62
+ let userId;
63
+ let dbTransaction;
64
+ beforeEach(() => {
65
+ sessionService = {};
66
+ userId = 1;
67
+ dbTransaction = null;
68
+ });
69
+ it('should initialize LoginUser with valid userId', () => __awaiter(void 0, void 0, void 0, function* () {
70
+ const user = {
71
+ UserId: 1,
72
+ FullName: 'John Doe',
73
+ Email: 'john.doe@example.com',
74
+ Password: 'password',
75
+ Status: 'active',
76
+ DefaultPasswordChangedYN: 'yes',
77
+ FirstLoginAt: new Date(),
78
+ LastLoginAt: new Date(),
79
+ MFAEnabled: 1,
80
+ MFAConfig: 'config',
81
+ RecoveryEmail: 'john.doe@example.com',
82
+ FailedLoginAttemptCount: 0,
83
+ LastFailedLoginAt: null,
84
+ LastPasswordChangedAt: new Date(),
85
+ NeedToChangePasswordYN: 'no',
86
+ CreatedById: 1,
87
+ CreatedAt: new Date(),
88
+ UpdatedById: 1,
89
+ UpdatedAt: new Date(),
90
+ Staff: {
91
+ FullName: 'John Doe',
92
+ IdNo: '1234567890',
93
+ Mobile: '1234567890',
94
+ },
95
+ };
96
+ const findOneMock = jest
97
+ .spyOn(user_repository_1.UserRepository.prototype, 'findOne')
98
+ .mockResolvedValueOnce(user);
99
+ const result = yield login_user_1.LoginUser.init(sessionService, userId, dbTransaction);
100
+ expect(findOneMock).toHaveBeenCalledTimes(1);
101
+ expect(findOneMock).toHaveBeenCalledWith({
102
+ where: {
103
+ UserId: userId,
104
+ },
105
+ include: [
106
+ {
107
+ model: expect.anything(),
108
+ },
109
+ ],
110
+ transaction: dbTransaction,
111
+ });
112
+ expect(result).toBeInstanceOf(login_user_1.LoginUser);
113
+ expect(result.UserId).toBe(user.UserId);
114
+ expect(result.FullName).toBe(user.FullName);
115
+ expect(result.Email).toBe(user.Email);
116
+ expect(result.Password).toBe(user.Password);
117
+ expect(result.Status).toBe(user.Status);
118
+ expect(result.DefaultPasswordChangedYN).toBe(user.DefaultPasswordChangedYN);
119
+ expect(result.FirstLoginAt).toBe(user.FirstLoginAt);
120
+ expect(result.LastLoginAt).toBe(user.LastLoginAt);
121
+ expect(result.MFAEnabled).toBe(user.MFAEnabled);
122
+ expect(result.MFAConfig).toBe(user.MFAConfig);
123
+ expect(result.RecoveryEmail).toBe(user.RecoveryEmail);
124
+ expect(result.FailedLoginAttemptCount).toBe(user.FailedLoginAttemptCount);
125
+ expect(result.LastFailedLoginAt).toBe(user.LastFailedLoginAt);
126
+ expect(result.LastPasswordChangedAt).toBe(user.LastPasswordChangedAt);
127
+ expect(result.NeedToChangePasswordYN).toBe(user.NeedToChangePasswordYN);
128
+ expect(result.CreatedById).toBe(user.CreatedById);
129
+ expect(result.CreatedAt).toBe(user.CreatedAt);
130
+ expect(result.UpdatedById).toBe(user.UpdatedById);
131
+ expect(result.UpdatedAt).toBe(user.UpdatedAt);
132
+ }));
133
+ it('should throw an error when user is not found', () => __awaiter(void 0, void 0, void 0, function* () {
134
+ const findOneMock = jest
135
+ .spyOn(user_repository_1.UserRepository.prototype, 'findOne')
136
+ .mockResolvedValueOnce(null);
137
+ yield expect(login_user_1.LoginUser.init(sessionService, userId, dbTransaction)).rejects.toThrow(Error);
138
+ expect(findOneMock).toHaveBeenCalledTimes(1);
139
+ expect(findOneMock).toHaveBeenCalledWith({
140
+ where: {
141
+ UserId: userId,
142
+ },
143
+ include: [
144
+ {
145
+ model: expect.anything(),
146
+ },
147
+ ],
148
+ transaction: dbTransaction,
149
+ });
150
+ }));
151
+ });
152
+ describe('shouldReleaseLock', () => {
153
+ const minuteToAutoRelease = 5;
154
+ const autoReleaseYN = 'Y';
155
+ beforeEach(() => {
156
+ jest
157
+ .spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
158
+ .mockImplementation((componentName, configKey) => {
159
+ if (configKey === 'minuteToAutoRelease') {
160
+ return minuteToAutoRelease;
161
+ }
162
+ if (configKey === 'autoReleaseYN') {
163
+ return autoReleaseYN;
164
+ }
165
+ });
166
+ });
167
+ it('should return true if autoReleaseYN is "Y" and time difference is greater than minuteToAutoRelease', () => __awaiter(void 0, void 0, void 0, function* () {
168
+ const lastFailedLoginAt = new Date();
169
+ lastFailedLoginAt.setMinutes(lastFailedLoginAt.getMinutes() - 10);
170
+ const result = login_user_1.LoginUser.shouldReleaseLock(lastFailedLoginAt);
171
+ expect(result).toBe(true);
172
+ }));
173
+ it('should return false if autoReleaseYN is "Y" and time difference is less than or equal to minuteToAutoRelease', () => __awaiter(void 0, void 0, void 0, function* () {
174
+ const lastFailedLoginAt = new Date();
175
+ lastFailedLoginAt.setMinutes(lastFailedLoginAt.getMinutes() - 3);
176
+ const result = login_user_1.LoginUser.shouldReleaseLock(lastFailedLoginAt);
177
+ expect(result).toBe(false);
178
+ }));
179
+ it('should return false if autoReleaseYN is "N"', () => __awaiter(void 0, void 0, void 0, function* () {
180
+ const lastFailedLoginAt = new Date();
181
+ const result = login_user_1.LoginUser.shouldReleaseLock(lastFailedLoginAt);
182
+ expect(result).toBe(false);
183
+ }));
184
+ });
185
+ describe('releaseLock', () => {
186
+ it('should release the lock for a user', () => __awaiter(void 0, void 0, void 0, function* () {
187
+ const UserId = 1;
188
+ const dbTransaction = null;
189
+ const updateMock = jest
190
+ .spyOn(login_user_1.LoginUser['_Repository'], 'update')
191
+ .mockImplementationOnce(() => Promise.resolve({}));
192
+ login_user_1.LoginUser['releaseLock'](UserId, dbTransaction);
193
+ expect(updateMock).toHaveBeenCalledTimes(1);
194
+ expect(updateMock).toHaveBeenCalledWith({
195
+ FailedLoginAttemptCount: 0,
196
+ Status: 'Active',
197
+ }, {
198
+ where: {
199
+ UserId,
200
+ },
201
+ transaction: dbTransaction,
202
+ });
203
+ }));
204
+ });
205
+ describe('checkUserInfoDuplicated', () => {
206
+ it('should throw an error if duplicate user info is found', () => __awaiter(void 0, void 0, void 0, function* () {
207
+ const dbTransaction = null;
208
+ const query = {
209
+ Email: 'test@example.com',
210
+ IdType: 'passport',
211
+ IdNo: '123456789',
212
+ ContactNo: '1234567890',
213
+ };
214
+ jest
215
+ .spyOn(login_user_1.LoginUser['_Repository'], 'findAll')
216
+ .mockResolvedValueOnce([{ id: 1 }]);
217
+ yield expect(login_user_1.LoginUser['checkUserInfoDuplicated'](dbTransaction, query)).rejects.toThrow();
218
+ }));
219
+ it('should not throw an error if duplicate user info is not found', () => __awaiter(void 0, void 0, void 0, function* () {
220
+ const dbTransaction = null;
221
+ const query = {
222
+ Email: 'test@example.com',
223
+ IdType: 'passport',
224
+ IdNo: '123456789',
225
+ ContactNo: '1234567890',
226
+ };
227
+ jest.spyOn(login_user_1.LoginUser['_Repository'], 'findAll').mockResolvedValueOnce([]);
228
+ yield expect(login_user_1.LoginUser['checkUserInfoDuplicated'](dbTransaction, query)).resolves.not.toThrow();
229
+ }));
230
+ });
231
+ describe('generateDefaultPassword', () => {
232
+ const passwordPolicy = {
233
+ minLen: 6,
234
+ maxLen: 10,
235
+ nonAcceptableChar: 'i,l,o',
236
+ numOfCapitalLetters: 1,
237
+ numOfNumbers: 1,
238
+ numOfSpecialChars: 1,
239
+ };
240
+ beforeEach(() => {
241
+ jest
242
+ .spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
243
+ .mockImplementation((componentName, configKey) => {
244
+ if (configKey === 'passwordPolicy') {
245
+ return passwordPolicy;
246
+ }
247
+ });
248
+ });
249
+ it('should generate a default password with the specified length', () => {
250
+ const password = login_user_1.LoginUser['generateDefaultPassword']();
251
+ expect(password.length).toBeGreaterThanOrEqual(6);
252
+ expect(password.length).toBeLessThanOrEqual(10);
253
+ });
254
+ it('should generate a default password with at least one capital letter', () => {
255
+ const password = login_user_1.LoginUser['generateDefaultPassword']();
256
+ expect(/[A-Z]/.test(password)).toBe(true);
257
+ });
258
+ it('should generate a default password with at least one number', () => {
259
+ const password = login_user_1.LoginUser['generateDefaultPassword']();
260
+ expect(/[0-9]/.test(password)).toBe(true);
261
+ });
262
+ it('should generate a default password with at least one special character', () => {
263
+ const password = login_user_1.LoginUser['generateDefaultPassword']();
264
+ expect(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?~`]/.test(password)).toBe(true);
265
+ });
266
+ it('should generate a default password without any non-acceptable characters', () => {
267
+ const password = login_user_1.LoginUser['generateDefaultPassword']();
268
+ const nonAcceptableChars = ['i', 'l', 'o'];
269
+ expect(nonAcceptableChars.some((char) => password.includes(char))).toBe(false);
270
+ });
271
+ });
272
+ describe('setPassword', () => {
273
+ const passwordPolicy = {
274
+ minLen: 6,
275
+ maxLen: 10,
276
+ nonAcceptableChar: 'i,l,o',
277
+ numOfCapitalLetters: 1,
278
+ numOfNumbers: 1,
279
+ numOfSpecialChars: 1,
280
+ };
281
+ beforeEach(() => {
282
+ jest
283
+ .spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
284
+ .mockImplementation((componentName, configKey) => {
285
+ if (configKey === 'passwordPolicy') {
286
+ return passwordPolicy;
287
+ }
288
+ });
289
+ });
290
+ it('should set the password for the user', () => __awaiter(void 0, void 0, void 0, function* () {
291
+ const dbTransaction = null;
292
+ const sessionService = yield session_service_1.SessionService.init();
293
+ const user = yield login_user_1.LoginUser.init(sessionService);
294
+ const password = 'N3wP@ssw0';
295
+ const result = yield login_user_1.LoginUser['setPassword'](dbTransaction, user, password);
296
+ expect(result).toBeInstanceOf(login_user_1.LoginUser);
297
+ yield expect(login_user_1.LoginUser['setPassword'](dbTransaction, user, password)).resolves.not.toThrow();
298
+ expect(result.Password).toBeDefined();
299
+ }));
300
+ it('should throw an error if the password does not meet the security requirements', () => __awaiter(void 0, void 0, void 0, function* () {
301
+ const dbTransaction = null;
302
+ const sessionService = yield session_service_1.SessionService.init();
303
+ const user = yield login_user_1.LoginUser.init(sessionService);
304
+ const password = 'weakpassword';
305
+ yield expect(login_user_1.LoginUser['setPassword'](dbTransaction, user, password)).rejects.toThrow();
306
+ }));
307
+ });
308
+ describe('incrementFailedLoginAttemptCount', () => {
309
+ afterAll(() => {
310
+ jest.restoreAllMocks();
311
+ });
312
+ it('should increment FailedLoginAttemptCount and update user status', () => __awaiter(void 0, void 0, void 0, function* () {
313
+ const sessionService = yield session_service_1.SessionService.init();
314
+ const loginUser = yield login_user_1.LoginUser.init(sessionService);
315
+ loginUser['FailedLoginAttemptCount'] = 2;
316
+ loginUser['LastFailedLoginAt'] = new Date();
317
+ loginUser['Status'] = user_status_enum_1.UserStatus.ACTIVE;
318
+ const dbTransaction = null;
319
+ jest
320
+ .spyOn(login_user_1.LoginUser['_Repository'], 'update')
321
+ .mockReturnValueOnce(null);
322
+ jest
323
+ .spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
324
+ .mockImplementation((componentName, configKey) => {
325
+ if (configKey === 'maxFailedLoginAttempts') {
326
+ return 3;
327
+ }
328
+ if (configKey === 'autoReleaseYN') {
329
+ return 'Y';
330
+ }
331
+ });
332
+ yield loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
333
+ expect(login_user_1.LoginUser['_Repository'].update).toHaveBeenCalledWith({
334
+ FailedLoginAttemptCount: 3,
335
+ LastFailedLoginAt: expect.any(Date),
336
+ Status: user_status_enum_1.UserStatus.ACTIVE,
337
+ }, {
338
+ where: {
339
+ UserId: loginUser.UserId,
340
+ },
341
+ transaction: dbTransaction,
342
+ });
343
+ }));
344
+ it('should throw an error if maxFailedLoginAttempts or autoReleaseYN is missing', () => __awaiter(void 0, void 0, void 0, function* () {
345
+ const sessionService = yield session_service_1.SessionService.init();
346
+ const loginUser = yield login_user_1.LoginUser.init(sessionService);
347
+ loginUser['FailedLoginAttemptCount'] = 2;
348
+ loginUser['LastFailedLoginAt'] = new Date();
349
+ loginUser['Status'] = user_status_enum_1.UserStatus.ACTIVE;
350
+ const dbTransaction = null;
351
+ jest
352
+ .spyOn(login_user_1.LoginUser['_Repository'], 'update')
353
+ .mockReturnValueOnce(null);
354
+ jest
355
+ .spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
356
+ .mockImplementationOnce((componentName, configKey) => {
357
+ if (configKey === 'maxFailedLoginAttempts') {
358
+ return undefined;
359
+ }
360
+ if (configKey === 'autoReleaseYN') {
361
+ return undefined;
362
+ }
363
+ });
364
+ yield expect(loginUser['incrementFailedLoginAttemptCount'](dbTransaction)).rejects.toThrow(new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'Missing maxFailedLoginAttempts and or autoReleaseYN. Please set in config file.'));
365
+ }));
366
+ it('should lock the user account if the failed login attempts exceed the maximum allowed', () => __awaiter(void 0, void 0, void 0, function* () {
367
+ const sessionService = yield session_service_1.SessionService.init();
368
+ const loginUser = yield login_user_1.LoginUser.init(sessionService);
369
+ loginUser['FailedLoginAttemptCount'] = 3;
370
+ loginUser['LastFailedLoginAt'] = new Date();
371
+ loginUser['Status'] = user_status_enum_1.UserStatus.ACTIVE;
372
+ const dbTransaction = null;
373
+ jest
374
+ .spyOn(login_user_1.LoginUser['_Repository'], 'update')
375
+ .mockReturnValueOnce(null);
376
+ jest
377
+ .spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
378
+ .mockImplementation((componentName, configKey) => {
379
+ if (configKey === 'maxFailedLoginAttempts') {
380
+ return 3;
381
+ }
382
+ if (configKey === 'autoReleaseYN') {
383
+ return 'Y';
384
+ }
385
+ });
386
+ try {
387
+ yield loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
388
+ expect(false).toBe(true);
389
+ }
390
+ catch (error) {
391
+ expect(login_user_1.LoginUser['_Repository'].update).toHaveBeenCalledWith({
392
+ FailedLoginAttemptCount: 4,
393
+ LastFailedLoginAt: expect.any(Date),
394
+ Status: user_status_enum_1.UserStatus.LOCKED,
395
+ }, {
396
+ where: {
397
+ UserId: loginUser.UserId,
398
+ },
399
+ transaction: dbTransaction,
400
+ });
401
+ expect(error).toBeInstanceOf(general_1.ClassError);
402
+ expect(error.message).toBe('Your account has been temporarily locked due to too many failed login attempts, please try again later.');
403
+ }
404
+ }));
405
+ it('should permanently lock the user account if the failed login attempts exceed the maximum allowed and autoReleaseYN is N', () => __awaiter(void 0, void 0, void 0, function* () {
406
+ const sessionService = yield session_service_1.SessionService.init();
407
+ const loginUser = yield login_user_1.LoginUser.init(sessionService);
408
+ loginUser['FailedLoginAttemptCount'] = 3;
409
+ loginUser['LastFailedLoginAt'] = new Date();
410
+ loginUser['Status'] = user_status_enum_1.UserStatus.ACTIVE;
411
+ const dbTransaction = null;
412
+ jest
413
+ .spyOn(login_user_1.LoginUser['_Repository'], 'update')
414
+ .mockReturnValueOnce(null);
415
+ jest
416
+ .spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
417
+ .mockImplementation((componentName, configKey) => {
418
+ if (configKey === 'maxFailedLoginAttempts') {
419
+ return 3;
420
+ }
421
+ if (configKey === 'autoReleaseYN') {
422
+ return 'N';
423
+ }
424
+ });
425
+ try {
426
+ yield loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
427
+ expect(false).toBe(true);
428
+ }
429
+ catch (error) {
430
+ expect(login_user_1.LoginUser['_Repository'].update).toHaveBeenCalledWith({
431
+ FailedLoginAttemptCount: 4,
432
+ LastFailedLoginAt: expect.any(Date),
433
+ Status: user_status_enum_1.UserStatus.LOCKED,
434
+ }, {
435
+ where: {
436
+ UserId: loginUser.UserId,
437
+ },
438
+ transaction: dbTransaction,
439
+ });
440
+ expect(error).toBeInstanceOf(general_1.ClassError);
441
+ expect(error.message).toBe('Your account has been locked due to too many failed login attempts, please contact IT Support for instructions on how to unlock your account');
442
+ }
443
+ }));
444
+ });
445
+ describe('combineSystemAccess', () => {
446
+ it('should combine user and group system access and remove duplicates', () => __awaiter(void 0, void 0, void 0, function* () {
447
+ const sessionService = yield session_service_1.SessionService.init();
448
+ const loginUser = yield login_user_1.LoginUser.init(sessionService);
449
+ const dbTransaction = null;
450
+ const groups = [
451
+ { InheritParentSystemAccessYN: true },
452
+ { InheritParentSystemAccessYN: false },
453
+ ];
454
+ jest
455
+ .spyOn(login_user_1.LoginUser, 'getInheritedSystemAccess')
456
+ .mockResolvedValueOnce([
457
+ { SystemCode: 'system1' },
458
+ { SystemCode: 'system2' },
459
+ ]);
460
+ jest
461
+ .spyOn(login_user_1.LoginUser['_UserSystemAccessRepo'], 'findAll')
462
+ .mockResolvedValueOnce([{ SystemCode: 'system3' }]);
463
+ const result = yield login_user_1.LoginUser['combineSystemAccess'](loginUser, dbTransaction, groups);
464
+ expect(result).toEqual([
465
+ { SystemCode: 'system3' },
466
+ { SystemCode: 'system1' },
467
+ { SystemCode: 'system2' },
468
+ ]);
469
+ }));
470
+ });
471
+ describe('checkPrivileges', () => {
472
+ beforeEach(() => {
473
+ jest
474
+ .spyOn(config_1.ApplicationConfig, 'getComponentConfigValue')
475
+ .mockReturnValue('test-session');
476
+ });
477
+ it('should return true if user has the specified privilege', () => __awaiter(void 0, void 0, void 0, function* () {
478
+ const systemCode = 'SS';
479
+ const privilegeName = 'Privilege 1';
480
+ const sessionService = yield session_service_1.SessionService.init();
481
+ const loginUser = yield login_user_1.LoginUser.init(sessionService);
482
+ loginUser.ObjectId = '1';
483
+ const rus = jest
484
+ .spyOn(session_service_1.SessionService.prototype, 'retrieveUserSession')
485
+ .mockResolvedValueOnce({
486
+ systemLogins: [
487
+ {
488
+ id: '1',
489
+ sessionId: 'sessionId',
490
+ code: systemCode,
491
+ privileges: [privilegeName],
492
+ },
493
+ ],
494
+ });
495
+ const hasPrivilege = yield loginUser.checkPrivileges(systemCode, privilegeName);
496
+ expect(hasPrivilege).toBe(true);
497
+ expect(rus).toHaveBeenCalledWith(loginUser.ObjectId, 'test-session');
498
+ }));
499
+ it('should return false if user does not have the specified privilege', () => __awaiter(void 0, void 0, void 0, function* () {
500
+ const systemCode = 'SS';
501
+ const privilegeName = 'Privilege 1';
502
+ const sessionService = yield session_service_1.SessionService.init();
503
+ const loginUser = yield login_user_1.LoginUser.init(sessionService);
504
+ loginUser.ObjectId = '1';
505
+ const rus = jest
506
+ .spyOn(session_service_1.SessionService.prototype, 'retrieveUserSession')
507
+ .mockResolvedValueOnce({
508
+ systemLogins: [
509
+ {
510
+ id: '1',
511
+ sessionId: 'sessionId',
512
+ code: systemCode,
513
+ privileges: [],
514
+ },
515
+ ],
516
+ });
517
+ const hasPrivilege = yield loginUser.checkPrivileges(systemCode, privilegeName);
518
+ expect(hasPrivilege).toBe(false);
519
+ expect(rus).toHaveBeenCalledWith(loginUser.ObjectId, 'test-session');
520
+ }));
521
+ it('should throw an error if ObjectId is not set', () => __awaiter(void 0, void 0, void 0, function* () {
522
+ const systemCode = 'SS';
523
+ const privilegeName = 'Privilege 1';
524
+ const sessionService = yield session_service_1.SessionService.init();
525
+ const loginUser = yield login_user_1.LoginUser.init(sessionService);
526
+ loginUser.ObjectId = null;
527
+ yield expect(loginUser.checkPrivileges(systemCode, privilegeName)).rejects.toThrow();
528
+ }));
529
+ });
530
+ describe('getObjectPrivileges', () => {
531
+ it('should return an array of privileges', () => __awaiter(void 0, void 0, void 0, function* () {
532
+ const systemCode = 'system1';
533
+ const dbTransaction = null;
534
+ const sessionService = yield session_service_1.SessionService.init();
535
+ const loginUser = yield login_user_1.LoginUser.init(sessionService);
536
+ const findAllMock = jest
537
+ .spyOn(login_user_1.LoginUser['_UserObjectPrivilegeRepo'], 'findAll')
538
+ .mockResolvedValue([
539
+ {
540
+ PrivilegeCode: 'privilege1',
541
+ Privilege: {
542
+ PrivilegeCode: 'privilege1',
543
+ SystemCode: systemCode,
544
+ Name: 'privilege1',
545
+ },
546
+ },
547
+ {
548
+ PrivilegeCode: 'privilege2',
549
+ Privilege: {
550
+ PrivilegeCode: 'privilege2',
551
+ Name: 'privilege2',
552
+ },
553
+ },
554
+ ]);
555
+ const result = yield loginUser['getObjectPrivileges'](systemCode, dbTransaction);
556
+ expect(findAllMock).toHaveBeenCalledTimes(1);
557
+ expect(findAllMock).toHaveBeenCalledWith({
558
+ where: {
559
+ UserId: loginUser.UserId,
560
+ },
561
+ include: {
562
+ model: system_privilege_entity_1.default,
563
+ where: {
564
+ SystemCode: systemCode,
565
+ Status: 'Active',
566
+ },
567
+ },
568
+ transaction: dbTransaction,
569
+ });
570
+ expect(result).toEqual(['privilege1', 'privilege2']);
571
+ }));
572
+ it('should throw an error if an exception occurs', () => __awaiter(void 0, void 0, void 0, function* () {
573
+ const systemCode = 'system1';
574
+ const dbTransaction = null;
575
+ const sessionService = yield session_service_1.SessionService.init();
576
+ const loginUser = yield login_user_1.LoginUser.init(sessionService);
577
+ jest
578
+ .spyOn(login_user_1.LoginUser['_UserObjectPrivilegeRepo'], 'findAll')
579
+ .mockRejectedValue(new Error('Database error'));
580
+ yield expect(loginUser['getObjectPrivileges'](systemCode, dbTransaction)).rejects.toThrow(Error);
581
+ }));
582
+ });
583
+ describe('getUserPersonalPrivileges', () => {
584
+ it('should return an array of privileges', () => __awaiter(void 0, void 0, void 0, function* () {
585
+ const sessionService = yield session_service_1.SessionService.init();
586
+ const loginUser = yield login_user_1.LoginUser.init(sessionService);
587
+ const systemCode = 'system1';
588
+ const dbTransaction = null;
589
+ const findAllMock = jest.spyOn(login_user_1.LoginUser['_UserPrivilegeRepo'], 'findAll');
590
+ findAllMock.mockResolvedValue([
591
+ { Privilege: { PrivilegeCode: 'privilege1' } },
592
+ { Privilege: { PrivilegeCode: 'privilege2' } },
593
+ ]);
594
+ const privileges = yield loginUser['getUserPersonalPrivileges'](systemCode, dbTransaction);
595
+ expect(privileges).toEqual(['privilege1', 'privilege2']);
596
+ expect(findAllMock).toHaveBeenCalledTimes(1);
597
+ expect(findAllMock).toHaveBeenCalledWith({
598
+ where: {
599
+ UserId: loginUser.UserId,
600
+ Status: 'Active',
601
+ },
602
+ include: {
603
+ model: system_privilege_entity_1.default,
604
+ where: {
605
+ SystemCode: systemCode,
606
+ Status: 'Active',
607
+ },
608
+ },
609
+ transaction: dbTransaction,
610
+ });
611
+ }));
612
+ it('should throw an error if an error occurs', () => __awaiter(void 0, void 0, void 0, function* () {
613
+ const sessionService = yield session_service_1.SessionService.init();
614
+ const loginUser = yield login_user_1.LoginUser.init(sessionService);
615
+ const systemCode = 'system1';
616
+ const dbTransaction = null;
617
+ const findAllMock = jest.spyOn(login_user_1.LoginUser['_UserPrivilegeRepo'], 'findAll');
618
+ findAllMock.mockRejectedValue(new Error('Database error'));
619
+ yield expect(loginUser['getUserPersonalPrivileges'](systemCode, dbTransaction)).rejects.toThrow(Error);
620
+ expect(findAllMock).toHaveBeenCalledTimes(1);
621
+ expect(findAllMock).toHaveBeenCalledWith({
622
+ where: {
623
+ UserId: loginUser.UserId,
624
+ Status: 'Active',
625
+ },
626
+ include: {
627
+ model: system_privilege_entity_1.default,
628
+ where: {
629
+ SystemCode: systemCode,
630
+ Status: 'Active',
631
+ },
632
+ },
633
+ transaction: dbTransaction,
634
+ });
635
+ }));
636
+ });
637
+ describe('getInheritedSystemAccess', () => {
638
+ it('should return group system access with its parent group system access if applicable', () => __awaiter(void 0, void 0, void 0, function* () {
639
+ const dbTransaction = null;
640
+ const group = {
641
+ GroupCode: 'group1',
642
+ InheritParentSystemAccessYN: 'Y',
643
+ ParentGroupCode: 'parentGroup',
644
+ };
645
+ const parentGroup = {
646
+ GroupCode: 'parentGroup',
647
+ InheritParentSystemAccessYN: 'N',
648
+ ParentGroupCode: null,
649
+ };
650
+ const systemAccess = [
651
+ {
652
+ SystemCode: 'system1',
653
+ GroupCode: 'group1',
654
+ System: { SystemCode: 'system1' },
655
+ },
656
+ {
657
+ SystemCode: 'system2',
658
+ GroupCode: 'group1',
659
+ System: { SystemCode: 'system1' },
660
+ },
661
+ ];
662
+ const parentSystemAccess = [
663
+ {
664
+ SystemCode: 'system3',
665
+ GroupCode: 'parentGroup',
666
+ System: { SystemCode: 'system3' },
667
+ },
668
+ ];
669
+ const groupFindByPkMock = jest
670
+ .spyOn(group_repository_1.GroupRepository.prototype, 'findByPk')
671
+ .mockResolvedValueOnce(parentGroup);
672
+ const systemAccessFindAllMock = jest
673
+ .spyOn(group_system_access_repository_1.GroupSystemAccessRepository.prototype, 'findAll')
674
+ .mockImplementation((options) => {
675
+ if (options.where.GroupCode === group.GroupCode) {
676
+ return Promise.resolve(systemAccess);
677
+ }
678
+ else if (options.where.GroupCode === parentGroup.GroupCode) {
679
+ return Promise.resolve(parentSystemAccess);
680
+ }
681
+ });
682
+ const result = yield login_user_1.LoginUser['getInheritedSystemAccess'](dbTransaction, group);
683
+ console.log(result);
684
+ expect(result).toEqual([
685
+ {
686
+ SystemCode: 'system1',
687
+ GroupCode: 'group1',
688
+ System: { SystemCode: 'system1' },
689
+ },
690
+ {
691
+ SystemCode: 'system2',
692
+ GroupCode: 'group1',
693
+ System: { SystemCode: 'system1' },
694
+ },
695
+ {
696
+ SystemCode: 'system3',
697
+ GroupCode: 'parentGroup',
698
+ System: { SystemCode: 'system3' },
699
+ },
700
+ ]);
701
+ expect(groupFindByPkMock).toHaveBeenCalledWith(group.ParentGroupCode, dbTransaction);
702
+ expect(systemAccessFindAllMock).toHaveBeenCalledTimes(2);
703
+ }));
704
+ });
705
+ });
3
706
  //# sourceMappingURL=login.spec.js.map