@tomei/sso 0.62.0 → 0.64.0-dev.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/.commitlintrc.json +22 -22
- package/.gitlab-ci.yml +16 -16
- package/.husky/commit-msg +9 -15
- package/.husky/pre-commit +7 -7
- package/.prettierrc +4 -4
- package/Jenkinsfile +57 -57
- package/README.md +23 -23
- package/__tests__/unit/components/group/group.spec.ts +79 -79
- package/__tests__/unit/components/group-object-privilege/group-object-privilege.spec.ts +88 -88
- package/__tests__/unit/components/group-privilege/group-privilege.spec.ts +68 -68
- package/__tests__/unit/components/group-reporting-user/group-reporting-user.spec.ts +66 -66
- package/__tests__/unit/components/group-system-access/group-system-access.spec.ts +83 -83
- package/__tests__/unit/components/login-user/l.spec.ts +746 -746
- package/__tests__/unit/components/login-user/login.spec.ts +1164 -1164
- package/__tests__/unit/components/password-hash/password-hash.service.spec.ts +31 -31
- package/__tests__/unit/components/system/system.spec.ts +254 -254
- package/__tests__/unit/components/system-privilege/system-privilege.spec.ts +83 -83
- package/__tests__/unit/components/user-group/user-group.spec.ts +86 -86
- package/__tests__/unit/components/user-object-privilege/user-object-privilege.spec.ts +78 -78
- package/__tests__/unit/components/user-privilege/user-privilege.spec.ts +72 -72
- package/__tests__/unit/components/user-system-access/user-system-access.spec.ts +89 -89
- package/__tests__/unit/redis-client/redis.service.spec.ts +23 -23
- package/__tests__/unit/session/session.service.spec.ts +47 -47
- package/__tests__/unit/system-privilege/system-privilage.spec.ts +91 -91
- package/create-sso-user.sql +39 -39
- package/dist/__tests__/unit/components/group-object-privilege/group-object-privilege.spec.js +1 -1
- package/dist/__tests__/unit/components/group-object-privilege/group-object-privilege.spec.js.map +1 -1
- package/dist/__tests__/unit/components/group-privilege/group-privilege.spec.js +2 -2
- package/dist/__tests__/unit/components/group-privilege/group-privilege.spec.js.map +1 -1
- 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/group-reporting-user/group-reporting-user.spec.js +2 -2
- package/dist/__tests__/unit/components/group-reporting-user/group-reporting-user.spec.js.map +1 -1
- 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/__tests__/unit/components/system/system.spec.js +4 -4
- package/dist/__tests__/unit/components/system/system.spec.js.map +1 -1
- package/dist/__tests__/unit/session/session.service.spec.js +2 -2
- package/dist/__tests__/unit/session/session.service.spec.js.map +1 -1
- package/dist/src/components/login-history/index.d.ts +1 -0
- package/dist/src/components/login-history/index.js +1 -0
- package/dist/src/components/login-history/index.js.map +1 -1
- package/dist/src/components/login-history/login-history.repository.d.ts +2 -2
- package/dist/src/components/login-history/login-history.repository.js.map +1 -1
- package/dist/src/components/login-user/interfaces/user-info.interface.d.ts +1 -0
- package/dist/src/components/login-user/login-user.js +1 -0
- package/dist/src/components/login-user/login-user.js.map +1 -1
- package/dist/src/components/login-user/user.d.ts +28 -3
- package/dist/src/components/login-user/user.js +363 -25
- package/dist/src/components/login-user/user.js.map +1 -1
- package/dist/src/components/user-system-access/user-system-access.js +1 -1
- package/dist/src/components/user-system-access/user-system-access.js.map +1 -1
- package/dist/src/models/login-history.entity.d.ts +2 -2
- package/dist/src/models/login-history.entity.js +13 -13
- package/dist/src/models/login-history.entity.js.map +1 -1
- package/dist/src/models/user.entity.d.ts +1 -0
- package/dist/src/models/user.entity.js +8 -0
- package/dist/src/models/user.entity.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/eslint.config.mjs +58 -58
- package/jest.config.js +14 -14
- package/migrations/20240314080602-create-user-table.js +124 -124
- package/migrations/20240314080603-create-user-group-table.js +85 -85
- package/migrations/20240314080604-create-user-user-group-table.js +55 -55
- package/migrations/20240314080605-create-login-history-table.js +53 -53
- package/migrations/20240527064925-create-system-table.js +78 -78
- package/migrations/20240527064926-create-system-privilege-table.js +71 -71
- package/migrations/20240527065342-create-group-table.js +93 -93
- package/migrations/20240527065633-create-group-reporting-user-table.js +76 -76
- package/migrations/20240528011551-create-group-system-access-table.js +72 -72
- package/migrations/20240528023018-user-system-access-table.js +75 -75
- package/migrations/20240528032229-user-privilege-table.js +76 -76
- package/migrations/20240528063003-create-group-privilege-table.js +76 -76
- package/migrations/20240528063051-create-group-object-privilege-table.js +84 -84
- package/migrations/20240528063107-create-user-object-privilege-table.js +84 -84
- package/migrations/20240528063108-create-api-key-table.js +85 -85
- package/migrations/20241104104802-create-building-table.js +95 -95
- package/migrations/20250108091132-add-area-manager-user-id-to-building-table.js +14 -14
- package/migrations/20250108091133-add-passcode-to-user-table.js +36 -36
- package/migrations/20250210115636-create-user-reporting-hierarchy.js +76 -76
- package/migrations/20250326043818-crate-user-password-history.js +42 -42
- package/migrations/20250610070720-added-MFBypassYN-to-sso-user.js +30 -0
- package/migrations/20250805085707-add-bulk-approval-code-to-sso-user.js +29 -0
- package/package.json +87 -90
- package/sampledotenv +7 -7
- package/src/components/login-history/index.ts +1 -0
- package/src/components/login-history/login-history.repository.ts +4 -4
- package/src/components/login-history/login-history.ts +124 -0
- package/src/components/login-user/interfaces/user-info.interface.ts +1 -0
- package/src/components/login-user/login-user.ts +1 -0
- package/src/components/login-user/user.ts +441 -27
- package/src/components/user-system-access/user-system-access.ts +1 -1
- package/src/interfaces/login-history-search-attr.interface.ts +8 -0
- package/src/interfaces/login-history.interface.ts +11 -0
- package/src/models/login-history.entity.ts +2 -2
- package/src/models/user.entity.ts +7 -0
- package/tsconfig.build.json +5 -5
- package/tsconfig.json +23 -23
- package/coverage/clover.xml +0 -1452
- package/coverage/coverage-final.json +0 -47
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/components/group/group.repository.ts.html +0 -118
- package/coverage/lcov-report/components/group/group.ts.html +0 -328
- package/coverage/lcov-report/components/group/index.html +0 -131
- package/coverage/lcov-report/components/group-object-privilege/group-object-privilege.repository.ts.html +0 -118
- package/coverage/lcov-report/components/group-object-privilege/group-object-privilege.ts.html +0 -322
- package/coverage/lcov-report/components/group-object-privilege/index.html +0 -131
- package/coverage/lcov-report/components/group-privilege/group-privilege.repository.ts.html +0 -118
- package/coverage/lcov-report/components/group-privilege/group-privilege.ts.html +0 -304
- package/coverage/lcov-report/components/group-privilege/index.html +0 -131
- package/coverage/lcov-report/components/group-reporting-user/group-reporting-user.repository.ts.html +0 -118
- package/coverage/lcov-report/components/group-reporting-user/group-reporting-user.ts.html +0 -328
- package/coverage/lcov-report/components/group-reporting-user/index.html +0 -131
- package/coverage/lcov-report/components/group-system-access/group-system-access.repository.ts.html +0 -118
- package/coverage/lcov-report/components/group-system-access/group-system-access.ts.html +0 -310
- package/coverage/lcov-report/components/group-system-access/index.html +0 -131
- package/coverage/lcov-report/components/login-history/index.html +0 -116
- package/coverage/lcov-report/components/login-history/login-history.repository.ts.html +0 -118
- package/coverage/lcov-report/components/login-user/index.html +0 -131
- package/coverage/lcov-report/components/login-user/login-user.ts.html +0 -5008
- package/coverage/lcov-report/components/login-user/user.repository.ts.html +0 -118
- package/coverage/lcov-report/components/password-hash/index.html +0 -116
- package/coverage/lcov-report/components/password-hash/password-hash.service.ts.html +0 -127
- package/coverage/lcov-report/components/system/index.html +0 -131
- package/coverage/lcov-report/components/system/system.repository.ts.html +0 -118
- package/coverage/lcov-report/components/system/system.ts.html +0 -910
- package/coverage/lcov-report/components/system-privilege/index.html +0 -131
- package/coverage/lcov-report/components/system-privilege/system-privilege.repository.ts.html +0 -121
- package/coverage/lcov-report/components/system-privilege/system-privilege.ts.html +0 -391
- package/coverage/lcov-report/components/user-group/index.html +0 -131
- package/coverage/lcov-report/components/user-group/user-group.repository.ts.html +0 -118
- package/coverage/lcov-report/components/user-group/user-group.ts.html +0 -355
- package/coverage/lcov-report/components/user-object-privilege/index.html +0 -131
- package/coverage/lcov-report/components/user-object-privilege/user-object-privilege.repository.ts.html +0 -118
- package/coverage/lcov-report/components/user-object-privilege/user-object-privilege.ts.html +0 -313
- package/coverage/lcov-report/components/user-privilege/index.html +0 -131
- package/coverage/lcov-report/components/user-privilege/user-privilege.repository.ts.html +0 -118
- package/coverage/lcov-report/components/user-privilege/user-privilege.ts.html +0 -307
- package/coverage/lcov-report/components/user-system-access/index.html +0 -131
- package/coverage/lcov-report/components/user-system-access/user-system-access.repository.ts.html +0 -118
- package/coverage/lcov-report/components/user-system-access/user-system-access.ts.html +0 -313
- package/coverage/lcov-report/enum/group-type.enum.ts.html +0 -109
- package/coverage/lcov-report/enum/index.html +0 -161
- package/coverage/lcov-report/enum/index.ts.html +0 -94
- package/coverage/lcov-report/enum/user-status.enum.ts.html +0 -106
- package/coverage/lcov-report/enum/yn.enum.ts.html +0 -97
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -371
- package/coverage/lcov-report/models/group-object-privilege.entity.ts.html +0 -334
- package/coverage/lcov-report/models/group-privilege.entity.ts.html +0 -316
- package/coverage/lcov-report/models/group-reporting-user.entity.ts.html +0 -340
- package/coverage/lcov-report/models/group-system-access.entity.ts.html +0 -325
- package/coverage/lcov-report/models/group.entity.ts.html +0 -436
- package/coverage/lcov-report/models/index.html +0 -311
- package/coverage/lcov-report/models/login-history.entity.ts.html +0 -253
- package/coverage/lcov-report/models/staff.entity.ts.html +0 -412
- package/coverage/lcov-report/models/system-privilege.entity.ts.html +0 -355
- package/coverage/lcov-report/models/system.entity.ts.html +0 -424
- package/coverage/lcov-report/models/user-group.entity.ts.html +0 -355
- package/coverage/lcov-report/models/user-object-privilege.entity.ts.html +0 -331
- package/coverage/lcov-report/models/user-privilege.entity.ts.html +0 -316
- package/coverage/lcov-report/models/user-system-access.entity.ts.html +0 -316
- package/coverage/lcov-report/models/user.entity.ts.html +0 -523
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/redis-client/index.html +0 -116
- package/coverage/lcov-report/redis-client/redis.service.ts.html +0 -241
- package/coverage/lcov-report/session/index.html +0 -116
- package/coverage/lcov-report/session/session.service.ts.html +0 -247
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -196
- package/coverage/lcov.info +0 -2490
- package/coverage/test-report.xml +0 -129
- package/sonar-project.properties +0 -23
@@ -100,6 +100,12 @@ class User extends general_1.UserBase {
|
|
100
100
|
set MFAConfig(value) {
|
101
101
|
this._MFAConfig = value;
|
102
102
|
}
|
103
|
+
get MFABypassYN() {
|
104
|
+
return this._MFABypassYN;
|
105
|
+
}
|
106
|
+
set MFABypassYN(value) {
|
107
|
+
this._MFABypassYN = value;
|
108
|
+
}
|
103
109
|
get RecoveryEmail() {
|
104
110
|
return this._RecoveryEmail;
|
105
111
|
}
|
@@ -203,6 +209,7 @@ class User extends general_1.UserBase {
|
|
203
209
|
this.LastLoginAt = userInfo.LastLoginAt;
|
204
210
|
this.MFAEnabled = userInfo.MFAEnabled;
|
205
211
|
this.MFAConfig = userInfo.MFAConfig;
|
212
|
+
this.MFABypassYN = userInfo.MFABypassYN;
|
206
213
|
this.RecoveryEmail = userInfo.RecoveryEmail;
|
207
214
|
this.FailedLoginAttemptCount = userInfo.FailedLoginAttemptCount;
|
208
215
|
this.LastFailedLoginAt = userInfo.LastFailedLoginAt;
|
@@ -253,6 +260,7 @@ class User extends general_1.UserBase {
|
|
253
260
|
LastLoginAt: user.LastLoginAt,
|
254
261
|
MFAEnabled: user.MFAEnabled,
|
255
262
|
MFAConfig: user.MFAConfig,
|
263
|
+
MFABypassYN: user.MFABypassYN,
|
256
264
|
RecoveryEmail: user.RecoveryEmail,
|
257
265
|
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
|
258
266
|
LastFailedLoginAt: user.LastFailedLoginAt,
|
@@ -312,6 +320,7 @@ class User extends general_1.UserBase {
|
|
312
320
|
LastLoginAt: user.LastLoginAt,
|
313
321
|
MFAEnabled: user.MFAEnabled,
|
314
322
|
MFAConfig: user.MFAConfig,
|
323
|
+
MFABypassYN: user.MFABypassYN,
|
315
324
|
RecoveryEmail: user.RecoveryEmail,
|
316
325
|
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
|
317
326
|
LastFailedLoginAt: user.LastFailedLoginAt,
|
@@ -389,6 +398,7 @@ class User extends general_1.UserBase {
|
|
389
398
|
LastLoginAt: user.LastLoginAt,
|
390
399
|
MFAEnabled: user.MFAEnabled,
|
391
400
|
MFAConfig: user.MFAConfig,
|
401
|
+
MFABypassYN: user.MFABypassYN,
|
392
402
|
RecoveryEmail: user.RecoveryEmail,
|
393
403
|
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
|
394
404
|
LastFailedLoginAt: user.LastFailedLoginAt,
|
@@ -426,12 +436,10 @@ class User extends general_1.UserBase {
|
|
426
436
|
this.staffs = userAttr.staffs;
|
427
437
|
}
|
428
438
|
else {
|
429
|
-
console.error('User not found for email:', email);
|
430
439
|
throw new general_1.ClassError('User', 'UserErrMsg0X', 'Invalid Credentials');
|
431
440
|
}
|
432
441
|
}
|
433
442
|
if (this.ObjectId && this.Email !== email) {
|
434
|
-
console.error('Email mismatch:', this.Email, email);
|
435
443
|
throw new Error('Invalid credentials.');
|
436
444
|
}
|
437
445
|
const check2FA = yield User.check2FA(this, dbTransaction);
|
@@ -443,13 +451,11 @@ class User extends general_1.UserBase {
|
|
443
451
|
},
|
444
452
|
});
|
445
453
|
if (!system) {
|
446
|
-
|
447
|
-
throw new Error('Invalid credentials.');
|
454
|
+
throw new Error('Access denied: invalid or unauthorized system.');
|
448
455
|
}
|
449
456
|
const passwordHashService = new password_hash_service_1.PasswordHashService();
|
450
457
|
const isPasswordValid = yield passwordHashService.verify(password, this.Password);
|
451
458
|
if (!isPasswordValid) {
|
452
|
-
console.error('Invalid password for user:', this.UserId);
|
453
459
|
throw new Error('Invalid credentials.');
|
454
460
|
}
|
455
461
|
yield this.checkSystemAccess(this.UserId, system.SystemCode, dbTransaction);
|
@@ -460,15 +466,13 @@ class User extends general_1.UserBase {
|
|
460
466
|
this.Status = enum_1.UserStatus.ACTIVE;
|
461
467
|
}
|
462
468
|
else {
|
463
|
-
|
464
|
-
throw new Error('Invalid credentials.');
|
469
|
+
throw new Error('Your account has been locked. Please contact the administrator for assistance.');
|
465
470
|
}
|
466
471
|
}
|
467
472
|
}
|
468
473
|
catch (error) {
|
469
474
|
yield this.incrementFailedLoginAttemptCount(dbTransaction);
|
470
|
-
|
471
|
-
throw new Error('Invalid credentials.');
|
475
|
+
throw error;
|
472
476
|
}
|
473
477
|
const system = yield User._SystemRepository.findOne({
|
474
478
|
where: {
|
@@ -507,7 +511,6 @@ class User extends general_1.UserBase {
|
|
507
511
|
});
|
508
512
|
const sessionName = config_1.ApplicationConfig.getComponentConfigValue('sessionName');
|
509
513
|
if (!sessionName) {
|
510
|
-
console.error('Session name is not set in the configuration');
|
511
514
|
throw new Error('Session name is not set in the configuration');
|
512
515
|
}
|
513
516
|
const userSession = yield this._SessionService.retrieveUserSession(this.ObjectId, sessionName);
|
@@ -560,7 +563,6 @@ class User extends general_1.UserBase {
|
|
560
563
|
transaction: dbTransaction,
|
561
564
|
});
|
562
565
|
}
|
563
|
-
console.error('Login failed:', error);
|
564
566
|
throw error;
|
565
567
|
}
|
566
568
|
});
|
@@ -594,13 +596,13 @@ class User extends general_1.UserBase {
|
|
594
596
|
],
|
595
597
|
dbTransaction,
|
596
598
|
});
|
597
|
-
|
599
|
+
for (const usergroup of userGroups) {
|
598
600
|
const group = usergroup.Group;
|
599
601
|
const groupSystemAccess = yield User.getInheritedSystemAccess(dbTransaction, group);
|
600
602
|
for (const system of groupSystemAccess) {
|
601
603
|
if (system.SystemCode === systemCode) {
|
602
604
|
isUserHaveAccess = true;
|
603
|
-
break
|
605
|
+
break;
|
604
606
|
}
|
605
607
|
}
|
606
608
|
}
|
@@ -610,7 +612,6 @@ class User extends general_1.UserBase {
|
|
610
612
|
}
|
611
613
|
}
|
612
614
|
catch (error) {
|
613
|
-
console.error('Error checking system access:', error);
|
614
615
|
throw error;
|
615
616
|
}
|
616
617
|
});
|
@@ -1085,6 +1086,7 @@ class User extends general_1.UserBase {
|
|
1085
1086
|
LastLoginAt: null,
|
1086
1087
|
MFAEnabled: null,
|
1087
1088
|
MFAConfig: null,
|
1089
|
+
MFABypassYN: yn_enum_1.YN.No,
|
1088
1090
|
RecoveryEmail: null,
|
1089
1091
|
FailedLoginAttemptCount: 0,
|
1090
1092
|
LastFailedLoginAt: null,
|
@@ -1173,7 +1175,7 @@ class User extends general_1.UserBase {
|
|
1173
1175
|
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'Your account has been locked due to too many failed login attempts, please contact IT Support for instructions on how to unlock your account');
|
1174
1176
|
}
|
1175
1177
|
if (this.Status == enum_1.UserStatus.LOCKED) {
|
1176
|
-
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', '
|
1178
|
+
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'Your account has been locked due to too many failed login attempts, please contact IT Support for instructions on how to unlock your account.');
|
1177
1179
|
}
|
1178
1180
|
});
|
1179
1181
|
}
|
@@ -1221,7 +1223,7 @@ class User extends general_1.UserBase {
|
|
1221
1223
|
transaction: dbTransaction,
|
1222
1224
|
});
|
1223
1225
|
let systemAccesses = dataSystemAccesses;
|
1224
|
-
if (group.
|
1226
|
+
if (group.InheritParentSystemAccessYN === 'Y' && group.ParentGroupCode) {
|
1225
1227
|
const GroupCode = group.ParentGroupCode;
|
1226
1228
|
const parentGroup = yield User._GroupRepo.findByPk(GroupCode, dbTransaction);
|
1227
1229
|
const dataParentSystemAccesses = yield User.getInheritedSystemAccess(dbTransaction, parentGroup);
|
@@ -1346,13 +1348,31 @@ class User extends general_1.UserBase {
|
|
1346
1348
|
console.error('Invalid JSON string on MFAConfig:', error);
|
1347
1349
|
}
|
1348
1350
|
}
|
1349
|
-
const
|
1351
|
+
const isCurrentValid = yield speakeasy.totp.verify({
|
1350
1352
|
secret: userMFAConfig.totp.secret,
|
1351
1353
|
encoding: 'base32',
|
1352
1354
|
token: mfaToken,
|
1355
|
+
window: 0,
|
1353
1356
|
});
|
1354
|
-
if (!
|
1355
|
-
|
1357
|
+
if (!isCurrentValid) {
|
1358
|
+
const isExpired = yield speakeasy.totp.verify({
|
1359
|
+
secret: userMFAConfig.totp.secret,
|
1360
|
+
encoding: 'base32',
|
1361
|
+
token: mfaToken,
|
1362
|
+
window: 2,
|
1363
|
+
});
|
1364
|
+
if (isExpired) {
|
1365
|
+
return {
|
1366
|
+
success: false,
|
1367
|
+
reason: 'MFA token has expired. Please try again.',
|
1368
|
+
};
|
1369
|
+
}
|
1370
|
+
else {
|
1371
|
+
return {
|
1372
|
+
success: false,
|
1373
|
+
reason: 'Invalid MFA token. Check your authenticator app.',
|
1374
|
+
};
|
1375
|
+
}
|
1356
1376
|
}
|
1357
1377
|
user.MFAEnabled = 1;
|
1358
1378
|
yield user.save({ transaction: dbTransaction });
|
@@ -1365,7 +1385,7 @@ class User extends general_1.UserBase {
|
|
1365
1385
|
systemCode = config_1.ApplicationConfig.getComponentConfigValue('system-code');
|
1366
1386
|
}
|
1367
1387
|
const systemLogin = userSession.systemLogins.find((e) => e.code === systemCode);
|
1368
|
-
return `${userId}:${systemLogin.sessionId}
|
1388
|
+
return { success: true, sessionId: `${userId}:${systemLogin.sessionId}` };
|
1369
1389
|
});
|
1370
1390
|
}
|
1371
1391
|
verify2FACode(userId, mfaToken, systemCode, dbTransaction) {
|
@@ -1388,13 +1408,31 @@ class User extends general_1.UserBase {
|
|
1388
1408
|
console.error('Invalid JSON string on MFAConfig:', error);
|
1389
1409
|
}
|
1390
1410
|
}
|
1391
|
-
const
|
1411
|
+
const isCurrentValid = yield speakeasy.totp.verify({
|
1392
1412
|
secret: userMFAConfig.totp.secret,
|
1393
1413
|
encoding: 'base32',
|
1394
1414
|
token: mfaToken,
|
1415
|
+
window: 0,
|
1395
1416
|
});
|
1396
|
-
if (!
|
1397
|
-
|
1417
|
+
if (!isCurrentValid) {
|
1418
|
+
const isExpired = yield speakeasy.totp.verify({
|
1419
|
+
secret: userMFAConfig.totp.secret,
|
1420
|
+
encoding: 'base32',
|
1421
|
+
token: mfaToken,
|
1422
|
+
window: 2,
|
1423
|
+
});
|
1424
|
+
if (isExpired) {
|
1425
|
+
return {
|
1426
|
+
success: false,
|
1427
|
+
reason: 'MFA token has expired. Please try again.',
|
1428
|
+
};
|
1429
|
+
}
|
1430
|
+
else {
|
1431
|
+
return {
|
1432
|
+
success: false,
|
1433
|
+
reason: 'Invalid MFA token. Check your authenticator app.',
|
1434
|
+
};
|
1435
|
+
}
|
1398
1436
|
}
|
1399
1437
|
const sessionName = config_1.ApplicationConfig.getComponentConfigValue('sessionName');
|
1400
1438
|
if (!sessionName) {
|
@@ -1405,7 +1443,7 @@ class User extends general_1.UserBase {
|
|
1405
1443
|
systemCode = config_1.ApplicationConfig.getComponentConfigValue('system-code');
|
1406
1444
|
}
|
1407
1445
|
const systemLogin = userSession.systemLogins.find((e) => e.code === systemCode);
|
1408
|
-
return `${userId}:${systemLogin.sessionId}
|
1446
|
+
return { success: true, sessionId: `${userId}:${systemLogin.sessionId}` };
|
1409
1447
|
});
|
1410
1448
|
}
|
1411
1449
|
bypass2FA(systemCode, dbTransaction) {
|
@@ -1429,7 +1467,10 @@ class User extends general_1.UserBase {
|
|
1429
1467
|
systemCode = config_1.ApplicationConfig.getComponentConfigValue('system-code');
|
1430
1468
|
}
|
1431
1469
|
const systemLogin = userSession.systemLogins.find((e) => e.code === systemCode);
|
1432
|
-
return
|
1470
|
+
return {
|
1471
|
+
success: true,
|
1472
|
+
sessionId: `${this.UserId}:${systemLogin.sessionId}`,
|
1473
|
+
};
|
1433
1474
|
}
|
1434
1475
|
catch (error) {
|
1435
1476
|
throw error;
|
@@ -1759,6 +1800,7 @@ class User extends general_1.UserBase {
|
|
1759
1800
|
LastLoginAt: user.LastLoginAt,
|
1760
1801
|
MFAEnabled: user.MFAEnabled,
|
1761
1802
|
MFAConfig: user.MFAConfig,
|
1803
|
+
MFABypassYN: user.MFABypassYN,
|
1762
1804
|
RecoveryEmail: user.RecoveryEmail,
|
1763
1805
|
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
|
1764
1806
|
LastFailedLoginAt: user.LastFailedLoginAt,
|
@@ -1841,6 +1883,7 @@ class User extends general_1.UserBase {
|
|
1841
1883
|
LastLoginAt: user.LastLoginAt,
|
1842
1884
|
MFAEnabled: user.MFAEnabled,
|
1843
1885
|
MFAConfig: user.MFAConfig,
|
1886
|
+
MFABypassYN: user.MFABypassYN,
|
1844
1887
|
RecoveryEmail: user.RecoveryEmail,
|
1845
1888
|
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
|
1846
1889
|
LastFailedLoginAt: user.LastFailedLoginAt,
|
@@ -1886,6 +1929,7 @@ class User extends general_1.UserBase {
|
|
1886
1929
|
LastLoginAt: this.LastLoginAt,
|
1887
1930
|
MFAEnabled: this.MFAEnabled,
|
1888
1931
|
MFAConfig: this.MFAConfig,
|
1932
|
+
MFABypassYN: this.MFABypassYN,
|
1889
1933
|
RecoveryEmail: this.RecoveryEmail,
|
1890
1934
|
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
1891
1935
|
LastFailedLoginAt: this.LastFailedLoginAt,
|
@@ -1915,6 +1959,7 @@ class User extends general_1.UserBase {
|
|
1915
1959
|
LastLoginAt: this.LastLoginAt,
|
1916
1960
|
MFAEnabled: this.MFAEnabled,
|
1917
1961
|
MFAConfig: this.MFAConfig,
|
1962
|
+
MFABypassYN: this.MFABypassYN,
|
1918
1963
|
RecoveryEmail: this.RecoveryEmail,
|
1919
1964
|
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
1920
1965
|
LastFailedLoginAt: this.LastFailedLoginAt,
|
@@ -1976,6 +2021,7 @@ class User extends general_1.UserBase {
|
|
1976
2021
|
LastLoginAt: this.LastLoginAt,
|
1977
2022
|
MFAEnabled: this.MFAEnabled,
|
1978
2023
|
MFAConfig: this.MFAConfig,
|
2024
|
+
MFABypassYN: this.MFABypassYN,
|
1979
2025
|
RecoveryEmail: this.RecoveryEmail,
|
1980
2026
|
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
1981
2027
|
LastFailedLoginAt: this.LastFailedLoginAt,
|
@@ -2005,6 +2051,7 @@ class User extends general_1.UserBase {
|
|
2005
2051
|
LastLoginAt: this.LastLoginAt,
|
2006
2052
|
MFAEnabled: this.MFAEnabled,
|
2007
2053
|
MFAConfig: this.MFAConfig,
|
2054
|
+
MFABypassYN: this.MFABypassYN,
|
2008
2055
|
RecoveryEmail: this.RecoveryEmail,
|
2009
2056
|
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
2010
2057
|
LastFailedLoginAt: this.LastFailedLoginAt,
|
@@ -2131,6 +2178,297 @@ class User extends general_1.UserBase {
|
|
2131
2178
|
}
|
2132
2179
|
});
|
2133
2180
|
}
|
2181
|
+
enable2FABypass(loginUser, dbTransaction) {
|
2182
|
+
return __awaiter(this, void 0, void 0, function* () {
|
2183
|
+
try {
|
2184
|
+
if (this.MFABypassYN === yn_enum_1.YN.Yes) {
|
2185
|
+
throw new general_1.ClassError('User', 'UserErrMsg0X', 'Bypass already enabled.', 'enable2FABypass');
|
2186
|
+
}
|
2187
|
+
const systemCode = config_1.ApplicationConfig.getComponentConfigValue('system-code');
|
2188
|
+
const isPrivileged = yield loginUser.checkPrivileges(systemCode, 'MANAGE_MFA');
|
2189
|
+
if (!isPrivileged) {
|
2190
|
+
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'You do not have permission to enable MFA bypass.');
|
2191
|
+
}
|
2192
|
+
const entityValueBefore = {
|
2193
|
+
UserId: this.UserId,
|
2194
|
+
UserName: this.UserName,
|
2195
|
+
FullName: this.FullName,
|
2196
|
+
IDNo: this.IDNo,
|
2197
|
+
IDType: this.IDType,
|
2198
|
+
ContactNo: this.ContactNo,
|
2199
|
+
Email: this.Email,
|
2200
|
+
Password: this.Password,
|
2201
|
+
Status: this.Status,
|
2202
|
+
DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
|
2203
|
+
FirstLoginAt: this.FirstLoginAt,
|
2204
|
+
LastLoginAt: this.LastLoginAt,
|
2205
|
+
MFAEnabled: this.MFAEnabled,
|
2206
|
+
MFAConfig: this.MFAConfig,
|
2207
|
+
MFABypassYN: this.MFABypassYN,
|
2208
|
+
RecoveryEmail: this.RecoveryEmail,
|
2209
|
+
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
2210
|
+
LastFailedLoginAt: this.LastFailedLoginAt,
|
2211
|
+
LastPasswordChangedAt: this.LastPasswordChangedAt,
|
2212
|
+
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
|
2213
|
+
CreatedById: this.CreatedById,
|
2214
|
+
CreatedAt: this.CreatedAt,
|
2215
|
+
UpdatedById: this.UpdatedById,
|
2216
|
+
UpdatedAt: this.UpdatedAt,
|
2217
|
+
PasscodeHash: this.PasscodeHash,
|
2218
|
+
PasscodeUpdatedAt: this.PasscodeUpdatedAt,
|
2219
|
+
};
|
2220
|
+
this.MFABypassYN = yn_enum_1.YN.Yes;
|
2221
|
+
this.MFAEnabled = 0;
|
2222
|
+
this.UpdatedAt = new Date();
|
2223
|
+
this.UpdatedById = loginUser.UserId;
|
2224
|
+
yield User._Repository.update({
|
2225
|
+
MFABypassYN: this.MFABypassYN,
|
2226
|
+
MFAEnabled: this.MFAEnabled,
|
2227
|
+
UpdatedAt: this.UpdatedAt,
|
2228
|
+
UpdatedById: this.UpdatedById,
|
2229
|
+
}, {
|
2230
|
+
where: {
|
2231
|
+
UserId: this.UserId,
|
2232
|
+
},
|
2233
|
+
transaction: dbTransaction,
|
2234
|
+
});
|
2235
|
+
const entityValueAfter = {
|
2236
|
+
UserId: this.UserId,
|
2237
|
+
UserName: this.UserName,
|
2238
|
+
FullName: this.FullName,
|
2239
|
+
IDNo: this.IDNo,
|
2240
|
+
IDType: this.IDType,
|
2241
|
+
ContactNo: this.ContactNo,
|
2242
|
+
Email: this.Email,
|
2243
|
+
Password: this.Password,
|
2244
|
+
Status: this.Status,
|
2245
|
+
DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
|
2246
|
+
FirstLoginAt: this.FirstLoginAt,
|
2247
|
+
LastLoginAt: this.LastLoginAt,
|
2248
|
+
MFAEnabled: this.MFAEnabled,
|
2249
|
+
MFAConfig: this.MFAConfig,
|
2250
|
+
MFABypassYN: this.MFABypassYN,
|
2251
|
+
RecoveryEmail: this.RecoveryEmail,
|
2252
|
+
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
2253
|
+
LastFailedLoginAt: this.LastFailedLoginAt,
|
2254
|
+
LastPasswordChangedAt: this.LastPasswordChangedAt,
|
2255
|
+
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
|
2256
|
+
CreatedById: this.CreatedById,
|
2257
|
+
CreatedAt: this.CreatedAt,
|
2258
|
+
UpdatedById: this.UpdatedById,
|
2259
|
+
UpdatedAt: this.UpdatedAt,
|
2260
|
+
PasscodeHash: this.PasscodeHash,
|
2261
|
+
PasscodeUpdatedAt: this.PasscodeUpdatedAt,
|
2262
|
+
};
|
2263
|
+
const activity = new activity_history_1.Activity();
|
2264
|
+
activity.ActivityId = activity.createId();
|
2265
|
+
activity.Action = activity_history_1.ActionEnum.UPDATE;
|
2266
|
+
activity.Description = `Enable 2FA Bypass For User ${this.Email}`;
|
2267
|
+
activity.EntityType = this.ObjectType;
|
2268
|
+
activity.EntityId = this.UserId.toString();
|
2269
|
+
activity.EntityValueBefore = JSON.stringify(entityValueBefore);
|
2270
|
+
activity.EntityValueAfter = JSON.stringify(entityValueAfter);
|
2271
|
+
yield activity.create(loginUser.ObjectId, dbTransaction);
|
2272
|
+
}
|
2273
|
+
catch (error) {
|
2274
|
+
throw error;
|
2275
|
+
}
|
2276
|
+
});
|
2277
|
+
}
|
2278
|
+
disable2FABypass(loginUser, dbTransaction) {
|
2279
|
+
return __awaiter(this, void 0, void 0, function* () {
|
2280
|
+
try {
|
2281
|
+
if (this.MFABypassYN === yn_enum_1.YN.No) {
|
2282
|
+
throw new general_1.ClassError('User', 'UserErrMsg0X', 'Bypass already disabled.', 'disable2FABypass');
|
2283
|
+
}
|
2284
|
+
const systemCode = config_1.ApplicationConfig.getComponentConfigValue('system-code');
|
2285
|
+
const isPrivileged = yield loginUser.checkPrivileges(systemCode, 'MANAGE_MFA');
|
2286
|
+
if (!isPrivileged) {
|
2287
|
+
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'You do not have permission to enable MFA bypass.');
|
2288
|
+
}
|
2289
|
+
const entityValueBefore = {
|
2290
|
+
UserId: this.UserId,
|
2291
|
+
UserName: this.UserName,
|
2292
|
+
FullName: this.FullName,
|
2293
|
+
IDNo: this.IDNo,
|
2294
|
+
IDType: this.IDType,
|
2295
|
+
ContactNo: this.ContactNo,
|
2296
|
+
Email: this.Email,
|
2297
|
+
Password: this.Password,
|
2298
|
+
Status: this.Status,
|
2299
|
+
DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
|
2300
|
+
FirstLoginAt: this.FirstLoginAt,
|
2301
|
+
LastLoginAt: this.LastLoginAt,
|
2302
|
+
MFAEnabled: this.MFAEnabled,
|
2303
|
+
MFAConfig: this.MFAConfig,
|
2304
|
+
MFABypassYN: this.MFABypassYN,
|
2305
|
+
RecoveryEmail: this.RecoveryEmail,
|
2306
|
+
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
2307
|
+
LastFailedLoginAt: this.LastFailedLoginAt,
|
2308
|
+
LastPasswordChangedAt: this.LastPasswordChangedAt,
|
2309
|
+
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
|
2310
|
+
CreatedById: this.CreatedById,
|
2311
|
+
CreatedAt: this.CreatedAt,
|
2312
|
+
UpdatedById: this.UpdatedById,
|
2313
|
+
UpdatedAt: this.UpdatedAt,
|
2314
|
+
PasscodeHash: this.PasscodeHash,
|
2315
|
+
PasscodeUpdatedAt: this.PasscodeUpdatedAt,
|
2316
|
+
};
|
2317
|
+
this.MFABypassYN = yn_enum_1.YN.No;
|
2318
|
+
this.MFAEnabled = 0;
|
2319
|
+
this.UpdatedAt = new Date();
|
2320
|
+
this.UpdatedById = loginUser.UserId;
|
2321
|
+
yield User._Repository.update({
|
2322
|
+
MFABypassYN: this.MFABypassYN,
|
2323
|
+
MFAEnabled: this.MFAEnabled,
|
2324
|
+
UpdatedAt: this.UpdatedAt,
|
2325
|
+
UpdatedById: this.UpdatedById,
|
2326
|
+
}, {
|
2327
|
+
where: {
|
2328
|
+
UserId: this.UserId,
|
2329
|
+
},
|
2330
|
+
transaction: dbTransaction,
|
2331
|
+
});
|
2332
|
+
const entityValueAfter = {
|
2333
|
+
UserId: this.UserId,
|
2334
|
+
UserName: this.UserName,
|
2335
|
+
FullName: this.FullName,
|
2336
|
+
IDNo: this.IDNo,
|
2337
|
+
IDType: this.IDType,
|
2338
|
+
ContactNo: this.ContactNo,
|
2339
|
+
Email: this.Email,
|
2340
|
+
Password: this.Password,
|
2341
|
+
Status: this.Status,
|
2342
|
+
DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
|
2343
|
+
FirstLoginAt: this.FirstLoginAt,
|
2344
|
+
LastLoginAt: this.LastLoginAt,
|
2345
|
+
MFAEnabled: this.MFAEnabled,
|
2346
|
+
MFAConfig: this.MFAConfig,
|
2347
|
+
MFABypassYN: this.MFABypassYN,
|
2348
|
+
RecoveryEmail: this.RecoveryEmail,
|
2349
|
+
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
2350
|
+
LastFailedLoginAt: this.LastFailedLoginAt,
|
2351
|
+
LastPasswordChangedAt: this.LastPasswordChangedAt,
|
2352
|
+
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
|
2353
|
+
CreatedById: this.CreatedById,
|
2354
|
+
CreatedAt: this.CreatedAt,
|
2355
|
+
UpdatedById: this.UpdatedById,
|
2356
|
+
UpdatedAt: this.UpdatedAt,
|
2357
|
+
PasscodeHash: this.PasscodeHash,
|
2358
|
+
PasscodeUpdatedAt: this.PasscodeUpdatedAt,
|
2359
|
+
};
|
2360
|
+
const activity = new activity_history_1.Activity();
|
2361
|
+
activity.ActivityId = activity.createId();
|
2362
|
+
activity.Action = activity_history_1.ActionEnum.UPDATE;
|
2363
|
+
activity.Description = `Disable 2FA Bypass For User ${this.Email}`;
|
2364
|
+
activity.EntityType = this.ObjectType;
|
2365
|
+
activity.EntityId = this.UserId.toString();
|
2366
|
+
activity.EntityValueBefore = JSON.stringify(entityValueBefore);
|
2367
|
+
activity.EntityValueAfter = JSON.stringify(entityValueAfter);
|
2368
|
+
yield activity.create(loginUser.ObjectId, dbTransaction);
|
2369
|
+
}
|
2370
|
+
catch (error) {
|
2371
|
+
throw error;
|
2372
|
+
}
|
2373
|
+
});
|
2374
|
+
}
|
2375
|
+
reset2FA(loginUser, dbTransaction) {
|
2376
|
+
return __awaiter(this, void 0, void 0, function* () {
|
2377
|
+
try {
|
2378
|
+
if (this.MFAEnabled === 0) {
|
2379
|
+
throw new general_1.ClassError('User', 'UserErrMsg0X', 'User not yet setup 2FA.', 'reset2FA');
|
2380
|
+
}
|
2381
|
+
const systemCode = config_1.ApplicationConfig.getComponentConfigValue('system-code');
|
2382
|
+
const isPrivileged = yield loginUser.checkPrivileges(systemCode, 'MANAGE_MFA');
|
2383
|
+
if (!isPrivileged) {
|
2384
|
+
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'You do not have permission to reset 2FA.');
|
2385
|
+
}
|
2386
|
+
const entityValueBefore = {
|
2387
|
+
UserId: this.UserId,
|
2388
|
+
UserName: this.UserName,
|
2389
|
+
FullName: this.FullName,
|
2390
|
+
IDNo: this.IDNo,
|
2391
|
+
IDType: this.IDType,
|
2392
|
+
ContactNo: this.ContactNo,
|
2393
|
+
Email: this.Email,
|
2394
|
+
Password: this.Password,
|
2395
|
+
Status: this.Status,
|
2396
|
+
DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
|
2397
|
+
FirstLoginAt: this.FirstLoginAt,
|
2398
|
+
LastLoginAt: this.LastLoginAt,
|
2399
|
+
MFAEnabled: this.MFAEnabled,
|
2400
|
+
MFAConfig: this.MFAConfig,
|
2401
|
+
MFABypassYN: this.MFABypassYN,
|
2402
|
+
RecoveryEmail: this.RecoveryEmail,
|
2403
|
+
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
2404
|
+
LastFailedLoginAt: this.LastFailedLoginAt,
|
2405
|
+
LastPasswordChangedAt: this.LastPasswordChangedAt,
|
2406
|
+
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
|
2407
|
+
CreatedById: this.CreatedById,
|
2408
|
+
CreatedAt: this.CreatedAt,
|
2409
|
+
UpdatedById: this.UpdatedById,
|
2410
|
+
UpdatedAt: this.UpdatedAt,
|
2411
|
+
PasscodeHash: this.PasscodeHash,
|
2412
|
+
PasscodeUpdatedAt: this.PasscodeUpdatedAt,
|
2413
|
+
};
|
2414
|
+
this.MFAEnabled = 0;
|
2415
|
+
this.MFABypassYN = yn_enum_1.YN.No;
|
2416
|
+
this.UpdatedAt = new Date();
|
2417
|
+
this.UpdatedById = loginUser.UserId;
|
2418
|
+
yield User._Repository.update({
|
2419
|
+
MFAEnabled: this.MFAEnabled,
|
2420
|
+
MFABypassYN: this.MFABypassYN,
|
2421
|
+
UpdatedAt: this.UpdatedAt,
|
2422
|
+
UpdatedById: this.UpdatedById,
|
2423
|
+
}, {
|
2424
|
+
where: {
|
2425
|
+
UserId: this.UserId,
|
2426
|
+
},
|
2427
|
+
transaction: dbTransaction,
|
2428
|
+
});
|
2429
|
+
const entityValueAfter = {
|
2430
|
+
UserId: this.UserId,
|
2431
|
+
UserName: this.UserName,
|
2432
|
+
FullName: this.FullName,
|
2433
|
+
IDNo: this.IDNo,
|
2434
|
+
IDType: this.IDType,
|
2435
|
+
ContactNo: this.ContactNo,
|
2436
|
+
Email: this.Email,
|
2437
|
+
Password: this.Password,
|
2438
|
+
Status: this.Status,
|
2439
|
+
DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
|
2440
|
+
FirstLoginAt: this.FirstLoginAt,
|
2441
|
+
LastLoginAt: this.LastLoginAt,
|
2442
|
+
MFAEnabled: this.MFAEnabled,
|
2443
|
+
MFAConfig: this.MFAConfig,
|
2444
|
+
MFABypassYN: this.MFABypassYN,
|
2445
|
+
RecoveryEmail: this.RecoveryEmail,
|
2446
|
+
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
|
2447
|
+
LastFailedLoginAt: this.LastFailedLoginAt,
|
2448
|
+
LastPasswordChangedAt: this.LastPasswordChangedAt,
|
2449
|
+
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
|
2450
|
+
CreatedById: this.CreatedById,
|
2451
|
+
CreatedAt: this.CreatedAt,
|
2452
|
+
UpdatedById: this.UpdatedById,
|
2453
|
+
UpdatedAt: this.UpdatedAt,
|
2454
|
+
PasscodeHash: this.PasscodeHash,
|
2455
|
+
PasscodeUpdatedAt: this.PasscodeUpdatedAt,
|
2456
|
+
};
|
2457
|
+
const activity = new activity_history_1.Activity();
|
2458
|
+
activity.ActivityId = activity.createId();
|
2459
|
+
activity.Action = activity_history_1.ActionEnum.UPDATE;
|
2460
|
+
activity.Description = `Reset 2FA for User ${this.Email}`;
|
2461
|
+
activity.EntityType = this.ObjectType;
|
2462
|
+
activity.EntityId = this.UserId.toString();
|
2463
|
+
activity.EntityValueBefore = JSON.stringify(entityValueBefore);
|
2464
|
+
activity.EntityValueAfter = JSON.stringify(entityValueAfter);
|
2465
|
+
yield activity.create(loginUser.ObjectId, dbTransaction);
|
2466
|
+
}
|
2467
|
+
catch (error) {
|
2468
|
+
throw error;
|
2469
|
+
}
|
2470
|
+
});
|
2471
|
+
}
|
2134
2472
|
}
|
2135
2473
|
exports.User = User;
|
2136
2474
|
User._Repository = new user_repository_1.UserRepository();
|